1 /** @file
2 
3   Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
4   SPDX-License-Identifier: BSD-2-Clause-Patent
5 
6 **/
7 
8 #include "DmaProtection.h"
9 
10 /**
11   Return the index of PCI data.
12 
13   @param[in]  VtdIndex          The index used to identify a VTd engine.
14   @param[in]  Segment           The Segment used to identify a VTd engine.
15   @param[in]  SourceId          The SourceId used to identify a VTd engine and table entry.
16 
17   @return The index of the PCI data.
18   @retval (UINTN)-1  The PCI data is not found.
19 **/
20 UINTN
GetPciDataIndex(IN UINTN VtdIndex,IN UINT16 Segment,IN VTD_SOURCE_ID SourceId)21 GetPciDataIndex (
22   IN UINTN          VtdIndex,
23   IN UINT16         Segment,
24   IN VTD_SOURCE_ID  SourceId
25   )
26 {
27   UINTN          Index;
28   VTD_SOURCE_ID  *PciSourceId;
29 
30   if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
31     return (UINTN)-1;
32   }
33 
34   for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
35     PciSourceId = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId;
36     if ((PciSourceId->Bits.Bus == SourceId.Bits.Bus) &&
37         (PciSourceId->Bits.Device == SourceId.Bits.Device) &&
38         (PciSourceId->Bits.Function == SourceId.Bits.Function) ) {
39       return Index;
40     }
41   }
42 
43   return (UINTN)-1;
44 }
45 
46 /**
47   Register PCI device to VTd engine.
48 
49   @param[in]  VtdIndex              The index of VTd engine.
50   @param[in]  Segment               The segment of the source.
51   @param[in]  SourceId              The SourceId of the source.
52   @param[in]  DeviceType            The DMAR device scope type.
53   @param[in]  CheckExist            TRUE: ERROR will be returned if the PCI device is already registered.
54                                     FALSE: SUCCESS will be returned if the PCI device is registered.
55 
56   @retval EFI_SUCCESS           The PCI device is registered.
57   @retval EFI_OUT_OF_RESOURCES  No enough resource to register a new PCI device.
58   @retval EFI_ALREADY_STARTED   The device is already registered.
59 **/
60 EFI_STATUS
RegisterPciDevice(IN UINTN VtdIndex,IN UINT16 Segment,IN VTD_SOURCE_ID SourceId,IN UINT8 DeviceType,IN BOOLEAN CheckExist)61 RegisterPciDevice (
62   IN UINTN          VtdIndex,
63   IN UINT16         Segment,
64   IN VTD_SOURCE_ID  SourceId,
65   IN UINT8          DeviceType,
66   IN BOOLEAN        CheckExist
67   )
68 {
69   PCI_DEVICE_INFORMATION           *PciDeviceInfo;
70   VTD_SOURCE_ID                    *PciSourceId;
71   UINTN                            PciDataIndex;
72   UINTN                            Index;
73   PCI_DEVICE_DATA                  *NewPciDeviceData;
74   EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId;
75 
76   PciDeviceInfo = &mVtdUnitInformation[VtdIndex].PciDeviceInfo;
77 
78   if (PciDeviceInfo->IncludeAllFlag) {
79     //
80     // Do not register device in other VTD Unit
81     //
82     for (Index = 0; Index < VtdIndex; Index++) {
83       PciDataIndex = GetPciDataIndex (Index, Segment, SourceId);
84       if (PciDataIndex != (UINTN)-1) {
85         DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered by Other Vtd(%d)\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, Index));
86         return EFI_SUCCESS;
87       }
88     }
89   }
90 
91   PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
92   if (PciDataIndex == (UINTN)-1) {
93     //
94     // Register new
95     //
96 
97     if (PciDeviceInfo->PciDeviceDataNumber >= PciDeviceInfo->PciDeviceDataMaxNumber) {
98       //
99       // Reallocate
100       //
101       NewPciDeviceData = AllocateZeroPool (sizeof(*NewPciDeviceData) * (PciDeviceInfo->PciDeviceDataMaxNumber + MAX_VTD_PCI_DATA_NUMBER));
102       if (NewPciDeviceData == NULL) {
103         return EFI_OUT_OF_RESOURCES;
104       }
105       PciDeviceInfo->PciDeviceDataMaxNumber += MAX_VTD_PCI_DATA_NUMBER;
106       if (PciDeviceInfo->PciDeviceData != NULL) {
107         CopyMem (NewPciDeviceData, PciDeviceInfo->PciDeviceData, sizeof(*NewPciDeviceData) * PciDeviceInfo->PciDeviceDataNumber);
108         FreePool (PciDeviceInfo->PciDeviceData);
109       }
110       PciDeviceInfo->PciDeviceData = NewPciDeviceData;
111     }
112 
113     ASSERT (PciDeviceInfo->PciDeviceDataNumber < PciDeviceInfo->PciDeviceDataMaxNumber);
114 
115     PciSourceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciSourceId;
116     PciSourceId->Bits.Bus = SourceId.Bits.Bus;
117     PciSourceId->Bits.Device = SourceId.Bits.Device;
118     PciSourceId->Bits.Function = SourceId.Bits.Function;
119 
120     DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
121 
122     PciDeviceId = &PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].PciDeviceId;
123     if ((DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) ||
124         (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
125       PciDeviceId->VendorId   = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_VENDOR_ID_OFFSET));
126       PciDeviceId->DeviceId   = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_DEVICE_ID_OFFSET));
127       PciDeviceId->RevisionId = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_REVISION_ID_OFFSET));
128 
129       DEBUG ((DEBUG_INFO, " (%04x:%04x:%02x", PciDeviceId->VendorId, PciDeviceId->DeviceId, PciDeviceId->RevisionId));
130 
131       if (DeviceType == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) {
132         PciDeviceId->SubsystemVendorId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_VENDOR_ID_OFFSET));
133         PciDeviceId->SubsystemDeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function, PCI_SUBSYSTEM_ID_OFFSET));
134         DEBUG ((DEBUG_INFO, ":%04x:%04x", PciDeviceId->SubsystemVendorId, PciDeviceId->SubsystemDeviceId));
135       }
136       DEBUG ((DEBUG_INFO, ")"));
137     }
138 
139     PciDeviceInfo->PciDeviceData[PciDeviceInfo->PciDeviceDataNumber].DeviceType = DeviceType;
140 
141     if ((DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT) &&
142         (DeviceType != EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE)) {
143       DEBUG ((DEBUG_INFO, " (*)"));
144     }
145     DEBUG ((DEBUG_INFO, "\n"));
146 
147     PciDeviceInfo->PciDeviceDataNumber++;
148   } else {
149     if (CheckExist) {
150       DEBUG ((DEBUG_INFO, "  RegisterPciDevice: PCI S%04x B%02x D%02x F%02x already registered\n", Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
151       return EFI_ALREADY_STARTED;
152     }
153   }
154 
155   return EFI_SUCCESS;
156 }
157 
158 /**
159   The scan bus callback function to register PCI device.
160 
161   @param[in]  Context               The context of the callback.
162   @param[in]  Segment               The segment of the source.
163   @param[in]  Bus                   The bus of the source.
164   @param[in]  Device                The device of the source.
165   @param[in]  Function              The function of the source.
166 
167   @retval EFI_SUCCESS           The PCI device is registered.
168 **/
169 EFI_STATUS
170 EFIAPI
ScanBusCallbackRegisterPciDevice(IN VOID * Context,IN UINT16 Segment,IN UINT8 Bus,IN UINT8 Device,IN UINT8 Function)171 ScanBusCallbackRegisterPciDevice (
172   IN VOID           *Context,
173   IN UINT16         Segment,
174   IN UINT8          Bus,
175   IN UINT8          Device,
176   IN UINT8          Function
177   )
178 {
179   VTD_SOURCE_ID           SourceId;
180   UINTN                   VtdIndex;
181   UINT8                   BaseClass;
182   UINT8                   SubClass;
183   UINT8                   DeviceType;
184   EFI_STATUS              Status;
185 
186   VtdIndex = (UINTN)Context;
187   SourceId.Bits.Bus = Bus;
188   SourceId.Bits.Device = Device;
189   SourceId.Bits.Function = Function;
190 
191   DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_ENDPOINT;
192   BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
193   if (BaseClass == PCI_CLASS_BRIDGE) {
194     SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
195     if (SubClass == PCI_CLASS_BRIDGE_P2P) {
196       DeviceType = EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE;
197     }
198   }
199 
200   Status = RegisterPciDevice (VtdIndex, Segment, SourceId, DeviceType, FALSE);
201   return Status;
202 }
203 
204 /**
205   Scan PCI bus and invoke callback function for each PCI devices under the bus.
206 
207   @param[in]  Context               The context of the callback function.
208   @param[in]  Segment               The segment of the source.
209   @param[in]  Bus                   The bus of the source.
210   @param[in]  Callback              The callback function in PCI scan.
211 
212   @retval EFI_SUCCESS           The PCI devices under the bus are scaned.
213 **/
214 EFI_STATUS
ScanPciBus(IN VOID * Context,IN UINT16 Segment,IN UINT8 Bus,IN SCAN_BUS_FUNC_CALLBACK_FUNC Callback)215 ScanPciBus (
216   IN VOID                         *Context,
217   IN UINT16                       Segment,
218   IN UINT8                        Bus,
219   IN SCAN_BUS_FUNC_CALLBACK_FUNC  Callback
220   )
221 {
222   UINT8                   Device;
223   UINT8                   Function;
224   UINT8                   SecondaryBusNumber;
225   UINT8                   HeaderType;
226   UINT8                   BaseClass;
227   UINT8                   SubClass;
228   UINT16                  VendorID;
229   UINT16                  DeviceID;
230   EFI_STATUS              Status;
231 
232   // Scan the PCI bus for devices
233   for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
234     for (Function = 0; Function <= PCI_MAX_FUNC; Function++) {
235       VendorID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_VENDOR_ID_OFFSET));
236       DeviceID  = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_DEVICE_ID_OFFSET));
237       if (VendorID == 0xFFFF && DeviceID == 0xFFFF) {
238         if (Function == 0) {
239           //
240           // If function 0 is not implemented, do not scan other functions.
241           //
242           break;
243         }
244         continue;
245       }
246 
247       Status = Callback (Context, Segment, Bus, Device, Function);
248       if (EFI_ERROR (Status)) {
249         return Status;
250       }
251 
252       BaseClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 2));
253       if (BaseClass == PCI_CLASS_BRIDGE) {
254         SubClass = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_CLASSCODE_OFFSET + 1));
255         if (SubClass == PCI_CLASS_BRIDGE_P2P) {
256           SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
257           DEBUG ((DEBUG_INFO,"  ScanPciBus: PCI bridge S%04x B%02x D%02x F%02x (SecondBus:%02x)\n", Segment, Bus, Device, Function, SecondaryBusNumber));
258           if (SecondaryBusNumber != 0) {
259             Status = ScanPciBus (Context, Segment, SecondaryBusNumber, Callback);
260             if (EFI_ERROR (Status)) {
261               return Status;
262             }
263           }
264         }
265       }
266 
267       if (Function == 0) {
268         HeaderType = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(Segment, Bus, Device, 0, PCI_HEADER_TYPE_OFFSET));
269         if ((HeaderType & HEADER_TYPE_MULTI_FUNCTION) == 0x00) {
270           //
271           // It is not a multi-function device, do not scan other functions.
272           //
273           break;
274         }
275       }
276     }
277   }
278 
279   return EFI_SUCCESS;
280 }
281 
282 /**
283   Dump the PCI device information managed by this VTd engine.
284 
285   @param[in]  VtdIndex              The index of VTd engine.
286 **/
287 VOID
DumpPciDeviceInfo(IN UINTN VtdIndex)288 DumpPciDeviceInfo (
289   IN UINTN  VtdIndex
290   )
291 {
292   UINTN  Index;
293 
294   DEBUG ((DEBUG_INFO,"PCI Device Information (Number 0x%x, IncludeAll - %d):\n",
295     mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber,
296     mVtdUnitInformation[VtdIndex].PciDeviceInfo.IncludeAllFlag
297     ));
298   for (Index = 0; Index < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; Index++) {
299     DEBUG ((DEBUG_INFO,"  S%04x B%02x D%02x F%02x\n",
300       mVtdUnitInformation[VtdIndex].Segment,
301       mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Bus,
302       mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Device,
303       mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[Index].PciSourceId.Bits.Function
304       ));
305   }
306 }
307 
308 /**
309   Find the VTd index by the Segment and SourceId.
310 
311   @param[in]  Segment               The segment of the source.
312   @param[in]  SourceId              The SourceId of the source.
313   @param[out] ExtContextEntry       The ExtContextEntry of the source.
314   @param[out] ContextEntry          The ContextEntry of the source.
315 
316   @return The index of the VTd engine.
317   @retval (UINTN)-1  The VTd engine is not found.
318 **/
319 UINTN
FindVtdIndexByPciDevice(IN UINT16 Segment,IN VTD_SOURCE_ID SourceId,OUT VTD_EXT_CONTEXT_ENTRY ** ExtContextEntry,OUT VTD_CONTEXT_ENTRY ** ContextEntry)320 FindVtdIndexByPciDevice (
321   IN  UINT16                  Segment,
322   IN  VTD_SOURCE_ID           SourceId,
323   OUT VTD_EXT_CONTEXT_ENTRY   **ExtContextEntry,
324   OUT VTD_CONTEXT_ENTRY       **ContextEntry
325   )
326 {
327   UINTN                   VtdIndex;
328   VTD_ROOT_ENTRY          *RootEntry;
329   VTD_CONTEXT_ENTRY       *ContextEntryTable;
330   VTD_CONTEXT_ENTRY       *ThisContextEntry;
331   VTD_EXT_ROOT_ENTRY      *ExtRootEntry;
332   VTD_EXT_CONTEXT_ENTRY   *ExtContextEntryTable;
333   VTD_EXT_CONTEXT_ENTRY   *ThisExtContextEntry;
334   UINTN                   PciDataIndex;
335 
336   for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
337     if (Segment != mVtdUnitInformation[VtdIndex].Segment) {
338       continue;
339     }
340 
341     PciDataIndex = GetPciDataIndex (VtdIndex, Segment, SourceId);
342     if (PciDataIndex == (UINTN)-1) {
343       continue;
344     }
345 
346 //    DEBUG ((DEBUG_INFO,"FindVtdIndex(0x%x) for S%04x B%02x D%02x F%02x\n", VtdIndex, Segment, SourceId.Bits.Bus, SourceId.Bits.Device, SourceId.Bits.Function));
347 
348     if (mVtdUnitInformation[VtdIndex].ExtRootEntryTable != 0) {
349       ExtRootEntry = &mVtdUnitInformation[VtdIndex].ExtRootEntryTable[SourceId.Index.RootIndex];
350       ExtContextEntryTable = (VTD_EXT_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(ExtRootEntry->Bits.LowerContextTablePointerLo, ExtRootEntry->Bits.LowerContextTablePointerHi) ;
351       ThisExtContextEntry  = &ExtContextEntryTable[SourceId.Index.ContextIndex];
352       if (ThisExtContextEntry->Bits.AddressWidth == 0) {
353         continue;
354       }
355       *ExtContextEntry = ThisExtContextEntry;
356       *ContextEntry    = NULL;
357     } else {
358       RootEntry = &mVtdUnitInformation[VtdIndex].RootEntryTable[SourceId.Index.RootIndex];
359       ContextEntryTable = (VTD_CONTEXT_ENTRY *)(UINTN)VTD_64BITS_ADDRESS(RootEntry->Bits.ContextTablePointerLo, RootEntry->Bits.ContextTablePointerHi) ;
360       ThisContextEntry  = &ContextEntryTable[SourceId.Index.ContextIndex];
361       if (ThisContextEntry->Bits.AddressWidth == 0) {
362         continue;
363       }
364       *ExtContextEntry = NULL;
365       *ContextEntry    = ThisContextEntry;
366     }
367 
368     return VtdIndex;
369   }
370 
371   return (UINTN)-1;
372 }
373 
374