3 Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions
7 of the BSD License which accompanies this distribution. The
8 full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
16 #include "LegacyBiosInterface.h"
17 #include <IndustryStandard/Pci.h>
19 #define BOOT_LEGACY_OS 0
21 #define BOOT_UNCONVENTIONAL_DEVICE 2
23 UINT32 mLoadOptionsSize
= 0;
24 UINTN mBootMode
= BOOT_LEGACY_OS
;
25 VOID
*mLoadOptions
= NULL
;
26 BBS_BBS_DEVICE_PATH
*mBbsDevicePathPtr
= NULL
;
27 BBS_BBS_DEVICE_PATH mBbsDevicePathNode
;
28 UDC_ATTRIBUTES mAttributes
= { 0, 0, 0, 0 };
30 VOID
*mBeerData
= NULL
;
31 VOID
*mServiceAreaData
= NULL
;
32 UINT64 mLowWater
= 0xffffffffffffffffULL
;
34 extern BBS_TABLE
*mBbsTable
;
36 extern VOID
*mRuntimeSmbiosEntryPoint
;
37 extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint
;
38 extern EFI_PHYSICAL_ADDRESS mStructureTableAddress
;
43 @param BbsTable The BBS table.
49 IN BBS_TABLE
*BbsTable
56 DEBUG ((EFI_D_INFO
, "\n"));
57 DEBUG ((EFI_D_INFO
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
58 DEBUG ((EFI_D_INFO
, "=================================================================\n"));
59 for (Index
= 0; Index
< MAX_BBS_ENTRIES
; Index
++) {
63 if (BbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) {
69 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
71 (UINTN
) BbsTable
[Index
].BootPriority
,
72 (UINTN
) BbsTable
[Index
].Bus
,
73 (UINTN
) BbsTable
[Index
].Device
,
74 (UINTN
) BbsTable
[Index
].Function
,
75 (UINTN
) BbsTable
[Index
].Class
,
76 (UINTN
) BbsTable
[Index
].SubClass
,
77 (UINTN
) BbsTable
[Index
].DeviceType
,
78 (UINTN
) * (UINT16
*) &BbsTable
[Index
].StatusFlags
82 " %04x:%04x %04x:%04x %04x:%04x",
83 (UINTN
) BbsTable
[Index
].BootHandlerSegment
,
84 (UINTN
) BbsTable
[Index
].BootHandlerOffset
,
85 (UINTN
) BbsTable
[Index
].MfgStringSegment
,
86 (UINTN
) BbsTable
[Index
].MfgStringOffset
,
87 (UINTN
) BbsTable
[Index
].DescStringSegment
,
88 (UINTN
) BbsTable
[Index
].DescStringOffset
94 String
= (CHAR8
*)(UINTN
)((BbsTable
[Index
].DescStringSegment
<< 4) + BbsTable
[Index
].DescStringOffset
);
96 DEBUG ((EFI_D_INFO
," ("));
97 for (SubIndex
= 0; String
[SubIndex
] != 0; SubIndex
++) {
98 DEBUG ((EFI_D_INFO
, "%c", String
[SubIndex
]));
100 DEBUG ((EFI_D_INFO
,")"));
102 DEBUG ((EFI_D_INFO
,"\n"));
105 DEBUG ((EFI_D_INFO
, "\n"));
113 @param HddInfo The HddInfo table.
124 DEBUG ((EFI_D_INFO
, "\n"));
125 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
126 DEBUG ((EFI_D_INFO
, "Index - %04x\n", Index
));
127 DEBUG ((EFI_D_INFO
, " Status - %04x\n", (UINTN
)HddInfo
[Index
].Status
));
128 DEBUG ((EFI_D_INFO
, " B/D/F - %02x/%02x/%02x\n", (UINTN
)HddInfo
[Index
].Bus
, (UINTN
)HddInfo
[Index
].Device
, (UINTN
)HddInfo
[Index
].Function
));
129 DEBUG ((EFI_D_INFO
, " Command - %04x\n", HddInfo
[Index
].CommandBaseAddress
));
130 DEBUG ((EFI_D_INFO
, " Control - %04x\n", HddInfo
[Index
].ControlBaseAddress
));
131 DEBUG ((EFI_D_INFO
, " BusMaster - %04x\n", HddInfo
[Index
].BusMasterAddress
));
132 DEBUG ((EFI_D_INFO
, " HddIrq - %02x\n", HddInfo
[Index
].HddIrq
));
133 DEBUG ((EFI_D_INFO
, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
134 DEBUG ((EFI_D_INFO
, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
137 DEBUG ((EFI_D_INFO
, "\n"));
143 Print the PCI Interrupt Line and Interrupt Pin registers.
146 PrintPciInterruptRegister (
154 EFI_PCI_IO_PROTOCOL
*PciIo
;
161 gBS
->LocateHandleBuffer (
163 &gEfiPciIoProtocolGuid
,
173 DEBUG ((EFI_D_INFO
, "\n"));
174 DEBUG ((EFI_D_INFO
, " bb/dd/ff interrupt line interrupt pin\n"));
175 DEBUG ((EFI_D_INFO
, "======================================\n"));
176 for (Index
= 0; Index
< HandleNum
; Index
++) {
177 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiPciIoProtocolGuid
, (VOID
**) &PciIo
);
178 if (!EFI_ERROR (Status
)) {
179 Status
= PciIo
->Pci
.Read (
187 if (!EFI_ERROR (Status
)) {
188 Status
= PciIo
->GetLocation (
196 if (!EFI_ERROR (Status
)) {
197 DEBUG ((EFI_D_INFO
, " %02x/%02x/%02x 0x%02x 0x%02x\n",
198 Bus
, Device
, Function
, Interrupt
[0], Interrupt
[1]));
201 DEBUG ((EFI_D_INFO
, "\n"));
203 if (Handles
!= NULL
) {
209 Identify drive data must be updated to actual parameters before boot.
211 @param IdentifyDriveData ATA Identify Data
215 UpdateIdentifyDriveData (
216 IN UINT8
*IdentifyDriveData
222 @param Private Legacy BIOS Instance data
224 @retval EFI_SUCCESS Removable media not present
229 IN LEGACY_BIOS_INSTANCE
*Private
235 UINT8 LegacyInterrupts
[16];
236 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
237 UINTN RoutingTableEntries
;
238 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY
*IrqPriorityTable
;
239 UINTN NumberPriorityEntries
;
240 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
246 EFI_HANDLE
*HandleBuffer
;
247 EFI_ISA_IO_PROTOCOL
*IsaIo
;
252 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
253 LegacyBiosBuildSioData (Private
);
254 SetMem (LegacyInterrupts
, sizeof (LegacyInterrupts
), 0);
257 // Create list of legacy interrupts.
259 for (Index
= 0; Index
< 4; Index
++) {
260 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Serial
[Index
].Irq
;
263 for (Index
= 4; Index
< 7; Index
++) {
264 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Parallel
[Index
- 4].Irq
;
267 LegacyInterrupts
[7] = EfiToLegacy16BootTable
->SioData
.Floppy
.Irq
;
270 // Get Legacy Hdd IRQs. If native mode treat as PCI
272 for (Index
= 0; Index
< 2; Index
++) {
273 HddIrq
= EfiToLegacy16BootTable
->HddInfo
[Index
].HddIrq
;
274 if ((HddIrq
!= 0) && ((HddIrq
== 15) || (HddIrq
== 14))) {
275 LegacyInterrupts
[Index
+ 8] = HddIrq
;
279 Private
->LegacyBiosPlatform
->GetRoutingTable (
280 Private
->LegacyBiosPlatform
,
281 (VOID
*) &RoutingTable
,
282 &RoutingTableEntries
,
285 (VOID
**) &IrqPriorityTable
,
286 &NumberPriorityEntries
289 // Remove legacy interrupts from the list of PCI interrupts available.
291 for (Index
= 0; Index
<= 0x0b; Index
++) {
292 for (Index1
= 0; Index1
<= NumberPriorityEntries
; Index1
++) {
293 if (LegacyInterrupts
[Index
] != 0) {
294 LegacyInt
= (UINT16
) (LegacyInt
| (1 << LegacyInterrupts
[Index
]));
295 if (LegacyInterrupts
[Index
] == IrqPriorityTable
[Index1
].Irq
) {
296 IrqPriorityTable
[Index1
].Used
= LEGACY_USED
;
302 Private
->Legacy8259
->GetMask (
311 // Set SIO interrupts and disable mouse. Let mouse driver
314 LegMask
= (UINT16
) ((LegMask
&~LegacyInt
) | 0x1000);
315 Private
->Legacy8259
->SetMask (
324 // Disable mouse in keyboard controller
327 Status
= gBS
->LocateHandleBuffer (
329 &gEfiIsaIoProtocolGuid
,
334 if (EFI_ERROR (Status
)) {
338 for (Index
= 0; Index
< HandleCount
; Index
++) {
339 Status
= gBS
->HandleProtocol (
341 &gEfiIsaIoProtocolGuid
,
344 ASSERT_EFI_ERROR (Status
);
345 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, 0x64, 1, &Register
);
349 if (HandleBuffer
!= NULL
) {
350 FreePool (HandleBuffer
);
358 Identify drive data must be updated to actual parameters before boot.
359 This requires updating the checksum, if it exists.
361 @param IdentifyDriveData ATA Identify Data
362 @param Checksum checksum of the ATA Identify Data
364 @retval EFI_SUCCESS checksum calculated
365 @retval EFI_SECURITY_VIOLATION IdentifyData invalid
369 CalculateIdentifyDriveChecksum (
370 IN UINT8
*IdentifyDriveData
,
378 if (IdentifyDriveData
[510] != 0xA5) {
379 return EFI_SECURITY_VIOLATION
;
382 for (Index
= 0; Index
< 512; Index
++) {
383 LocalChecksum
= (UINT8
) (LocalChecksum
+ IdentifyDriveData
[Index
]);
386 *Checksum
= LocalChecksum
;
392 Identify drive data must be updated to actual parameters before boot.
394 @param IdentifyDriveData ATA Identify Data
399 UpdateIdentifyDriveData (
400 IN UINT8
*IdentifyDriveData
403 UINT16 NumberCylinders
;
405 UINT16 NumberSectorsTrack
;
406 UINT32 CapacityInSectors
;
407 UINT8 OriginalChecksum
;
410 ATAPI_IDENTIFY
*ReadInfo
;
413 // Status indicates if Integrity byte is correct. Checksum should be
416 ReadInfo
= (ATAPI_IDENTIFY
*) IdentifyDriveData
;
417 Status
= CalculateIdentifyDriveChecksum (IdentifyDriveData
, &OriginalChecksum
);
418 if (OriginalChecksum
!= 0) {
419 Status
= EFI_SECURITY_VIOLATION
;
422 // If NumberCylinders = 0 then do data(Controller present but don drive attached).
424 NumberCylinders
= ReadInfo
->Raw
[1];
425 if (NumberCylinders
!= 0) {
426 ReadInfo
->Raw
[54] = NumberCylinders
;
428 NumberHeads
= ReadInfo
->Raw
[3];
429 ReadInfo
->Raw
[55] = NumberHeads
;
431 NumberSectorsTrack
= ReadInfo
->Raw
[6];
432 ReadInfo
->Raw
[56] = NumberSectorsTrack
;
435 // Copy Multisector info and set valid bit.
437 ReadInfo
->Raw
[59] = (UINT16
) (ReadInfo
->Raw
[47] + 0x100);
438 CapacityInSectors
= (UINT32
) ((UINT32
) (NumberCylinders
) * (UINT32
) (NumberHeads
) * (UINT32
) (NumberSectorsTrack
));
439 ReadInfo
->Raw
[57] = (UINT16
) (CapacityInSectors
>> 16);
440 ReadInfo
->Raw
[58] = (UINT16
) (CapacityInSectors
& 0xffff);
441 if (Status
== EFI_SUCCESS
) {
443 // Forece checksum byte to 0 and get new checksum.
445 ReadInfo
->Raw
[255] &= 0xff;
446 CalculateIdentifyDriveChecksum (IdentifyDriveData
, &FinalChecksum
);
449 // Force new checksum such that sum is 0.
451 FinalChecksum
= (UINT8
) ((UINT8
)0 - FinalChecksum
);
452 ReadInfo
->Raw
[255] = (UINT16
) (ReadInfo
->Raw
[255] | (FinalChecksum
<< 8));
458 Identify drive data must be updated to actual parameters before boot.
461 @param Private Legacy BIOS Instance data
466 UpdateAllIdentifyDriveData (
467 IN LEGACY_BIOS_INSTANCE
*Private
473 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
475 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
477 // Each controller can have 2 devices. Update for each device
479 if ((HddInfo
[Index
].Status
& HDD_MASTER_IDE
) != 0) {
480 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
483 if ((HddInfo
[Index
].Status
& HDD_SLAVE_IDE
) != 0) {
484 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
490 Enable ide controller. This gets disabled when LegacyBoot.c is about
491 to run the Option ROMs.
493 @param Private Legacy BIOS Instance data
498 EnableIdeController (
499 IN LEGACY_BIOS_INSTANCE
*Private
502 EFI_PCI_IO_PROTOCOL
*PciIo
;
504 EFI_HANDLE IdeController
;
507 EFI_HANDLE
*HandleBuffer
;
509 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
510 Private
->LegacyBiosPlatform
,
511 EfiGetPlatformIdeHandle
,
517 if (!EFI_ERROR (Status
)) {
518 IdeController
= HandleBuffer
[0];
519 Status
= gBS
->HandleProtocol (
521 &gEfiPciIoProtocolGuid
,
525 if (!EFI_ERROR (Status
)) {
526 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x04, 1, &ByteBuffer
);
533 Enable ide controller. This gets disabled when LegacyBoot.c is about
534 to run the Option ROMs.
536 @param Private Legacy BIOS Instance data
541 EnableAllControllers (
542 IN LEGACY_BIOS_INSTANCE
*Private
546 EFI_HANDLE
*HandleBuffer
;
548 EFI_PCI_IO_PROTOCOL
*PciIo
;
549 PCI_TYPE01 PciConfigHeader
;
555 EnableIdeController (Private
);
558 // Assumption is table is built from low bus to high bus numbers.
560 Status
= gBS
->LocateHandleBuffer (
562 &gEfiPciIoProtocolGuid
,
567 ASSERT_EFI_ERROR (Status
);
569 for (Index
= 0; Index
< HandleCount
; Index
++) {
570 Status
= gBS
->HandleProtocol (
572 &gEfiPciIoProtocolGuid
,
575 ASSERT_EFI_ERROR (Status
);
581 sizeof (PciConfigHeader
) / sizeof (UINT32
),
586 // We do not enable PPB here. This is for HotPlug Consideration.
587 // The Platform HotPlug Driver is responsible for Padding enough hot plug
588 // resources. It is also responsible for enable this bridge. If it
589 // does not pad it. It will cause some early Windows fail to installation.
590 // If the platform driver does not pad resource for PPB, PPB should be in
591 // un-enabled state to let Windows know that this PPB is not configured by
592 // BIOS. So Windows will allocate default resource for PPB.
594 // The reason for why we enable the command register is:
595 // The CSM will use the IO bar to detect some IRQ status, if the command
596 // is disabled, the IO resource will be out of scope.
598 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
599 // comes up, the handle will check the IO space to identify is the
600 // controller generated the IRQ source.
601 // If the IO command is not enabled, the IRQ handler will has wrong
602 // information. It will cause IRQ storm when the correctly IRQ handler fails
605 if (!(IS_PCI_VGA (&PciConfigHeader
) ||
606 IS_PCI_OLD_VGA (&PciConfigHeader
) ||
607 IS_PCI_IDE (&PciConfigHeader
) ||
608 IS_PCI_P2P (&PciConfigHeader
) ||
609 IS_PCI_P2P_SUB (&PciConfigHeader
) ||
610 IS_PCI_LPC (&PciConfigHeader
) )) {
612 PciConfigHeader
.Hdr
.Command
|= 0x1f;
614 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 4, 1, &PciConfigHeader
.Hdr
.Command
);
620 The following routines are identical in operation, so combine
622 EfiGetPlatformBinaryGetMpTable
623 EfiGetPlatformBinaryGetOemIntData
624 EfiGetPlatformBinaryGetOem32Data
625 EfiGetPlatformBinaryGetOem16Data
627 @param This Protocol instance pointer.
628 @param Id Table/Data identifier
630 @retval EFI_SUCCESS Success
631 @retval EFI_INVALID_PARAMETER Invalid ID
632 @retval EFI_OUT_OF_RESOURCES no resource to get data or table
636 LegacyGetDataOrTable (
637 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
638 IN EFI_GET_PLATFORM_INFO_MODE Id
647 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
648 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
649 EFI_IA32_REGISTER_SET Regs
;
650 LEGACY_BIOS_INSTANCE
*Private
;
652 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
654 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
655 Legacy16Table
= Private
->Legacy16Table
;
658 // Phase 1 - get an address allocated in 16-bit code
662 case EfiGetPlatformBinaryMpTable
:
663 case EfiGetPlatformBinaryOemIntData
:
664 case EfiGetPlatformBinaryOem32Data
:
665 case EfiGetPlatformBinaryOem16Data
:
667 Status
= LegacyBiosPlatform
->GetPlatformInfo (
677 DEBUG ((EFI_D_INFO
, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN
)Id
, Status
));
678 DEBUG ((EFI_D_INFO
, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN
)Table
, (UINTN
)TableSize
, (UINTN
)Location
, (UINTN
)Alignment
));
684 return EFI_INVALID_PARAMETER
;
688 if (EFI_ERROR (Status
)) {
692 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
693 Regs
.X
.AX
= Legacy16GetTableAddress
;
694 Regs
.X
.CX
= (UINT16
) TableSize
;
695 Regs
.X
.BX
= (UINT16
) Location
;
696 Regs
.X
.DX
= (UINT16
) Alignment
;
697 Private
->LegacyBios
.FarCall86 (
699 Private
->Legacy16CallSegment
,
700 Private
->Legacy16CallOffset
,
706 if (Regs
.X
.AX
!= 0) {
707 DEBUG ((EFI_D_ERROR
, "Table ID %x length insufficient\n", Id
));
708 return EFI_OUT_OF_RESOURCES
;
714 // Phase 2 Call routine second time with address to allow address adjustment
716 Status
= LegacyBiosPlatform
->GetPlatformInfo (
727 case EfiGetPlatformBinaryMpTable
:
729 Legacy16Table
->MpTablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
730 Legacy16Table
->MpTableLength
= (UINT32
)TableSize
;
731 DEBUG ((EFI_D_INFO
, "MP table in legacy region - %x\n", (UINTN
)Legacy16Table
->MpTablePtr
));
735 case EfiGetPlatformBinaryOemIntData
:
738 Legacy16Table
->OemIntSegment
= Regs
.X
.DS
;
739 Legacy16Table
->OemIntOffset
= Regs
.X
.BX
;
740 DEBUG ((EFI_D_INFO
, "OemInt table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->OemIntSegment
, (UINTN
)Legacy16Table
->OemIntOffset
));
744 case EfiGetPlatformBinaryOem32Data
:
746 Legacy16Table
->Oem32Segment
= Regs
.X
.DS
;
747 Legacy16Table
->Oem32Offset
= Regs
.X
.BX
;
748 DEBUG ((EFI_D_INFO
, "Oem32 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem32Segment
, (UINTN
)Legacy16Table
->Oem32Offset
));
752 case EfiGetPlatformBinaryOem16Data
:
755 // Legacy16Table->Oem16Segment = Regs.X.DS;
756 // Legacy16Table->Oem16Offset = Regs.X.BX;
757 DEBUG ((EFI_D_INFO
, "Oem16 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem16Segment
, (UINTN
)Legacy16Table
->Oem16Offset
));
763 return EFI_INVALID_PARAMETER
;
767 if (EFI_ERROR (Status
)) {
771 // Phase 3 Copy table to final location
773 TablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
776 (VOID
*) (UINTN
)TablePtr
,
785 Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot.
789 CreateSmbiosTableInReservedMemory (
793 SMBIOS_TABLE_ENTRY_POINT
*EntryPointStructure
;
795 if ((mRuntimeSmbiosEntryPoint
== NULL
) ||
796 (mReserveSmbiosEntryPoint
== 0) ||
797 (mStructureTableAddress
== 0)) {
801 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*) mRuntimeSmbiosEntryPoint
;
804 // Copy SMBIOS Entry Point Structure
807 (VOID
*)(UINTN
) mReserveSmbiosEntryPoint
,
809 EntryPointStructure
->EntryPointLength
813 // Copy SMBIOS Structure Table into EfiReservedMemoryType memory
816 (VOID
*)(UINTN
) mStructureTableAddress
,
817 (VOID
*)(UINTN
) EntryPointStructure
->TableAddress
,
818 EntryPointStructure
->TableLength
822 // Update TableAddress in Entry Point Structure
824 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*)(UINTN
) mReserveSmbiosEntryPoint
;
825 EntryPointStructure
->TableAddress
= (UINT32
)(UINTN
) mStructureTableAddress
;
828 // Fixup checksums in the Entry Point Structure
830 EntryPointStructure
->IntermediateChecksum
= 0;
831 EntryPointStructure
->EntryPointStructureChecksum
= 0;
833 EntryPointStructure
->IntermediateChecksum
=
835 (UINT8
*) EntryPointStructure
+ OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT
, IntermediateAnchorString
),
836 EntryPointStructure
->EntryPointLength
- OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT
, IntermediateAnchorString
)
838 EntryPointStructure
->EntryPointStructureChecksum
=
839 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
, EntryPointStructure
->EntryPointLength
);
843 Assign drive number to legacy HDD drives prior to booting an EFI
844 aware OS so the OS can access drives without an EFI driver.
845 Note: BBS compliant drives ARE NOT available until this call by
848 @param This Protocol instance pointer.
850 @retval EFI_SUCCESS Drive numbers assigned
855 IN EFI_LEGACY_BIOS_PROTOCOL
*This
859 LEGACY_BIOS_INSTANCE
*Private
;
860 EFI_IA32_REGISTER_SET Regs
;
861 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
862 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
866 HDD_INFO
*LocalHddInfo
;
868 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
872 BBS_TABLE
*LocalBbsTable
;
873 UINT32
*BaseVectorMaster
;
876 EFI_HANDLE IdeController
;
878 EFI_HANDLE
*HandleBuffer
;
886 LocalBbsTable
= NULL
;
888 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
890 DEBUG ((EFI_D_ERROR
, "Start of legacy boot\n"));
893 Legacy16Table
= Private
->Legacy16Table
;
894 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
895 HddInfo
= &EfiToLegacy16BootTable
->HddInfo
[0];
897 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
899 EfiToLegacy16BootTable
->MajorVersion
= EFI_TO_LEGACY_MAJOR_VERSION
;
900 EfiToLegacy16BootTable
->MinorVersion
= EFI_TO_LEGACY_MINOR_VERSION
;
903 // If booting to a legacy OS then force HDD drives to the appropriate
904 // boot mode by calling GetIdeHandle.
905 // A reconnect -r can force all HDDs back to native mode.
907 IdeController
= NULL
;
908 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
909 Status
= LegacyBiosPlatform
->GetPlatformHandle (
910 Private
->LegacyBiosPlatform
,
911 EfiGetPlatformIdeHandle
,
917 if (!EFI_ERROR (Status
)) {
918 IdeController
= HandleBuffer
[0];
922 // Unlock the Legacy BIOS region
924 Private
->LegacyRegion
->UnLock (
925 Private
->LegacyRegion
,
932 // Reconstruct the Legacy16 boot memory map
934 LegacyBiosBuildE820 (Private
, &CopySize
);
935 if (CopySize
> Private
->Legacy16Table
->E820Length
) {
936 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
937 Regs
.X
.AX
= Legacy16GetTableAddress
;
938 Regs
.X
.CX
= (UINT16
) CopySize
;
939 Private
->LegacyBios
.FarCall86 (
940 &Private
->LegacyBios
,
941 Private
->Legacy16Table
->Compatibility16CallSegment
,
942 Private
->Legacy16Table
->Compatibility16CallOffset
,
948 Private
->Legacy16Table
->E820Pointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
949 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
950 if (Regs
.X
.AX
!= 0) {
951 DEBUG ((EFI_D_ERROR
, "Legacy16 E820 length insufficient\n"));
954 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
961 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
965 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
969 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
971 if (mReserveSmbiosEntryPoint
== 0) {
972 DEBUG ((EFI_D_INFO
, "Smbios table is not found!\n"));
974 CreateSmbiosTableInReservedMemory ();
975 EfiToLegacy16BootTable
->SmbiosTable
= (UINT32
)(UINTN
)mReserveSmbiosEntryPoint
;
978 Status
= EfiGetSystemConfigurationTable (
979 &gEfiAcpi20TableGuid
,
982 if (EFI_ERROR (Status
)) {
983 Status
= EfiGetSystemConfigurationTable (
984 &gEfiAcpi10TableGuid
,
989 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
991 if (AcpiTable
== NULL
) {
992 DEBUG ((EFI_D_INFO
, "ACPI table is not found!\n"));
994 EfiToLegacy16BootTable
->AcpiTable
= (UINT32
)(UINTN
)AcpiTable
;
997 // Get RSD Ptr table rev at offset 15 decimal
998 // Rev = 0 Length is 20 decimal
999 // Rev != 0 Length is UINT32 at offset 20 decimal
1001 if (AcpiTable
!= NULL
) {
1003 AcpiPtr
= AcpiTable
;
1004 if (*((UINT8
*) AcpiPtr
+ 15) == 0) {
1007 AcpiPtr
= ((UINT8
*) AcpiPtr
+ 20);
1008 CopySize
= (*(UINT32
*) AcpiPtr
);
1012 (VOID
*)(UINTN
) Private
->Legacy16Table
->AcpiRsdPtrPointer
,
1018 // Make sure all PCI Interrupt Line register are programmed to match 8259
1020 PciProgramAllInterruptLineRegisters (Private
);
1023 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
1026 Private
->LegacyRegion
->UnLock (
1027 Private
->LegacyRegion
,
1029 Private
->LegacyBiosImageSize
,
1034 // Configure Legacy Device Magic
1036 // Only do this code if booting legacy OS
1038 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1039 UpdateSioData (Private
);
1042 // Setup BDA and EBDA standard areas before Legacy Boot
1044 LegacyBiosCompleteBdaBeforeBoot (Private
);
1045 LegacyBiosCompleteStandardCmosBeforeBoot (Private
);
1048 // We must build IDE data, if it hasn't been done, before PciShadowRoms
1049 // to insure EFI drivers are connected.
1051 LegacyBiosBuildIdeData (Private
, &HddInfo
, 1);
1052 UpdateAllIdentifyDriveData (Private
);
1055 // Clear IO BAR, if IDE controller in legacy mode.
1057 InitLegacyIdeController (IdeController
);
1060 // Generate number of ticks since midnight for BDA. DOS requires this
1061 // for its time. We have to make assumptions as to how long following
1062 // code takes since after PciShadowRoms PciIo is gone. Place result in
1065 // Adjust value by 1 second.
1067 gRT
->GetTime (&BootTime
, NULL
);
1068 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
1072 // Multiply result by 18.2 for number of ticks since midnight.
1073 // Use 182/10 to avoid floating point math.
1075 LocalTime
= (LocalTime
* 182) / 10;
1076 BdaPtr
= (UINT32
*) (UINTN
)0x46C;
1077 *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.
1323 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1324 for (Index
= 0; Index
< 8; Index
++) {
1325 Private
->ThunkSavedInt
[Index
] = BaseVectorMaster
[Index
];
1326 if (Private
->ThunkSeg
== (UINT16
) (BaseVectorMaster
[Index
] >> 16)) {
1327 BaseVectorMaster
[Index
] = (UINT32
) (Private
->BiosUnexpectedInt
);
1331 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1332 Regs
.X
.AX
= Legacy16Boot
;
1334 Private
->LegacyBios
.FarCall86 (
1336 Private
->Legacy16CallSegment
,
1337 Private
->Legacy16CallOffset
,
1343 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1344 for (Index
= 0; Index
< 8; Index
++) {
1345 BaseVectorMaster
[Index
] = Private
->ThunkSavedInt
[Index
];
1348 Private
->LegacyBootEntered
= TRUE
;
1349 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1351 // Should never return unless never passed control to 0:7c00(first stage
1352 // OS loader) and only then if no bootable device found.
1354 return EFI_DEVICE_ERROR
;
1357 // If boot to EFI then expect to return to caller
1365 Assign drive number to legacy HDD drives prior to booting an EFI
1366 aware OS so the OS can access drives without an EFI driver.
1367 Note: BBS compliant drives ARE NOT available until this call by
1368 either shell or EFI.
1370 @param This Protocol instance pointer.
1371 @param BbsCount Number of BBS_TABLE structures
1372 @param BbsTable List BBS entries
1374 @retval EFI_SUCCESS Drive numbers assigned
1379 LegacyBiosPrepareToBootEfi (
1380 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1381 OUT UINT16
*BbsCount
,
1382 OUT BBS_TABLE
**BbsTable
1386 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1387 LEGACY_BIOS_INSTANCE
*Private
;
1389 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1390 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1391 mBootMode
= BOOT_EFI_OS
;
1392 mBbsDevicePathPtr
= NULL
;
1393 Status
= GenericLegacyBoot (This
);
1394 *BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1395 *BbsCount
= (UINT16
) (sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
));
1400 To boot from an unconventional device like parties and/or execute HDD diagnostics.
1402 @param This Protocol instance pointer.
1403 @param Attributes How to interpret the other input parameters
1404 @param BbsEntry The 0-based index into the BbsTable for the parent
1406 @param BeerData Pointer to the 128 bytes of ram BEER data.
1407 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1408 caller must provide a pointer to the specific Service
1409 Area and not the start all Service Areas.
1411 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1416 LegacyBiosBootUnconventionalDevice (
1417 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1418 IN UDC_ATTRIBUTES Attributes
,
1421 IN VOID
*ServiceAreaData
1425 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1426 LEGACY_BIOS_INSTANCE
*Private
;
1429 UINT16 BootPriority
;
1430 BBS_TABLE
*BbsTable
;
1433 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1434 mBootMode
= BOOT_UNCONVENTIONAL_DEVICE
;
1435 mBbsDevicePathPtr
= &mBbsDevicePathNode
;
1436 mAttributes
= Attributes
;
1437 mBbsEntry
= BbsEntry
;
1438 mBeerData
= BeerData
, mServiceAreaData
= ServiceAreaData
;
1440 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1443 // Do input parameter checking
1445 if ((Attributes
.DirectoryServiceValidity
== 0) &&
1446 (Attributes
.RabcaUsedFlag
== 0) &&
1447 (Attributes
.ExecuteHddDiagnosticsFlag
== 0)
1449 return EFI_INVALID_PARAMETER
;
1452 if (((Attributes
.DirectoryServiceValidity
!= 0) && (ServiceAreaData
== NULL
)) ||
1453 (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
) != 0) && (BeerData
== NULL
))
1455 return EFI_INVALID_PARAMETER
;
1458 UcdTable
= (UD_TABLE
*) AllocatePool (
1461 if (NULL
== UcdTable
) {
1462 return EFI_OUT_OF_RESOURCES
;
1465 EfiToLegacy16BootTable
->UnconventionalDeviceTable
= (UINT32
)(UINTN
)UcdTable
;
1466 UcdTable
->Attributes
= Attributes
;
1467 UcdTable
->BbsTableEntryNumberForParentDevice
= (UINT8
) BbsEntry
;
1469 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1470 // to assign drive numbers but bot boot from. Only newly created entries
1473 BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1474 for (Index
= 0; Index
< EfiToLegacy16BootTable
->NumberBbsEntries
; Index
++) {
1475 BbsTable
[Index
].BootPriority
= BBS_DO_NOT_BOOT_FROM
;
1478 // If parent is onboard IDE then assign controller & device number
1481 if (BbsEntry
< MAX_IDE_CONTROLLER
* 2) {
1482 UcdTable
->DeviceNumber
= (UINT8
) ((BbsEntry
- 1) % 2);
1485 if (BeerData
!= NULL
) {
1487 (VOID
*) UcdTable
->BeerData
,
1493 if (ServiceAreaData
!= NULL
) {
1495 (VOID
*) UcdTable
->ServiceAreaData
,
1501 // For each new entry do the following:
1502 // 1. Increment current number of BBS entries
1503 // 2. Copy parent entry to new entry.
1504 // 3. Zero out BootHandler Offset & segment
1505 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1506 // and Floppy(0x01) for PARTIES boot.
1507 // 5. Assign new priority.
1509 if ((Attributes
.ExecuteHddDiagnosticsFlag
) != 0) {
1510 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1513 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1514 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1518 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1519 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1520 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x80;
1522 UcdTable
->BbsTableEntryNumberForHddDiag
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1524 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1528 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1530 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_BEV
;
1533 if (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
)) != 0) {
1534 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1536 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1537 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1541 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1542 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1543 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x01;
1544 UcdTable
->BbsTableEntryNumberForBoot
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1545 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1548 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1550 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_FLOPPY
;
1553 // Build the BBS Device Path for this boot selection
1555 mBbsDevicePathNode
.Header
.Type
= BBS_DEVICE_PATH
;
1556 mBbsDevicePathNode
.Header
.SubType
= BBS_BBS_DP
;
1557 SetDevicePathNodeLength (&mBbsDevicePathNode
.Header
, sizeof (BBS_BBS_DEVICE_PATH
));
1558 mBbsDevicePathNode
.StatusFlag
= 0;
1559 mBbsDevicePathNode
.String
[0] = 0;
1561 Status
= GenericLegacyBoot (This
);
1566 Attempt to legacy boot the BootOption. If the EFI contexted has been
1567 compromised this function will not return.
1569 @param This Protocol instance pointer.
1570 @param BbsDevicePath EFI Device Path from BootXXXX variable.
1571 @param LoadOptionsSize Size of LoadOption in size.
1572 @param LoadOptions LoadOption from BootXXXX variable
1574 @retval EFI_SUCCESS Removable media not present
1579 LegacyBiosLegacyBoot (
1580 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1581 IN BBS_BBS_DEVICE_PATH
*BbsDevicePath
,
1582 IN UINT32 LoadOptionsSize
,
1583 IN VOID
*LoadOptions
1588 mBbsDevicePathPtr
= BbsDevicePath
;
1589 mLoadOptionsSize
= LoadOptionsSize
;
1590 mLoadOptions
= LoadOptions
;
1591 mBootMode
= BOOT_LEGACY_OS
;
1592 Status
= GenericLegacyBoot (This
);
1598 Convert EFI Memory Type to E820 Memory Type.
1600 @param Type EFI Memory Type
1602 @return ACPI Memory Type for EFI Memory Type
1605 EFI_ACPI_MEMORY_TYPE
1606 EfiMemoryTypeToE820Type (
1613 case EfiBootServicesCode
:
1614 case EfiBootServicesData
:
1615 case EfiConventionalMemory
:
1616 case EfiRuntimeServicesCode
:
1617 case EfiRuntimeServicesData
:
1618 return EfiAcpiAddressRangeMemory
;
1620 case EfiACPIReclaimMemory
:
1621 return EfiAcpiAddressRangeACPI
;
1623 case EfiACPIMemoryNVS
:
1624 return EfiAcpiAddressRangeNVS
;
1627 // All other types map to reserved.
1628 // Adding the code just waists FLASH space.
1630 // case EfiReservedMemoryType:
1631 // case EfiUnusableMemory:
1632 // case EfiMemoryMappedIO:
1633 // case EfiMemoryMappedIOPortSpace:
1637 return EfiAcpiAddressRangeReserved
;
1642 Build the E820 table.
1644 @param Private Legacy BIOS Instance data
1645 @param Size Size of E820 Table
1647 @retval EFI_SUCCESS It should always work.
1651 LegacyBiosBuildE820 (
1652 IN LEGACY_BIOS_INSTANCE
*Private
,
1657 EFI_E820_ENTRY64
*E820Table
;
1658 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMap
;
1659 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMapEnd
;
1660 EFI_MEMORY_DESCRIPTOR
*EfiEntry
;
1661 EFI_MEMORY_DESCRIPTOR
*NextEfiEntry
;
1662 EFI_MEMORY_DESCRIPTOR TempEfiEntry
;
1663 UINTN EfiMemoryMapSize
;
1665 UINTN EfiDescriptorSize
;
1666 UINT32 EfiDescriptorVersion
;
1668 EFI_PEI_HOB_POINTERS Hob
;
1669 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
1672 UINTN TempNextIndex
;
1673 EFI_E820_ENTRY64 TempE820
;
1674 EFI_ACPI_MEMORY_TYPE TempType
;
1675 BOOLEAN ChangedFlag
;
1677 UINT64 MemoryBlockLength
;
1679 E820Table
= (EFI_E820_ENTRY64
*) Private
->E820Table
;
1682 // Get the EFI memory map.
1684 EfiMemoryMapSize
= 0;
1685 EfiMemoryMap
= NULL
;
1686 Status
= gBS
->GetMemoryMap (
1691 &EfiDescriptorVersion
1693 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1697 // Use size returned back plus 1 descriptor for the AllocatePool.
1698 // We don't just multiply by 2 since the "for" loop below terminates on
1699 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
1700 // we process bogus entries and create bogus E820 entries.
1702 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*) AllocatePool (EfiMemoryMapSize
);
1703 ASSERT (EfiMemoryMap
!= NULL
);
1704 Status
= gBS
->GetMemoryMap (
1709 &EfiDescriptorVersion
1711 if (EFI_ERROR (Status
)) {
1712 FreePool (EfiMemoryMap
);
1714 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1716 ASSERT_EFI_ERROR (Status
);
1719 // Punch in the E820 table for memory less than 1 MB.
1720 // Assume ZeroMem () has been done on data structure.
1723 // First entry is 0 to (640k - EBDA)
1725 E820Table
[0].BaseAddr
= 0;
1726 E820Table
[0].Length
= (UINT64
) ((*(UINT16
*) (UINTN
)0x40E) << 4);
1727 E820Table
[0].Type
= EfiAcpiAddressRangeMemory
;
1730 // Second entry is (640k - EBDA) to 640k
1732 E820Table
[1].BaseAddr
= E820Table
[0].Length
;
1733 E820Table
[1].Length
= (UINT64
) ((640 * 1024) - E820Table
[0].Length
);
1734 E820Table
[1].Type
= EfiAcpiAddressRangeReserved
;
1737 // Third Entry is legacy BIOS
1738 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1739 // to page in memory under 1MB.
1740 // Omit region from 0xE0000 to start of BIOS, if any. This can be
1741 // used for a multiple reasons including OPROMS.
1745 // The CSM binary image size is not the actually size that CSM binary used,
1746 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1748 E820Table
[2].BaseAddr
= 0xE0000;
1749 E820Table
[2].Length
= 0x20000;
1750 E820Table
[2].Type
= EfiAcpiAddressRangeReserved
;
1755 // Process the EFI map to produce E820 map;
1759 // Sort memory map from low to high
1761 EfiEntry
= EfiMemoryMap
;
1762 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1763 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1764 while (EfiEntry
< EfiMemoryMapEnd
) {
1765 while (NextEfiEntry
< EfiMemoryMapEnd
) {
1766 if (EfiEntry
->PhysicalStart
> NextEfiEntry
->PhysicalStart
) {
1767 CopyMem (&TempEfiEntry
, EfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1768 CopyMem (EfiEntry
, NextEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1769 CopyMem (NextEfiEntry
, &TempEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1772 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (NextEfiEntry
, EfiDescriptorSize
);
1775 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1776 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1779 EfiEntry
= EfiMemoryMap
;
1780 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1781 for (Index
= Above1MIndex
; (EfiEntry
< EfiMemoryMapEnd
) && (Index
< EFI_MAX_E820_ENTRY
- 1); ) {
1782 MemoryBlockLength
= (UINT64
) (LShiftU64 (EfiEntry
->NumberOfPages
, 12));
1783 if ((EfiEntry
->PhysicalStart
+ MemoryBlockLength
) < 0x100000) {
1785 // Skip the memory block is under 1MB
1788 if (EfiEntry
->PhysicalStart
< 0x100000) {
1790 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1792 MemoryBlockLength
-= 0x100000 - EfiEntry
->PhysicalStart
;
1793 EfiEntry
->PhysicalStart
= 0x100000;
1797 // Convert memory type to E820 type
1799 TempType
= EfiMemoryTypeToE820Type (EfiEntry
->Type
);
1801 if ((E820Table
[Index
].Type
== TempType
) && (EfiEntry
->PhysicalStart
== (E820Table
[Index
].BaseAddr
+ E820Table
[Index
].Length
))) {
1803 // Grow an existing entry
1805 E820Table
[Index
].Length
+= MemoryBlockLength
;
1811 E820Table
[Index
].BaseAddr
= EfiEntry
->PhysicalStart
;
1812 E820Table
[Index
].Length
= MemoryBlockLength
;
1813 E820Table
[Index
].Type
= TempType
;
1816 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1819 FreePool (EfiMemoryMap
);
1822 // Process the reserved memory map to produce E820 map ;
1824 for (Hob
.Raw
= GetHobList (); !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
1825 if (Hob
.Raw
!= NULL
&& GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
1826 ResourceHob
= Hob
.ResourceDescriptor
;
1827 if (((ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_MAPPED_IO
) ||
1828 (ResourceHob
->ResourceType
== EFI_RESOURCE_FIRMWARE_DEVICE
) ||
1829 (ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_RESERVED
) ) &&
1830 (ResourceHob
->PhysicalStart
> 0x100000) &&
1831 (Index
< EFI_MAX_E820_ENTRY
- 1)) {
1833 E820Table
[Index
].BaseAddr
= ResourceHob
->PhysicalStart
;
1834 E820Table
[Index
].Length
= ResourceHob
->ResourceLength
;
1835 E820Table
[Index
].Type
= EfiAcpiAddressRangeReserved
;
1841 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1842 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1843 Private
->NumberE820Entries
= (UINT32
)Index
;
1844 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1847 // Sort E820Table from low to high
1849 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1850 ChangedFlag
= FALSE
;
1851 for (TempNextIndex
= 1; TempNextIndex
< Index
- TempIndex
; TempNextIndex
++) {
1852 if (E820Table
[TempNextIndex
- 1].BaseAddr
> E820Table
[TempNextIndex
].BaseAddr
) {
1854 TempE820
.BaseAddr
= E820Table
[TempNextIndex
- 1].BaseAddr
;
1855 TempE820
.Length
= E820Table
[TempNextIndex
- 1].Length
;
1856 TempE820
.Type
= E820Table
[TempNextIndex
- 1].Type
;
1858 E820Table
[TempNextIndex
- 1].BaseAddr
= E820Table
[TempNextIndex
].BaseAddr
;
1859 E820Table
[TempNextIndex
- 1].Length
= E820Table
[TempNextIndex
].Length
;
1860 E820Table
[TempNextIndex
- 1].Type
= E820Table
[TempNextIndex
].Type
;
1862 E820Table
[TempNextIndex
].BaseAddr
= TempE820
.BaseAddr
;
1863 E820Table
[TempNextIndex
].Length
= TempE820
.Length
;
1864 E820Table
[TempNextIndex
].Type
= TempE820
.Type
;
1874 // Remove the overlap range
1876 for (TempIndex
= 1; TempIndex
< Index
; TempIndex
++) {
1877 if (E820Table
[TempIndex
- 1].BaseAddr
<= E820Table
[TempIndex
].BaseAddr
&&
1878 ((E820Table
[TempIndex
- 1].BaseAddr
+ E820Table
[TempIndex
- 1].Length
) >=
1879 (E820Table
[TempIndex
].BaseAddr
+E820Table
[TempIndex
].Length
))) {
1881 //Overlap range is found
1883 ASSERT (E820Table
[TempIndex
- 1].Type
== E820Table
[TempIndex
].Type
);
1885 if (TempIndex
== Index
- 1) {
1886 E820Table
[TempIndex
].BaseAddr
= 0;
1887 E820Table
[TempIndex
].Length
= 0;
1888 E820Table
[TempIndex
].Type
= (EFI_ACPI_MEMORY_TYPE
) 0;
1892 for (IndexSort
= TempIndex
; IndexSort
< Index
- 1; IndexSort
++) {
1893 E820Table
[IndexSort
].BaseAddr
= E820Table
[IndexSort
+ 1].BaseAddr
;
1894 E820Table
[IndexSort
].Length
= E820Table
[IndexSort
+ 1].Length
;
1895 E820Table
[IndexSort
].Type
= E820Table
[IndexSort
+ 1].Type
;
1904 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1905 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1906 Private
->NumberE820Entries
= (UINT32
)Index
;
1907 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1910 // Determine OS usable memory above 1Mb
1912 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
= 0x0000;
1913 for (TempIndex
= Above1MIndex
; TempIndex
< Index
; TempIndex
++) {
1914 if (E820Table
[TempIndex
].BaseAddr
>= 0x100000 && E820Table
[TempIndex
].BaseAddr
< 0x100000000ULL
) { // not include above 4G memory
1916 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1918 if ((E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeMemory
) || (E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeACPI
)) {
1919 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
+= (UINT32
) (E820Table
[TempIndex
].Length
);
1921 break; // break at first not normal memory, because SMM may use reserved memory.
1926 Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
= Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
;
1929 // Print DEBUG information
1931 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1932 DEBUG((EFI_D_INFO
, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
1934 E820Table
[TempIndex
].BaseAddr
,
1935 (E820Table
[TempIndex
].BaseAddr
+ E820Table
[TempIndex
].Length
),
1936 E820Table
[TempIndex
].Type
1945 Fill in the standard BDA and EBDA stuff prior to legacy Boot
1947 @param Private Legacy BIOS Instance data
1949 @retval EFI_SUCCESS It should always work.
1953 LegacyBiosCompleteBdaBeforeBoot (
1954 IN LEGACY_BIOS_INSTANCE
*Private
1958 UINT16 MachineConfig
;
1959 DEVICE_PRODUCER_DATA_HEADER
*SioPtr
;
1961 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
1964 SioPtr
= &(Private
->IntThunk
->EfiToLegacy16BootTable
.SioData
);
1965 Bda
->Com1
= SioPtr
->Serial
[0].Address
;
1966 Bda
->Com2
= SioPtr
->Serial
[1].Address
;
1967 Bda
->Com3
= SioPtr
->Serial
[2].Address
;
1968 Bda
->Com4
= SioPtr
->Serial
[3].Address
;
1970 if (SioPtr
->Serial
[0].Address
!= 0x00) {
1971 MachineConfig
+= 0x200;
1974 if (SioPtr
->Serial
[1].Address
!= 0x00) {
1975 MachineConfig
+= 0x200;
1978 if (SioPtr
->Serial
[2].Address
!= 0x00) {
1979 MachineConfig
+= 0x200;
1982 if (SioPtr
->Serial
[3].Address
!= 0x00) {
1983 MachineConfig
+= 0x200;
1986 Bda
->Lpt1
= SioPtr
->Parallel
[0].Address
;
1987 Bda
->Lpt2
= SioPtr
->Parallel
[1].Address
;
1988 Bda
->Lpt3
= SioPtr
->Parallel
[2].Address
;
1990 if (SioPtr
->Parallel
[0].Address
!= 0x00) {
1991 MachineConfig
+= 0x4000;
1994 if (SioPtr
->Parallel
[1].Address
!= 0x00) {
1995 MachineConfig
+= 0x4000;
1998 if (SioPtr
->Parallel
[2].Address
!= 0x00) {
1999 MachineConfig
+= 0x4000;
2002 Bda
->NumberOfDrives
= (UINT8
) (Bda
->NumberOfDrives
+ Private
->IdeDriveCount
);
2003 if (SioPtr
->Floppy
.NumberOfFloppy
!= 0x00) {
2004 MachineConfig
= (UINT16
) (MachineConfig
+ 0x01 + (SioPtr
->Floppy
.NumberOfFloppy
- 1) * 0x40);
2005 Bda
->FloppyXRate
= 0x07;
2008 Bda
->Lpt1_2Timeout
= 0x1414;
2009 Bda
->Lpt3_4Timeout
= 0x1414;
2010 Bda
->Com1_2Timeout
= 0x0101;
2011 Bda
->Com3_4Timeout
= 0x0101;
2014 // Force VGA and Coprocessor, indicate 101/102 keyboard
2016 MachineConfig
= (UINT16
) (MachineConfig
+ 0x00 + 0x02 + (SioPtr
->MousePresent
* 0x04));
2017 Bda
->MachineConfig
= MachineConfig
;
2023 Fill in the standard BDA for Keyboard LEDs
2025 @param This Protocol instance pointer.
2026 @param Leds Current LED status
2028 @retval EFI_SUCCESS It should always work.
2033 LegacyBiosUpdateKeyboardLedStatus (
2034 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
2038 LEGACY_BIOS_INSTANCE
*Private
;
2041 EFI_IA32_REGISTER_SET Regs
;
2043 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
2045 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
2047 Bda
->LedStatus
= (UINT8
) ((Bda
->LedStatus
&~0x07) | LocalLeds
);
2048 LocalLeds
= (UINT8
) (LocalLeds
<< 4);
2049 Bda
->ShiftStatus
= (UINT8
) ((Bda
->ShiftStatus
&~0x70) | LocalLeds
);
2050 LocalLeds
= (UINT8
) (Leds
& 0x20);
2051 Bda
->KeyboardStatus
= (UINT8
) ((Bda
->KeyboardStatus
&~0x20) | LocalLeds
);
2053 // Call into Legacy16 code to allow it to do any processing
2055 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
2056 Regs
.X
.AX
= Legacy16SetKeyboardLeds
;
2059 Private
->LegacyBios
.FarCall86 (
2060 &Private
->LegacyBios
,
2061 Private
->Legacy16Table
->Compatibility16CallSegment
,
2062 Private
->Legacy16Table
->Compatibility16CallOffset
,
2073 Fill in the standard CMOS stuff prior to legacy Boot
2075 @param Private Legacy BIOS Instance data
2077 @retval EFI_SUCCESS It should always work.
2081 LegacyBiosCompleteStandardCmosBeforeBoot (
2082 IN LEGACY_BIOS_INSTANCE
*Private
2090 // Update CMOS locations
2092 // 12,19,1A - ignore as OS don't use them and there is no standard due
2093 // to large capacity drives
2094 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
2096 Bda
= (UINT8
)(*((UINT8
*)((UINTN
)0x410)) | BIT3
);
2099 // Force display enabled
2102 if ((Bda
& BIT0
) != 0) {
2107 // Check if 2.88MB floppy set
2109 if ((Bda
& (BIT7
| BIT6
)) != 0) {
2110 Floppy
= (UINT8
)(Floppy
| BIT1
);
2113 LegacyWriteStandardCmos (CMOS_10
, Floppy
);
2114 LegacyWriteStandardCmos (CMOS_14
, Bda
);
2117 // Force Status Register A to set rate selection bits and divider
2119 LegacyWriteStandardCmos (CMOS_0A
, 0x26);
2122 // redo memory size since it can change
2124 Size
= (15 * SIZE_1MB
) >> 10;
2125 if (Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
< (15 * SIZE_1MB
)) {
2126 Size
= Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
>> 10;
2129 LegacyWriteStandardCmos (CMOS_17
, (UINT8
)(Size
& 0xFF));
2130 LegacyWriteStandardCmos (CMOS_30
, (UINT8
)(Size
& 0xFF));
2131 LegacyWriteStandardCmos (CMOS_18
, (UINT8
)(Size
>> 8));
2132 LegacyWriteStandardCmos (CMOS_31
, (UINT8
)(Size
>> 8));
2134 LegacyCalculateWriteStandardCmosChecksum ();
2140 Relocate this image under 4G memory for IPF.
2142 @param ImageHandle Handle of driver image.
2143 @param SystemTable Pointer to system table.
2145 @retval EFI_SUCCESS Image successfully relocated.
2146 @retval EFI_ABORTED Failed to relocate image.
2150 RelocateImageUnder4GIfNeeded (
2151 IN EFI_HANDLE ImageHandle
,
2152 IN EFI_SYSTEM_TABLE
*SystemTable