DmaProtection.c 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689
  1. /** @file
  2. Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
  3. SPDX-License-Identifier: BSD-2-Clause-Patent
  4. **/
  5. #include "DmaProtection.h"
  6. UINT64 mBelow4GMemoryLimit;
  7. UINT64 mAbove4GMemoryLimit;
  8. EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;
  9. VTD_ACCESS_REQUEST *mAccessRequest = NULL;
  10. UINTN mAccessRequestCount = 0;
  11. UINTN mAccessRequestMaxCount = 0;
  12. /**
  13. Append VTd Access Request to global.
  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. @param[in] BaseAddress The base of device memory address to be used as the DMA memory.
  17. @param[in] Length The length of device memory address to be used as the DMA memory.
  18. @param[in] IoMmuAccess The IOMMU access.
  19. @retval EFI_SUCCESS The IoMmuAccess is set for the memory range specified by BaseAddress and Length.
  20. @retval EFI_INVALID_PARAMETER BaseAddress is not IoMmu Page size aligned.
  21. @retval EFI_INVALID_PARAMETER Length is not IoMmu Page size aligned.
  22. @retval EFI_INVALID_PARAMETER Length is 0.
  23. @retval EFI_INVALID_PARAMETER IoMmuAccess specified an illegal combination of access.
  24. @retval EFI_UNSUPPORTED The bit mask of IoMmuAccess is not supported by the IOMMU.
  25. @retval EFI_UNSUPPORTED The IOMMU does not support the memory range specified by BaseAddress and Length.
  26. @retval EFI_OUT_OF_RESOURCES There are not enough resources available to modify the IOMMU access.
  27. @retval EFI_DEVICE_ERROR The IOMMU device reported an error while attempting the operation.
  28. **/
  29. EFI_STATUS
  30. RequestAccessAttribute (
  31. IN UINT16 Segment,
  32. IN VTD_SOURCE_ID SourceId,
  33. IN UINT64 BaseAddress,
  34. IN UINT64 Length,
  35. IN UINT64 IoMmuAccess
  36. )
  37. {
  38. VTD_ACCESS_REQUEST *NewAccessRequest;
  39. UINTN Index;
  40. //
  41. // Optimization for memory.
  42. //
  43. // If the last record is to IoMmuAccess=0,
  44. // Check previous records and remove the matched entry.
  45. //
  46. if (IoMmuAccess == 0) {
  47. for (Index = 0; Index < mAccessRequestCount; Index++) {
  48. if ((mAccessRequest[Index].Segment == Segment) &&
  49. (mAccessRequest[Index].SourceId.Uint16 == SourceId.Uint16) &&
  50. (mAccessRequest[Index].BaseAddress == BaseAddress) &&
  51. (mAccessRequest[Index].Length == Length) &&
  52. (mAccessRequest[Index].IoMmuAccess != 0)) {
  53. //
  54. // Remove this record [Index].
  55. // No need to add the new record.
  56. //
  57. if (Index != mAccessRequestCount - 1) {
  58. CopyMem (
  59. &mAccessRequest[Index],
  60. &mAccessRequest[Index + 1],
  61. sizeof (VTD_ACCESS_REQUEST) * (mAccessRequestCount - 1 - Index)
  62. );
  63. }
  64. ZeroMem (&mAccessRequest[mAccessRequestCount - 1], sizeof(VTD_ACCESS_REQUEST));
  65. mAccessRequestCount--;
  66. return EFI_SUCCESS;
  67. }
  68. }
  69. }
  70. if (mAccessRequestCount >= mAccessRequestMaxCount) {
  71. NewAccessRequest = AllocateZeroPool (sizeof(*NewAccessRequest) * (mAccessRequestMaxCount + MAX_VTD_ACCESS_REQUEST));
  72. if (NewAccessRequest == NULL) {
  73. return EFI_OUT_OF_RESOURCES;
  74. }
  75. mAccessRequestMaxCount += MAX_VTD_ACCESS_REQUEST;
  76. if (mAccessRequest != NULL) {
  77. CopyMem (NewAccessRequest, mAccessRequest, sizeof(*NewAccessRequest) * mAccessRequestCount);
  78. FreePool (mAccessRequest);
  79. }
  80. mAccessRequest = NewAccessRequest;
  81. }
  82. ASSERT (mAccessRequestCount < mAccessRequestMaxCount);
  83. mAccessRequest[mAccessRequestCount].Segment = Segment;
  84. mAccessRequest[mAccessRequestCount].SourceId = SourceId;
  85. mAccessRequest[mAccessRequestCount].BaseAddress = BaseAddress;
  86. mAccessRequest[mAccessRequestCount].Length = Length;
  87. mAccessRequest[mAccessRequestCount].IoMmuAccess = IoMmuAccess;
  88. mAccessRequestCount++;
  89. return EFI_SUCCESS;
  90. }
  91. /**
  92. Process Access Requests from before DMAR table is installed.
  93. **/
  94. VOID
  95. ProcessRequestedAccessAttribute (
  96. VOID
  97. )
  98. {
  99. UINTN Index;
  100. EFI_STATUS Status;
  101. DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute ...\n"));
  102. for (Index = 0; Index < mAccessRequestCount; Index++) {
  103. DEBUG ((
  104. DEBUG_INFO,
  105. "PCI(S%x.B%x.D%x.F%x) ",
  106. mAccessRequest[Index].Segment,
  107. mAccessRequest[Index].SourceId.Bits.Bus,
  108. mAccessRequest[Index].SourceId.Bits.Device,
  109. mAccessRequest[Index].SourceId.Bits.Function
  110. ));
  111. DEBUG ((
  112. DEBUG_INFO,
  113. "(0x%lx~0x%lx) - %lx\n",
  114. mAccessRequest[Index].BaseAddress,
  115. mAccessRequest[Index].Length,
  116. mAccessRequest[Index].IoMmuAccess
  117. ));
  118. Status = SetAccessAttribute (
  119. mAccessRequest[Index].Segment,
  120. mAccessRequest[Index].SourceId,
  121. mAccessRequest[Index].BaseAddress,
  122. mAccessRequest[Index].Length,
  123. mAccessRequest[Index].IoMmuAccess
  124. );
  125. if (EFI_ERROR (Status)) {
  126. DEBUG ((DEBUG_ERROR, "SetAccessAttribute %r: ", Status));
  127. }
  128. }
  129. if (mAccessRequest != NULL) {
  130. FreePool (mAccessRequest);
  131. }
  132. mAccessRequest = NULL;
  133. mAccessRequestCount = 0;
  134. mAccessRequestMaxCount = 0;
  135. DEBUG ((DEBUG_INFO, "ProcessRequestedAccessAttribute Done\n"));
  136. }
  137. /**
  138. Return UEFI memory map information.
  139. @param[out] Below4GMemoryLimit The below 4GiB memory limit address or 0 if insufficient resources exist to
  140. determine the address.
  141. @param[out] Above4GMemoryLimit The above 4GiB memory limit address or 0 if insufficient resources exist to
  142. determine the address.
  143. **/
  144. VOID
  145. ReturnUefiMemoryMap (
  146. OUT UINT64 *Below4GMemoryLimit,
  147. OUT UINT64 *Above4GMemoryLimit
  148. )
  149. {
  150. EFI_STATUS Status;
  151. EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
  152. EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
  153. EFI_MEMORY_DESCRIPTOR *EfiEntry;
  154. EFI_MEMORY_DESCRIPTOR *NextEfiEntry;
  155. EFI_MEMORY_DESCRIPTOR TempEfiEntry;
  156. UINTN EfiMemoryMapSize;
  157. UINTN EfiMapKey;
  158. UINTN EfiDescriptorSize;
  159. UINT32 EfiDescriptorVersion;
  160. UINT64 MemoryBlockLength;
  161. *Below4GMemoryLimit = 0;
  162. *Above4GMemoryLimit = 0;
  163. //
  164. // Get the EFI memory map.
  165. //
  166. EfiMemoryMapSize = 0;
  167. EfiMemoryMap = NULL;
  168. Status = gBS->GetMemoryMap (
  169. &EfiMemoryMapSize,
  170. EfiMemoryMap,
  171. &EfiMapKey,
  172. &EfiDescriptorSize,
  173. &EfiDescriptorVersion
  174. );
  175. ASSERT (Status == EFI_BUFFER_TOO_SMALL);
  176. do {
  177. //
  178. // Use size returned back plus 1 descriptor for the AllocatePool.
  179. // We don't just multiply by 2 since the "for" loop below terminates on
  180. // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
  181. // we process bogus entries and create bogus E820 entries.
  182. //
  183. EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
  184. if (EfiMemoryMap == NULL) {
  185. ASSERT (EfiMemoryMap != NULL);
  186. return;
  187. }
  188. Status = gBS->GetMemoryMap (
  189. &EfiMemoryMapSize,
  190. EfiMemoryMap,
  191. &EfiMapKey,
  192. &EfiDescriptorSize,
  193. &EfiDescriptorVersion
  194. );
  195. if (EFI_ERROR (Status)) {
  196. FreePool (EfiMemoryMap);
  197. }
  198. } while (Status == EFI_BUFFER_TOO_SMALL);
  199. ASSERT_EFI_ERROR (Status);
  200. //
  201. // Sort memory map from low to high
  202. //
  203. EfiEntry = EfiMemoryMap;
  204. NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
  205. EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
  206. while (EfiEntry < EfiMemoryMapEnd) {
  207. while (NextEfiEntry < EfiMemoryMapEnd) {
  208. if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
  209. CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
  210. CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
  211. CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
  212. }
  213. NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
  214. }
  215. EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
  216. NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
  217. }
  218. DEBUG ((DEBUG_INFO, "MemoryMap:\n"));
  219. EfiEntry = EfiMemoryMap;
  220. EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
  221. while (EfiEntry < EfiMemoryMapEnd) {
  222. MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
  223. DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));
  224. switch (EfiEntry->Type) {
  225. case EfiLoaderCode:
  226. case EfiLoaderData:
  227. case EfiBootServicesCode:
  228. case EfiBootServicesData:
  229. case EfiConventionalMemory:
  230. case EfiRuntimeServicesCode:
  231. case EfiRuntimeServicesData:
  232. case EfiACPIReclaimMemory:
  233. case EfiACPIMemoryNVS:
  234. case EfiReservedMemoryType:
  235. if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {
  236. //
  237. // Skip the memory block is under 1MB
  238. //
  239. } else if (EfiEntry->PhysicalStart >= BASE_4GB) {
  240. if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {
  241. *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;
  242. }
  243. } else {
  244. if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {
  245. *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;
  246. }
  247. }
  248. break;
  249. }
  250. EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
  251. }
  252. FreePool (EfiMemoryMap);
  253. DEBUG ((DEBUG_INFO, "Result:\n"));
  254. DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit));
  255. DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit));
  256. return ;
  257. }
  258. /**
  259. The scan bus callback function to always enable page attribute.
  260. @param[in] Context The context of the callback.
  261. @param[in] Segment The segment of the source.
  262. @param[in] Bus The bus of the source.
  263. @param[in] Device The device of the source.
  264. @param[in] Function The function of the source.
  265. @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.
  266. **/
  267. EFI_STATUS
  268. EFIAPI
  269. ScanBusCallbackAlwaysEnablePageAttribute (
  270. IN VOID *Context,
  271. IN UINT16 Segment,
  272. IN UINT8 Bus,
  273. IN UINT8 Device,
  274. IN UINT8 Function
  275. )
  276. {
  277. VTD_SOURCE_ID SourceId;
  278. EFI_STATUS Status;
  279. SourceId.Bits.Bus = Bus;
  280. SourceId.Bits.Device = Device;
  281. SourceId.Bits.Function = Function;
  282. Status = AlwaysEnablePageAttribute (Segment, SourceId);
  283. return Status;
  284. }
  285. /**
  286. Always enable the VTd page attribute for the device in the DeviceScope.
  287. @param[in] DeviceScope the input device scope data structure
  288. @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope.
  289. **/
  290. EFI_STATUS
  291. AlwaysEnablePageAttributeDeviceScope (
  292. IN EDKII_PLATFORM_VTD_DEVICE_SCOPE *DeviceScope
  293. )
  294. {
  295. UINT8 Bus;
  296. UINT8 Device;
  297. UINT8 Function;
  298. VTD_SOURCE_ID SourceId;
  299. UINT8 SecondaryBusNumber;
  300. EFI_STATUS Status;
  301. Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function);
  302. if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) {
  303. //
  304. // Need scan the bridge and add all devices.
  305. //
  306. SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
  307. Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute);
  308. return Status;
  309. } else {
  310. SourceId.Bits.Bus = Bus;
  311. SourceId.Bits.Device = Device;
  312. SourceId.Bits.Function = Function;
  313. Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId);
  314. return Status;
  315. }
  316. }
  317. /**
  318. Always enable the VTd page attribute for the device matching DeviceId.
  319. @param[in] PciDeviceId the input PCI device ID
  320. @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.
  321. **/
  322. EFI_STATUS
  323. AlwaysEnablePageAttributePciDeviceId (
  324. IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId
  325. )
  326. {
  327. UINTN VtdIndex;
  328. UINTN PciIndex;
  329. PCI_DEVICE_DATA *PciDeviceData;
  330. EFI_STATUS Status;
  331. for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
  332. for (PciIndex = 0; PciIndex < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; PciIndex++) {
  333. PciDeviceData = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciIndex];
  334. if (((PciDeviceId->VendorId == 0xFFFF) || (PciDeviceId->VendorId == PciDeviceData->PciDeviceId.VendorId)) &&
  335. ((PciDeviceId->DeviceId == 0xFFFF) || (PciDeviceId->DeviceId == PciDeviceData->PciDeviceId.DeviceId)) &&
  336. ((PciDeviceId->RevisionId == 0xFF) || (PciDeviceId->RevisionId == PciDeviceData->PciDeviceId.RevisionId)) &&
  337. ((PciDeviceId->SubsystemVendorId == 0xFFFF) || (PciDeviceId->SubsystemVendorId == PciDeviceData->PciDeviceId.SubsystemVendorId)) &&
  338. ((PciDeviceId->SubsystemDeviceId == 0xFFFF) || (PciDeviceId->SubsystemDeviceId == PciDeviceData->PciDeviceId.SubsystemDeviceId)) ) {
  339. Status = AlwaysEnablePageAttribute (mVtdUnitInformation[VtdIndex].Segment, PciDeviceData->PciSourceId);
  340. if (EFI_ERROR(Status)) {
  341. continue;
  342. }
  343. }
  344. }
  345. }
  346. return EFI_SUCCESS;
  347. }
  348. /**
  349. Always enable the VTd page attribute for the device.
  350. @param[in] DeviceInfo the exception device information
  351. @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device info.
  352. **/
  353. EFI_STATUS
  354. AlwaysEnablePageAttributeExceptionDeviceInfo (
  355. IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *DeviceInfo
  356. )
  357. {
  358. switch (DeviceInfo->Type) {
  359. case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE:
  360. return AlwaysEnablePageAttributeDeviceScope ((VOID *)(DeviceInfo + 1));
  361. case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID:
  362. return AlwaysEnablePageAttributePciDeviceId ((VOID *)(DeviceInfo + 1));
  363. default:
  364. return EFI_UNSUPPORTED;
  365. }
  366. }
  367. /**
  368. Initialize platform VTd policy.
  369. **/
  370. VOID
  371. InitializePlatformVTdPolicy (
  372. VOID
  373. )
  374. {
  375. EFI_STATUS Status;
  376. UINTN DeviceInfoCount;
  377. VOID *DeviceInfo;
  378. EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *ThisDeviceInfo;
  379. UINTN Index;
  380. //
  381. // It is optional.
  382. //
  383. Status = gBS->LocateProtocol (
  384. &gEdkiiPlatformVTdPolicyProtocolGuid,
  385. NULL,
  386. (VOID **)&mPlatformVTdPolicy
  387. );
  388. if (!EFI_ERROR(Status)) {
  389. DEBUG ((DEBUG_INFO, "InitializePlatformVTdPolicy\n"));
  390. Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);
  391. if (!EFI_ERROR(Status)) {
  392. ThisDeviceInfo = DeviceInfo;
  393. for (Index = 0; Index < DeviceInfoCount; Index++) {
  394. if (ThisDeviceInfo->Type == EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END) {
  395. break;
  396. }
  397. AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo);
  398. ThisDeviceInfo = (VOID *)((UINTN)ThisDeviceInfo + ThisDeviceInfo->Length);
  399. }
  400. FreePool (DeviceInfo);
  401. }
  402. }
  403. }
  404. /**
  405. Setup VTd engine.
  406. **/
  407. VOID
  408. SetupVtd (
  409. VOID
  410. )
  411. {
  412. EFI_STATUS Status;
  413. VOID *PciEnumerationComplete;
  414. UINTN Index;
  415. UINT64 Below4GMemoryLimit;
  416. UINT64 Above4GMemoryLimit;
  417. //
  418. // PCI Enumeration must be done
  419. //
  420. Status = gBS->LocateProtocol (
  421. &gEfiPciEnumerationCompleteProtocolGuid,
  422. NULL,
  423. &PciEnumerationComplete
  424. );
  425. ASSERT_EFI_ERROR (Status);
  426. ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);
  427. Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);
  428. DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));
  429. mBelow4GMemoryLimit = Below4GMemoryLimit;
  430. mAbove4GMemoryLimit = Above4GMemoryLimit;
  431. //
  432. // 1. setup
  433. //
  434. DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));
  435. Status = ParseDmarAcpiTableDrhd ();
  436. if (EFI_ERROR (Status)) {
  437. return;
  438. }
  439. DumpVtdIfError ();
  440. DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));
  441. PrepareVtdConfig ();
  442. //
  443. // 2. initialization
  444. //
  445. DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));
  446. Status = SetupTranslationTable ();
  447. if (EFI_ERROR (Status)) {
  448. return;
  449. }
  450. InitializePlatformVTdPolicy ();
  451. ParseDmarAcpiTableRmrr ();
  452. if ((PcdGet8 (PcdVTdPolicyPropertyMask) & BIT2) == 0) {
  453. //
  454. // Support IOMMU access attribute request recording before DMAR table is installed.
  455. // Here is to process the requests.
  456. //
  457. ProcessRequestedAccessAttribute ();
  458. }
  459. for (Index = 0; Index < mVtdUnitNumber; Index++) {
  460. DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment));
  461. if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {
  462. DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable, mVtdUnitInformation[Index].Is5LevelPaging);
  463. }
  464. if (mVtdUnitInformation[Index].RootEntryTable != NULL) {
  465. DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable, mVtdUnitInformation[Index].Is5LevelPaging);
  466. }
  467. }
  468. //
  469. // 3. enable
  470. //
  471. DEBUG ((DEBUG_INFO, "EnableDmar\n"));
  472. Status = EnableDmar ();
  473. if (EFI_ERROR (Status)) {
  474. return;
  475. }
  476. DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));
  477. DumpVtdRegsAll ();
  478. }
  479. /**
  480. Notification function of ACPI Table change.
  481. This is a notification function registered on ACPI Table change event.
  482. @param Event Event whose notification function is being invoked.
  483. @param Context Pointer to the notification function's context.
  484. **/
  485. VOID
  486. EFIAPI
  487. AcpiNotificationFunc (
  488. IN EFI_EVENT Event,
  489. IN VOID *Context
  490. )
  491. {
  492. EFI_STATUS Status;
  493. Status = GetDmarAcpiTable ();
  494. if (EFI_ERROR (Status)) {
  495. if (Status == EFI_ALREADY_STARTED) {
  496. gBS->CloseEvent (Event);
  497. }
  498. return;
  499. }
  500. SetupVtd ();
  501. gBS->CloseEvent (Event);
  502. }
  503. /**
  504. Exit boot service callback function.
  505. @param[in] Event The event handle.
  506. @param[in] Context The event content.
  507. **/
  508. VOID
  509. EFIAPI
  510. OnExitBootServices (
  511. IN EFI_EVENT Event,
  512. IN VOID *Context
  513. )
  514. {
  515. UINTN VtdIndex;
  516. DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));
  517. DumpVtdRegsAll ();
  518. DEBUG ((DEBUG_INFO, "Invalidate all\n"));
  519. for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {
  520. FlushWriteBuffer (VtdIndex);
  521. InvalidateContextCache (VtdIndex);
  522. InvalidateIOTLB (VtdIndex);
  523. }
  524. if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {
  525. DisableDmar ();
  526. DumpVtdRegsAll ();
  527. }
  528. }
  529. /**
  530. Legacy boot callback function.
  531. @param[in] Event The event handle.
  532. @param[in] Context The event content.
  533. **/
  534. VOID
  535. EFIAPI
  536. OnLegacyBoot (
  537. EFI_EVENT Event,
  538. VOID *Context
  539. )
  540. {
  541. DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));
  542. DumpVtdRegsAll ();
  543. DisableDmar ();
  544. DumpVtdRegsAll ();
  545. }
  546. /**
  547. Initialize DMA protection.
  548. **/
  549. VOID
  550. InitializeDmaProtection (
  551. VOID
  552. )
  553. {
  554. EFI_STATUS Status;
  555. EFI_EVENT ExitBootServicesEvent;
  556. EFI_EVENT LegacyBootEvent;
  557. EFI_EVENT EventAcpi10;
  558. EFI_EVENT EventAcpi20;
  559. Status = gBS->CreateEventEx (
  560. EVT_NOTIFY_SIGNAL,
  561. VTD_TPL_LEVEL,
  562. AcpiNotificationFunc,
  563. NULL,
  564. &gEfiAcpi10TableGuid,
  565. &EventAcpi10
  566. );
  567. ASSERT_EFI_ERROR (Status);
  568. Status = gBS->CreateEventEx (
  569. EVT_NOTIFY_SIGNAL,
  570. VTD_TPL_LEVEL,
  571. AcpiNotificationFunc,
  572. NULL,
  573. &gEfiAcpi20TableGuid,
  574. &EventAcpi20
  575. );
  576. ASSERT_EFI_ERROR (Status);
  577. //
  578. // Signal the events initially for the case
  579. // that DMAR table has been installed.
  580. //
  581. gBS->SignalEvent (EventAcpi20);
  582. gBS->SignalEvent (EventAcpi10);
  583. Status = gBS->CreateEventEx (
  584. EVT_NOTIFY_SIGNAL,
  585. TPL_CALLBACK,
  586. OnExitBootServices,
  587. NULL,
  588. &gEfiEventExitBootServicesGuid,
  589. &ExitBootServicesEvent
  590. );
  591. ASSERT_EFI_ERROR (Status);
  592. Status = EfiCreateEventLegacyBootEx (
  593. TPL_CALLBACK,
  594. OnLegacyBoot,
  595. NULL,
  596. &LegacyBootEvent
  597. );
  598. ASSERT_EFI_ERROR (Status);
  599. return ;
  600. }