1 /** @file
2 
3   Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
4 
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7 **/
8 
9 #include <PiPei.h>
10 #include <Library/BaseLib.h>
11 #include <Library/BaseMemoryLib.h>
12 #include <Library/IoLib.h>
13 #include <Library/DebugLib.h>
14 #include <Library/MemoryAllocationLib.h>
15 #include <Library/CacheMaintenanceLib.h>
16 #include <Library/PeiServicesLib.h>
17 #include <IndustryStandard/Vtd.h>
18 #include <Ppi/VtdInfo.h>
19 #include <Ppi/VtdNullRootEntryTable.h>
20 #include <Ppi/IoMmu.h>
21 #include "IntelVTdDmarPei.h"
22 
23 /**
24   Flush VTD page table and context table memory.
25 
26   This action is to make sure the IOMMU engine can get final data in memory.
27 
28   @param[in]  VTdUnitInfo       The VTd engine unit information.
29   @param[in]  Base              The base address of memory to be flushed.
30   @param[in]  Size              The size of memory in bytes to be flushed.
31 **/
32 VOID
FlushPageTableMemory(IN VTD_UNIT_INFO * VTdUnitInfo,IN UINTN Base,IN UINTN Size)33 FlushPageTableMemory (
34   IN VTD_UNIT_INFO              *VTdUnitInfo,
35   IN UINTN                      Base,
36   IN UINTN                      Size
37   )
38 {
39   if (VTdUnitInfo->ECapReg.Bits.C == 0) {
40     WriteBackDataCacheRange ((VOID *) Base, Size);
41   }
42 }
43 
44 /**
45   Flush VTd engine write buffer.
46 
47   @param[in]  VtdUnitBaseAddress        The base address of the VTd engine.
48 **/
49 VOID
FlushWriteBuffer(IN UINTN VtdUnitBaseAddress)50 FlushWriteBuffer (
51   IN UINTN                      VtdUnitBaseAddress
52   )
53 {
54   UINT32                        Reg32;
55   VTD_CAP_REG                   CapReg;
56 
57   CapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_CAP_REG);
58 
59   if (CapReg.Bits.RWBF != 0) {
60     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
61     MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Reg32 | B_GMCD_REG_WBF);
62     do {
63       Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
64     } while ((Reg32 & B_GSTS_REG_WBF) != 0);
65   }
66 }
67 
68 /**
69   Invalidate VTd context cache.
70 
71   @param[in]  VtdUnitBaseAddress        The base address of the VTd engine.
72 **/
73 EFI_STATUS
InvalidateContextCache(IN UINTN VtdUnitBaseAddress)74 InvalidateContextCache (
75   IN UINTN                      VtdUnitBaseAddress
76   )
77 {
78   UINT64                        Reg64;
79 
80   Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
81   if ((Reg64 & B_CCMD_REG_ICC) != 0) {
82     DEBUG ((DEBUG_ERROR,"ERROR: InvalidateContextCache: B_CCMD_REG_ICC is set for VTD(%x)\n",VtdUnitBaseAddress));
83     return EFI_DEVICE_ERROR;
84   }
85 
86   Reg64 &= ((~B_CCMD_REG_ICC) & (~B_CCMD_REG_CIRG_MASK));
87   Reg64 |= (B_CCMD_REG_ICC | V_CCMD_REG_CIRG_GLOBAL);
88   MmioWrite64 (VtdUnitBaseAddress + R_CCMD_REG, Reg64);
89 
90   do {
91     Reg64 = MmioRead64 (VtdUnitBaseAddress + R_CCMD_REG);
92   } while ((Reg64 & B_CCMD_REG_ICC) != 0);
93 
94   return EFI_SUCCESS;
95 }
96 
97 /**
98   Invalidate VTd IOTLB.
99 
100   @param[in]  VtdUnitBaseAddress        The base address of the VTd engine.
101 **/
102 EFI_STATUS
InvalidateIOTLB(IN UINTN VtdUnitBaseAddress)103 InvalidateIOTLB (
104   IN UINTN                      VtdUnitBaseAddress
105   )
106 {
107   UINT64                        Reg64;
108   VTD_ECAP_REG                  ECapReg;
109 
110   ECapReg.Uint64 = MmioRead64 (VtdUnitBaseAddress + R_ECAP_REG);
111 
112   Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
113   if ((Reg64 & B_IOTLB_REG_IVT) != 0) {
114     DEBUG ((DEBUG_ERROR, "ERROR: InvalidateIOTLB: B_IOTLB_REG_IVT is set for VTD(%x)\n", VtdUnitBaseAddress));
115     return EFI_DEVICE_ERROR;
116   }
117 
118   Reg64 &= ((~B_IOTLB_REG_IVT) & (~B_IOTLB_REG_IIRG_MASK));
119   Reg64 |= (B_IOTLB_REG_IVT | V_IOTLB_REG_IIRG_GLOBAL);
120   MmioWrite64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG, Reg64);
121 
122   do {
123     Reg64 = MmioRead64 (VtdUnitBaseAddress + (ECapReg.Bits.IRO * 16) + R_IOTLB_REG);
124   } while ((Reg64 & B_IOTLB_REG_IVT) != 0);
125 
126   return EFI_SUCCESS;
127 }
128 
129 /**
130   Enable DMAR translation.
131 
132   @param[in]  VtdUnitBaseAddress        The base address of the VTd engine.
133   @param[in]  RootEntryTable            The address of the VTd RootEntryTable.
134 
135   @retval EFI_SUCCESS           DMAR translation is enabled.
136   @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
137 **/
138 EFI_STATUS
EnableDmar(IN UINTN VtdUnitBaseAddress,IN UINTN RootEntryTable)139 EnableDmar (
140   IN UINTN                      VtdUnitBaseAddress,
141   IN UINTN                      RootEntryTable
142   )
143 {
144   UINT32                        Reg32;
145 
146   DEBUG ((DEBUG_INFO, ">>>>>>EnableDmar() for engine [%x] \n", VtdUnitBaseAddress));
147 
148   DEBUG ((DEBUG_INFO, "RootEntryTable 0x%x \n", RootEntryTable));
149   MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, (UINT64) (UINTN) RootEntryTable);
150 
151   MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_SRTP);
152 
153   DEBUG ((DEBUG_INFO, "EnableDmar: waiting for RTPS bit to be set... \n"));
154   do {
155     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
156   } while((Reg32 & B_GSTS_REG_RTPS) == 0);
157 
158   //
159   // Init DMAr Fault Event and Data registers
160   //
161   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_FEDATA_REG);
162 
163   //
164   // Write Buffer Flush before invalidation
165   //
166   FlushWriteBuffer (VtdUnitBaseAddress);
167 
168   //
169   // Invalidate the context cache
170   //
171   InvalidateContextCache (VtdUnitBaseAddress);
172 
173   //
174   // Invalidate the IOTLB cache
175   //
176   InvalidateIOTLB (VtdUnitBaseAddress);
177 
178   //
179   // Enable VTd
180   //
181   MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, B_GMCD_REG_TE);
182   DEBUG ((DEBUG_INFO, "EnableDmar: Waiting B_GSTS_REG_TE ...\n"));
183   do {
184     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
185   } while ((Reg32 & B_GSTS_REG_TE) == 0);
186 
187   DEBUG ((DEBUG_INFO, "VTD () enabled!<<<<<<\n"));
188 
189   return EFI_SUCCESS;
190 }
191 
192 /**
193   Disable DMAR translation.
194 
195   @param[in] VtdUnitBaseAddress         The base address of the VTd engine.
196 
197   @retval EFI_SUCCESS           DMAR translation is disabled.
198   @retval EFI_DEVICE_ERROR      DMAR translation is not disabled.
199 **/
200 EFI_STATUS
DisableDmar(IN UINTN VtdUnitBaseAddress)201 DisableDmar (
202   IN UINTN                      VtdUnitBaseAddress
203   )
204 {
205   UINT32                        Reg32;
206   UINT32                        Status;
207   UINT32                        Command;
208 
209   DEBUG ((DEBUG_INFO, ">>>>>>DisableDmar() for engine [%x] \n", VtdUnitBaseAddress));
210 
211   //
212   // Write Buffer Flush before invalidation
213   //
214   FlushWriteBuffer (VtdUnitBaseAddress);
215 
216   //
217   // Disable Dmar
218   //
219   //
220   // Set TE (Translation Enable: BIT31) of Global command register to zero
221   //
222   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
223   Status = (Reg32 & 0x96FFFFFF);       // Reset the one-shot bits
224   Command = (Status & ~B_GMCD_REG_TE);
225   MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Command);
226 
227    //
228    // Poll on TE Status bit of Global status register to become zero
229    //
230    do {
231      Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
232    } while ((Reg32 & B_GSTS_REG_TE) == B_GSTS_REG_TE);
233 
234   //
235   // Set SRTP (Set Root Table Pointer: BIT30) of Global command register in order to update the root table pointerDisable VTd
236   //
237   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
238   Status = (Reg32 & 0x96FFFFFF);       // Reset the one-shot bits
239   Command = (Status | B_GMCD_REG_SRTP);
240   MmioWrite32 (VtdUnitBaseAddress + R_GCMD_REG, Command);
241   do {
242     Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
243   } while((Reg32 & B_GSTS_REG_RTPS) == 0);
244 
245   Reg32 = MmioRead32 (VtdUnitBaseAddress + R_GSTS_REG);
246   DEBUG((DEBUG_INFO, "DisableDmar: GSTS_REG - 0x%08x\n", Reg32));
247 
248   MmioWrite64 (VtdUnitBaseAddress + R_RTADDR_REG, 0);
249 
250   DEBUG ((DEBUG_INFO,"VTD () Disabled!<<<<<<\n"));
251 
252   return EFI_SUCCESS;
253 }
254 
255 /**
256   Enable VTd translation table protection for all.
257 
258   @param[in]  VTdInfo           The VTd engine context information.
259   @param[in]  EngineMask        The mask of the VTd engine to be accessed.
260 **/
261 VOID
EnableVTdTranslationProtectionAll(IN VTD_INFO * VTdInfo,IN UINT64 EngineMask)262 EnableVTdTranslationProtectionAll (
263   IN VTD_INFO                   *VTdInfo,
264   IN UINT64                     EngineMask
265   )
266 {
267   EFI_STATUS                                Status;
268   EDKII_VTD_NULL_ROOT_ENTRY_TABLE_PPI       *RootEntryTable;
269   UINTN                                     Index;
270 
271   DEBUG ((DEBUG_INFO, "EnableVTdTranslationProtectionAll - 0x%lx\n", EngineMask));
272 
273   Status = PeiServicesLocatePpi (
274                  &gEdkiiVTdNullRootEntryTableGuid,
275                  0,
276                  NULL,
277                  (VOID **)&RootEntryTable
278                  );
279   if (EFI_ERROR(Status)) {
280     DEBUG ((DEBUG_ERROR, "Locate Null Root Entry Table Ppi Failed : %r\n", Status));
281     ASSERT (FALSE);
282     return;
283   }
284 
285   for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
286     if ((EngineMask & LShiftU64(1, Index)) == 0) {
287       continue;
288     }
289     EnableDmar ((UINTN) VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress, (UINTN) *RootEntryTable);
290   }
291 
292   return;
293 }
294 
295 /**
296   Enable VTd translation table protection.
297 
298   @param[in]  VTdInfo           The VTd engine context information.
299 
300   @retval EFI_SUCCESS           DMAR translation is enabled.
301   @retval EFI_DEVICE_ERROR      DMAR translation is not enabled.
302 **/
303 EFI_STATUS
EnableVTdTranslationProtection(IN VTD_INFO * VTdInfo)304 EnableVTdTranslationProtection (
305   IN VTD_INFO                   *VTdInfo
306   )
307 {
308   EFI_STATUS                    Status;
309   UINTN                         VtdIndex;
310 
311   for (VtdIndex = 0; VtdIndex < VTdInfo->VTdEngineCount; VtdIndex++) {
312     if (VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable != 0) {
313       DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) ExtRootEntryTable 0x%x\n", VtdIndex, VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable));
314       Status = EnableDmar (VTdInfo->VtdUnitInfo[VtdIndex].VtdUnitBaseAddress, VTdInfo->VtdUnitInfo[VtdIndex].ExtRootEntryTable);
315     } else {
316       DEBUG ((DEBUG_INFO, "EnableVtdDmar (%d) RootEntryTable 0x%x\n", VtdIndex, VTdInfo->VtdUnitInfo[VtdIndex].RootEntryTable));
317       Status = EnableDmar (VTdInfo->VtdUnitInfo[VtdIndex].VtdUnitBaseAddress, VTdInfo->VtdUnitInfo[VtdIndex].RootEntryTable);
318     }
319     if (EFI_ERROR (Status)) {
320       DEBUG ((DEBUG_ERROR, "EnableVtdDmar (%d) Failed !\n", VtdIndex));
321       return Status;
322     }
323   }
324   return EFI_SUCCESS;
325 }
326 
327 /**
328   Disable VTd translation table protection.
329 
330   @param[in]  VTdInfo           The VTd engine context information.
331   @param[in]  EngineMask        The mask of the VTd engine to be accessed.
332 **/
333 VOID
DisableVTdTranslationProtection(IN VTD_INFO * VTdInfo,IN UINT64 EngineMask)334 DisableVTdTranslationProtection (
335   IN VTD_INFO                   *VTdInfo,
336   IN UINT64                     EngineMask
337   )
338 {
339   UINTN                         Index;
340 
341   DEBUG ((DEBUG_INFO, "DisableVTdTranslationProtection - 0x%lx\n", EngineMask));
342 
343   for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
344     if ((EngineMask & LShiftU64(1, Index)) == 0) {
345       continue;
346     }
347     DisableDmar ((UINTN) VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress);
348   }
349 
350   return;
351 }
352 
353 /**
354   Dump VTd capability registers.
355 
356   @param[in]  CapReg            The capability register.
357 **/
358 VOID
DumpVtdCapRegs(IN VTD_CAP_REG * CapReg)359 DumpVtdCapRegs (
360   IN VTD_CAP_REG                *CapReg
361   )
362 {
363   DEBUG ((DEBUG_INFO, "  CapReg:\n", CapReg->Uint64));
364   DEBUG ((DEBUG_INFO, "    ND     - 0x%x\n", CapReg->Bits.ND));
365   DEBUG ((DEBUG_INFO, "    AFL    - 0x%x\n", CapReg->Bits.AFL));
366   DEBUG ((DEBUG_INFO, "    RWBF   - 0x%x\n", CapReg->Bits.RWBF));
367   DEBUG ((DEBUG_INFO, "    PLMR   - 0x%x\n", CapReg->Bits.PLMR));
368   DEBUG ((DEBUG_INFO, "    PHMR   - 0x%x\n", CapReg->Bits.PHMR));
369   DEBUG ((DEBUG_INFO, "    CM     - 0x%x\n", CapReg->Bits.CM));
370   DEBUG ((DEBUG_INFO, "    SAGAW  - 0x%x\n", CapReg->Bits.SAGAW));
371   DEBUG ((DEBUG_INFO, "    MGAW   - 0x%x\n", CapReg->Bits.MGAW));
372   DEBUG ((DEBUG_INFO, "    ZLR    - 0x%x\n", CapReg->Bits.ZLR));
373   DEBUG ((DEBUG_INFO, "    FRO    - 0x%x\n", CapReg->Bits.FRO));
374   DEBUG ((DEBUG_INFO, "    SLLPS  - 0x%x\n", CapReg->Bits.SLLPS));
375   DEBUG ((DEBUG_INFO, "    PSI    - 0x%x\n", CapReg->Bits.PSI));
376   DEBUG ((DEBUG_INFO, "    NFR    - 0x%x\n", CapReg->Bits.NFR));
377   DEBUG ((DEBUG_INFO, "    MAMV   - 0x%x\n", CapReg->Bits.MAMV));
378   DEBUG ((DEBUG_INFO, "    DWD    - 0x%x\n", CapReg->Bits.DWD));
379   DEBUG ((DEBUG_INFO, "    DRD    - 0x%x\n", CapReg->Bits.DRD));
380   DEBUG ((DEBUG_INFO, "    FL1GP  - 0x%x\n", CapReg->Bits.FL1GP));
381   DEBUG ((DEBUG_INFO, "    PI     - 0x%x\n", CapReg->Bits.PI));
382 }
383 
384 /**
385   Dump VTd extended capability registers.
386 
387   @param[in]  ECapReg           The extended capability register.
388 **/
389 VOID
DumpVtdECapRegs(IN VTD_ECAP_REG * ECapReg)390 DumpVtdECapRegs (
391   IN VTD_ECAP_REG               *ECapReg
392   )
393 {
394   DEBUG ((DEBUG_INFO, "  ECapReg:\n", ECapReg->Uint64));
395   DEBUG ((DEBUG_INFO, "    C      - 0x%x\n", ECapReg->Bits.C));
396   DEBUG ((DEBUG_INFO, "    QI     - 0x%x\n", ECapReg->Bits.QI));
397   DEBUG ((DEBUG_INFO, "    DT     - 0x%x\n", ECapReg->Bits.DT));
398   DEBUG ((DEBUG_INFO, "    IR     - 0x%x\n", ECapReg->Bits.IR));
399   DEBUG ((DEBUG_INFO, "    EIM    - 0x%x\n", ECapReg->Bits.EIM));
400   DEBUG ((DEBUG_INFO, "    PT     - 0x%x\n", ECapReg->Bits.PT));
401   DEBUG ((DEBUG_INFO, "    SC     - 0x%x\n", ECapReg->Bits.SC));
402   DEBUG ((DEBUG_INFO, "    IRO    - 0x%x\n", ECapReg->Bits.IRO));
403   DEBUG ((DEBUG_INFO, "    MHMV   - 0x%x\n", ECapReg->Bits.MHMV));
404   DEBUG ((DEBUG_INFO, "    ECS    - 0x%x\n", ECapReg->Bits.ECS));
405   DEBUG ((DEBUG_INFO, "    MTS    - 0x%x\n", ECapReg->Bits.MTS));
406   DEBUG ((DEBUG_INFO, "    NEST   - 0x%x\n", ECapReg->Bits.NEST));
407   DEBUG ((DEBUG_INFO, "    DIS    - 0x%x\n", ECapReg->Bits.DIS));
408   DEBUG ((DEBUG_INFO, "    PASID  - 0x%x\n", ECapReg->Bits.PASID));
409   DEBUG ((DEBUG_INFO, "    PRS    - 0x%x\n", ECapReg->Bits.PRS));
410   DEBUG ((DEBUG_INFO, "    ERS    - 0x%x\n", ECapReg->Bits.ERS));
411   DEBUG ((DEBUG_INFO, "    SRS    - 0x%x\n", ECapReg->Bits.SRS));
412   DEBUG ((DEBUG_INFO, "    NWFS   - 0x%x\n", ECapReg->Bits.NWFS));
413   DEBUG ((DEBUG_INFO, "    EAFS   - 0x%x\n", ECapReg->Bits.EAFS));
414   DEBUG ((DEBUG_INFO, "    PSS    - 0x%x\n", ECapReg->Bits.PSS));
415 }
416 
417 /**
418   Prepare VTD configuration.
419 
420   @param[in]  VTdInfo           The VTd engine context information.
421 
422   @retval EFI_SUCCESS           Prepare Vtd config success
423 **/
424 EFI_STATUS
PrepareVtdConfig(IN VTD_INFO * VTdInfo)425 PrepareVtdConfig (
426   IN VTD_INFO                   *VTdInfo
427   )
428 {
429   UINTN                         Index;
430   UINTN                         DomainNumber;
431 
432   for (Index = 0; Index < VTdInfo->VTdEngineCount; Index++) {
433     DEBUG ((DEBUG_ERROR, "Dump VTd Capability (%d)\n", Index));
434     VTdInfo->VtdUnitInfo[Index].CapReg.Uint64 = MmioRead64 (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress + R_CAP_REG);
435     DumpVtdCapRegs (&VTdInfo->VtdUnitInfo[Index].CapReg);
436     VTdInfo->VtdUnitInfo[Index].ECapReg.Uint64 = MmioRead64 (VTdInfo->VtdUnitInfo[Index].VtdUnitBaseAddress + R_ECAP_REG);
437     DumpVtdECapRegs (&VTdInfo->VtdUnitInfo[Index].ECapReg);
438 
439     VTdInfo->VtdUnitInfo[Index].Is5LevelPaging = FALSE;
440     if ((VTdInfo->VtdUnitInfo[Index].CapReg.Bits.SAGAW & BIT2) != 0) {
441       DEBUG ((DEBUG_INFO, "Support 4-level page-table on VTD %d\n", Index));
442     }
443     if ((VTdInfo->VtdUnitInfo[Index].CapReg.Bits.SAGAW & BIT3) != 0) {
444       DEBUG((DEBUG_INFO, "Support 5-level page-table on VTD %d\n", Index));
445       VTdInfo->VtdUnitInfo[Index].Is5LevelPaging = TRUE;
446 
447       if ((VTdInfo->HostAddressWidth <= 48) &&
448           ((VTdInfo->VtdUnitInfo[Index].CapReg.Bits.SAGAW & BIT2) != 0)) {
449         DEBUG ((DEBUG_INFO, "Rollback to 4-level page-table on VTD %d\n", Index));
450         VTdInfo->VtdUnitInfo[Index].Is5LevelPaging = FALSE;
451       }
452     }
453     if ((VTdInfo->VtdUnitInfo[Index].CapReg.Bits.SAGAW & (BIT3 | BIT2)) == 0) {
454       DEBUG ((DEBUG_ERROR, "!!!! Page-table type 0x%X is not supported on VTD %d !!!!\n", Index, VTdInfo->VtdUnitInfo[Index].CapReg.Bits.SAGAW));
455       return EFI_UNSUPPORTED;
456     }
457 
458     DomainNumber = (UINTN)1 << (UINT8) ((UINTN) VTdInfo->VtdUnitInfo[Index].CapReg.Bits.ND * 2 + 4);
459     if (VTdInfo->VtdUnitInfo[Index].PciDeviceInfo.PciDeviceDataNumber >= DomainNumber) {
460       DEBUG ((DEBUG_ERROR, "!!!! Pci device Number(0x%x) >= DomainNumber(0x%x) !!!!\n", VTdInfo->VtdUnitInfo[Index].PciDeviceInfo.PciDeviceDataNumber, DomainNumber));
461       return EFI_UNSUPPORTED;
462     }
463   }
464   return EFI_SUCCESS;
465 }
466 
467