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