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 ((DEBUG_INFO
, "\n"));
50 DEBUG ((DEBUG_INFO
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
51 DEBUG ((DEBUG_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 ((DEBUG_INFO
, " ("));
90 for (SubIndex
= 0; String
[SubIndex
] != 0; SubIndex
++) {
91 DEBUG ((DEBUG_INFO
, "%c", String
[SubIndex
]));
94 DEBUG ((DEBUG_INFO
, ")"));
97 DEBUG ((DEBUG_INFO
, "\n"));
100 DEBUG ((DEBUG_INFO
, "\n"));
108 @param HddInfo The HddInfo table.
119 DEBUG ((DEBUG_INFO
, "\n"));
120 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
121 DEBUG ((DEBUG_INFO
, "Index - %04x\n", Index
));
122 DEBUG ((DEBUG_INFO
, " Status - %04x\n", (UINTN
)HddInfo
[Index
].Status
));
123 DEBUG ((DEBUG_INFO
, " B/D/F - %02x/%02x/%02x\n", (UINTN
)HddInfo
[Index
].Bus
, (UINTN
)HddInfo
[Index
].Device
, (UINTN
)HddInfo
[Index
].Function
));
124 DEBUG ((DEBUG_INFO
, " Command - %04x\n", HddInfo
[Index
].CommandBaseAddress
));
125 DEBUG ((DEBUG_INFO
, " Control - %04x\n", HddInfo
[Index
].ControlBaseAddress
));
126 DEBUG ((DEBUG_INFO
, " BusMaster - %04x\n", HddInfo
[Index
].BusMasterAddress
));
127 DEBUG ((DEBUG_INFO
, " HddIrq - %02x\n", HddInfo
[Index
].HddIrq
));
128 DEBUG ((DEBUG_INFO
, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
129 DEBUG ((DEBUG_INFO
, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
132 DEBUG ((DEBUG_INFO
, "\n"));
138 Print the PCI Interrupt Line and Interrupt Pin registers.
141 PrintPciInterruptRegister (
149 EFI_PCI_IO_PROTOCOL
*PciIo
;
156 gBS
->LocateHandleBuffer (
158 &gEfiPciIoProtocolGuid
,
168 DEBUG ((DEBUG_INFO
, "\n"));
169 DEBUG ((DEBUG_INFO
, " bb/dd/ff interrupt line interrupt pin\n"));
170 DEBUG ((DEBUG_INFO
, "======================================\n"));
171 for (Index
= 0; Index
< HandleNum
; Index
++) {
172 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiPciIoProtocolGuid
, (VOID
**)&PciIo
);
173 if (!EFI_ERROR (Status
)) {
174 Status
= PciIo
->Pci
.Read (
183 if (!EFI_ERROR (Status
)) {
184 Status
= PciIo
->GetLocation (
193 if (!EFI_ERROR (Status
)) {
196 " %02x/%02x/%02x 0x%02x 0x%02x\n",
206 DEBUG ((DEBUG_INFO
, "\n"));
208 if (Handles
!= NULL
) {
214 Identify drive data must be updated to actual parameters before boot.
216 @param IdentifyDriveData ATA Identify Data
220 UpdateIdentifyDriveData (
221 IN UINT8
*IdentifyDriveData
227 @param Private Legacy BIOS Instance data
229 @retval EFI_SUCCESS Removable media not present
234 IN LEGACY_BIOS_INSTANCE
*Private
240 UINT8 LegacyInterrupts
[16];
241 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
242 UINTN RoutingTableEntries
;
243 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY
*IrqPriorityTable
;
244 UINTN NumberPriorityEntries
;
245 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
251 EFI_HANDLE
*HandleBuffer
;
252 EFI_ISA_IO_PROTOCOL
*IsaIo
;
257 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
258 LegacyBiosBuildSioData (Private
);
259 SetMem (LegacyInterrupts
, sizeof (LegacyInterrupts
), 0);
262 // Create list of legacy interrupts.
264 for (Index
= 0; Index
< 4; Index
++) {
265 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Serial
[Index
].Irq
;
268 for (Index
= 4; Index
< 7; Index
++) {
269 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Parallel
[Index
- 4].Irq
;
272 LegacyInterrupts
[7] = EfiToLegacy16BootTable
->SioData
.Floppy
.Irq
;
275 // Get Legacy Hdd IRQs. If native mode treat as PCI
277 for (Index
= 0; Index
< 2; Index
++) {
278 HddIrq
= EfiToLegacy16BootTable
->HddInfo
[Index
].HddIrq
;
279 if ((HddIrq
!= 0) && ((HddIrq
== 15) || (HddIrq
== 14))) {
280 LegacyInterrupts
[Index
+ 8] = HddIrq
;
284 Private
->LegacyBiosPlatform
->GetRoutingTable (
285 Private
->LegacyBiosPlatform
,
286 (VOID
*)&RoutingTable
,
287 &RoutingTableEntries
,
290 (VOID
**)&IrqPriorityTable
,
291 &NumberPriorityEntries
294 // Remove legacy interrupts from the list of PCI interrupts available.
296 for (Index
= 0; Index
<= 0x0b; Index
++) {
297 for (Index1
= 0; Index1
<= NumberPriorityEntries
; Index1
++) {
298 if (LegacyInterrupts
[Index
] != 0) {
299 LegacyInt
= (UINT16
)(LegacyInt
| (1 << LegacyInterrupts
[Index
]));
300 if (LegacyInterrupts
[Index
] == IrqPriorityTable
[Index1
].Irq
) {
301 IrqPriorityTable
[Index1
].Used
= LEGACY_USED
;
307 Private
->Legacy8259
->GetMask (
316 // Set SIO interrupts and disable mouse. Let mouse driver
319 LegMask
= (UINT16
)((LegMask
&~LegacyInt
) | 0x1000);
320 Private
->Legacy8259
->SetMask (
329 // Disable mouse in keyboard controller
332 Status
= gBS
->LocateHandleBuffer (
334 &gEfiIsaIoProtocolGuid
,
339 if (EFI_ERROR (Status
)) {
343 for (Index
= 0; Index
< HandleCount
; Index
++) {
344 Status
= gBS
->HandleProtocol (
346 &gEfiIsaIoProtocolGuid
,
349 ASSERT_EFI_ERROR (Status
);
350 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, 0x64, 1, &Register
);
353 if (HandleBuffer
!= NULL
) {
354 FreePool (HandleBuffer
);
361 Identify drive data must be updated to actual parameters before boot.
362 This requires updating the checksum, if it exists.
364 @param IdentifyDriveData ATA Identify Data
365 @param Checksum checksum of the ATA Identify Data
367 @retval EFI_SUCCESS checksum calculated
368 @retval EFI_SECURITY_VIOLATION IdentifyData invalid
372 CalculateIdentifyDriveChecksum (
373 IN UINT8
*IdentifyDriveData
,
382 if (IdentifyDriveData
[510] != 0xA5) {
383 return EFI_SECURITY_VIOLATION
;
386 for (Index
= 0; Index
< 512; Index
++) {
387 LocalChecksum
= (UINT8
)(LocalChecksum
+ IdentifyDriveData
[Index
]);
390 *Checksum
= LocalChecksum
;
395 Identify drive data must be updated to actual parameters before boot.
397 @param IdentifyDriveData ATA Identify Data
402 UpdateIdentifyDriveData (
403 IN UINT8
*IdentifyDriveData
406 UINT16 NumberCylinders
;
408 UINT16 NumberSectorsTrack
;
409 UINT32 CapacityInSectors
;
410 UINT8 OriginalChecksum
;
413 ATAPI_IDENTIFY
*ReadInfo
;
416 // Status indicates if Integrity byte is correct. Checksum should be
419 ReadInfo
= (ATAPI_IDENTIFY
*)IdentifyDriveData
;
420 Status
= CalculateIdentifyDriveChecksum (IdentifyDriveData
, &OriginalChecksum
);
421 if (OriginalChecksum
!= 0) {
422 Status
= EFI_SECURITY_VIOLATION
;
426 // If NumberCylinders = 0 then do data(Controller present but don drive attached).
428 NumberCylinders
= ReadInfo
->Raw
[1];
429 if (NumberCylinders
!= 0) {
430 ReadInfo
->Raw
[54] = NumberCylinders
;
432 NumberHeads
= ReadInfo
->Raw
[3];
433 ReadInfo
->Raw
[55] = NumberHeads
;
435 NumberSectorsTrack
= ReadInfo
->Raw
[6];
436 ReadInfo
->Raw
[56] = NumberSectorsTrack
;
439 // Copy Multisector info and set valid bit.
441 ReadInfo
->Raw
[59] = (UINT16
)(ReadInfo
->Raw
[47] + 0x100);
442 CapacityInSectors
= (UINT32
)((UINT32
)(NumberCylinders
) * (UINT32
)(NumberHeads
) * (UINT32
)(NumberSectorsTrack
));
443 ReadInfo
->Raw
[57] = (UINT16
)(CapacityInSectors
>> 16);
444 ReadInfo
->Raw
[58] = (UINT16
)(CapacityInSectors
& 0xffff);
445 if (Status
== EFI_SUCCESS
) {
447 // Forece checksum byte to 0 and get new checksum.
449 ReadInfo
->Raw
[255] &= 0xff;
450 CalculateIdentifyDriveChecksum (IdentifyDriveData
, &FinalChecksum
);
453 // Force new checksum such that sum is 0.
455 FinalChecksum
= (UINT8
)((UINT8
)0 - FinalChecksum
);
456 ReadInfo
->Raw
[255] = (UINT16
)(ReadInfo
->Raw
[255] | (FinalChecksum
<< 8));
462 Identify drive data must be updated to actual parameters before boot.
465 @param Private Legacy BIOS Instance data
470 UpdateAllIdentifyDriveData (
471 IN LEGACY_BIOS_INSTANCE
*Private
477 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
479 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
481 // Each controller can have 2 devices. Update for each device
483 if ((HddInfo
[Index
].Status
& HDD_MASTER_IDE
) != 0) {
484 UpdateIdentifyDriveData ((UINT8
*)(&HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
487 if ((HddInfo
[Index
].Status
& HDD_SLAVE_IDE
) != 0) {
488 UpdateIdentifyDriveData ((UINT8
*)(&HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
494 Enable ide controller. This gets disabled when LegacyBoot.c is about
495 to run the Option ROMs.
497 @param Private Legacy BIOS Instance data
502 EnableIdeController (
503 IN LEGACY_BIOS_INSTANCE
*Private
506 EFI_PCI_IO_PROTOCOL
*PciIo
;
508 EFI_HANDLE IdeController
;
511 EFI_HANDLE
*HandleBuffer
;
513 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
514 Private
->LegacyBiosPlatform
,
515 EfiGetPlatformIdeHandle
,
521 if (!EFI_ERROR (Status
)) {
522 IdeController
= HandleBuffer
[0];
523 Status
= gBS
->HandleProtocol (
525 &gEfiPciIoProtocolGuid
,
529 if (!EFI_ERROR (Status
)) {
530 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x04, 1, &ByteBuffer
);
536 Enable ide controller. This gets disabled when LegacyBoot.c is about
537 to run the Option ROMs.
539 @param Private Legacy BIOS Instance data
544 EnableAllControllers (
545 IN LEGACY_BIOS_INSTANCE
*Private
549 EFI_HANDLE
*HandleBuffer
;
551 EFI_PCI_IO_PROTOCOL
*PciIo
;
552 PCI_TYPE01 PciConfigHeader
;
558 EnableIdeController (Private
);
561 // Assumption is table is built from low bus to high bus numbers.
563 Status
= gBS
->LocateHandleBuffer (
565 &gEfiPciIoProtocolGuid
,
570 ASSERT_EFI_ERROR (Status
);
572 for (Index
= 0; Index
< HandleCount
; Index
++) {
573 Status
= gBS
->HandleProtocol (
575 &gEfiPciIoProtocolGuid
,
578 ASSERT_EFI_ERROR (Status
);
584 sizeof (PciConfigHeader
) / sizeof (UINT32
),
589 // We do not enable PPB here. This is for HotPlug Consideration.
590 // The Platform HotPlug Driver is responsible for Padding enough hot plug
591 // resources. It is also responsible for enable this bridge. If it
592 // does not pad it. It will cause some early Windows fail to installation.
593 // If the platform driver does not pad resource for PPB, PPB should be in
594 // un-enabled state to let Windows know that this PPB is not configured by
595 // BIOS. So Windows will allocate default resource for PPB.
597 // The reason for why we enable the command register is:
598 // The CSM will use the IO bar to detect some IRQ status, if the command
599 // is disabled, the IO resource will be out of scope.
601 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
602 // comes up, the handle will check the IO space to identify is the
603 // controller generated the IRQ source.
604 // If the IO command is not enabled, the IRQ handler will has wrong
605 // information. It will cause IRQ storm when the correctly IRQ handler fails
608 if (!(IS_PCI_VGA (&PciConfigHeader
) ||
609 IS_PCI_OLD_VGA (&PciConfigHeader
) ||
610 IS_PCI_IDE (&PciConfigHeader
) ||
611 IS_PCI_P2P (&PciConfigHeader
) ||
612 IS_PCI_P2P_SUB (&PciConfigHeader
) ||
613 IS_PCI_LPC (&PciConfigHeader
)))
615 PciConfigHeader
.Hdr
.Command
|= 0x1f;
617 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 4, 1, &PciConfigHeader
.Hdr
.Command
);
623 The following routines are identical in operation, so combine
625 EfiGetPlatformBinaryGetMpTable
626 EfiGetPlatformBinaryGetOemIntData
627 EfiGetPlatformBinaryGetOem32Data
628 EfiGetPlatformBinaryGetOem16Data
630 @param This Protocol instance pointer.
631 @param Id Table/Data identifier
633 @retval EFI_SUCCESS Success
634 @retval EFI_INVALID_PARAMETER Invalid ID
635 @retval EFI_OUT_OF_RESOURCES no resource to get data or table
639 LegacyGetDataOrTable (
640 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
641 IN EFI_GET_PLATFORM_INFO_MODE Id
650 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
651 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
652 EFI_IA32_REGISTER_SET Regs
;
653 LEGACY_BIOS_INSTANCE
*Private
;
655 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
657 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
658 Legacy16Table
= Private
->Legacy16Table
;
661 // Phase 1 - get an address allocated in 16-bit code
665 case EfiGetPlatformBinaryMpTable
:
666 case EfiGetPlatformBinaryOemIntData
:
667 case EfiGetPlatformBinaryOem32Data
:
668 case EfiGetPlatformBinaryOem16Data
:
670 Status
= LegacyBiosPlatform
->GetPlatformInfo (
680 DEBUG ((DEBUG_INFO
, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN
)Id
, Status
));
681 DEBUG ((DEBUG_INFO
, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN
)Table
, (UINTN
)TableSize
, (UINTN
)Location
, (UINTN
)Alignment
));
687 return EFI_INVALID_PARAMETER
;
691 if (EFI_ERROR (Status
)) {
695 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
696 Regs
.X
.AX
= Legacy16GetTableAddress
;
697 Regs
.X
.CX
= (UINT16
)TableSize
;
698 Regs
.X
.BX
= (UINT16
)Location
;
699 Regs
.X
.DX
= (UINT16
)Alignment
;
700 Private
->LegacyBios
.FarCall86 (
702 Private
->Legacy16CallSegment
,
703 Private
->Legacy16CallOffset
,
709 if (Regs
.X
.AX
!= 0) {
710 DEBUG ((DEBUG_ERROR
, "Table ID %x length insufficient\n", Id
));
711 return EFI_OUT_OF_RESOURCES
;
718 // Phase 2 Call routine second time with address to allow address adjustment
720 Status
= LegacyBiosPlatform
->GetPlatformInfo (
731 case EfiGetPlatformBinaryMpTable
:
733 Legacy16Table
->MpTablePtr
= (UINT32
)(Regs
.X
.DS
* 16 + Regs
.X
.BX
);
734 Legacy16Table
->MpTableLength
= (UINT32
)TableSize
;
735 DEBUG ((DEBUG_INFO
, "MP table in legacy region - %x\n", (UINTN
)Legacy16Table
->MpTablePtr
));
739 case EfiGetPlatformBinaryOemIntData
:
741 Legacy16Table
->OemIntSegment
= Regs
.X
.DS
;
742 Legacy16Table
->OemIntOffset
= Regs
.X
.BX
;
743 DEBUG ((DEBUG_INFO
, "OemInt table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->OemIntSegment
, (UINTN
)Legacy16Table
->OemIntOffset
));
747 case EfiGetPlatformBinaryOem32Data
:
749 Legacy16Table
->Oem32Segment
= Regs
.X
.DS
;
750 Legacy16Table
->Oem32Offset
= Regs
.X
.BX
;
751 DEBUG ((DEBUG_INFO
, "Oem32 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem32Segment
, (UINTN
)Legacy16Table
->Oem32Offset
));
755 case EfiGetPlatformBinaryOem16Data
:
758 // Legacy16Table->Oem16Segment = Regs.X.DS;
759 // Legacy16Table->Oem16Offset = Regs.X.BX;
760 DEBUG ((DEBUG_INFO
, "Oem16 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem16Segment
, (UINTN
)Legacy16Table
->Oem16Offset
));
766 return EFI_INVALID_PARAMETER
;
770 if (EFI_ERROR (Status
)) {
775 // Phase 3 Copy table to final location
777 TablePtr
= (UINT32
)(Regs
.X
.DS
* 16 + Regs
.X
.BX
);
780 (VOID
*)(UINTN
)TablePtr
,
789 Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot.
793 CreateSmbiosTableInReservedMemory (
797 SMBIOS_TABLE_ENTRY_POINT
*EntryPointStructure
;
799 if ((mRuntimeSmbiosEntryPoint
== NULL
) ||
800 (mReserveSmbiosEntryPoint
== 0) ||
801 (mStructureTableAddress
== 0))
806 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*)mRuntimeSmbiosEntryPoint
;
809 // Copy SMBIOS Entry Point Structure
812 (VOID
*)(UINTN
)mReserveSmbiosEntryPoint
,
814 EntryPointStructure
->EntryPointLength
818 // Copy SMBIOS Structure Table into EfiReservedMemoryType memory
821 (VOID
*)(UINTN
)mStructureTableAddress
,
822 (VOID
*)(UINTN
)EntryPointStructure
->TableAddress
,
823 EntryPointStructure
->TableLength
827 // Update TableAddress in Entry Point Structure
829 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*)(UINTN
)mReserveSmbiosEntryPoint
;
830 EntryPointStructure
->TableAddress
= (UINT32
)(UINTN
)mStructureTableAddress
;
833 // Fixup checksums in the Entry Point Structure
835 EntryPointStructure
->IntermediateChecksum
= 0;
836 EntryPointStructure
->EntryPointStructureChecksum
= 0;
838 EntryPointStructure
->IntermediateChecksum
=
840 (UINT8
*)EntryPointStructure
+ OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT
, IntermediateAnchorString
),
841 EntryPointStructure
->EntryPointLength
- OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT
, IntermediateAnchorString
)
843 EntryPointStructure
->EntryPointStructureChecksum
=
844 CalculateCheckSum8 ((UINT8
*)EntryPointStructure
, EntryPointStructure
->EntryPointLength
);
848 Assign drive number to legacy HDD drives prior to booting an EFI
849 aware OS so the OS can access drives without an EFI driver.
850 Note: BBS compliant drives ARE NOT available until this call by
853 @param This Protocol instance pointer.
855 @retval EFI_SUCCESS Drive numbers assigned
860 IN EFI_LEGACY_BIOS_PROTOCOL
*This
864 LEGACY_BIOS_INSTANCE
*Private
;
865 EFI_IA32_REGISTER_SET Regs
;
866 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
867 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
871 HDD_INFO
*LocalHddInfo
;
873 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
877 BBS_TABLE
*LocalBbsTable
;
878 UINT32
*BaseVectorMaster
;
881 EFI_HANDLE IdeController
;
883 EFI_HANDLE
*HandleBuffer
;
891 LocalBbsTable
= NULL
;
893 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
895 DEBUG ((DEBUG_ERROR
, "Start of legacy boot\n"));
898 Legacy16Table
= Private
->Legacy16Table
;
899 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
900 HddInfo
= &EfiToLegacy16BootTable
->HddInfo
[0];
902 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
904 EfiToLegacy16BootTable
->MajorVersion
= EFI_TO_LEGACY_MAJOR_VERSION
;
905 EfiToLegacy16BootTable
->MinorVersion
= EFI_TO_LEGACY_MINOR_VERSION
;
908 // If booting to a legacy OS then force HDD drives to the appropriate
909 // boot mode by calling GetIdeHandle.
910 // A reconnect -r can force all HDDs back to native mode.
912 IdeController
= NULL
;
913 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
914 Status
= LegacyBiosPlatform
->GetPlatformHandle (
915 Private
->LegacyBiosPlatform
,
916 EfiGetPlatformIdeHandle
,
922 if (!EFI_ERROR (Status
)) {
923 IdeController
= HandleBuffer
[0];
928 // Unlock the Legacy BIOS region
930 Private
->LegacyRegion
->UnLock (
931 Private
->LegacyRegion
,
938 // Reconstruct the Legacy16 boot memory map
940 LegacyBiosBuildE820 (Private
, &CopySize
);
941 if (CopySize
> Private
->Legacy16Table
->E820Length
) {
942 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
943 Regs
.X
.AX
= Legacy16GetTableAddress
;
944 Regs
.X
.BX
= (UINT16
)0x0; // Any region
945 Regs
.X
.CX
= (UINT16
)CopySize
;
946 Regs
.X
.DX
= (UINT16
)0x4; // Alignment
947 Private
->LegacyBios
.FarCall86 (
948 &Private
->LegacyBios
,
949 Private
->Legacy16Table
->Compatibility16CallSegment
,
950 Private
->Legacy16Table
->Compatibility16CallOffset
,
956 Private
->Legacy16Table
->E820Pointer
= (UINT32
)(Regs
.X
.DS
* 16 + Regs
.X
.BX
);
957 Private
->Legacy16Table
->E820Length
= (UINT32
)CopySize
;
958 if (Regs
.X
.AX
!= 0) {
959 DEBUG ((DEBUG_ERROR
, "Legacy16 E820 length insufficient\n"));
960 return EFI_OUT_OF_RESOURCES
;
963 (VOID
*)(UINTN
)Private
->Legacy16Table
->E820Pointer
,
970 (VOID
*)(UINTN
)Private
->Legacy16Table
->E820Pointer
,
974 Private
->Legacy16Table
->E820Length
= (UINT32
)CopySize
;
978 // We do not ASSERT if SmbiosTable not found. It is possible that a platform does not produce SmbiosTable.
980 if (mReserveSmbiosEntryPoint
== 0) {
981 DEBUG ((DEBUG_INFO
, "Smbios table is not found!\n"));
984 CreateSmbiosTableInReservedMemory ();
985 EfiToLegacy16BootTable
->SmbiosTable
= (UINT32
)(UINTN
)mReserveSmbiosEntryPoint
;
988 Status
= EfiGetSystemConfigurationTable (
989 &gEfiAcpi20TableGuid
,
992 if (EFI_ERROR (Status
)) {
993 Status
= EfiGetSystemConfigurationTable (
994 &gEfiAcpi10TableGuid
,
1000 // We do not ASSERT if AcpiTable not found. It is possible that a platform does not produce AcpiTable.
1002 if (AcpiTable
== NULL
) {
1003 DEBUG ((DEBUG_INFO
, "ACPI table is not found!\n"));
1006 EfiToLegacy16BootTable
->AcpiTable
= (UINT32
)(UINTN
)AcpiTable
;
1009 // Get RSD Ptr table rev at offset 15 decimal
1010 // Rev = 0 Length is 20 decimal
1011 // Rev != 0 Length is UINT32 at offset 20 decimal
1013 if (AcpiTable
!= NULL
) {
1014 AcpiPtr
= AcpiTable
;
1015 if (*((UINT8
*)AcpiPtr
+ 15) == 0) {
1018 AcpiPtr
= ((UINT8
*)AcpiPtr
+ 20);
1019 CopySize
= (*(UINT32
*)AcpiPtr
);
1023 (VOID
*)(UINTN
)Private
->Legacy16Table
->AcpiRsdPtrPointer
,
1030 // Make sure all PCI Interrupt Line register are programmed to match 8259
1032 PciProgramAllInterruptLineRegisters (Private
);
1035 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
1038 Private
->LegacyRegion
->UnLock (
1039 Private
->LegacyRegion
,
1041 Private
->LegacyBiosImageSize
,
1046 // Configure Legacy Device Magic
1048 // Only do this code if booting legacy OS
1050 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1051 UpdateSioData (Private
);
1055 // Setup BDA and EBDA standard areas before Legacy Boot
1058 LegacyBiosCompleteBdaBeforeBoot (Private
);
1060 LegacyBiosCompleteStandardCmosBeforeBoot (Private
);
1063 // We must build IDE data, if it hasn't been done, before PciShadowRoms
1064 // to insure EFI drivers are connected.
1066 LegacyBiosBuildIdeData (Private
, &HddInfo
, 1);
1067 UpdateAllIdentifyDriveData (Private
);
1070 // Clear IO BAR, if IDE controller in legacy mode.
1072 InitLegacyIdeController (IdeController
);
1075 // Generate number of ticks since midnight for BDA. DOS requires this
1076 // for its time. We have to make assumptions as to how long following
1077 // code takes since after PciShadowRoms PciIo is gone. Place result in
1080 // Adjust value by 1 second.
1082 gRT
->GetTime (&BootTime
, NULL
);
1083 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
1087 // Multiply result by 18.2 for number of ticks since midnight.
1088 // Use 182/10 to avoid floating point math.
1090 LocalTime
= (LocalTime
* 182) / 10;
1092 BdaPtr
= (UINT32
*)(UINTN
)0x46C;
1093 *BdaPtr
= LocalTime
;
1097 // Shadow PCI ROMs. We must do this near the end since this will kick
1098 // of Native EFI drivers that may be needed to collect info for Legacy16
1100 // WARNING: PciIo is gone after this call.
1102 PciShadowRoms (Private
);
1105 // Shadow PXE base code, BIS etc.
1107 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xc0000, 0x40000, &Granularity
);
1108 ShadowAddress
= Private
->OptionRom
;
1109 Private
->LegacyBiosPlatform
->PlatformHooks (
1110 Private
->LegacyBiosPlatform
,
1111 EfiPlatformHookShadowServiceRoms
,
1118 Private
->OptionRom
= (UINT32
)ShadowAddress
;
1120 // Register Legacy SMI Handler
1122 LegacyBiosPlatform
->SmmInit (
1124 EfiToLegacy16BootTable
1128 // Let platform code know the boot options
1130 LegacyBiosGetBbsInfo (
1139 PrintPciInterruptRegister ();
1140 PrintBbsTable (LocalBbsTable
);
1141 PrintHddInfo (LocalHddInfo
);
1144 // If drive wasn't spun up then BuildIdeData may have found new drives.
1145 // Need to update BBS boot priority.
1147 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
1148 if ((LocalHddInfo
[Index
].IdentifyDrive
[0].Raw
[0] != 0) &&
1149 (LocalBbsTable
[2 * Index
+ 1].BootPriority
== BBS_IGNORE_ENTRY
)
1152 LocalBbsTable
[2 * Index
+ 1].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1155 if ((LocalHddInfo
[Index
].IdentifyDrive
[1].Raw
[0] != 0) &&
1156 (LocalBbsTable
[2 * Index
+ 2].BootPriority
== BBS_IGNORE_ENTRY
)
1159 LocalBbsTable
[2 * Index
+ 2].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1163 Private
->LegacyRegion
->UnLock (
1164 Private
->LegacyRegion
,
1170 LegacyBiosPlatform
->PrepareToBoot (
1176 (VOID
*)&Private
->IntThunk
->EfiToLegacy16BootTable
1180 // If no boot device return to BDS
1182 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1183 for (Index
= 0; Index
< BbsCount
; Index
++) {
1184 if ((LocalBbsTable
[Index
].BootPriority
!= BBS_DO_NOT_BOOT_FROM
) &&
1185 (LocalBbsTable
[Index
].BootPriority
!= BBS_UNPRIORITIZED_ENTRY
) &&
1186 (LocalBbsTable
[Index
].BootPriority
!= BBS_IGNORE_ENTRY
))
1192 if (Index
== BbsCount
) {
1193 return EFI_DEVICE_ERROR
;
1198 // Let the Legacy16 code know the device path type for legacy boot
1200 EfiToLegacy16BootTable
->DevicePathType
= mBbsDevicePathPtr
->DeviceType
;
1203 // Copy MP table, if it exists.
1205 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryMpTable
);
1207 if (!Private
->LegacyBootEntered
) {
1209 // Copy OEM INT Data, if it exists. Note: This code treats any data
1210 // as a bag of bits and knows nothing of the contents nor cares.
1211 // Contents are IBV specific.
1213 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOemIntData
);
1216 // Copy OEM16 Data, if it exists.Note: This code treats any data
1217 // as a bag of bits and knows nothing of the contents nor cares.
1218 // Contents are IBV specific.
1220 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem16Data
);
1223 // Copy OEM32 Data, if it exists.Note: This code treats any data
1224 // as a bag of bits and knows nothing of the contents nor cares.
1225 // Contents are IBV specific.
1227 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem32Data
);
1231 // Call into Legacy16 code to prepare for INT 19h
1233 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1234 Regs
.X
.AX
= Legacy16PrepareToBoot
;
1237 // Pass in handoff data
1239 Regs
.X
.ES
= NORMALIZE_EFI_SEGMENT ((UINTN
)EfiToLegacy16BootTable
);
1240 Regs
.X
.BX
= NORMALIZE_EFI_OFFSET ((UINTN
)EfiToLegacy16BootTable
);
1242 Private
->LegacyBios
.FarCall86 (
1244 Private
->Legacy16CallSegment
,
1245 Private
->Legacy16CallOffset
,
1251 if (Regs
.X
.AX
!= 0) {
1252 return EFI_DEVICE_ERROR
;
1256 // Lock the Legacy BIOS region
1258 Private
->LegacyRegion
->Lock (
1259 Private
->LegacyRegion
,
1265 if ((Private
->Legacy16Table
->TableLength
>= OFFSET_OF (EFI_COMPATIBILITY16_TABLE
, HiPermanentMemoryAddress
)) &&
1266 ((Private
->Legacy16Table
->UmaAddress
!= 0) && (Private
->Legacy16Table
->UmaSize
!= 0)))
1269 // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into
1270 // account the granularity of the access control.
1274 "Unlocking UMB RAM region 0x%x-0x%x\n",
1275 Private
->Legacy16Table
->UmaAddress
,
1276 Private
->Legacy16Table
->UmaAddress
+ Private
->Legacy16Table
->UmaSize
1279 Private
->LegacyRegion
->UnLock (
1280 Private
->LegacyRegion
,
1281 Private
->Legacy16Table
->UmaAddress
,
1282 Private
->Legacy16Table
->UmaSize
,
1288 // Lock attributes of the Legacy Region if chipset supports
1290 Private
->LegacyRegion
->BootLock (
1291 Private
->LegacyRegion
,
1298 // Call into Legacy16 code to do the INT 19h
1300 EnableAllControllers (Private
);
1301 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1303 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
1305 EfiSignalEventLegacyBoot ();
1308 // Report Status Code to indicate legacy boot event was signalled
1310 REPORT_STATUS_CODE (
1312 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT
)
1315 DEBUG ((DEBUG_INFO
, "Legacy INT19 Boot...\n"));
1318 // Disable DXE Timer while executing in real mode
1320 Private
->Timer
->SetTimerPeriod (Private
->Timer
, 0);
1323 // Save and disable interrupt of debug timer
1325 SaveAndSetDebugTimerInterrupt (FALSE
);
1328 // Put the 8259 into its legacy mode by reprogramming the vector bases
1330 Private
->Legacy8259
->SetVectorBase (Private
->Legacy8259
, LEGACY_MODE_BASE_VECTOR_MASTER
, LEGACY_MODE_BASE_VECTOR_SLAVE
);
1333 // The original PC used INT8-F for master PIC. Since these mapped over
1334 // processor exceptions TIANO moved the master PIC to INT68-6F.
1335 // We need to set these back to the Legacy16 unexpected interrupt(saved
1336 // in LegacyBios.c) since some OS see that these have values different from
1337 // what is expected and invoke them. Since the legacy OS corrupts EFI
1338 // memory, there is no handler for these interrupts and OS blows up.
1340 // We need to save the TIANO values for the rare case that the Legacy16
1341 // code cannot boot but knows memory hasn't been destroyed.
1343 // To compound the problem, video takes over one of these INTS and must be
1345 // @bug - determine if video hooks INT(in which case we must find new
1346 // set of TIANO vectors) or takes it over.
1350 BaseVectorMaster
= (UINT32
*)(sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1351 for (Index
= 0; Index
< 8; Index
++) {
1352 Private
->ThunkSavedInt
[Index
] = BaseVectorMaster
[Index
];
1353 if (Private
->ThunkSeg
== (UINT16
)(BaseVectorMaster
[Index
] >> 16)) {
1354 BaseVectorMaster
[Index
] = (UINT32
)(Private
->BiosUnexpectedInt
);
1360 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1361 Regs
.X
.AX
= Legacy16Boot
;
1363 Private
->LegacyBios
.FarCall86 (
1365 Private
->Legacy16CallSegment
,
1366 Private
->Legacy16CallOffset
,
1373 BaseVectorMaster
= (UINT32
*)(sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1374 for (Index
= 0; Index
< 8; Index
++) {
1375 BaseVectorMaster
[Index
] = Private
->ThunkSavedInt
[Index
];
1381 Private
->LegacyBootEntered
= TRUE
;
1382 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1384 // Should never return unless never passed control to 0:7c00(first stage
1385 // OS loader) and only then if no bootable device found.
1387 return EFI_DEVICE_ERROR
;
1390 // If boot to EFI then expect to return to caller
1397 Assign drive number to legacy HDD drives prior to booting an EFI
1398 aware OS so the OS can access drives without an EFI driver.
1399 Note: BBS compliant drives ARE NOT available until this call by
1400 either shell or EFI.
1402 @param This Protocol instance pointer.
1403 @param BbsCount Number of BBS_TABLE structures
1404 @param BbsTable List BBS entries
1406 @retval EFI_SUCCESS Drive numbers assigned
1411 LegacyBiosPrepareToBootEfi (
1412 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1413 OUT UINT16
*BbsCount
,
1414 OUT BBS_TABLE
**BbsTable
1418 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1419 LEGACY_BIOS_INSTANCE
*Private
;
1421 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1422 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1423 mBootMode
= BOOT_EFI_OS
;
1424 mBbsDevicePathPtr
= NULL
;
1425 Status
= GenericLegacyBoot (This
);
1426 *BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1427 *BbsCount
= (UINT16
)(sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
));
1432 To boot from an unconventional device like parties and/or execute HDD diagnostics.
1434 @param This Protocol instance pointer.
1435 @param Attributes How to interpret the other input parameters
1436 @param BbsEntry The 0-based index into the BbsTable for the parent
1438 @param BeerData Pointer to the 128 bytes of ram BEER data.
1439 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1440 caller must provide a pointer to the specific Service
1441 Area and not the start all Service Areas.
1443 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1448 LegacyBiosBootUnconventionalDevice (
1449 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1450 IN UDC_ATTRIBUTES Attributes
,
1453 IN VOID
*ServiceAreaData
1457 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1458 LEGACY_BIOS_INSTANCE
*Private
;
1461 UINT16 BootPriority
;
1462 BBS_TABLE
*BbsTable
;
1465 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1466 mBootMode
= BOOT_UNCONVENTIONAL_DEVICE
;
1467 mBbsDevicePathPtr
= &mBbsDevicePathNode
;
1468 mAttributes
= Attributes
;
1469 mBbsEntry
= BbsEntry
;
1470 mBeerData
= BeerData
, mServiceAreaData
= ServiceAreaData
;
1472 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1475 // Do input parameter checking
1477 if ((Attributes
.DirectoryServiceValidity
== 0) &&
1478 (Attributes
.RabcaUsedFlag
== 0) &&
1479 (Attributes
.ExecuteHddDiagnosticsFlag
== 0)
1482 return EFI_INVALID_PARAMETER
;
1485 if (((Attributes
.DirectoryServiceValidity
!= 0) && (ServiceAreaData
== NULL
)) ||
1486 (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
) != 0) && (BeerData
== NULL
))
1489 return EFI_INVALID_PARAMETER
;
1492 UcdTable
= (UD_TABLE
*)AllocatePool (
1495 if (NULL
== UcdTable
) {
1496 return EFI_OUT_OF_RESOURCES
;
1499 EfiToLegacy16BootTable
->UnconventionalDeviceTable
= (UINT32
)(UINTN
)UcdTable
;
1500 UcdTable
->Attributes
= Attributes
;
1501 UcdTable
->BbsTableEntryNumberForParentDevice
= (UINT8
)BbsEntry
;
1503 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1504 // to assign drive numbers but bot boot from. Only newly created entries
1507 BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1508 for (Index
= 0; Index
< EfiToLegacy16BootTable
->NumberBbsEntries
; Index
++) {
1509 BbsTable
[Index
].BootPriority
= BBS_DO_NOT_BOOT_FROM
;
1513 // If parent is onboard IDE then assign controller & device number
1516 if (BbsEntry
< MAX_IDE_CONTROLLER
* 2) {
1517 UcdTable
->DeviceNumber
= (UINT8
)((BbsEntry
- 1) % 2);
1520 if (BeerData
!= NULL
) {
1522 (VOID
*)UcdTable
->BeerData
,
1528 if (ServiceAreaData
!= NULL
) {
1530 (VOID
*)UcdTable
->ServiceAreaData
,
1537 // For each new entry do the following:
1538 // 1. Increment current number of BBS entries
1539 // 2. Copy parent entry to new entry.
1540 // 3. Zero out BootHandler Offset & segment
1541 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1542 // and Floppy(0x01) for PARTIES boot.
1543 // 5. Assign new priority.
1545 if ((Attributes
.ExecuteHddDiagnosticsFlag
) != 0) {
1546 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1549 (VOID
*)&BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1550 (VOID
*)&BbsTable
[BbsEntry
].BootPriority
,
1554 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1555 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1556 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x80;
1558 UcdTable
->BbsTableEntryNumberForHddDiag
= (UINT8
)(EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1560 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1564 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1566 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_BEV
;
1569 if (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
)) != 0) {
1570 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1572 (VOID
*)&BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1573 (VOID
*)&BbsTable
[BbsEntry
].BootPriority
,
1577 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1578 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1579 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x01;
1580 UcdTable
->BbsTableEntryNumberForBoot
= (UINT8
)(EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1581 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1584 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1586 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_FLOPPY
;
1590 // Build the BBS Device Path for this boot selection
1592 mBbsDevicePathNode
.Header
.Type
= BBS_DEVICE_PATH
;
1593 mBbsDevicePathNode
.Header
.SubType
= BBS_BBS_DP
;
1594 SetDevicePathNodeLength (&mBbsDevicePathNode
.Header
, sizeof (BBS_BBS_DEVICE_PATH
));
1595 mBbsDevicePathNode
.StatusFlag
= 0;
1596 mBbsDevicePathNode
.String
[0] = 0;
1598 Status
= GenericLegacyBoot (This
);
1603 Attempt to legacy boot the BootOption. If the EFI contexted has been
1604 compromised this function will not return.
1606 @param This Protocol instance pointer.
1607 @param BbsDevicePath EFI Device Path from BootXXXX variable.
1608 @param LoadOptionsSize Size of LoadOption in size.
1609 @param LoadOptions LoadOption from BootXXXX variable
1611 @retval EFI_SUCCESS Removable media not present
1616 LegacyBiosLegacyBoot (
1617 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1618 IN BBS_BBS_DEVICE_PATH
*BbsDevicePath
,
1619 IN UINT32 LoadOptionsSize
,
1620 IN VOID
*LoadOptions
1625 mBbsDevicePathPtr
= BbsDevicePath
;
1626 mLoadOptionsSize
= LoadOptionsSize
;
1627 mLoadOptions
= LoadOptions
;
1628 mBootMode
= BOOT_LEGACY_OS
;
1629 Status
= GenericLegacyBoot (This
);
1635 Convert EFI Memory Type to E820 Memory Type.
1637 @param Type EFI Memory Type
1639 @return ACPI Memory Type for EFI Memory Type
1642 EFI_ACPI_MEMORY_TYPE
1643 EfiMemoryTypeToE820Type (
1650 case EfiBootServicesCode
:
1651 case EfiBootServicesData
:
1652 case EfiConventionalMemory
:
1654 // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are
1655 // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept.
1656 // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData
1657 // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS.
1659 case EfiRuntimeServicesCode
:
1660 case EfiRuntimeServicesData
:
1661 return EfiAcpiAddressRangeMemory
;
1663 case EfiPersistentMemory
:
1664 return EfiAddressRangePersistentMemory
;
1666 case EfiACPIReclaimMemory
:
1667 return EfiAcpiAddressRangeACPI
;
1669 case EfiACPIMemoryNVS
:
1670 return EfiAcpiAddressRangeNVS
;
1673 // All other types map to reserved.
1674 // Adding the code just waists FLASH space.
1676 // case EfiReservedMemoryType:
1677 // case EfiUnusableMemory:
1678 // case EfiMemoryMappedIO:
1679 // case EfiMemoryMappedIOPortSpace:
1683 return EfiAcpiAddressRangeReserved
;
1688 Build the E820 table.
1690 @param Private Legacy BIOS Instance data
1691 @param Size Size of E820 Table
1693 @retval EFI_SUCCESS It should always work.
1697 LegacyBiosBuildE820 (
1698 IN LEGACY_BIOS_INSTANCE
*Private
,
1703 EFI_E820_ENTRY64
*E820Table
;
1704 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMap
;
1705 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMapEnd
;
1706 EFI_MEMORY_DESCRIPTOR
*EfiEntry
;
1707 EFI_MEMORY_DESCRIPTOR
*NextEfiEntry
;
1708 EFI_MEMORY_DESCRIPTOR TempEfiEntry
;
1709 UINTN EfiMemoryMapSize
;
1711 UINTN EfiDescriptorSize
;
1712 UINT32 EfiDescriptorVersion
;
1714 EFI_PEI_HOB_POINTERS Hob
;
1715 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
1718 UINTN TempNextIndex
;
1719 EFI_E820_ENTRY64 TempE820
;
1720 EFI_ACPI_MEMORY_TYPE TempType
;
1721 BOOLEAN ChangedFlag
;
1723 UINT64 MemoryBlockLength
;
1725 E820Table
= (EFI_E820_ENTRY64
*)Private
->E820Table
;
1728 // Get the EFI memory map.
1730 EfiMemoryMapSize
= 0;
1731 EfiMemoryMap
= NULL
;
1732 Status
= gBS
->GetMemoryMap (
1737 &EfiDescriptorVersion
1739 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1743 // Use size returned for the AllocatePool.
1744 // We don't just multiply by 2 since the "for" loop below terminates on
1745 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwise
1746 // we process bogus entries and create bogus E820 entries.
1748 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*)AllocatePool (EfiMemoryMapSize
);
1749 ASSERT (EfiMemoryMap
!= NULL
);
1750 Status
= gBS
->GetMemoryMap (
1755 &EfiDescriptorVersion
1757 if (EFI_ERROR (Status
)) {
1758 FreePool (EfiMemoryMap
);
1760 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1762 ASSERT_EFI_ERROR (Status
);
1765 // Punch in the E820 table for memory less than 1 MB.
1766 // Assume ZeroMem () has been done on data structure.
1769 // First entry is 0 to (640k - EBDA)
1772 E820Table
[0].BaseAddr
= 0;
1773 E820Table
[0].Length
= (UINT64
)((*(UINT16
*)(UINTN
)0x40E) << 4);
1774 E820Table
[0].Type
= EfiAcpiAddressRangeMemory
;
1778 // Second entry is (640k - EBDA) to 640k
1780 E820Table
[1].BaseAddr
= E820Table
[0].Length
;
1781 E820Table
[1].Length
= (UINT64
)((640 * 1024) - E820Table
[0].Length
);
1782 E820Table
[1].Type
= EfiAcpiAddressRangeReserved
;
1785 // Third Entry is legacy BIOS
1786 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1787 // to page in memory under 1MB.
1788 // Omit region from 0xE0000 to start of BIOS, if any. This can be
1789 // used for a multiple reasons including OPROMS.
1793 // The CSM binary image size is not the actually size that CSM binary used,
1794 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1796 E820Table
[2].BaseAddr
= 0xE0000;
1797 E820Table
[2].Length
= 0x20000;
1798 E820Table
[2].Type
= EfiAcpiAddressRangeReserved
;
1803 // Process the EFI map to produce E820 map;
1807 // Sort memory map from low to high
1809 EfiEntry
= EfiMemoryMap
;
1810 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1811 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)EfiMemoryMap
+ EfiMemoryMapSize
);
1812 while (EfiEntry
< EfiMemoryMapEnd
) {
1813 while (NextEfiEntry
< EfiMemoryMapEnd
) {
1814 if (EfiEntry
->PhysicalStart
> NextEfiEntry
->PhysicalStart
) {
1815 CopyMem (&TempEfiEntry
, EfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1816 CopyMem (EfiEntry
, NextEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1817 CopyMem (NextEfiEntry
, &TempEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1820 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (NextEfiEntry
, EfiDescriptorSize
);
1823 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1824 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1827 EfiEntry
= EfiMemoryMap
;
1828 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*)((UINT8
*)EfiMemoryMap
+ EfiMemoryMapSize
);
1829 for (Index
= Above1MIndex
; (EfiEntry
< EfiMemoryMapEnd
) && (Index
< EFI_MAX_E820_ENTRY
- 1); ) {
1830 MemoryBlockLength
= (UINT64
)(LShiftU64 (EfiEntry
->NumberOfPages
, 12));
1831 if ((EfiEntry
->PhysicalStart
+ MemoryBlockLength
) < 0x100000) {
1833 // Skip the memory block if under 1MB
1836 if (EfiEntry
->PhysicalStart
< 0x100000) {
1838 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1840 MemoryBlockLength
-= 0x100000 - EfiEntry
->PhysicalStart
;
1841 EfiEntry
->PhysicalStart
= 0x100000;
1845 // Convert memory type to E820 type
1847 TempType
= EfiMemoryTypeToE820Type (EfiEntry
->Type
);
1849 if ((E820Table
[Index
].Type
== TempType
) && (EfiEntry
->PhysicalStart
== (E820Table
[Index
].BaseAddr
+ E820Table
[Index
].Length
))) {
1851 // Grow an existing entry
1853 E820Table
[Index
].Length
+= MemoryBlockLength
;
1859 E820Table
[Index
].BaseAddr
= EfiEntry
->PhysicalStart
;
1860 E820Table
[Index
].Length
= MemoryBlockLength
;
1861 E820Table
[Index
].Type
= TempType
;
1865 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1868 FreePool (EfiMemoryMap
);
1871 // Process the reserved memory map to produce E820 map ;
1873 for (Hob
.Raw
= GetHobList (); !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
1874 if ((Hob
.Raw
!= NULL
) && (GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
)) {
1875 ResourceHob
= Hob
.ResourceDescriptor
;
1876 if (((ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_MAPPED_IO
) ||
1877 (ResourceHob
->ResourceType
== EFI_RESOURCE_FIRMWARE_DEVICE
) ||
1878 (ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_RESERVED
)) &&
1879 (ResourceHob
->PhysicalStart
> 0x100000) &&
1880 (Index
< EFI_MAX_E820_ENTRY
- 1))
1883 E820Table
[Index
].BaseAddr
= ResourceHob
->PhysicalStart
;
1884 E820Table
[Index
].Length
= ResourceHob
->ResourceLength
;
1885 E820Table
[Index
].Type
= EfiAcpiAddressRangeReserved
;
1891 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1892 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1893 Private
->NumberE820Entries
= (UINT32
)Index
;
1894 *Size
= (UINTN
)(Index
* sizeof (EFI_E820_ENTRY64
));
1897 // Sort E820Table from low to high
1899 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1900 ChangedFlag
= FALSE
;
1901 for (TempNextIndex
= 1; TempNextIndex
< Index
- TempIndex
; TempNextIndex
++) {
1902 if (E820Table
[TempNextIndex
- 1].BaseAddr
> E820Table
[TempNextIndex
].BaseAddr
) {
1904 TempE820
.BaseAddr
= E820Table
[TempNextIndex
- 1].BaseAddr
;
1905 TempE820
.Length
= E820Table
[TempNextIndex
- 1].Length
;
1906 TempE820
.Type
= E820Table
[TempNextIndex
- 1].Type
;
1908 E820Table
[TempNextIndex
- 1].BaseAddr
= E820Table
[TempNextIndex
].BaseAddr
;
1909 E820Table
[TempNextIndex
- 1].Length
= E820Table
[TempNextIndex
].Length
;
1910 E820Table
[TempNextIndex
- 1].Type
= E820Table
[TempNextIndex
].Type
;
1912 E820Table
[TempNextIndex
].BaseAddr
= TempE820
.BaseAddr
;
1913 E820Table
[TempNextIndex
].Length
= TempE820
.Length
;
1914 E820Table
[TempNextIndex
].Type
= TempE820
.Type
;
1924 // Remove the overlap range
1926 for (TempIndex
= 1; TempIndex
< Index
; TempIndex
++) {
1927 if ((E820Table
[TempIndex
- 1].BaseAddr
<= E820Table
[TempIndex
].BaseAddr
) &&
1928 ((E820Table
[TempIndex
- 1].BaseAddr
+ E820Table
[TempIndex
- 1].Length
) >=
1929 (E820Table
[TempIndex
].BaseAddr
+E820Table
[TempIndex
].Length
)))
1932 // Overlap range is found
1934 ASSERT (E820Table
[TempIndex
- 1].Type
== E820Table
[TempIndex
].Type
);
1936 if (TempIndex
== Index
- 1) {
1937 E820Table
[TempIndex
].BaseAddr
= 0;
1938 E820Table
[TempIndex
].Length
= 0;
1939 E820Table
[TempIndex
].Type
= (EFI_ACPI_MEMORY_TYPE
)0;
1943 for (IndexSort
= TempIndex
; IndexSort
< Index
- 1; IndexSort
++) {
1944 E820Table
[IndexSort
].BaseAddr
= E820Table
[IndexSort
+ 1].BaseAddr
;
1945 E820Table
[IndexSort
].Length
= E820Table
[IndexSort
+ 1].Length
;
1946 E820Table
[IndexSort
].Type
= E820Table
[IndexSort
+ 1].Type
;
1954 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1955 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1956 Private
->NumberE820Entries
= (UINT32
)Index
;
1957 *Size
= (UINTN
)(Index
* sizeof (EFI_E820_ENTRY64
));
1960 // Determine OS usable memory above 1MB
1962 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
= 0x0000;
1963 for (TempIndex
= Above1MIndex
; TempIndex
< Index
; TempIndex
++) {
1964 if ((E820Table
[TempIndex
].BaseAddr
>= 0x100000) && (E820Table
[TempIndex
].BaseAddr
< 0x100000000ULL
)) {
1965 // not include above 4G memory
1967 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1969 if ((E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeMemory
) || (E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeACPI
)) {
1970 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
+= (UINT32
)(E820Table
[TempIndex
].Length
);
1972 break; // break at first not normal memory, because SMM may use reserved memory.
1977 Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
= Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
;
1980 // Print DEBUG information
1982 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1985 "E820[%2d]: 0x%016lx - 0x%016lx, Type = %d\n",
1987 E820Table
[TempIndex
].BaseAddr
,
1988 (E820Table
[TempIndex
].BaseAddr
+ E820Table
[TempIndex
].Length
),
1989 E820Table
[TempIndex
].Type
1997 Fill in the standard BDA and EBDA stuff prior to legacy Boot
1999 @param Private Legacy BIOS Instance data
2001 @retval EFI_SUCCESS It should always work.
2005 LegacyBiosCompleteBdaBeforeBoot (
2006 IN LEGACY_BIOS_INSTANCE
*Private
2010 UINT16 MachineConfig
;
2011 DEVICE_PRODUCER_DATA_HEADER
*SioPtr
;
2013 Bda
= (BDA_STRUC
*)((UINTN
)0x400);
2016 SioPtr
= &(Private
->IntThunk
->EfiToLegacy16BootTable
.SioData
);
2017 Bda
->Com1
= SioPtr
->Serial
[0].Address
;
2018 Bda
->Com2
= SioPtr
->Serial
[1].Address
;
2019 Bda
->Com3
= SioPtr
->Serial
[2].Address
;
2020 Bda
->Com4
= SioPtr
->Serial
[3].Address
;
2022 if (SioPtr
->Serial
[0].Address
!= 0x00) {
2023 MachineConfig
+= 0x200;
2026 if (SioPtr
->Serial
[1].Address
!= 0x00) {
2027 MachineConfig
+= 0x200;
2030 if (SioPtr
->Serial
[2].Address
!= 0x00) {
2031 MachineConfig
+= 0x200;
2034 if (SioPtr
->Serial
[3].Address
!= 0x00) {
2035 MachineConfig
+= 0x200;
2038 Bda
->Lpt1
= SioPtr
->Parallel
[0].Address
;
2039 Bda
->Lpt2
= SioPtr
->Parallel
[1].Address
;
2040 Bda
->Lpt3
= SioPtr
->Parallel
[2].Address
;
2042 if (SioPtr
->Parallel
[0].Address
!= 0x00) {
2043 MachineConfig
+= 0x4000;
2046 if (SioPtr
->Parallel
[1].Address
!= 0x00) {
2047 MachineConfig
+= 0x4000;
2050 if (SioPtr
->Parallel
[2].Address
!= 0x00) {
2051 MachineConfig
+= 0x4000;
2054 Bda
->NumberOfDrives
= (UINT8
)(Bda
->NumberOfDrives
+ Private
->IdeDriveCount
);
2055 if (SioPtr
->Floppy
.NumberOfFloppy
!= 0x00) {
2056 MachineConfig
= (UINT16
)(MachineConfig
+ 0x01 + (SioPtr
->Floppy
.NumberOfFloppy
- 1) * 0x40);
2057 Bda
->FloppyXRate
= 0x07;
2060 Bda
->Lpt1_2Timeout
= 0x1414;
2061 Bda
->Lpt3_4Timeout
= 0x1414;
2062 Bda
->Com1_2Timeout
= 0x0101;
2063 Bda
->Com3_4Timeout
= 0x0101;
2066 // Force VGA and Coprocessor, indicate 101/102 keyboard
2068 MachineConfig
= (UINT16
)(MachineConfig
+ 0x00 + 0x02 + (SioPtr
->MousePresent
* 0x04));
2069 Bda
->MachineConfig
= MachineConfig
;
2075 Fill in the standard BDA for Keyboard LEDs
2077 @param This Protocol instance pointer.
2078 @param Leds Current LED status
2080 @retval EFI_SUCCESS It should always work.
2085 LegacyBiosUpdateKeyboardLedStatus (
2086 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
2090 LEGACY_BIOS_INSTANCE
*Private
;
2093 EFI_IA32_REGISTER_SET Regs
;
2095 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
2098 Bda
= (BDA_STRUC
*)((UINTN
)0x400);
2100 Bda
->LedStatus
= (UINT8
)((Bda
->LedStatus
&~0x07) | LocalLeds
);
2101 LocalLeds
= (UINT8
)(LocalLeds
<< 4);
2102 Bda
->ShiftStatus
= (UINT8
)((Bda
->ShiftStatus
&~0x70) | LocalLeds
);
2103 LocalLeds
= (UINT8
)(Leds
& 0x20);
2104 Bda
->KeyboardStatus
= (UINT8
)((Bda
->KeyboardStatus
&~0x20) | LocalLeds
);
2108 // Call into Legacy16 code to allow it to do any processing
2110 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
2111 Regs
.X
.AX
= Legacy16SetKeyboardLeds
;
2114 Private
->LegacyBios
.FarCall86 (
2115 &Private
->LegacyBios
,
2116 Private
->Legacy16Table
->Compatibility16CallSegment
,
2117 Private
->Legacy16Table
->Compatibility16CallOffset
,
2127 Fill in the standard CMOS stuff prior to legacy Boot
2129 @param Private Legacy BIOS Instance data
2131 @retval EFI_SUCCESS It should always work.
2135 LegacyBiosCompleteStandardCmosBeforeBoot (
2136 IN LEGACY_BIOS_INSTANCE
*Private
2144 // Update CMOS locations
2146 // 12,19,1A - ignore as OS don't use them and there is no standard due
2147 // to large capacity drives
2148 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
2151 Bda
= (UINT8
)(*((UINT8
*)((UINTN
)0x410)) | BIT3
);
2155 // Force display enabled
2158 if ((Bda
& BIT0
) != 0) {
2163 // Check if 2.88MB floppy set
2165 if ((Bda
& (BIT7
| BIT6
)) != 0) {
2166 Floppy
= (UINT8
)(Floppy
| BIT1
);
2169 LegacyWriteStandardCmos (CMOS_10
, Floppy
);
2170 LegacyWriteStandardCmos (CMOS_14
, Bda
);
2173 // Force Status Register A to set rate selection bits and divider
2175 LegacyWriteStandardCmos (CMOS_0A
, 0x26);
2178 // redo memory size since it can change
2180 Size
= (15 * SIZE_1MB
) >> 10;
2181 if (Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
< (15 * SIZE_1MB
)) {
2182 Size
= Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
>> 10;
2185 LegacyWriteStandardCmos (CMOS_17
, (UINT8
)(Size
& 0xFF));
2186 LegacyWriteStandardCmos (CMOS_30
, (UINT8
)(Size
& 0xFF));
2187 LegacyWriteStandardCmos (CMOS_18
, (UINT8
)(Size
>> 8));
2188 LegacyWriteStandardCmos (CMOS_31
, (UINT8
)(Size
>> 8));
2190 LegacyCalculateWriteStandardCmosChecksum ();
2196 Relocate this image under 4G memory for IPF.
2198 @param ImageHandle Handle of driver image.
2199 @param SystemTable Pointer to system table.
2201 @retval EFI_SUCCESS Image successfully relocated.
2202 @retval EFI_ABORTED Failed to relocate image.
2206 RelocateImageUnder4GIfNeeded (
2207 IN EFI_HANDLE ImageHandle
,
2208 IN EFI_SYSTEM_TABLE
*SystemTable