3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "LegacyBiosInterface.h"
10 #include <IndustryStandard/Pci.h>
12 #define BOOT_LEGACY_OS 0
14 #define BOOT_UNCONVENTIONAL_DEVICE 2
16 UINT32 mLoadOptionsSize
= 0;
17 UINTN mBootMode
= BOOT_LEGACY_OS
;
18 VOID
*mLoadOptions
= NULL
;
19 BBS_BBS_DEVICE_PATH
*mBbsDevicePathPtr
= NULL
;
20 BBS_BBS_DEVICE_PATH mBbsDevicePathNode
;
21 UDC_ATTRIBUTES mAttributes
= { 0, 0, 0, 0 };
23 VOID
*mBeerData
= NULL
;
24 VOID
*mServiceAreaData
= NULL
;
25 UINT64 mLowWater
= 0xffffffffffffffffULL
;
27 extern BBS_TABLE
*mBbsTable
;
29 extern VOID
*mRuntimeSmbiosEntryPoint
;
30 extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint
;
31 extern EFI_PHYSICAL_ADDRESS mStructureTableAddress
;
36 @param BbsTable The BBS table.
42 IN BBS_TABLE
*BbsTable
49 DEBUG ((EFI_D_INFO
, "\n"));
50 DEBUG ((EFI_D_INFO
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
51 DEBUG ((EFI_D_INFO
, "=================================================================\n"));
52 for (Index
= 0; Index
< MAX_BBS_ENTRIES
; Index
++) {
56 if (BbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) {
62 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
64 (UINTN
) BbsTable
[Index
].BootPriority
,
65 (UINTN
) BbsTable
[Index
].Bus
,
66 (UINTN
) BbsTable
[Index
].Device
,
67 (UINTN
) BbsTable
[Index
].Function
,
68 (UINTN
) BbsTable
[Index
].Class
,
69 (UINTN
) BbsTable
[Index
].SubClass
,
70 (UINTN
) BbsTable
[Index
].DeviceType
,
71 (UINTN
) * (UINT16
*) &BbsTable
[Index
].StatusFlags
75 " %04x:%04x %04x:%04x %04x:%04x",
76 (UINTN
) BbsTable
[Index
].BootHandlerSegment
,
77 (UINTN
) BbsTable
[Index
].BootHandlerOffset
,
78 (UINTN
) BbsTable
[Index
].MfgStringSegment
,
79 (UINTN
) BbsTable
[Index
].MfgStringOffset
,
80 (UINTN
) BbsTable
[Index
].DescStringSegment
,
81 (UINTN
) BbsTable
[Index
].DescStringOffset
87 String
= (CHAR8
*)(((UINTN
)BbsTable
[Index
].DescStringSegment
<< 4) + BbsTable
[Index
].DescStringOffset
);
89 DEBUG ((EFI_D_INFO
," ("));
90 for (SubIndex
= 0; String
[SubIndex
] != 0; SubIndex
++) {
91 DEBUG ((EFI_D_INFO
, "%c", String
[SubIndex
]));
93 DEBUG ((EFI_D_INFO
,")"));
95 DEBUG ((EFI_D_INFO
,"\n"));
98 DEBUG ((EFI_D_INFO
, "\n"));
106 @param HddInfo The HddInfo table.
117 DEBUG ((EFI_D_INFO
, "\n"));
118 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
119 DEBUG ((EFI_D_INFO
, "Index - %04x\n", Index
));
120 DEBUG ((EFI_D_INFO
, " Status - %04x\n", (UINTN
)HddInfo
[Index
].Status
));
121 DEBUG ((EFI_D_INFO
, " B/D/F - %02x/%02x/%02x\n", (UINTN
)HddInfo
[Index
].Bus
, (UINTN
)HddInfo
[Index
].Device
, (UINTN
)HddInfo
[Index
].Function
));
122 DEBUG ((EFI_D_INFO
, " Command - %04x\n", HddInfo
[Index
].CommandBaseAddress
));
123 DEBUG ((EFI_D_INFO
, " Control - %04x\n", HddInfo
[Index
].ControlBaseAddress
));
124 DEBUG ((EFI_D_INFO
, " BusMaster - %04x\n", HddInfo
[Index
].BusMasterAddress
));
125 DEBUG ((EFI_D_INFO
, " HddIrq - %02x\n", HddInfo
[Index
].HddIrq
));
126 DEBUG ((EFI_D_INFO
, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
127 DEBUG ((EFI_D_INFO
, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
130 DEBUG ((EFI_D_INFO
, "\n"));
136 Print the PCI Interrupt Line and Interrupt Pin registers.
139 PrintPciInterruptRegister (
147 EFI_PCI_IO_PROTOCOL
*PciIo
;
154 gBS
->LocateHandleBuffer (
156 &gEfiPciIoProtocolGuid
,
166 DEBUG ((EFI_D_INFO
, "\n"));
167 DEBUG ((EFI_D_INFO
, " bb/dd/ff interrupt line interrupt pin\n"));
168 DEBUG ((EFI_D_INFO
, "======================================\n"));
169 for (Index
= 0; Index
< HandleNum
; Index
++) {
170 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiPciIoProtocolGuid
, (VOID
**) &PciIo
);
171 if (!EFI_ERROR (Status
)) {
172 Status
= PciIo
->Pci
.Read (
180 if (!EFI_ERROR (Status
)) {
181 Status
= PciIo
->GetLocation (
189 if (!EFI_ERROR (Status
)) {
190 DEBUG ((EFI_D_INFO
, " %02x/%02x/%02x 0x%02x 0x%02x\n",
191 Bus
, Device
, Function
, Interrupt
[0], Interrupt
[1]));
194 DEBUG ((EFI_D_INFO
, "\n"));
196 if (Handles
!= NULL
) {
202 Identify drive data must be updated to actual parameters before boot.
204 @param IdentifyDriveData ATA Identify Data
208 UpdateIdentifyDriveData (
209 IN UINT8
*IdentifyDriveData
215 @param Private Legacy BIOS Instance data
217 @retval EFI_SUCCESS Removable media not present
222 IN LEGACY_BIOS_INSTANCE
*Private
228 UINT8 LegacyInterrupts
[16];
229 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
230 UINTN RoutingTableEntries
;
231 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY
*IrqPriorityTable
;
232 UINTN NumberPriorityEntries
;
233 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
239 EFI_HANDLE
*HandleBuffer
;
240 EFI_ISA_IO_PROTOCOL
*IsaIo
;
245 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
246 LegacyBiosBuildSioData (Private
);
247 SetMem (LegacyInterrupts
, sizeof (LegacyInterrupts
), 0);
250 // Create list of legacy interrupts.
252 for (Index
= 0; Index
< 4; Index
++) {
253 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Serial
[Index
].Irq
;
256 for (Index
= 4; Index
< 7; Index
++) {
257 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Parallel
[Index
- 4].Irq
;
260 LegacyInterrupts
[7] = EfiToLegacy16BootTable
->SioData
.Floppy
.Irq
;
263 // Get Legacy Hdd IRQs. If native mode treat as PCI
265 for (Index
= 0; Index
< 2; Index
++) {
266 HddIrq
= EfiToLegacy16BootTable
->HddInfo
[Index
].HddIrq
;
267 if ((HddIrq
!= 0) && ((HddIrq
== 15) || (HddIrq
== 14))) {
268 LegacyInterrupts
[Index
+ 8] = HddIrq
;
272 Private
->LegacyBiosPlatform
->GetRoutingTable (
273 Private
->LegacyBiosPlatform
,
274 (VOID
*) &RoutingTable
,
275 &RoutingTableEntries
,
278 (VOID
**) &IrqPriorityTable
,
279 &NumberPriorityEntries
282 // Remove legacy interrupts from the list of PCI interrupts available.
284 for (Index
= 0; Index
<= 0x0b; Index
++) {
285 for (Index1
= 0; Index1
<= NumberPriorityEntries
; Index1
++) {
286 if (LegacyInterrupts
[Index
] != 0) {
287 LegacyInt
= (UINT16
) (LegacyInt
| (1 << LegacyInterrupts
[Index
]));
288 if (LegacyInterrupts
[Index
] == IrqPriorityTable
[Index1
].Irq
) {
289 IrqPriorityTable
[Index1
].Used
= LEGACY_USED
;
295 Private
->Legacy8259
->GetMask (
304 // Set SIO interrupts and disable mouse. Let mouse driver
307 LegMask
= (UINT16
) ((LegMask
&~LegacyInt
) | 0x1000);
308 Private
->Legacy8259
->SetMask (
317 // Disable mouse in keyboard controller
320 Status
= gBS
->LocateHandleBuffer (
322 &gEfiIsaIoProtocolGuid
,
327 if (EFI_ERROR (Status
)) {
331 for (Index
= 0; Index
< HandleCount
; Index
++) {
332 Status
= gBS
->HandleProtocol (
334 &gEfiIsaIoProtocolGuid
,
337 ASSERT_EFI_ERROR (Status
);
338 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, 0x64, 1, &Register
);
342 if (HandleBuffer
!= NULL
) {
343 FreePool (HandleBuffer
);
351 Identify drive data must be updated to actual parameters before boot.
352 This requires updating the checksum, if it exists.
354 @param IdentifyDriveData ATA Identify Data
355 @param Checksum checksum of the ATA Identify Data
357 @retval EFI_SUCCESS checksum calculated
358 @retval EFI_SECURITY_VIOLATION IdentifyData invalid
362 CalculateIdentifyDriveChecksum (
363 IN UINT8
*IdentifyDriveData
,
371 if (IdentifyDriveData
[510] != 0xA5) {
372 return EFI_SECURITY_VIOLATION
;
375 for (Index
= 0; Index
< 512; Index
++) {
376 LocalChecksum
= (UINT8
) (LocalChecksum
+ IdentifyDriveData
[Index
]);
379 *Checksum
= LocalChecksum
;
385 Identify drive data must be updated to actual parameters before boot.
387 @param IdentifyDriveData ATA Identify Data
392 UpdateIdentifyDriveData (
393 IN UINT8
*IdentifyDriveData
396 UINT16 NumberCylinders
;
398 UINT16 NumberSectorsTrack
;
399 UINT32 CapacityInSectors
;
400 UINT8 OriginalChecksum
;
403 ATAPI_IDENTIFY
*ReadInfo
;
406 // Status indicates if Integrity byte is correct. Checksum should be
409 ReadInfo
= (ATAPI_IDENTIFY
*) IdentifyDriveData
;
410 Status
= CalculateIdentifyDriveChecksum (IdentifyDriveData
, &OriginalChecksum
);
411 if (OriginalChecksum
!= 0) {
412 Status
= EFI_SECURITY_VIOLATION
;
415 // If NumberCylinders = 0 then do data(Controller present but don drive attached).
417 NumberCylinders
= ReadInfo
->Raw
[1];
418 if (NumberCylinders
!= 0) {
419 ReadInfo
->Raw
[54] = NumberCylinders
;
421 NumberHeads
= ReadInfo
->Raw
[3];
422 ReadInfo
->Raw
[55] = NumberHeads
;
424 NumberSectorsTrack
= ReadInfo
->Raw
[6];
425 ReadInfo
->Raw
[56] = NumberSectorsTrack
;
428 // Copy Multisector info and set valid bit.
430 ReadInfo
->Raw
[59] = (UINT16
) (ReadInfo
->Raw
[47] + 0x100);
431 CapacityInSectors
= (UINT32
) ((UINT32
) (NumberCylinders
) * (UINT32
) (NumberHeads
) * (UINT32
) (NumberSectorsTrack
));
432 ReadInfo
->Raw
[57] = (UINT16
) (CapacityInSectors
>> 16);
433 ReadInfo
->Raw
[58] = (UINT16
) (CapacityInSectors
& 0xffff);
434 if (Status
== EFI_SUCCESS
) {
436 // Forece checksum byte to 0 and get new checksum.
438 ReadInfo
->Raw
[255] &= 0xff;
439 CalculateIdentifyDriveChecksum (IdentifyDriveData
, &FinalChecksum
);
442 // Force new checksum such that sum is 0.
444 FinalChecksum
= (UINT8
) ((UINT8
)0 - FinalChecksum
);
445 ReadInfo
->Raw
[255] = (UINT16
) (ReadInfo
->Raw
[255] | (FinalChecksum
<< 8));
451 Identify drive data must be updated to actual parameters before boot.
454 @param Private Legacy BIOS Instance data
459 UpdateAllIdentifyDriveData (
460 IN LEGACY_BIOS_INSTANCE
*Private
466 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
468 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
470 // Each controller can have 2 devices. Update for each device
472 if ((HddInfo
[Index
].Status
& HDD_MASTER_IDE
) != 0) {
473 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
476 if ((HddInfo
[Index
].Status
& HDD_SLAVE_IDE
) != 0) {
477 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
483 Enable ide controller. This gets disabled when LegacyBoot.c is about
484 to run the Option ROMs.
486 @param Private Legacy BIOS Instance data
491 EnableIdeController (
492 IN LEGACY_BIOS_INSTANCE
*Private
495 EFI_PCI_IO_PROTOCOL
*PciIo
;
497 EFI_HANDLE IdeController
;
500 EFI_HANDLE
*HandleBuffer
;
502 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
503 Private
->LegacyBiosPlatform
,
504 EfiGetPlatformIdeHandle
,
510 if (!EFI_ERROR (Status
)) {
511 IdeController
= HandleBuffer
[0];
512 Status
= gBS
->HandleProtocol (
514 &gEfiPciIoProtocolGuid
,
518 if (!EFI_ERROR (Status
)) {
519 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x04, 1, &ByteBuffer
);
526 Enable ide controller. This gets disabled when LegacyBoot.c is about
527 to run the Option ROMs.
529 @param Private Legacy BIOS Instance data
534 EnableAllControllers (
535 IN LEGACY_BIOS_INSTANCE
*Private
539 EFI_HANDLE
*HandleBuffer
;
541 EFI_PCI_IO_PROTOCOL
*PciIo
;
542 PCI_TYPE01 PciConfigHeader
;
548 EnableIdeController (Private
);
551 // Assumption is table is built from low bus to high bus numbers.
553 Status
= gBS
->LocateHandleBuffer (
555 &gEfiPciIoProtocolGuid
,
560 ASSERT_EFI_ERROR (Status
);
562 for (Index
= 0; Index
< HandleCount
; Index
++) {
563 Status
= gBS
->HandleProtocol (
565 &gEfiPciIoProtocolGuid
,
568 ASSERT_EFI_ERROR (Status
);
574 sizeof (PciConfigHeader
) / sizeof (UINT32
),
579 // We do not enable PPB here. This is for HotPlug Consideration.
580 // The Platform HotPlug Driver is responsible for Padding enough hot plug
581 // resources. It is also responsible for enable this bridge. If it
582 // does not pad it. It will cause some early Windows fail to installation.
583 // If the platform driver does not pad resource for PPB, PPB should be in
584 // un-enabled state to let Windows know that this PPB is not configured by
585 // BIOS. So Windows will allocate default resource for PPB.
587 // The reason for why we enable the command register is:
588 // The CSM will use the IO bar to detect some IRQ status, if the command
589 // is disabled, the IO resource will be out of scope.
591 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
592 // comes up, the handle will check the IO space to identify is the
593 // controller generated the IRQ source.
594 // If the IO command is not enabled, the IRQ handler will has wrong
595 // information. It will cause IRQ storm when the correctly IRQ handler fails
598 if (!(IS_PCI_VGA (&PciConfigHeader
) ||
599 IS_PCI_OLD_VGA (&PciConfigHeader
) ||
600 IS_PCI_IDE (&PciConfigHeader
) ||
601 IS_PCI_P2P (&PciConfigHeader
) ||
602 IS_PCI_P2P_SUB (&PciConfigHeader
) ||
603 IS_PCI_LPC (&PciConfigHeader
) )) {
605 PciConfigHeader
.Hdr
.Command
|= 0x1f;
607 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 4, 1, &PciConfigHeader
.Hdr
.Command
);
613 The following routines are identical in operation, so combine
615 EfiGetPlatformBinaryGetMpTable
616 EfiGetPlatformBinaryGetOemIntData
617 EfiGetPlatformBinaryGetOem32Data
618 EfiGetPlatformBinaryGetOem16Data
620 @param This Protocol instance pointer.
621 @param Id Table/Data identifier
623 @retval EFI_SUCCESS Success
624 @retval EFI_INVALID_PARAMETER Invalid ID
625 @retval EFI_OUT_OF_RESOURCES no resource to get data or table
629 LegacyGetDataOrTable (
630 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
631 IN EFI_GET_PLATFORM_INFO_MODE Id
640 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
641 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
642 EFI_IA32_REGISTER_SET Regs
;
643 LEGACY_BIOS_INSTANCE
*Private
;
645 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
647 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
648 Legacy16Table
= Private
->Legacy16Table
;
651 // Phase 1 - get an address allocated in 16-bit code
655 case EfiGetPlatformBinaryMpTable
:
656 case EfiGetPlatformBinaryOemIntData
:
657 case EfiGetPlatformBinaryOem32Data
:
658 case EfiGetPlatformBinaryOem16Data
:
660 Status
= LegacyBiosPlatform
->GetPlatformInfo (
670 DEBUG ((EFI_D_INFO
, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN
)Id
, Status
));
671 DEBUG ((EFI_D_INFO
, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN
)Table
, (UINTN
)TableSize
, (UINTN
)Location
, (UINTN
)Alignment
));
677 return EFI_INVALID_PARAMETER
;
681 if (EFI_ERROR (Status
)) {
685 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
686 Regs
.X
.AX
= Legacy16GetTableAddress
;
687 Regs
.X
.CX
= (UINT16
) TableSize
;
688 Regs
.X
.BX
= (UINT16
) Location
;
689 Regs
.X
.DX
= (UINT16
) Alignment
;
690 Private
->LegacyBios
.FarCall86 (
692 Private
->Legacy16CallSegment
,
693 Private
->Legacy16CallOffset
,
699 if (Regs
.X
.AX
!= 0) {
700 DEBUG ((EFI_D_ERROR
, "Table ID %x length insufficient\n", Id
));
701 return EFI_OUT_OF_RESOURCES
;
707 // Phase 2 Call routine second time with address to allow address adjustment
709 Status
= LegacyBiosPlatform
->GetPlatformInfo (
720 case EfiGetPlatformBinaryMpTable
:
722 Legacy16Table
->MpTablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
723 Legacy16Table
->MpTableLength
= (UINT32
)TableSize
;
724 DEBUG ((EFI_D_INFO
, "MP table in legacy region - %x\n", (UINTN
)Legacy16Table
->MpTablePtr
));
728 case EfiGetPlatformBinaryOemIntData
:
731 Legacy16Table
->OemIntSegment
= Regs
.X
.DS
;
732 Legacy16Table
->OemIntOffset
= Regs
.X
.BX
;
733 DEBUG ((EFI_D_INFO
, "OemInt table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->OemIntSegment
, (UINTN
)Legacy16Table
->OemIntOffset
));
737 case EfiGetPlatformBinaryOem32Data
:
739 Legacy16Table
->Oem32Segment
= Regs
.X
.DS
;
740 Legacy16Table
->Oem32Offset
= Regs
.X
.BX
;
741 DEBUG ((EFI_D_INFO
, "Oem32 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem32Segment
, (UINTN
)Legacy16Table
->Oem32Offset
));
745 case EfiGetPlatformBinaryOem16Data
:
748 // Legacy16Table->Oem16Segment = Regs.X.DS;
749 // Legacy16Table->Oem16Offset = Regs.X.BX;
750 DEBUG ((EFI_D_INFO
, "Oem16 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem16Segment
, (UINTN
)Legacy16Table
->Oem16Offset
));
756 return EFI_INVALID_PARAMETER
;
760 if (EFI_ERROR (Status
)) {
764 // Phase 3 Copy table to final location
766 TablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
769 (VOID
*) (UINTN
)TablePtr
,
778 Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot.
782 CreateSmbiosTableInReservedMemory (
786 SMBIOS_TABLE_ENTRY_POINT
*EntryPointStructure
;
788 if ((mRuntimeSmbiosEntryPoint
== NULL
) ||
789 (mReserveSmbiosEntryPoint
== 0) ||
790 (mStructureTableAddress
== 0)) {
794 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*) mRuntimeSmbiosEntryPoint
;
797 // Copy SMBIOS Entry Point Structure
800 (VOID
*)(UINTN
) mReserveSmbiosEntryPoint
,
802 EntryPointStructure
->EntryPointLength
806 // Copy SMBIOS Structure Table into EfiReservedMemoryType memory
809 (VOID
*)(UINTN
) mStructureTableAddress
,
810 (VOID
*)(UINTN
) EntryPointStructure
->TableAddress
,
811 EntryPointStructure
->TableLength
815 // Update TableAddress in Entry Point Structure
817 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*)(UINTN
) mReserveSmbiosEntryPoint
;
818 EntryPointStructure
->TableAddress
= (UINT32
)(UINTN
) mStructureTableAddress
;
821 // Fixup checksums in the Entry Point Structure
823 EntryPointStructure
->IntermediateChecksum
= 0;
824 EntryPointStructure
->EntryPointStructureChecksum
= 0;
826 EntryPointStructure
->IntermediateChecksum
=
828 (UINT8
*) EntryPointStructure
+ OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT
, IntermediateAnchorString
),
829 EntryPointStructure
->EntryPointLength
- OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT
, IntermediateAnchorString
)
831 EntryPointStructure
->EntryPointStructureChecksum
=
832 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
, EntryPointStructure
->EntryPointLength
);
836 Assign drive number to legacy HDD drives prior to booting an EFI
837 aware OS so the OS can access drives without an EFI driver.
838 Note: BBS compliant drives ARE NOT available until this call by
841 @param This Protocol instance pointer.
843 @retval EFI_SUCCESS Drive numbers assigned
848 IN EFI_LEGACY_BIOS_PROTOCOL
*This
852 LEGACY_BIOS_INSTANCE
*Private
;
853 EFI_IA32_REGISTER_SET Regs
;
854 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
855 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
859 HDD_INFO
*LocalHddInfo
;
861 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
865 BBS_TABLE
*LocalBbsTable
;
866 UINT32
*BaseVectorMaster
;
869 EFI_HANDLE IdeController
;
871 EFI_HANDLE
*HandleBuffer
;
879 LocalBbsTable
= NULL
;
881 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
883 DEBUG ((EFI_D_ERROR
, "Start of legacy boot\n"));
886 Legacy16Table
= Private
->Legacy16Table
;
887 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
888 HddInfo
= &EfiToLegacy16BootTable
->HddInfo
[0];
890 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
892 EfiToLegacy16BootTable
->MajorVersion
= EFI_TO_LEGACY_MAJOR_VERSION
;
893 EfiToLegacy16BootTable
->MinorVersion
= EFI_TO_LEGACY_MINOR_VERSION
;
896 // If booting to a legacy OS then force HDD drives to the appropriate
897 // boot mode by calling GetIdeHandle.
898 // A reconnect -r can force all HDDs back to native mode.
900 IdeController
= NULL
;
901 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
902 Status
= LegacyBiosPlatform
->GetPlatformHandle (
903 Private
->LegacyBiosPlatform
,
904 EfiGetPlatformIdeHandle
,
910 if (!EFI_ERROR (Status
)) {
911 IdeController
= HandleBuffer
[0];
915 // Unlock the Legacy BIOS region
917 Private
->LegacyRegion
->UnLock (
918 Private
->LegacyRegion
,
925 // Reconstruct the Legacy16 boot memory map
927 LegacyBiosBuildE820 (Private
, &CopySize
);
928 if (CopySize
> Private
->Legacy16Table
->E820Length
) {
929 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
930 Regs
.X
.AX
= Legacy16GetTableAddress
;
931 Regs
.X
.BX
= (UINT16
) 0x0; // Any region
932 Regs
.X
.CX
= (UINT16
) CopySize
;
933 Regs
.X
.DX
= (UINT16
) 0x4; // Alignment
934 Private
->LegacyBios
.FarCall86 (
935 &Private
->LegacyBios
,
936 Private
->Legacy16Table
->Compatibility16CallSegment
,
937 Private
->Legacy16Table
->Compatibility16CallOffset
,
943 Private
->Legacy16Table
->E820Pointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
944 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
945 if (Regs
.X
.AX
!= 0) {
946 DEBUG ((EFI_D_ERROR
, "Legacy16 E820 length insufficient\n"));
947 return EFI_OUT_OF_RESOURCES
;
950 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
957 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
961 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
965 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
967 if (mReserveSmbiosEntryPoint
== 0) {
968 DEBUG ((EFI_D_INFO
, "Smbios table is not found!\n"));
970 CreateSmbiosTableInReservedMemory ();
971 EfiToLegacy16BootTable
->SmbiosTable
= (UINT32
)(UINTN
)mReserveSmbiosEntryPoint
;
974 Status
= EfiGetSystemConfigurationTable (
975 &gEfiAcpi20TableGuid
,
978 if (EFI_ERROR (Status
)) {
979 Status
= EfiGetSystemConfigurationTable (
980 &gEfiAcpi10TableGuid
,
985 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
987 if (AcpiTable
== NULL
) {
988 DEBUG ((EFI_D_INFO
, "ACPI table is not found!\n"));
990 EfiToLegacy16BootTable
->AcpiTable
= (UINT32
)(UINTN
)AcpiTable
;
993 // Get RSD Ptr table rev at offset 15 decimal
994 // Rev = 0 Length is 20 decimal
995 // Rev != 0 Length is UINT32 at offset 20 decimal
997 if (AcpiTable
!= NULL
) {
1000 if (*((UINT8
*) AcpiPtr
+ 15) == 0) {
1003 AcpiPtr
= ((UINT8
*) AcpiPtr
+ 20);
1004 CopySize
= (*(UINT32
*) AcpiPtr
);
1008 (VOID
*)(UINTN
) Private
->Legacy16Table
->AcpiRsdPtrPointer
,
1014 // Make sure all PCI Interrupt Line register are programmed to match 8259
1016 PciProgramAllInterruptLineRegisters (Private
);
1019 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
1022 Private
->LegacyRegion
->UnLock (
1023 Private
->LegacyRegion
,
1025 Private
->LegacyBiosImageSize
,
1030 // Configure Legacy Device Magic
1032 // Only do this code if booting legacy OS
1034 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1035 UpdateSioData (Private
);
1038 // Setup BDA and EBDA standard areas before Legacy Boot
1041 LegacyBiosCompleteBdaBeforeBoot (Private
);
1043 LegacyBiosCompleteStandardCmosBeforeBoot (Private
);
1046 // We must build IDE data, if it hasn't been done, before PciShadowRoms
1047 // to insure EFI drivers are connected.
1049 LegacyBiosBuildIdeData (Private
, &HddInfo
, 1);
1050 UpdateAllIdentifyDriveData (Private
);
1053 // Clear IO BAR, if IDE controller in legacy mode.
1055 InitLegacyIdeController (IdeController
);
1058 // Generate number of ticks since midnight for BDA. DOS requires this
1059 // for its time. We have to make assumptions as to how long following
1060 // code takes since after PciShadowRoms PciIo is gone. Place result in
1063 // Adjust value by 1 second.
1065 gRT
->GetTime (&BootTime
, NULL
);
1066 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
1070 // Multiply result by 18.2 for number of ticks since midnight.
1071 // Use 182/10 to avoid floating point math.
1073 LocalTime
= (LocalTime
* 182) / 10;
1075 BdaPtr
= (UINT32
*) (UINTN
)0x46C;
1076 *BdaPtr
= LocalTime
;
1080 // Shadow PCI ROMs. We must do this near the end since this will kick
1081 // of Native EFI drivers that may be needed to collect info for Legacy16
1083 // WARNING: PciIo is gone after this call.
1085 PciShadowRoms (Private
);
1088 // Shadow PXE base code, BIS etc.
1090 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xc0000, 0x40000, &Granularity
);
1091 ShadowAddress
= Private
->OptionRom
;
1092 Private
->LegacyBiosPlatform
->PlatformHooks (
1093 Private
->LegacyBiosPlatform
,
1094 EfiPlatformHookShadowServiceRoms
,
1101 Private
->OptionRom
= (UINT32
)ShadowAddress
;
1103 // Register Legacy SMI Handler
1105 LegacyBiosPlatform
->SmmInit (
1107 EfiToLegacy16BootTable
1111 // Let platform code know the boot options
1113 LegacyBiosGetBbsInfo (
1122 PrintPciInterruptRegister ();
1123 PrintBbsTable (LocalBbsTable
);
1124 PrintHddInfo (LocalHddInfo
);
1127 // If drive wasn't spun up then BuildIdeData may have found new drives.
1128 // Need to update BBS boot priority.
1130 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
1131 if ((LocalHddInfo
[Index
].IdentifyDrive
[0].Raw
[0] != 0) &&
1132 (LocalBbsTable
[2 * Index
+ 1].BootPriority
== BBS_IGNORE_ENTRY
)
1134 LocalBbsTable
[2 * Index
+ 1].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1137 if ((LocalHddInfo
[Index
].IdentifyDrive
[1].Raw
[0] != 0) &&
1138 (LocalBbsTable
[2 * Index
+ 2].BootPriority
== BBS_IGNORE_ENTRY
)
1140 LocalBbsTable
[2 * Index
+ 2].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1144 Private
->LegacyRegion
->UnLock (
1145 Private
->LegacyRegion
,
1151 LegacyBiosPlatform
->PrepareToBoot (
1157 (VOID
*) &Private
->IntThunk
->EfiToLegacy16BootTable
1161 // If no boot device return to BDS
1163 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1164 for (Index
= 0; Index
< BbsCount
; Index
++){
1165 if ((LocalBbsTable
[Index
].BootPriority
!= BBS_DO_NOT_BOOT_FROM
) &&
1166 (LocalBbsTable
[Index
].BootPriority
!= BBS_UNPRIORITIZED_ENTRY
) &&
1167 (LocalBbsTable
[Index
].BootPriority
!= BBS_IGNORE_ENTRY
)) {
1171 if (Index
== BbsCount
) {
1172 return EFI_DEVICE_ERROR
;
1176 // Let the Legacy16 code know the device path type for legacy boot
1178 EfiToLegacy16BootTable
->DevicePathType
= mBbsDevicePathPtr
->DeviceType
;
1181 // Copy MP table, if it exists.
1183 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryMpTable
);
1185 if (!Private
->LegacyBootEntered
) {
1187 // Copy OEM INT Data, if it exists. Note: This code treats any data
1188 // as a bag of bits and knows nothing of the contents nor cares.
1189 // Contents are IBV specific.
1191 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOemIntData
);
1194 // Copy OEM16 Data, if it exists.Note: This code treats any data
1195 // as a bag of bits and knows nothing of the contents nor cares.
1196 // Contents are IBV specific.
1198 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem16Data
);
1201 // Copy OEM32 Data, if it exists.Note: This code treats any data
1202 // as a bag of bits and knows nothing of the contents nor cares.
1203 // Contents are IBV specific.
1205 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem32Data
);
1209 // Call into Legacy16 code to prepare for INT 19h
1211 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1212 Regs
.X
.AX
= Legacy16PrepareToBoot
;
1215 // Pass in handoff data
1217 Regs
.X
.ES
= NORMALIZE_EFI_SEGMENT ((UINTN
)EfiToLegacy16BootTable
);
1218 Regs
.X
.BX
= NORMALIZE_EFI_OFFSET ((UINTN
)EfiToLegacy16BootTable
);
1220 Private
->LegacyBios
.FarCall86 (
1222 Private
->Legacy16CallSegment
,
1223 Private
->Legacy16CallOffset
,
1229 if (Regs
.X
.AX
!= 0) {
1230 return EFI_DEVICE_ERROR
;
1233 // Lock the Legacy BIOS region
1235 Private
->LegacyRegion
->Lock (
1236 Private
->LegacyRegion
,
1242 if ((Private
->Legacy16Table
->TableLength
>= OFFSET_OF (EFI_COMPATIBILITY16_TABLE
, HiPermanentMemoryAddress
)) &&
1243 ((Private
->Legacy16Table
->UmaAddress
!= 0) && (Private
->Legacy16Table
->UmaSize
!= 0))) {
1245 // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into
1246 // account the granularity of the access control.
1248 DEBUG((EFI_D_INFO
, "Unlocking UMB RAM region 0x%x-0x%x\n", Private
->Legacy16Table
->UmaAddress
,
1249 Private
->Legacy16Table
->UmaAddress
+ Private
->Legacy16Table
->UmaSize
));
1251 Private
->LegacyRegion
->UnLock (
1252 Private
->LegacyRegion
,
1253 Private
->Legacy16Table
->UmaAddress
,
1254 Private
->Legacy16Table
->UmaSize
,
1260 // Lock attributes of the Legacy Region if chipset supports
1262 Private
->LegacyRegion
->BootLock (
1263 Private
->LegacyRegion
,
1270 // Call into Legacy16 code to do the INT 19h
1272 EnableAllControllers (Private
);
1273 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1276 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
1278 EfiSignalEventLegacyBoot ();
1281 // Report Status Code to indicate legacy boot event was signalled
1283 REPORT_STATUS_CODE (
1285 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT
)
1288 DEBUG ((EFI_D_INFO
, "Legacy INT19 Boot...\n"));
1291 // Disable DXE Timer while executing in real mode
1293 Private
->Timer
->SetTimerPeriod (Private
->Timer
, 0);
1296 // Save and disable interrupt of debug timer
1298 SaveAndSetDebugTimerInterrupt (FALSE
);
1302 // Put the 8259 into its legacy mode by reprogramming the vector bases
1304 Private
->Legacy8259
->SetVectorBase (Private
->Legacy8259
, LEGACY_MODE_BASE_VECTOR_MASTER
, LEGACY_MODE_BASE_VECTOR_SLAVE
);
1307 // The original PC used INT8-F for master PIC. Since these mapped over
1308 // processor exceptions TIANO moved the master PIC to INT68-6F.
1309 // We need to set these back to the Legacy16 unexpected interrupt(saved
1310 // in LegacyBios.c) since some OS see that these have values different from
1311 // what is expected and invoke them. Since the legacy OS corrupts EFI
1312 // memory, there is no handler for these interrupts and OS blows up.
1314 // We need to save the TIANO values for the rare case that the Legacy16
1315 // code cannot boot but knows memory hasn't been destroyed.
1317 // To compound the problem, video takes over one of these INTS and must be
1319 // @bug - determine if video hooks INT(in which case we must find new
1320 // set of TIANO vectors) or takes it over.
1324 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1325 for (Index
= 0; Index
< 8; Index
++) {
1326 Private
->ThunkSavedInt
[Index
] = BaseVectorMaster
[Index
];
1327 if (Private
->ThunkSeg
== (UINT16
) (BaseVectorMaster
[Index
] >> 16)) {
1328 BaseVectorMaster
[Index
] = (UINT32
) (Private
->BiosUnexpectedInt
);
1333 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1334 Regs
.X
.AX
= Legacy16Boot
;
1336 Private
->LegacyBios
.FarCall86 (
1338 Private
->Legacy16CallSegment
,
1339 Private
->Legacy16CallOffset
,
1346 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1347 for (Index
= 0; Index
< 8; Index
++) {
1348 BaseVectorMaster
[Index
] = Private
->ThunkSavedInt
[Index
];
1352 Private
->LegacyBootEntered
= TRUE
;
1353 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1355 // Should never return unless never passed control to 0:7c00(first stage
1356 // OS loader) and only then if no bootable device found.
1358 return EFI_DEVICE_ERROR
;
1361 // If boot to EFI then expect to return to caller
1369 Assign drive number to legacy HDD drives prior to booting an EFI
1370 aware OS so the OS can access drives without an EFI driver.
1371 Note: BBS compliant drives ARE NOT available until this call by
1372 either shell or EFI.
1374 @param This Protocol instance pointer.
1375 @param BbsCount Number of BBS_TABLE structures
1376 @param BbsTable List BBS entries
1378 @retval EFI_SUCCESS Drive numbers assigned
1383 LegacyBiosPrepareToBootEfi (
1384 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1385 OUT UINT16
*BbsCount
,
1386 OUT BBS_TABLE
**BbsTable
1390 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1391 LEGACY_BIOS_INSTANCE
*Private
;
1393 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1394 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1395 mBootMode
= BOOT_EFI_OS
;
1396 mBbsDevicePathPtr
= NULL
;
1397 Status
= GenericLegacyBoot (This
);
1398 *BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1399 *BbsCount
= (UINT16
) (sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
));
1404 To boot from an unconventional device like parties and/or execute HDD diagnostics.
1406 @param This Protocol instance pointer.
1407 @param Attributes How to interpret the other input parameters
1408 @param BbsEntry The 0-based index into the BbsTable for the parent
1410 @param BeerData Pointer to the 128 bytes of ram BEER data.
1411 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1412 caller must provide a pointer to the specific Service
1413 Area and not the start all Service Areas.
1415 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1420 LegacyBiosBootUnconventionalDevice (
1421 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1422 IN UDC_ATTRIBUTES Attributes
,
1425 IN VOID
*ServiceAreaData
1429 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1430 LEGACY_BIOS_INSTANCE
*Private
;
1433 UINT16 BootPriority
;
1434 BBS_TABLE
*BbsTable
;
1437 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1438 mBootMode
= BOOT_UNCONVENTIONAL_DEVICE
;
1439 mBbsDevicePathPtr
= &mBbsDevicePathNode
;
1440 mAttributes
= Attributes
;
1441 mBbsEntry
= BbsEntry
;
1442 mBeerData
= BeerData
, mServiceAreaData
= ServiceAreaData
;
1444 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1447 // Do input parameter checking
1449 if ((Attributes
.DirectoryServiceValidity
== 0) &&
1450 (Attributes
.RabcaUsedFlag
== 0) &&
1451 (Attributes
.ExecuteHddDiagnosticsFlag
== 0)
1453 return EFI_INVALID_PARAMETER
;
1456 if (((Attributes
.DirectoryServiceValidity
!= 0) && (ServiceAreaData
== NULL
)) ||
1457 (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
) != 0) && (BeerData
== NULL
))
1459 return EFI_INVALID_PARAMETER
;
1462 UcdTable
= (UD_TABLE
*) AllocatePool (
1465 if (NULL
== UcdTable
) {
1466 return EFI_OUT_OF_RESOURCES
;
1469 EfiToLegacy16BootTable
->UnconventionalDeviceTable
= (UINT32
)(UINTN
)UcdTable
;
1470 UcdTable
->Attributes
= Attributes
;
1471 UcdTable
->BbsTableEntryNumberForParentDevice
= (UINT8
) BbsEntry
;
1473 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1474 // to assign drive numbers but bot boot from. Only newly created entries
1477 BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1478 for (Index
= 0; Index
< EfiToLegacy16BootTable
->NumberBbsEntries
; Index
++) {
1479 BbsTable
[Index
].BootPriority
= BBS_DO_NOT_BOOT_FROM
;
1482 // If parent is onboard IDE then assign controller & device number
1485 if (BbsEntry
< MAX_IDE_CONTROLLER
* 2) {
1486 UcdTable
->DeviceNumber
= (UINT8
) ((BbsEntry
- 1) % 2);
1489 if (BeerData
!= NULL
) {
1491 (VOID
*) UcdTable
->BeerData
,
1497 if (ServiceAreaData
!= NULL
) {
1499 (VOID
*) UcdTable
->ServiceAreaData
,
1505 // For each new entry do the following:
1506 // 1. Increment current number of BBS entries
1507 // 2. Copy parent entry to new entry.
1508 // 3. Zero out BootHandler Offset & segment
1509 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1510 // and Floppy(0x01) for PARTIES boot.
1511 // 5. Assign new priority.
1513 if ((Attributes
.ExecuteHddDiagnosticsFlag
) != 0) {
1514 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1517 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1518 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1522 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1523 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1524 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x80;
1526 UcdTable
->BbsTableEntryNumberForHddDiag
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1528 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1532 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1534 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_BEV
;
1537 if (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
)) != 0) {
1538 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1540 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1541 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1545 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1546 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1547 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x01;
1548 UcdTable
->BbsTableEntryNumberForBoot
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1549 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1552 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1554 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_FLOPPY
;
1557 // Build the BBS Device Path for this boot selection
1559 mBbsDevicePathNode
.Header
.Type
= BBS_DEVICE_PATH
;
1560 mBbsDevicePathNode
.Header
.SubType
= BBS_BBS_DP
;
1561 SetDevicePathNodeLength (&mBbsDevicePathNode
.Header
, sizeof (BBS_BBS_DEVICE_PATH
));
1562 mBbsDevicePathNode
.StatusFlag
= 0;
1563 mBbsDevicePathNode
.String
[0] = 0;
1565 Status
= GenericLegacyBoot (This
);
1570 Attempt to legacy boot the BootOption. If the EFI contexted has been
1571 compromised this function will not return.
1573 @param This Protocol instance pointer.
1574 @param BbsDevicePath EFI Device Path from BootXXXX variable.
1575 @param LoadOptionsSize Size of LoadOption in size.
1576 @param LoadOptions LoadOption from BootXXXX variable
1578 @retval EFI_SUCCESS Removable media not present
1583 LegacyBiosLegacyBoot (
1584 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1585 IN BBS_BBS_DEVICE_PATH
*BbsDevicePath
,
1586 IN UINT32 LoadOptionsSize
,
1587 IN VOID
*LoadOptions
1592 mBbsDevicePathPtr
= BbsDevicePath
;
1593 mLoadOptionsSize
= LoadOptionsSize
;
1594 mLoadOptions
= LoadOptions
;
1595 mBootMode
= BOOT_LEGACY_OS
;
1596 Status
= GenericLegacyBoot (This
);
1602 Convert EFI Memory Type to E820 Memory Type.
1604 @param Type EFI Memory Type
1606 @return ACPI Memory Type for EFI Memory Type
1609 EFI_ACPI_MEMORY_TYPE
1610 EfiMemoryTypeToE820Type (
1617 case EfiBootServicesCode
:
1618 case EfiBootServicesData
:
1619 case EfiConventionalMemory
:
1621 // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are
1622 // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept.
1623 // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData
1624 // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS.
1626 case EfiRuntimeServicesCode
:
1627 case EfiRuntimeServicesData
:
1628 return EfiAcpiAddressRangeMemory
;
1630 case EfiPersistentMemory
:
1631 return EfiAddressRangePersistentMemory
;
1633 case EfiACPIReclaimMemory
:
1634 return EfiAcpiAddressRangeACPI
;
1636 case EfiACPIMemoryNVS
:
1637 return EfiAcpiAddressRangeNVS
;
1640 // All other types map to reserved.
1641 // Adding the code just waists FLASH space.
1643 // case EfiReservedMemoryType:
1644 // case EfiUnusableMemory:
1645 // case EfiMemoryMappedIO:
1646 // case EfiMemoryMappedIOPortSpace:
1650 return EfiAcpiAddressRangeReserved
;
1655 Build the E820 table.
1657 @param Private Legacy BIOS Instance data
1658 @param Size Size of E820 Table
1660 @retval EFI_SUCCESS It should always work.
1664 LegacyBiosBuildE820 (
1665 IN LEGACY_BIOS_INSTANCE
*Private
,
1670 EFI_E820_ENTRY64
*E820Table
;
1671 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMap
;
1672 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMapEnd
;
1673 EFI_MEMORY_DESCRIPTOR
*EfiEntry
;
1674 EFI_MEMORY_DESCRIPTOR
*NextEfiEntry
;
1675 EFI_MEMORY_DESCRIPTOR TempEfiEntry
;
1676 UINTN EfiMemoryMapSize
;
1678 UINTN EfiDescriptorSize
;
1679 UINT32 EfiDescriptorVersion
;
1681 EFI_PEI_HOB_POINTERS Hob
;
1682 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
1685 UINTN TempNextIndex
;
1686 EFI_E820_ENTRY64 TempE820
;
1687 EFI_ACPI_MEMORY_TYPE TempType
;
1688 BOOLEAN ChangedFlag
;
1690 UINT64 MemoryBlockLength
;
1692 E820Table
= (EFI_E820_ENTRY64
*) Private
->E820Table
;
1695 // Get the EFI memory map.
1697 EfiMemoryMapSize
= 0;
1698 EfiMemoryMap
= NULL
;
1699 Status
= gBS
->GetMemoryMap (
1704 &EfiDescriptorVersion
1706 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1710 // Use size returned for the AllocatePool.
1711 // We don't just multiply by 2 since the "for" loop below terminates on
1712 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwise
1713 // we process bogus entries and create bogus E820 entries.
1715 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*) AllocatePool (EfiMemoryMapSize
);
1716 ASSERT (EfiMemoryMap
!= NULL
);
1717 Status
= gBS
->GetMemoryMap (
1722 &EfiDescriptorVersion
1724 if (EFI_ERROR (Status
)) {
1725 FreePool (EfiMemoryMap
);
1727 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1729 ASSERT_EFI_ERROR (Status
);
1732 // Punch in the E820 table for memory less than 1 MB.
1733 // Assume ZeroMem () has been done on data structure.
1736 // First entry is 0 to (640k - EBDA)
1739 E820Table
[0].BaseAddr
= 0;
1740 E820Table
[0].Length
= (UINT64
) ((*(UINT16
*) (UINTN
)0x40E) << 4);
1741 E820Table
[0].Type
= EfiAcpiAddressRangeMemory
;
1745 // Second entry is (640k - EBDA) to 640k
1747 E820Table
[1].BaseAddr
= E820Table
[0].Length
;
1748 E820Table
[1].Length
= (UINT64
) ((640 * 1024) - E820Table
[0].Length
);
1749 E820Table
[1].Type
= EfiAcpiAddressRangeReserved
;
1752 // Third Entry is legacy BIOS
1753 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1754 // to page in memory under 1MB.
1755 // Omit region from 0xE0000 to start of BIOS, if any. This can be
1756 // used for a multiple reasons including OPROMS.
1760 // The CSM binary image size is not the actually size that CSM binary used,
1761 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1763 E820Table
[2].BaseAddr
= 0xE0000;
1764 E820Table
[2].Length
= 0x20000;
1765 E820Table
[2].Type
= EfiAcpiAddressRangeReserved
;
1770 // Process the EFI map to produce E820 map;
1774 // Sort memory map from low to high
1776 EfiEntry
= EfiMemoryMap
;
1777 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1778 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1779 while (EfiEntry
< EfiMemoryMapEnd
) {
1780 while (NextEfiEntry
< EfiMemoryMapEnd
) {
1781 if (EfiEntry
->PhysicalStart
> NextEfiEntry
->PhysicalStart
) {
1782 CopyMem (&TempEfiEntry
, EfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1783 CopyMem (EfiEntry
, NextEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1784 CopyMem (NextEfiEntry
, &TempEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1787 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (NextEfiEntry
, EfiDescriptorSize
);
1790 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1791 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1794 EfiEntry
= EfiMemoryMap
;
1795 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1796 for (Index
= Above1MIndex
; (EfiEntry
< EfiMemoryMapEnd
) && (Index
< EFI_MAX_E820_ENTRY
- 1); ) {
1797 MemoryBlockLength
= (UINT64
) (LShiftU64 (EfiEntry
->NumberOfPages
, 12));
1798 if ((EfiEntry
->PhysicalStart
+ MemoryBlockLength
) < 0x100000) {
1800 // Skip the memory block if under 1MB
1803 if (EfiEntry
->PhysicalStart
< 0x100000) {
1805 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1807 MemoryBlockLength
-= 0x100000 - EfiEntry
->PhysicalStart
;
1808 EfiEntry
->PhysicalStart
= 0x100000;
1812 // Convert memory type to E820 type
1814 TempType
= EfiMemoryTypeToE820Type (EfiEntry
->Type
);
1816 if ((E820Table
[Index
].Type
== TempType
) && (EfiEntry
->PhysicalStart
== (E820Table
[Index
].BaseAddr
+ E820Table
[Index
].Length
))) {
1818 // Grow an existing entry
1820 E820Table
[Index
].Length
+= MemoryBlockLength
;
1826 E820Table
[Index
].BaseAddr
= EfiEntry
->PhysicalStart
;
1827 E820Table
[Index
].Length
= MemoryBlockLength
;
1828 E820Table
[Index
].Type
= TempType
;
1831 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1834 FreePool (EfiMemoryMap
);
1837 // Process the reserved memory map to produce E820 map ;
1839 for (Hob
.Raw
= GetHobList (); !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
1840 if (Hob
.Raw
!= NULL
&& GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
1841 ResourceHob
= Hob
.ResourceDescriptor
;
1842 if (((ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_MAPPED_IO
) ||
1843 (ResourceHob
->ResourceType
== EFI_RESOURCE_FIRMWARE_DEVICE
) ||
1844 (ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_RESERVED
) ) &&
1845 (ResourceHob
->PhysicalStart
> 0x100000) &&
1846 (Index
< EFI_MAX_E820_ENTRY
- 1)) {
1848 E820Table
[Index
].BaseAddr
= ResourceHob
->PhysicalStart
;
1849 E820Table
[Index
].Length
= ResourceHob
->ResourceLength
;
1850 E820Table
[Index
].Type
= EfiAcpiAddressRangeReserved
;
1856 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1857 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1858 Private
->NumberE820Entries
= (UINT32
)Index
;
1859 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1862 // Sort E820Table from low to high
1864 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1865 ChangedFlag
= FALSE
;
1866 for (TempNextIndex
= 1; TempNextIndex
< Index
- TempIndex
; TempNextIndex
++) {
1867 if (E820Table
[TempNextIndex
- 1].BaseAddr
> E820Table
[TempNextIndex
].BaseAddr
) {
1869 TempE820
.BaseAddr
= E820Table
[TempNextIndex
- 1].BaseAddr
;
1870 TempE820
.Length
= E820Table
[TempNextIndex
- 1].Length
;
1871 TempE820
.Type
= E820Table
[TempNextIndex
- 1].Type
;
1873 E820Table
[TempNextIndex
- 1].BaseAddr
= E820Table
[TempNextIndex
].BaseAddr
;
1874 E820Table
[TempNextIndex
- 1].Length
= E820Table
[TempNextIndex
].Length
;
1875 E820Table
[TempNextIndex
- 1].Type
= E820Table
[TempNextIndex
].Type
;
1877 E820Table
[TempNextIndex
].BaseAddr
= TempE820
.BaseAddr
;
1878 E820Table
[TempNextIndex
].Length
= TempE820
.Length
;
1879 E820Table
[TempNextIndex
].Type
= TempE820
.Type
;
1889 // Remove the overlap range
1891 for (TempIndex
= 1; TempIndex
< Index
; TempIndex
++) {
1892 if (E820Table
[TempIndex
- 1].BaseAddr
<= E820Table
[TempIndex
].BaseAddr
&&
1893 ((E820Table
[TempIndex
- 1].BaseAddr
+ E820Table
[TempIndex
- 1].Length
) >=
1894 (E820Table
[TempIndex
].BaseAddr
+E820Table
[TempIndex
].Length
))) {
1896 //Overlap range is found
1898 ASSERT (E820Table
[TempIndex
- 1].Type
== E820Table
[TempIndex
].Type
);
1900 if (TempIndex
== Index
- 1) {
1901 E820Table
[TempIndex
].BaseAddr
= 0;
1902 E820Table
[TempIndex
].Length
= 0;
1903 E820Table
[TempIndex
].Type
= (EFI_ACPI_MEMORY_TYPE
) 0;
1907 for (IndexSort
= TempIndex
; IndexSort
< Index
- 1; IndexSort
++) {
1908 E820Table
[IndexSort
].BaseAddr
= E820Table
[IndexSort
+ 1].BaseAddr
;
1909 E820Table
[IndexSort
].Length
= E820Table
[IndexSort
+ 1].Length
;
1910 E820Table
[IndexSort
].Type
= E820Table
[IndexSort
+ 1].Type
;
1919 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1920 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1921 Private
->NumberE820Entries
= (UINT32
)Index
;
1922 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1925 // Determine OS usable memory above 1MB
1927 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
= 0x0000;
1928 for (TempIndex
= Above1MIndex
; TempIndex
< Index
; TempIndex
++) {
1929 if (E820Table
[TempIndex
].BaseAddr
>= 0x100000 && E820Table
[TempIndex
].BaseAddr
< 0x100000000ULL
) { // not include above 4G memory
1931 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1933 if ((E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeMemory
) || (E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeACPI
)) {
1934 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
+= (UINT32
) (E820Table
[TempIndex
].Length
);
1936 break; // break at first not normal memory, because SMM may use reserved memory.
1941 Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
= Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
;
1944 // Print DEBUG information
1946 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1947 DEBUG((EFI_D_INFO
, "E820[%2d]: 0x%016lx - 0x%016lx, Type = %d\n",
1949 E820Table
[TempIndex
].BaseAddr
,
1950 (E820Table
[TempIndex
].BaseAddr
+ E820Table
[TempIndex
].Length
),
1951 E820Table
[TempIndex
].Type
1960 Fill in the standard BDA and EBDA stuff prior to legacy Boot
1962 @param Private Legacy BIOS Instance data
1964 @retval EFI_SUCCESS It should always work.
1968 LegacyBiosCompleteBdaBeforeBoot (
1969 IN LEGACY_BIOS_INSTANCE
*Private
1973 UINT16 MachineConfig
;
1974 DEVICE_PRODUCER_DATA_HEADER
*SioPtr
;
1976 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
1979 SioPtr
= &(Private
->IntThunk
->EfiToLegacy16BootTable
.SioData
);
1980 Bda
->Com1
= SioPtr
->Serial
[0].Address
;
1981 Bda
->Com2
= SioPtr
->Serial
[1].Address
;
1982 Bda
->Com3
= SioPtr
->Serial
[2].Address
;
1983 Bda
->Com4
= SioPtr
->Serial
[3].Address
;
1985 if (SioPtr
->Serial
[0].Address
!= 0x00) {
1986 MachineConfig
+= 0x200;
1989 if (SioPtr
->Serial
[1].Address
!= 0x00) {
1990 MachineConfig
+= 0x200;
1993 if (SioPtr
->Serial
[2].Address
!= 0x00) {
1994 MachineConfig
+= 0x200;
1997 if (SioPtr
->Serial
[3].Address
!= 0x00) {
1998 MachineConfig
+= 0x200;
2001 Bda
->Lpt1
= SioPtr
->Parallel
[0].Address
;
2002 Bda
->Lpt2
= SioPtr
->Parallel
[1].Address
;
2003 Bda
->Lpt3
= SioPtr
->Parallel
[2].Address
;
2005 if (SioPtr
->Parallel
[0].Address
!= 0x00) {
2006 MachineConfig
+= 0x4000;
2009 if (SioPtr
->Parallel
[1].Address
!= 0x00) {
2010 MachineConfig
+= 0x4000;
2013 if (SioPtr
->Parallel
[2].Address
!= 0x00) {
2014 MachineConfig
+= 0x4000;
2017 Bda
->NumberOfDrives
= (UINT8
) (Bda
->NumberOfDrives
+ Private
->IdeDriveCount
);
2018 if (SioPtr
->Floppy
.NumberOfFloppy
!= 0x00) {
2019 MachineConfig
= (UINT16
) (MachineConfig
+ 0x01 + (SioPtr
->Floppy
.NumberOfFloppy
- 1) * 0x40);
2020 Bda
->FloppyXRate
= 0x07;
2023 Bda
->Lpt1_2Timeout
= 0x1414;
2024 Bda
->Lpt3_4Timeout
= 0x1414;
2025 Bda
->Com1_2Timeout
= 0x0101;
2026 Bda
->Com3_4Timeout
= 0x0101;
2029 // Force VGA and Coprocessor, indicate 101/102 keyboard
2031 MachineConfig
= (UINT16
) (MachineConfig
+ 0x00 + 0x02 + (SioPtr
->MousePresent
* 0x04));
2032 Bda
->MachineConfig
= MachineConfig
;
2038 Fill in the standard BDA for Keyboard LEDs
2040 @param This Protocol instance pointer.
2041 @param Leds Current LED status
2043 @retval EFI_SUCCESS It should always work.
2048 LegacyBiosUpdateKeyboardLedStatus (
2049 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
2053 LEGACY_BIOS_INSTANCE
*Private
;
2056 EFI_IA32_REGISTER_SET Regs
;
2058 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
2061 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
2063 Bda
->LedStatus
= (UINT8
) ((Bda
->LedStatus
&~0x07) | LocalLeds
);
2064 LocalLeds
= (UINT8
) (LocalLeds
<< 4);
2065 Bda
->ShiftStatus
= (UINT8
) ((Bda
->ShiftStatus
&~0x70) | LocalLeds
);
2066 LocalLeds
= (UINT8
) (Leds
& 0x20);
2067 Bda
->KeyboardStatus
= (UINT8
) ((Bda
->KeyboardStatus
&~0x20) | LocalLeds
);
2071 // Call into Legacy16 code to allow it to do any processing
2073 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
2074 Regs
.X
.AX
= Legacy16SetKeyboardLeds
;
2077 Private
->LegacyBios
.FarCall86 (
2078 &Private
->LegacyBios
,
2079 Private
->Legacy16Table
->Compatibility16CallSegment
,
2080 Private
->Legacy16Table
->Compatibility16CallOffset
,
2091 Fill in the standard CMOS stuff prior to legacy Boot
2093 @param Private Legacy BIOS Instance data
2095 @retval EFI_SUCCESS It should always work.
2099 LegacyBiosCompleteStandardCmosBeforeBoot (
2100 IN LEGACY_BIOS_INSTANCE
*Private
2108 // Update CMOS locations
2110 // 12,19,1A - ignore as OS don't use them and there is no standard due
2111 // to large capacity drives
2112 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
2115 Bda
= (UINT8
)(*((UINT8
*)((UINTN
)0x410)) | BIT3
);
2119 // Force display enabled
2122 if ((Bda
& BIT0
) != 0) {
2127 // Check if 2.88MB floppy set
2129 if ((Bda
& (BIT7
| BIT6
)) != 0) {
2130 Floppy
= (UINT8
)(Floppy
| BIT1
);
2133 LegacyWriteStandardCmos (CMOS_10
, Floppy
);
2134 LegacyWriteStandardCmos (CMOS_14
, Bda
);
2137 // Force Status Register A to set rate selection bits and divider
2139 LegacyWriteStandardCmos (CMOS_0A
, 0x26);
2142 // redo memory size since it can change
2144 Size
= (15 * SIZE_1MB
) >> 10;
2145 if (Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
< (15 * SIZE_1MB
)) {
2146 Size
= Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
>> 10;
2149 LegacyWriteStandardCmos (CMOS_17
, (UINT8
)(Size
& 0xFF));
2150 LegacyWriteStandardCmos (CMOS_30
, (UINT8
)(Size
& 0xFF));
2151 LegacyWriteStandardCmos (CMOS_18
, (UINT8
)(Size
>> 8));
2152 LegacyWriteStandardCmos (CMOS_31
, (UINT8
)(Size
>> 8));
2154 LegacyCalculateWriteStandardCmosChecksum ();
2160 Relocate this image under 4G memory for IPF.
2162 @param ImageHandle Handle of driver image.
2163 @param SystemTable Pointer to system table.
2165 @retval EFI_SUCCESS Image successfully relocated.
2166 @retval EFI_ABORTED Failed to relocate image.
2170 RelocateImageUnder4GIfNeeded (
2171 IN EFI_HANDLE ImageHandle
,
2172 IN EFI_SYSTEM_TABLE
*SystemTable