]> git.proxmox.com Git - mirror_edk2.git/blame - IntelSiliconPkg/Feature/VTd/IntelVTdDxe/DmaProtection.c
IntelSiliconPkg IntelVTdDxe: Use TPL to protect list/engine operation
[mirror_edk2.git] / IntelSiliconPkg / Feature / VTd / IntelVTdDxe / DmaProtection.c
CommitLineData
c049fc99
JY
1/** @file\r
2\r
dcd39e09 3 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>\r
c049fc99
JY
4 This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution. The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php.\r
8\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12**/\r
13\r
14#include "DmaProtection.h"\r
15\r
c049fc99
JY
16UINT64 mBelow4GMemoryLimit;\r
17UINT64 mAbove4GMemoryLimit;\r
18\r
19EDKII_PLATFORM_VTD_POLICY_PROTOCOL *mPlatformVTdPolicy;\r
20\r
21/**\r
22 return the UEFI memory information.\r
23\r
24 @param[out] Below4GMemoryLimit The below 4GiB memory limit\r
25 @param[out] Above4GMemoryLimit The above 4GiB memory limit\r
26**/\r
27VOID\r
28ReturnUefiMemoryMap (\r
29 OUT UINT64 *Below4GMemoryLimit,\r
30 OUT UINT64 *Above4GMemoryLimit\r
31 )\r
32{\r
33 EFI_STATUS Status;\r
34 EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;\r
35 EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;\r
36 EFI_MEMORY_DESCRIPTOR *EfiEntry;\r
37 EFI_MEMORY_DESCRIPTOR *NextEfiEntry;\r
38 EFI_MEMORY_DESCRIPTOR TempEfiEntry;\r
39 UINTN EfiMemoryMapSize;\r
40 UINTN EfiMapKey;\r
41 UINTN EfiDescriptorSize;\r
42 UINT32 EfiDescriptorVersion;\r
43 UINT64 MemoryBlockLength;\r
44\r
45 *Below4GMemoryLimit = 0;\r
46 *Above4GMemoryLimit = 0;\r
47\r
48 //\r
49 // Get the EFI memory map.\r
50 //\r
51 EfiMemoryMapSize = 0;\r
52 EfiMemoryMap = NULL;\r
53 Status = gBS->GetMemoryMap (\r
54 &EfiMemoryMapSize,\r
55 EfiMemoryMap,\r
56 &EfiMapKey,\r
57 &EfiDescriptorSize,\r
58 &EfiDescriptorVersion\r
59 );\r
60 ASSERT (Status == EFI_BUFFER_TOO_SMALL);\r
61\r
62 do {\r
63 //\r
64 // Use size returned back plus 1 descriptor for the AllocatePool.\r
65 // We don't just multiply by 2 since the "for" loop below terminates on\r
66 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize\r
67 // we process bogus entries and create bogus E820 entries.\r
68 //\r
69 EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);\r
70 ASSERT (EfiMemoryMap != NULL);\r
71 Status = gBS->GetMemoryMap (\r
72 &EfiMemoryMapSize,\r
73 EfiMemoryMap,\r
74 &EfiMapKey,\r
75 &EfiDescriptorSize,\r
76 &EfiDescriptorVersion\r
77 );\r
78 if (EFI_ERROR (Status)) {\r
79 FreePool (EfiMemoryMap);\r
80 }\r
81 } while (Status == EFI_BUFFER_TOO_SMALL);\r
82\r
83 ASSERT_EFI_ERROR (Status);\r
84\r
85 //\r
86 // Sort memory map from low to high\r
87 //\r
88 EfiEntry = EfiMemoryMap;\r
89 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
90 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
91 while (EfiEntry < EfiMemoryMapEnd) {\r
92 while (NextEfiEntry < EfiMemoryMapEnd) {\r
93 if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {\r
94 CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
95 CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
96 CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));\r
97 }\r
98\r
99 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);\r
100 }\r
101\r
102 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
103 NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
104 }\r
105\r
106 //\r
107 //\r
108 //\r
109 DEBUG ((DEBUG_INFO, "MemoryMap:\n"));\r
110 EfiEntry = EfiMemoryMap;\r
111 EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);\r
112 while (EfiEntry < EfiMemoryMapEnd) {\r
113 MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));\r
114 DEBUG ((DEBUG_INFO, "Entry(0x%02x) 0x%016lx - 0x%016lx\n", EfiEntry->Type, EfiEntry->PhysicalStart, EfiEntry->PhysicalStart + MemoryBlockLength));\r
115 switch (EfiEntry->Type) {\r
116 case EfiLoaderCode:\r
117 case EfiLoaderData:\r
118 case EfiBootServicesCode:\r
119 case EfiBootServicesData:\r
120 case EfiConventionalMemory:\r
121 case EfiRuntimeServicesCode:\r
122 case EfiRuntimeServicesData:\r
123 case EfiACPIReclaimMemory:\r
124 case EfiACPIMemoryNVS:\r
125 case EfiReservedMemoryType:\r
126 if ((EfiEntry->PhysicalStart + MemoryBlockLength) <= BASE_1MB) {\r
127 //\r
128 // Skip the memory block is under 1MB\r
129 //\r
130 } else if (EfiEntry->PhysicalStart >= BASE_4GB) {\r
131 if (*Above4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
132 *Above4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
133 }\r
134 } else {\r
135 if (*Below4GMemoryLimit < EfiEntry->PhysicalStart + MemoryBlockLength) {\r
136 *Below4GMemoryLimit = EfiEntry->PhysicalStart + MemoryBlockLength;\r
137 }\r
138 }\r
139 break;\r
140 }\r
141 EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);\r
142 }\r
143\r
144 FreePool (EfiMemoryMap);\r
145\r
146 DEBUG ((DEBUG_INFO, "Result:\n"));\r
147 DEBUG ((DEBUG_INFO, "Below4GMemoryLimit: 0x%016lx\n", *Below4GMemoryLimit));\r
148 DEBUG ((DEBUG_INFO, "Above4GMemoryLimit: 0x%016lx\n", *Above4GMemoryLimit));\r
149\r
150 return ;\r
151}\r
152\r
f77d35c7
JY
153/**\r
154 The scan bus callback function to always enable page attribute.\r
155\r
156 @param[in] Context The context of the callback.\r
157 @param[in] Segment The segment of the source.\r
158 @param[in] Bus The bus of the source.\r
159 @param[in] Device The device of the source.\r
160 @param[in] Function The function of the source.\r
161\r
162 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device.\r
163**/\r
164EFI_STATUS\r
165EFIAPI\r
166ScanBusCallbackAlwaysEnablePageAttribute (\r
167 IN VOID *Context,\r
168 IN UINT16 Segment,\r
169 IN UINT8 Bus,\r
170 IN UINT8 Device,\r
171 IN UINT8 Function\r
172 )\r
173{\r
174 VTD_SOURCE_ID SourceId;\r
175 EFI_STATUS Status;\r
176\r
177 SourceId.Bits.Bus = Bus;\r
178 SourceId.Bits.Device = Device;\r
179 SourceId.Bits.Function = Function;\r
180 Status = AlwaysEnablePageAttribute (Segment, SourceId);\r
181 return Status;\r
182}\r
183\r
184/**\r
185 Always enable the VTd page attribute for the device in the DeviceScope.\r
186\r
187 @param[in] DeviceScope the input device scope data structure\r
188\r
189 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device scope.\r
190**/\r
191EFI_STATUS\r
192AlwaysEnablePageAttributeDeviceScope (\r
193 IN EDKII_PLATFORM_VTD_DEVICE_SCOPE *DeviceScope\r
194 )\r
195{\r
196 UINT8 Bus;\r
197 UINT8 Device;\r
198 UINT8 Function;\r
199 VTD_SOURCE_ID SourceId;\r
200 UINT8 SecondaryBusNumber;\r
201 EFI_STATUS Status;\r
202\r
203 Status = GetPciBusDeviceFunction (DeviceScope->SegmentNumber, &DeviceScope->DeviceScope, &Bus, &Device, &Function);\r
204\r
205 if (DeviceScope->DeviceScope.Type == EFI_ACPI_DEVICE_SCOPE_ENTRY_TYPE_PCI_BRIDGE) {\r
206 //\r
207 // Need scan the bridge and add all devices.\r
208 //\r
209 SecondaryBusNumber = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS(DeviceScope->SegmentNumber, Bus, Device, Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));\r
210 Status = ScanPciBus (NULL, DeviceScope->SegmentNumber, SecondaryBusNumber, ScanBusCallbackAlwaysEnablePageAttribute);\r
211 return Status;\r
212 } else {\r
213 SourceId.Bits.Bus = Bus;\r
214 SourceId.Bits.Device = Device;\r
215 SourceId.Bits.Function = Function;\r
216 Status = AlwaysEnablePageAttribute (DeviceScope->SegmentNumber, SourceId);\r
217 return Status;\r
218 }\r
219}\r
220\r
221/**\r
222 Always enable the VTd page attribute for the device matching DeviceId.\r
223\r
224 @param[in] PciDeviceId the input PCI device ID\r
225\r
226 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device matching DeviceId.\r
227**/\r
228EFI_STATUS\r
229AlwaysEnablePageAttributePciDeviceId (\r
230 IN EDKII_PLATFORM_VTD_PCI_DEVICE_ID *PciDeviceId\r
231 )\r
232{\r
233 UINTN VtdIndex;\r
234 UINTN PciIndex;\r
235 PCI_DEVICE_DATA *PciDeviceData;\r
236 EFI_STATUS Status;\r
237\r
238 for (VtdIndex = 0; VtdIndex < mVtdUnitNumber; VtdIndex++) {\r
239 for (PciIndex = 0; PciIndex < mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceDataNumber; PciIndex++) {\r
240 PciDeviceData = &mVtdUnitInformation[VtdIndex].PciDeviceInfo.PciDeviceData[PciIndex];\r
241\r
242 if (((PciDeviceId->VendorId == 0xFFFF) || (PciDeviceId->VendorId == PciDeviceData->PciDeviceId.VendorId)) &&\r
243 ((PciDeviceId->DeviceId == 0xFFFF) || (PciDeviceId->DeviceId == PciDeviceData->PciDeviceId.DeviceId)) &&\r
244 ((PciDeviceId->RevisionId == 0xFF) || (PciDeviceId->RevisionId == PciDeviceData->PciDeviceId.RevisionId)) &&\r
245 ((PciDeviceId->SubsystemVendorId == 0xFFFF) || (PciDeviceId->SubsystemVendorId == PciDeviceData->PciDeviceId.SubsystemVendorId)) &&\r
246 ((PciDeviceId->SubsystemDeviceId == 0xFFFF) || (PciDeviceId->SubsystemDeviceId == PciDeviceData->PciDeviceId.SubsystemDeviceId)) ) {\r
247 Status = AlwaysEnablePageAttribute (mVtdUnitInformation[VtdIndex].Segment, PciDeviceData->PciSourceId);\r
248 if (EFI_ERROR(Status)) {\r
249 continue;\r
250 }\r
251 }\r
252 }\r
253 }\r
254 return EFI_SUCCESS;\r
255}\r
256\r
257/**\r
258 Always enable the VTd page attribute for the device.\r
259\r
260 @param[in] DeviceInfo the exception device information\r
261\r
262 @retval EFI_SUCCESS The VTd entry is updated to always enable all DMA access for the specific device in the device info.\r
263**/\r
264EFI_STATUS\r
265AlwaysEnablePageAttributeExceptionDeviceInfo (\r
266 IN EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *DeviceInfo\r
267 )\r
268{\r
269 switch (DeviceInfo->Type) {\r
270 case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_DEVICE_SCOPE:\r
271 return AlwaysEnablePageAttributeDeviceScope ((VOID *)(DeviceInfo + 1));\r
272 case EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_PCI_DEVICE_ID:\r
273 return AlwaysEnablePageAttributePciDeviceId ((VOID *)(DeviceInfo + 1));\r
274 default:\r
275 return EFI_UNSUPPORTED;\r
276 }\r
277}\r
278\r
c049fc99
JY
279/**\r
280 Initialize platform VTd policy.\r
281**/\r
282VOID\r
283InitializePlatformVTdPolicy (\r
284 VOID\r
285 )\r
286{\r
f77d35c7
JY
287 EFI_STATUS Status;\r
288 UINTN DeviceInfoCount;\r
289 VOID *DeviceInfo;\r
290 EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO *ThisDeviceInfo;\r
291 UINTN Index;\r
c049fc99
JY
292\r
293 //\r
294 // It is optional.\r
295 //\r
296 Status = gBS->LocateProtocol (\r
297 &gEdkiiPlatformVTdPolicyProtocolGuid,\r
298 NULL,\r
299 (VOID **)&mPlatformVTdPolicy\r
300 );\r
301 if (!EFI_ERROR(Status)) {\r
f77d35c7 302 DEBUG ((DEBUG_INFO, "InitializePlatformVTdPolicy\n"));\r
c049fc99
JY
303 Status = mPlatformVTdPolicy->GetExceptionDeviceList (mPlatformVTdPolicy, &DeviceInfoCount, &DeviceInfo);\r
304 if (!EFI_ERROR(Status)) {\r
f77d35c7 305 ThisDeviceInfo = DeviceInfo;\r
c049fc99 306 for (Index = 0; Index < DeviceInfoCount; Index++) {\r
f77d35c7
JY
307 if (ThisDeviceInfo->Type == EDKII_PLATFORM_VTD_EXCEPTION_DEVICE_INFO_TYPE_END) {\r
308 break;\r
309 }\r
310 AlwaysEnablePageAttributeExceptionDeviceInfo (ThisDeviceInfo);\r
311 ThisDeviceInfo = (VOID *)((UINTN)ThisDeviceInfo + ThisDeviceInfo->Length);\r
c049fc99
JY
312 }\r
313 FreePool (DeviceInfo);\r
314 }\r
315 }\r
316}\r
317\r
318/**\r
319 Setup VTd engine.\r
320**/\r
321VOID\r
322SetupVtd (\r
323 VOID\r
324 )\r
325{\r
326 EFI_STATUS Status;\r
327 VOID *PciEnumerationComplete;\r
328 UINTN Index;\r
329 UINT64 Below4GMemoryLimit;\r
330 UINT64 Above4GMemoryLimit;\r
331\r
332 //\r
333 // PCI Enumeration must be done\r
334 //\r
335 Status = gBS->LocateProtocol (\r
336 &gEfiPciEnumerationCompleteProtocolGuid,\r
337 NULL,\r
338 &PciEnumerationComplete\r
339 );\r
340 ASSERT_EFI_ERROR (Status);\r
341\r
342 ReturnUefiMemoryMap (&Below4GMemoryLimit, &Above4GMemoryLimit);\r
343 Below4GMemoryLimit = ALIGN_VALUE_UP(Below4GMemoryLimit, SIZE_256MB);\r
344 DEBUG ((DEBUG_INFO, " Adjusted Below4GMemoryLimit: 0x%016lx\n", Below4GMemoryLimit));\r
345\r
346 mBelow4GMemoryLimit = Below4GMemoryLimit;\r
347 mAbove4GMemoryLimit = Above4GMemoryLimit;\r
348\r
349 //\r
350 // 1. setup\r
351 //\r
c049fc99
JY
352 DEBUG ((DEBUG_INFO, "ParseDmarAcpiTable\n"));\r
353 Status = ParseDmarAcpiTableDrhd ();\r
354 if (EFI_ERROR (Status)) {\r
355 return;\r
356 }\r
357 DEBUG ((DEBUG_INFO, "PrepareVtdConfig\n"));\r
358 PrepareVtdConfig ();\r
359\r
360 //\r
361 // 2. initialization\r
362 //\r
363 DEBUG ((DEBUG_INFO, "SetupTranslationTable\n"));\r
364 Status = SetupTranslationTable ();\r
365 if (EFI_ERROR (Status)) {\r
366 return;\r
367 }\r
368\r
369 InitializePlatformVTdPolicy ();\r
370\r
371 ParseDmarAcpiTableRmrr ();\r
372\r
373 for (Index = 0; Index < mVtdUnitNumber; Index++) {\r
374 DEBUG ((DEBUG_INFO,"VTD Unit %d (Segment: %04x)\n", Index, mVtdUnitInformation[Index].Segment));\r
375 if (mVtdUnitInformation[Index].ExtRootEntryTable != NULL) {\r
376 DumpDmarExtContextEntryTable (mVtdUnitInformation[Index].ExtRootEntryTable);\r
377 }\r
378 if (mVtdUnitInformation[Index].RootEntryTable != NULL) {\r
379 DumpDmarContextEntryTable (mVtdUnitInformation[Index].RootEntryTable);\r
380 }\r
381 }\r
382\r
383 //\r
384 // 3. enable\r
385 //\r
386 DEBUG ((DEBUG_INFO, "EnableDmar\n"));\r
387 Status = EnableDmar ();\r
388 if (EFI_ERROR (Status)) {\r
389 return;\r
390 }\r
391 DEBUG ((DEBUG_INFO, "DumpVtdRegs\n"));\r
392 DumpVtdRegsAll ();\r
393}\r
394\r
395/**\r
f6f486e7
SZ
396 Notification function of ACPI Table change.\r
397\r
398 This is a notification function registered on ACPI Table change event.\r
c049fc99 399\r
f6f486e7
SZ
400 @param Event Event whose notification function is being invoked.\r
401 @param Context Pointer to the notification function's context.\r
c049fc99 402\r
c049fc99 403**/\r
f6f486e7 404VOID\r
c049fc99
JY
405EFIAPI\r
406AcpiNotificationFunc (\r
f6f486e7
SZ
407 IN EFI_EVENT Event,\r
408 IN VOID *Context\r
c049fc99
JY
409 )\r
410{\r
f6f486e7
SZ
411 EFI_STATUS Status;\r
412\r
413 Status = GetDmarAcpiTable ();\r
414 if (EFI_ERROR (Status)) {\r
7729e3c4
SZ
415 if (Status == EFI_ALREADY_STARTED) {\r
416 gBS->CloseEvent (Event);\r
417 }\r
f6f486e7 418 return;\r
c049fc99 419 }\r
f6f486e7
SZ
420 SetupVtd ();\r
421 gBS->CloseEvent (Event);\r
c049fc99
JY
422}\r
423\r
424/**\r
425 Exit boot service callback function.\r
426\r
427 @param[in] Event The event handle.\r
428 @param[in] Context The event content.\r
429**/\r
430VOID\r
431EFIAPI\r
432OnExitBootServices (\r
433 IN EFI_EVENT Event,\r
434 IN VOID *Context\r
435 )\r
436{\r
437 DEBUG ((DEBUG_INFO, "Vtd OnExitBootServices\n"));\r
438 DumpVtdRegsAll ();\r
c50596a7
JY
439\r
440 if ((PcdGet8(PcdVTdPolicyPropertyMask) & BIT1) == 0) {\r
441 DisableDmar ();\r
442 DumpVtdRegsAll ();\r
443 }\r
c049fc99
JY
444}\r
445\r
446/**\r
447 Legacy boot callback function.\r
448\r
449 @param[in] Event The event handle.\r
450 @param[in] Context The event content.\r
451**/\r
452VOID\r
453EFIAPI\r
454OnLegacyBoot (\r
455 EFI_EVENT Event,\r
456 VOID *Context\r
457 )\r
458{\r
459 DEBUG ((DEBUG_INFO, "Vtd OnLegacyBoot\n"));\r
460 DumpVtdRegsAll ();\r
461 DisableDmar ();\r
462 DumpVtdRegsAll ();\r
463}\r
464\r
465/**\r
466 Initialize DMA protection.\r
467**/\r
468VOID\r
469InitializeDmaProtection (\r
470 VOID\r
471 )\r
472{\r
473 EFI_STATUS Status;\r
474 EFI_EVENT ExitBootServicesEvent;\r
475 EFI_EVENT LegacyBootEvent;\r
dcd39e09
SZ
476 EFI_EVENT EventAcpi10;\r
477 EFI_EVENT EventAcpi20;\r
f6f486e7
SZ
478 \r
479 Status = gBS->CreateEventEx (\r
480 EVT_NOTIFY_SIGNAL,\r
3a716706 481 VTD_TPL_LEVEL,\r
f6f486e7
SZ
482 AcpiNotificationFunc,\r
483 NULL,\r
484 &gEfiAcpi10TableGuid,\r
dcd39e09 485 &EventAcpi10\r
f6f486e7 486 );\r
c049fc99
JY
487 ASSERT_EFI_ERROR (Status);\r
488\r
f6f486e7
SZ
489 Status = gBS->CreateEventEx (\r
490 EVT_NOTIFY_SIGNAL,\r
3a716706 491 VTD_TPL_LEVEL,\r
f6f486e7
SZ
492 AcpiNotificationFunc,\r
493 NULL,\r
494 &gEfiAcpi20TableGuid,\r
dcd39e09 495 &EventAcpi20\r
f6f486e7 496 );\r
c049fc99
JY
497 ASSERT_EFI_ERROR (Status);\r
498\r
dcd39e09
SZ
499 //\r
500 // Signal the events initially for the case\r
501 // that DMAR table has been installed.\r
502 //\r
503 gBS->SignalEvent (EventAcpi20);\r
504 gBS->SignalEvent (EventAcpi10);\r
505\r
c049fc99
JY
506 Status = gBS->CreateEventEx (\r
507 EVT_NOTIFY_SIGNAL,\r
01df5103 508 TPL_CALLBACK,\r
c049fc99
JY
509 OnExitBootServices,\r
510 NULL,\r
511 &gEfiEventExitBootServicesGuid,\r
512 &ExitBootServicesEvent\r
513 );\r
514 ASSERT_EFI_ERROR (Status);\r
515\r
516 Status = EfiCreateEventLegacyBootEx (\r
01df5103 517 TPL_CALLBACK,\r
c049fc99
JY
518 OnLegacyBoot,\r
519 NULL,\r
520 &LegacyBootEvent\r
521 );\r
522 ASSERT_EFI_ERROR (Status);\r
523\r
524 return ;\r
525}\r