3 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "LegacyBiosInterface.h"
10 #include <IndustryStandard/Pci.h>
12 #define BOOT_LEGACY_OS 0
14 #define BOOT_UNCONVENTIONAL_DEVICE 2
16 UINT32 mLoadOptionsSize
= 0;
17 UINTN mBootMode
= BOOT_LEGACY_OS
;
18 VOID
*mLoadOptions
= NULL
;
19 BBS_BBS_DEVICE_PATH
*mBbsDevicePathPtr
= NULL
;
20 BBS_BBS_DEVICE_PATH mBbsDevicePathNode
;
21 UDC_ATTRIBUTES mAttributes
= { 0, 0, 0, 0 };
23 VOID
*mBeerData
= NULL
;
24 VOID
*mServiceAreaData
= NULL
;
25 UINT64 mLowWater
= 0xffffffffffffffffULL
;
27 extern BBS_TABLE
*mBbsTable
;
29 extern VOID
*mRuntimeSmbiosEntryPoint
;
30 extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint
;
31 extern EFI_PHYSICAL_ADDRESS mStructureTableAddress
;
36 @param BbsTable The BBS table.
42 IN BBS_TABLE
*BbsTable
49 DEBUG ((EFI_D_INFO
, "\n"));
50 DEBUG ((EFI_D_INFO
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
51 DEBUG ((EFI_D_INFO
, "=================================================================\n"));
52 for (Index
= 0; Index
< MAX_BBS_ENTRIES
; Index
++) {
56 if (BbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) {
62 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
64 (UINTN
) BbsTable
[Index
].BootPriority
,
65 (UINTN
) BbsTable
[Index
].Bus
,
66 (UINTN
) BbsTable
[Index
].Device
,
67 (UINTN
) BbsTable
[Index
].Function
,
68 (UINTN
) BbsTable
[Index
].Class
,
69 (UINTN
) BbsTable
[Index
].SubClass
,
70 (UINTN
) BbsTable
[Index
].DeviceType
,
71 (UINTN
) * (UINT16
*) &BbsTable
[Index
].StatusFlags
75 " %04x:%04x %04x:%04x %04x:%04x",
76 (UINTN
) BbsTable
[Index
].BootHandlerSegment
,
77 (UINTN
) BbsTable
[Index
].BootHandlerOffset
,
78 (UINTN
) BbsTable
[Index
].MfgStringSegment
,
79 (UINTN
) BbsTable
[Index
].MfgStringOffset
,
80 (UINTN
) BbsTable
[Index
].DescStringSegment
,
81 (UINTN
) BbsTable
[Index
].DescStringOffset
87 String
= (CHAR8
*)(((UINTN
)BbsTable
[Index
].DescStringSegment
<< 4) + BbsTable
[Index
].DescStringOffset
);
89 DEBUG ((EFI_D_INFO
," ("));
90 for (SubIndex
= 0; String
[SubIndex
] != 0; SubIndex
++) {
91 DEBUG ((EFI_D_INFO
, "%c", String
[SubIndex
]));
93 DEBUG ((EFI_D_INFO
,")"));
95 DEBUG ((EFI_D_INFO
,"\n"));
98 DEBUG ((EFI_D_INFO
, "\n"));
106 @param HddInfo The HddInfo table.
117 DEBUG ((EFI_D_INFO
, "\n"));
118 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
119 DEBUG ((EFI_D_INFO
, "Index - %04x\n", Index
));
120 DEBUG ((EFI_D_INFO
, " Status - %04x\n", (UINTN
)HddInfo
[Index
].Status
));
121 DEBUG ((EFI_D_INFO
, " B/D/F - %02x/%02x/%02x\n", (UINTN
)HddInfo
[Index
].Bus
, (UINTN
)HddInfo
[Index
].Device
, (UINTN
)HddInfo
[Index
].Function
));
122 DEBUG ((EFI_D_INFO
, " Command - %04x\n", HddInfo
[Index
].CommandBaseAddress
));
123 DEBUG ((EFI_D_INFO
, " Control - %04x\n", HddInfo
[Index
].ControlBaseAddress
));
124 DEBUG ((EFI_D_INFO
, " BusMaster - %04x\n", HddInfo
[Index
].BusMasterAddress
));
125 DEBUG ((EFI_D_INFO
, " HddIrq - %02x\n", HddInfo
[Index
].HddIrq
));
126 DEBUG ((EFI_D_INFO
, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
127 DEBUG ((EFI_D_INFO
, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
130 DEBUG ((EFI_D_INFO
, "\n"));
136 Print the PCI Interrupt Line and Interrupt Pin registers.
139 PrintPciInterruptRegister (
147 EFI_PCI_IO_PROTOCOL
*PciIo
;
154 gBS
->LocateHandleBuffer (
156 &gEfiPciIoProtocolGuid
,
166 DEBUG ((EFI_D_INFO
, "\n"));
167 DEBUG ((EFI_D_INFO
, " bb/dd/ff interrupt line interrupt pin\n"));
168 DEBUG ((EFI_D_INFO
, "======================================\n"));
169 for (Index
= 0; Index
< HandleNum
; Index
++) {
170 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiPciIoProtocolGuid
, (VOID
**) &PciIo
);
171 if (!EFI_ERROR (Status
)) {
172 Status
= PciIo
->Pci
.Read (
180 if (!EFI_ERROR (Status
)) {
181 Status
= PciIo
->GetLocation (
189 if (!EFI_ERROR (Status
)) {
190 DEBUG ((EFI_D_INFO
, " %02x/%02x/%02x 0x%02x 0x%02x\n",
191 Bus
, Device
, Function
, Interrupt
[0], Interrupt
[1]));
194 DEBUG ((EFI_D_INFO
, "\n"));
196 if (Handles
!= NULL
) {
202 Identify drive data must be updated to actual parameters before boot.
204 @param IdentifyDriveData ATA Identify Data
208 UpdateIdentifyDriveData (
209 IN UINT8
*IdentifyDriveData
215 @param Private Legacy BIOS Instance data
217 @retval EFI_SUCCESS Removable media not present
222 IN LEGACY_BIOS_INSTANCE
*Private
228 UINT8 LegacyInterrupts
[16];
229 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
230 UINTN RoutingTableEntries
;
231 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY
*IrqPriorityTable
;
232 UINTN NumberPriorityEntries
;
233 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
239 EFI_HANDLE
*HandleBuffer
;
240 EFI_ISA_IO_PROTOCOL
*IsaIo
;
245 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
246 LegacyBiosBuildSioData (Private
);
247 SetMem (LegacyInterrupts
, sizeof (LegacyInterrupts
), 0);
250 // Create list of legacy interrupts.
252 for (Index
= 0; Index
< 4; Index
++) {
253 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Serial
[Index
].Irq
;
256 for (Index
= 4; Index
< 7; Index
++) {
257 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Parallel
[Index
- 4].Irq
;
260 LegacyInterrupts
[7] = EfiToLegacy16BootTable
->SioData
.Floppy
.Irq
;
263 // Get Legacy Hdd IRQs. If native mode treat as PCI
265 for (Index
= 0; Index
< 2; Index
++) {
266 HddIrq
= EfiToLegacy16BootTable
->HddInfo
[Index
].HddIrq
;
267 if ((HddIrq
!= 0) && ((HddIrq
== 15) || (HddIrq
== 14))) {
268 LegacyInterrupts
[Index
+ 8] = HddIrq
;
272 Private
->LegacyBiosPlatform
->GetRoutingTable (
273 Private
->LegacyBiosPlatform
,
274 (VOID
*) &RoutingTable
,
275 &RoutingTableEntries
,
278 (VOID
**) &IrqPriorityTable
,
279 &NumberPriorityEntries
282 // Remove legacy interrupts from the list of PCI interrupts available.
284 for (Index
= 0; Index
<= 0x0b; Index
++) {
285 for (Index1
= 0; Index1
<= NumberPriorityEntries
; Index1
++) {
286 if (LegacyInterrupts
[Index
] != 0) {
287 LegacyInt
= (UINT16
) (LegacyInt
| (1 << LegacyInterrupts
[Index
]));
288 if (LegacyInterrupts
[Index
] == IrqPriorityTable
[Index1
].Irq
) {
289 IrqPriorityTable
[Index1
].Used
= LEGACY_USED
;
295 Private
->Legacy8259
->GetMask (
304 // Set SIO interrupts and disable mouse. Let mouse driver
307 LegMask
= (UINT16
) ((LegMask
&~LegacyInt
) | 0x1000);
308 Private
->Legacy8259
->SetMask (
317 // Disable mouse in keyboard controller
320 Status
= gBS
->LocateHandleBuffer (
322 &gEfiIsaIoProtocolGuid
,
327 if (EFI_ERROR (Status
)) {
331 for (Index
= 0; Index
< HandleCount
; Index
++) {
332 Status
= gBS
->HandleProtocol (
334 &gEfiIsaIoProtocolGuid
,
337 ASSERT_EFI_ERROR (Status
);
338 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, 0x64, 1, &Register
);
342 if (HandleBuffer
!= NULL
) {
343 FreePool (HandleBuffer
);
351 Identify drive data must be updated to actual parameters before boot.
352 This requires updating the checksum, if it exists.
354 @param IdentifyDriveData ATA Identify Data
355 @param Checksum checksum of the ATA Identify Data
357 @retval EFI_SUCCESS checksum calculated
358 @retval EFI_SECURITY_VIOLATION IdentifyData invalid
362 CalculateIdentifyDriveChecksum (
363 IN UINT8
*IdentifyDriveData
,
371 if (IdentifyDriveData
[510] != 0xA5) {
372 return EFI_SECURITY_VIOLATION
;
375 for (Index
= 0; Index
< 512; Index
++) {
376 LocalChecksum
= (UINT8
) (LocalChecksum
+ IdentifyDriveData
[Index
]);
379 *Checksum
= LocalChecksum
;
385 Identify drive data must be updated to actual parameters before boot.
387 @param IdentifyDriveData ATA Identify Data
392 UpdateIdentifyDriveData (
393 IN UINT8
*IdentifyDriveData
396 UINT16 NumberCylinders
;
398 UINT16 NumberSectorsTrack
;
399 UINT32 CapacityInSectors
;
400 UINT8 OriginalChecksum
;
403 ATAPI_IDENTIFY
*ReadInfo
;
406 // Status indicates if Integrity byte is correct. Checksum should be
409 ReadInfo
= (ATAPI_IDENTIFY
*) IdentifyDriveData
;
410 Status
= CalculateIdentifyDriveChecksum (IdentifyDriveData
, &OriginalChecksum
);
411 if (OriginalChecksum
!= 0) {
412 Status
= EFI_SECURITY_VIOLATION
;
415 // If NumberCylinders = 0 then do data(Controller present but don drive attached).
417 NumberCylinders
= ReadInfo
->Raw
[1];
418 if (NumberCylinders
!= 0) {
419 ReadInfo
->Raw
[54] = NumberCylinders
;
421 NumberHeads
= ReadInfo
->Raw
[3];
422 ReadInfo
->Raw
[55] = NumberHeads
;
424 NumberSectorsTrack
= ReadInfo
->Raw
[6];
425 ReadInfo
->Raw
[56] = NumberSectorsTrack
;
428 // Copy Multisector info and set valid bit.
430 ReadInfo
->Raw
[59] = (UINT16
) (ReadInfo
->Raw
[47] + 0x100);
431 CapacityInSectors
= (UINT32
) ((UINT32
) (NumberCylinders
) * (UINT32
) (NumberHeads
) * (UINT32
) (NumberSectorsTrack
));
432 ReadInfo
->Raw
[57] = (UINT16
) (CapacityInSectors
>> 16);
433 ReadInfo
->Raw
[58] = (UINT16
) (CapacityInSectors
& 0xffff);
434 if (Status
== EFI_SUCCESS
) {
436 // Forece checksum byte to 0 and get new checksum.
438 ReadInfo
->Raw
[255] &= 0xff;
439 CalculateIdentifyDriveChecksum (IdentifyDriveData
, &FinalChecksum
);
442 // Force new checksum such that sum is 0.
444 FinalChecksum
= (UINT8
) ((UINT8
)0 - FinalChecksum
);
445 ReadInfo
->Raw
[255] = (UINT16
) (ReadInfo
->Raw
[255] | (FinalChecksum
<< 8));
451 Identify drive data must be updated to actual parameters before boot.
454 @param Private Legacy BIOS Instance data
459 UpdateAllIdentifyDriveData (
460 IN LEGACY_BIOS_INSTANCE
*Private
466 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
468 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
470 // Each controller can have 2 devices. Update for each device
472 if ((HddInfo
[Index
].Status
& HDD_MASTER_IDE
) != 0) {
473 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
476 if ((HddInfo
[Index
].Status
& HDD_SLAVE_IDE
) != 0) {
477 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
483 Enable ide controller. This gets disabled when LegacyBoot.c is about
484 to run the Option ROMs.
486 @param Private Legacy BIOS Instance data
491 EnableIdeController (
492 IN LEGACY_BIOS_INSTANCE
*Private
495 EFI_PCI_IO_PROTOCOL
*PciIo
;
497 EFI_HANDLE IdeController
;
500 EFI_HANDLE
*HandleBuffer
;
502 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
503 Private
->LegacyBiosPlatform
,
504 EfiGetPlatformIdeHandle
,
510 if (!EFI_ERROR (Status
)) {
511 IdeController
= HandleBuffer
[0];
512 Status
= gBS
->HandleProtocol (
514 &gEfiPciIoProtocolGuid
,
518 if (!EFI_ERROR (Status
)) {
519 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x04, 1, &ByteBuffer
);
526 Enable ide controller. This gets disabled when LegacyBoot.c is about
527 to run the Option ROMs.
529 @param Private Legacy BIOS Instance data
534 EnableAllControllers (
535 IN LEGACY_BIOS_INSTANCE
*Private
539 EFI_HANDLE
*HandleBuffer
;
541 EFI_PCI_IO_PROTOCOL
*PciIo
;
542 PCI_TYPE01 PciConfigHeader
;
548 EnableIdeController (Private
);
551 // Assumption is table is built from low bus to high bus numbers.
553 Status
= gBS
->LocateHandleBuffer (
555 &gEfiPciIoProtocolGuid
,
560 ASSERT_EFI_ERROR (Status
);
562 for (Index
= 0; Index
< HandleCount
; Index
++) {
563 Status
= gBS
->HandleProtocol (
565 &gEfiPciIoProtocolGuid
,
568 ASSERT_EFI_ERROR (Status
);
574 sizeof (PciConfigHeader
) / sizeof (UINT32
),
579 // We do not enable PPB here. This is for HotPlug Consideration.
580 // The Platform HotPlug Driver is responsible for Padding enough hot plug
581 // resources. It is also responsible for enable this bridge. If it
582 // does not pad it. It will cause some early Windows fail to installation.
583 // If the platform driver does not pad resource for PPB, PPB should be in
584 // un-enabled state to let Windows know that this PPB is not configured by
585 // BIOS. So Windows will allocate default resource for PPB.
587 // The reason for why we enable the command register is:
588 // The CSM will use the IO bar to detect some IRQ status, if the command
589 // is disabled, the IO resource will be out of scope.
591 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
592 // comes up, the handle will check the IO space to identify is the
593 // controller generated the IRQ source.
594 // If the IO command is not enabled, the IRQ handler will has wrong
595 // information. It will cause IRQ storm when the correctly IRQ handler fails
598 if (!(IS_PCI_VGA (&PciConfigHeader
) ||
599 IS_PCI_OLD_VGA (&PciConfigHeader
) ||
600 IS_PCI_IDE (&PciConfigHeader
) ||
601 IS_PCI_P2P (&PciConfigHeader
) ||
602 IS_PCI_P2P_SUB (&PciConfigHeader
) ||
603 IS_PCI_LPC (&PciConfigHeader
) )) {
605 PciConfigHeader
.Hdr
.Command
|= 0x1f;
607 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 4, 1, &PciConfigHeader
.Hdr
.Command
);
613 The following routines are identical in operation, so combine
615 EfiGetPlatformBinaryGetMpTable
616 EfiGetPlatformBinaryGetOemIntData
617 EfiGetPlatformBinaryGetOem32Data
618 EfiGetPlatformBinaryGetOem16Data
620 @param This Protocol instance pointer.
621 @param Id Table/Data identifier
623 @retval EFI_SUCCESS Success
624 @retval EFI_INVALID_PARAMETER Invalid ID
625 @retval EFI_OUT_OF_RESOURCES no resource to get data or table
629 LegacyGetDataOrTable (
630 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
631 IN EFI_GET_PLATFORM_INFO_MODE Id
640 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
641 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
642 EFI_IA32_REGISTER_SET Regs
;
643 LEGACY_BIOS_INSTANCE
*Private
;
645 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
647 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
648 Legacy16Table
= Private
->Legacy16Table
;
651 // Phase 1 - get an address allocated in 16-bit code
655 case EfiGetPlatformBinaryMpTable
:
656 case EfiGetPlatformBinaryOemIntData
:
657 case EfiGetPlatformBinaryOem32Data
:
658 case EfiGetPlatformBinaryOem16Data
:
660 Status
= LegacyBiosPlatform
->GetPlatformInfo (
670 DEBUG ((EFI_D_INFO
, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN
)Id
, Status
));
671 DEBUG ((EFI_D_INFO
, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN
)Table
, (UINTN
)TableSize
, (UINTN
)Location
, (UINTN
)Alignment
));
677 return EFI_INVALID_PARAMETER
;
681 if (EFI_ERROR (Status
)) {
685 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
686 Regs
.X
.AX
= Legacy16GetTableAddress
;
687 Regs
.X
.CX
= (UINT16
) TableSize
;
688 Regs
.X
.BX
= (UINT16
) Location
;
689 Regs
.X
.DX
= (UINT16
) Alignment
;
690 Private
->LegacyBios
.FarCall86 (
692 Private
->Legacy16CallSegment
,
693 Private
->Legacy16CallOffset
,
699 if (Regs
.X
.AX
!= 0) {
700 DEBUG ((EFI_D_ERROR
, "Table ID %x length insufficient\n", Id
));
701 return EFI_OUT_OF_RESOURCES
;
707 // Phase 2 Call routine second time with address to allow address adjustment
709 Status
= LegacyBiosPlatform
->GetPlatformInfo (
720 case EfiGetPlatformBinaryMpTable
:
722 Legacy16Table
->MpTablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
723 Legacy16Table
->MpTableLength
= (UINT32
)TableSize
;
724 DEBUG ((EFI_D_INFO
, "MP table in legacy region - %x\n", (UINTN
)Legacy16Table
->MpTablePtr
));
728 case EfiGetPlatformBinaryOemIntData
:
731 Legacy16Table
->OemIntSegment
= Regs
.X
.DS
;
732 Legacy16Table
->OemIntOffset
= Regs
.X
.BX
;
733 DEBUG ((EFI_D_INFO
, "OemInt table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->OemIntSegment
, (UINTN
)Legacy16Table
->OemIntOffset
));
737 case EfiGetPlatformBinaryOem32Data
:
739 Legacy16Table
->Oem32Segment
= Regs
.X
.DS
;
740 Legacy16Table
->Oem32Offset
= Regs
.X
.BX
;
741 DEBUG ((EFI_D_INFO
, "Oem32 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem32Segment
, (UINTN
)Legacy16Table
->Oem32Offset
));
745 case EfiGetPlatformBinaryOem16Data
:
748 // Legacy16Table->Oem16Segment = Regs.X.DS;
749 // Legacy16Table->Oem16Offset = Regs.X.BX;
750 DEBUG ((EFI_D_INFO
, "Oem16 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem16Segment
, (UINTN
)Legacy16Table
->Oem16Offset
));
756 return EFI_INVALID_PARAMETER
;
760 if (EFI_ERROR (Status
)) {
764 // Phase 3 Copy table to final location
766 TablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
769 (VOID
*) (UINTN
)TablePtr
,
778 Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot.
782 CreateSmbiosTableInReservedMemory (
786 SMBIOS_TABLE_ENTRY_POINT
*EntryPointStructure
;
788 if ((mRuntimeSmbiosEntryPoint
== NULL
) ||
789 (mReserveSmbiosEntryPoint
== 0) ||
790 (mStructureTableAddress
== 0)) {
794 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*) mRuntimeSmbiosEntryPoint
;
797 // Copy SMBIOS Entry Point Structure
800 (VOID
*)(UINTN
) mReserveSmbiosEntryPoint
,
802 EntryPointStructure
->EntryPointLength
806 // Copy SMBIOS Structure Table into EfiReservedMemoryType memory
809 (VOID
*)(UINTN
) mStructureTableAddress
,
810 (VOID
*)(UINTN
) EntryPointStructure
->TableAddress
,
811 EntryPointStructure
->TableLength
815 // Update TableAddress in Entry Point Structure
817 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*)(UINTN
) mReserveSmbiosEntryPoint
;
818 EntryPointStructure
->TableAddress
= (UINT32
)(UINTN
) mStructureTableAddress
;
821 // Fixup checksums in the Entry Point Structure
823 EntryPointStructure
->IntermediateChecksum
= 0;
824 EntryPointStructure
->EntryPointStructureChecksum
= 0;
826 EntryPointStructure
->IntermediateChecksum
=
828 (UINT8
*) EntryPointStructure
+ OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT
, IntermediateAnchorString
),
829 EntryPointStructure
->EntryPointLength
- OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT
, IntermediateAnchorString
)
831 EntryPointStructure
->EntryPointStructureChecksum
=
832 CalculateCheckSum8 ((UINT8
*) EntryPointStructure
, EntryPointStructure
->EntryPointLength
);
836 Assign drive number to legacy HDD drives prior to booting an EFI
837 aware OS so the OS can access drives without an EFI driver.
838 Note: BBS compliant drives ARE NOT available until this call by
841 @param This Protocol instance pointer.
843 @retval EFI_SUCCESS Drive numbers assigned
848 IN EFI_LEGACY_BIOS_PROTOCOL
*This
852 LEGACY_BIOS_INSTANCE
*Private
;
853 EFI_IA32_REGISTER_SET Regs
;
854 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
855 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
859 HDD_INFO
*LocalHddInfo
;
861 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
865 BBS_TABLE
*LocalBbsTable
;
866 UINT32
*BaseVectorMaster
;
869 EFI_HANDLE IdeController
;
871 EFI_HANDLE
*HandleBuffer
;
879 LocalBbsTable
= NULL
;
881 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
883 DEBUG ((EFI_D_ERROR
, "Start of legacy boot\n"));
886 Legacy16Table
= Private
->Legacy16Table
;
887 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
888 HddInfo
= &EfiToLegacy16BootTable
->HddInfo
[0];
890 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
892 EfiToLegacy16BootTable
->MajorVersion
= EFI_TO_LEGACY_MAJOR_VERSION
;
893 EfiToLegacy16BootTable
->MinorVersion
= EFI_TO_LEGACY_MINOR_VERSION
;
896 // If booting to a legacy OS then force HDD drives to the appropriate
897 // boot mode by calling GetIdeHandle.
898 // A reconnect -r can force all HDDs back to native mode.
900 IdeController
= NULL
;
901 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
902 Status
= LegacyBiosPlatform
->GetPlatformHandle (
903 Private
->LegacyBiosPlatform
,
904 EfiGetPlatformIdeHandle
,
910 if (!EFI_ERROR (Status
)) {
911 IdeController
= HandleBuffer
[0];
915 // Unlock the Legacy BIOS region
917 Private
->LegacyRegion
->UnLock (
918 Private
->LegacyRegion
,
925 // Reconstruct the Legacy16 boot memory map
927 LegacyBiosBuildE820 (Private
, &CopySize
);
928 if (CopySize
> Private
->Legacy16Table
->E820Length
) {
929 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
930 Regs
.X
.AX
= Legacy16GetTableAddress
;
931 Regs
.X
.CX
= (UINT16
) CopySize
;
932 Private
->LegacyBios
.FarCall86 (
933 &Private
->LegacyBios
,
934 Private
->Legacy16Table
->Compatibility16CallSegment
,
935 Private
->Legacy16Table
->Compatibility16CallOffset
,
941 Private
->Legacy16Table
->E820Pointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
942 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
943 if (Regs
.X
.AX
!= 0) {
944 DEBUG ((EFI_D_ERROR
, "Legacy16 E820 length insufficient\n"));
947 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
954 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
958 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
962 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
964 if (mReserveSmbiosEntryPoint
== 0) {
965 DEBUG ((EFI_D_INFO
, "Smbios table is not found!\n"));
967 CreateSmbiosTableInReservedMemory ();
968 EfiToLegacy16BootTable
->SmbiosTable
= (UINT32
)(UINTN
)mReserveSmbiosEntryPoint
;
971 Status
= EfiGetSystemConfigurationTable (
972 &gEfiAcpi20TableGuid
,
975 if (EFI_ERROR (Status
)) {
976 Status
= EfiGetSystemConfigurationTable (
977 &gEfiAcpi10TableGuid
,
982 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
984 if (AcpiTable
== NULL
) {
985 DEBUG ((EFI_D_INFO
, "ACPI table is not found!\n"));
987 EfiToLegacy16BootTable
->AcpiTable
= (UINT32
)(UINTN
)AcpiTable
;
990 // Get RSD Ptr table rev at offset 15 decimal
991 // Rev = 0 Length is 20 decimal
992 // Rev != 0 Length is UINT32 at offset 20 decimal
994 if (AcpiTable
!= NULL
) {
997 if (*((UINT8
*) AcpiPtr
+ 15) == 0) {
1000 AcpiPtr
= ((UINT8
*) AcpiPtr
+ 20);
1001 CopySize
= (*(UINT32
*) AcpiPtr
);
1005 (VOID
*)(UINTN
) Private
->Legacy16Table
->AcpiRsdPtrPointer
,
1011 // Make sure all PCI Interrupt Line register are programmed to match 8259
1013 PciProgramAllInterruptLineRegisters (Private
);
1016 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
1019 Private
->LegacyRegion
->UnLock (
1020 Private
->LegacyRegion
,
1022 Private
->LegacyBiosImageSize
,
1027 // Configure Legacy Device Magic
1029 // Only do this code if booting legacy OS
1031 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1032 UpdateSioData (Private
);
1035 // Setup BDA and EBDA standard areas before Legacy Boot
1038 LegacyBiosCompleteBdaBeforeBoot (Private
);
1040 LegacyBiosCompleteStandardCmosBeforeBoot (Private
);
1043 // We must build IDE data, if it hasn't been done, before PciShadowRoms
1044 // to insure EFI drivers are connected.
1046 LegacyBiosBuildIdeData (Private
, &HddInfo
, 1);
1047 UpdateAllIdentifyDriveData (Private
);
1050 // Clear IO BAR, if IDE controller in legacy mode.
1052 InitLegacyIdeController (IdeController
);
1055 // Generate number of ticks since midnight for BDA. DOS requires this
1056 // for its time. We have to make assumptions as to how long following
1057 // code takes since after PciShadowRoms PciIo is gone. Place result in
1060 // Adjust value by 1 second.
1062 gRT
->GetTime (&BootTime
, NULL
);
1063 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
1067 // Multiply result by 18.2 for number of ticks since midnight.
1068 // Use 182/10 to avoid floating point math.
1070 LocalTime
= (LocalTime
* 182) / 10;
1072 BdaPtr
= (UINT32
*) (UINTN
)0x46C;
1073 *BdaPtr
= LocalTime
;
1077 // Shadow PCI ROMs. We must do this near the end since this will kick
1078 // of Native EFI drivers that may be needed to collect info for Legacy16
1080 // WARNING: PciIo is gone after this call.
1082 PciShadowRoms (Private
);
1085 // Shadow PXE base code, BIS etc.
1087 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xc0000, 0x40000, &Granularity
);
1088 ShadowAddress
= Private
->OptionRom
;
1089 Private
->LegacyBiosPlatform
->PlatformHooks (
1090 Private
->LegacyBiosPlatform
,
1091 EfiPlatformHookShadowServiceRoms
,
1098 Private
->OptionRom
= (UINT32
)ShadowAddress
;
1100 // Register Legacy SMI Handler
1102 LegacyBiosPlatform
->SmmInit (
1104 EfiToLegacy16BootTable
1108 // Let platform code know the boot options
1110 LegacyBiosGetBbsInfo (
1119 PrintPciInterruptRegister ();
1120 PrintBbsTable (LocalBbsTable
);
1121 PrintHddInfo (LocalHddInfo
);
1124 // If drive wasn't spun up then BuildIdeData may have found new drives.
1125 // Need to update BBS boot priority.
1127 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
1128 if ((LocalHddInfo
[Index
].IdentifyDrive
[0].Raw
[0] != 0) &&
1129 (LocalBbsTable
[2 * Index
+ 1].BootPriority
== BBS_IGNORE_ENTRY
)
1131 LocalBbsTable
[2 * Index
+ 1].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1134 if ((LocalHddInfo
[Index
].IdentifyDrive
[1].Raw
[0] != 0) &&
1135 (LocalBbsTable
[2 * Index
+ 2].BootPriority
== BBS_IGNORE_ENTRY
)
1137 LocalBbsTable
[2 * Index
+ 2].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1141 Private
->LegacyRegion
->UnLock (
1142 Private
->LegacyRegion
,
1148 LegacyBiosPlatform
->PrepareToBoot (
1154 (VOID
*) &Private
->IntThunk
->EfiToLegacy16BootTable
1158 // If no boot device return to BDS
1160 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1161 for (Index
= 0; Index
< BbsCount
; Index
++){
1162 if ((LocalBbsTable
[Index
].BootPriority
!= BBS_DO_NOT_BOOT_FROM
) &&
1163 (LocalBbsTable
[Index
].BootPriority
!= BBS_UNPRIORITIZED_ENTRY
) &&
1164 (LocalBbsTable
[Index
].BootPriority
!= BBS_IGNORE_ENTRY
)) {
1168 if (Index
== BbsCount
) {
1169 return EFI_DEVICE_ERROR
;
1173 // Let the Legacy16 code know the device path type for legacy boot
1175 EfiToLegacy16BootTable
->DevicePathType
= mBbsDevicePathPtr
->DeviceType
;
1178 // Copy MP table, if it exists.
1180 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryMpTable
);
1182 if (!Private
->LegacyBootEntered
) {
1184 // Copy OEM INT Data, if it exists. Note: This code treats any data
1185 // as a bag of bits and knows nothing of the contents nor cares.
1186 // Contents are IBV specific.
1188 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOemIntData
);
1191 // Copy OEM16 Data, if it exists.Note: This code treats any data
1192 // as a bag of bits and knows nothing of the contents nor cares.
1193 // Contents are IBV specific.
1195 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem16Data
);
1198 // Copy OEM32 Data, if it exists.Note: This code treats any data
1199 // as a bag of bits and knows nothing of the contents nor cares.
1200 // Contents are IBV specific.
1202 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem32Data
);
1206 // Call into Legacy16 code to prepare for INT 19h
1208 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1209 Regs
.X
.AX
= Legacy16PrepareToBoot
;
1212 // Pass in handoff data
1214 Regs
.X
.ES
= NORMALIZE_EFI_SEGMENT ((UINTN
)EfiToLegacy16BootTable
);
1215 Regs
.X
.BX
= NORMALIZE_EFI_OFFSET ((UINTN
)EfiToLegacy16BootTable
);
1217 Private
->LegacyBios
.FarCall86 (
1219 Private
->Legacy16CallSegment
,
1220 Private
->Legacy16CallOffset
,
1226 if (Regs
.X
.AX
!= 0) {
1227 return EFI_DEVICE_ERROR
;
1230 // Lock the Legacy BIOS region
1232 Private
->LegacyRegion
->Lock (
1233 Private
->LegacyRegion
,
1239 if ((Private
->Legacy16Table
->TableLength
>= OFFSET_OF (EFI_COMPATIBILITY16_TABLE
, HiPermanentMemoryAddress
)) &&
1240 ((Private
->Legacy16Table
->UmaAddress
!= 0) && (Private
->Legacy16Table
->UmaSize
!= 0))) {
1242 // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into
1243 // account the granularity of the access control.
1245 DEBUG((EFI_D_INFO
, "Unlocking UMB RAM region 0x%x-0x%x\n", Private
->Legacy16Table
->UmaAddress
,
1246 Private
->Legacy16Table
->UmaAddress
+ Private
->Legacy16Table
->UmaSize
));
1248 Private
->LegacyRegion
->UnLock (
1249 Private
->LegacyRegion
,
1250 Private
->Legacy16Table
->UmaAddress
,
1251 Private
->Legacy16Table
->UmaSize
,
1257 // Lock attributes of the Legacy Region if chipset supports
1259 Private
->LegacyRegion
->BootLock (
1260 Private
->LegacyRegion
,
1267 // Call into Legacy16 code to do the INT 19h
1269 EnableAllControllers (Private
);
1270 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1273 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
1275 EfiSignalEventLegacyBoot ();
1278 // Report Status Code to indicate legacy boot event was signalled
1280 REPORT_STATUS_CODE (
1282 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT
)
1285 DEBUG ((EFI_D_INFO
, "Legacy INT19 Boot...\n"));
1288 // Disable DXE Timer while executing in real mode
1290 Private
->Timer
->SetTimerPeriod (Private
->Timer
, 0);
1293 // Save and disable interrupt of debug timer
1295 SaveAndSetDebugTimerInterrupt (FALSE
);
1299 // Put the 8259 into its legacy mode by reprogramming the vector bases
1301 Private
->Legacy8259
->SetVectorBase (Private
->Legacy8259
, LEGACY_MODE_BASE_VECTOR_MASTER
, LEGACY_MODE_BASE_VECTOR_SLAVE
);
1304 // The original PC used INT8-F for master PIC. Since these mapped over
1305 // processor exceptions TIANO moved the master PIC to INT68-6F.
1306 // We need to set these back to the Legacy16 unexpected interrupt(saved
1307 // in LegacyBios.c) since some OS see that these have values different from
1308 // what is expected and invoke them. Since the legacy OS corrupts EFI
1309 // memory, there is no handler for these interrupts and OS blows up.
1311 // We need to save the TIANO values for the rare case that the Legacy16
1312 // code cannot boot but knows memory hasn't been destroyed.
1314 // To compound the problem, video takes over one of these INTS and must be
1316 // @bug - determine if video hooks INT(in which case we must find new
1317 // set of TIANO vectors) or takes it over.
1321 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1322 for (Index
= 0; Index
< 8; Index
++) {
1323 Private
->ThunkSavedInt
[Index
] = BaseVectorMaster
[Index
];
1324 if (Private
->ThunkSeg
== (UINT16
) (BaseVectorMaster
[Index
] >> 16)) {
1325 BaseVectorMaster
[Index
] = (UINT32
) (Private
->BiosUnexpectedInt
);
1330 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1331 Regs
.X
.AX
= Legacy16Boot
;
1333 Private
->LegacyBios
.FarCall86 (
1335 Private
->Legacy16CallSegment
,
1336 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
];
1349 Private
->LegacyBootEntered
= TRUE
;
1350 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1352 // Should never return unless never passed control to 0:7c00(first stage
1353 // OS loader) and only then if no bootable device found.
1355 return EFI_DEVICE_ERROR
;
1358 // If boot to EFI then expect to return to caller
1366 Assign drive number to legacy HDD drives prior to booting an EFI
1367 aware OS so the OS can access drives without an EFI driver.
1368 Note: BBS compliant drives ARE NOT available until this call by
1369 either shell or EFI.
1371 @param This Protocol instance pointer.
1372 @param BbsCount Number of BBS_TABLE structures
1373 @param BbsTable List BBS entries
1375 @retval EFI_SUCCESS Drive numbers assigned
1380 LegacyBiosPrepareToBootEfi (
1381 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1382 OUT UINT16
*BbsCount
,
1383 OUT BBS_TABLE
**BbsTable
1387 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1388 LEGACY_BIOS_INSTANCE
*Private
;
1390 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1391 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1392 mBootMode
= BOOT_EFI_OS
;
1393 mBbsDevicePathPtr
= NULL
;
1394 Status
= GenericLegacyBoot (This
);
1395 *BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1396 *BbsCount
= (UINT16
) (sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
));
1401 To boot from an unconventional device like parties and/or execute HDD diagnostics.
1403 @param This Protocol instance pointer.
1404 @param Attributes How to interpret the other input parameters
1405 @param BbsEntry The 0-based index into the BbsTable for the parent
1407 @param BeerData Pointer to the 128 bytes of ram BEER data.
1408 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1409 caller must provide a pointer to the specific Service
1410 Area and not the start all Service Areas.
1412 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1417 LegacyBiosBootUnconventionalDevice (
1418 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1419 IN UDC_ATTRIBUTES Attributes
,
1422 IN VOID
*ServiceAreaData
1426 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1427 LEGACY_BIOS_INSTANCE
*Private
;
1430 UINT16 BootPriority
;
1431 BBS_TABLE
*BbsTable
;
1434 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1435 mBootMode
= BOOT_UNCONVENTIONAL_DEVICE
;
1436 mBbsDevicePathPtr
= &mBbsDevicePathNode
;
1437 mAttributes
= Attributes
;
1438 mBbsEntry
= BbsEntry
;
1439 mBeerData
= BeerData
, mServiceAreaData
= ServiceAreaData
;
1441 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1444 // Do input parameter checking
1446 if ((Attributes
.DirectoryServiceValidity
== 0) &&
1447 (Attributes
.RabcaUsedFlag
== 0) &&
1448 (Attributes
.ExecuteHddDiagnosticsFlag
== 0)
1450 return EFI_INVALID_PARAMETER
;
1453 if (((Attributes
.DirectoryServiceValidity
!= 0) && (ServiceAreaData
== NULL
)) ||
1454 (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
) != 0) && (BeerData
== NULL
))
1456 return EFI_INVALID_PARAMETER
;
1459 UcdTable
= (UD_TABLE
*) AllocatePool (
1462 if (NULL
== UcdTable
) {
1463 return EFI_OUT_OF_RESOURCES
;
1466 EfiToLegacy16BootTable
->UnconventionalDeviceTable
= (UINT32
)(UINTN
)UcdTable
;
1467 UcdTable
->Attributes
= Attributes
;
1468 UcdTable
->BbsTableEntryNumberForParentDevice
= (UINT8
) BbsEntry
;
1470 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1471 // to assign drive numbers but bot boot from. Only newly created entries
1474 BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1475 for (Index
= 0; Index
< EfiToLegacy16BootTable
->NumberBbsEntries
; Index
++) {
1476 BbsTable
[Index
].BootPriority
= BBS_DO_NOT_BOOT_FROM
;
1479 // If parent is onboard IDE then assign controller & device number
1482 if (BbsEntry
< MAX_IDE_CONTROLLER
* 2) {
1483 UcdTable
->DeviceNumber
= (UINT8
) ((BbsEntry
- 1) % 2);
1486 if (BeerData
!= NULL
) {
1488 (VOID
*) UcdTable
->BeerData
,
1494 if (ServiceAreaData
!= NULL
) {
1496 (VOID
*) UcdTable
->ServiceAreaData
,
1502 // For each new entry do the following:
1503 // 1. Increment current number of BBS entries
1504 // 2. Copy parent entry to new entry.
1505 // 3. Zero out BootHandler Offset & segment
1506 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1507 // and Floppy(0x01) for PARTIES boot.
1508 // 5. Assign new priority.
1510 if ((Attributes
.ExecuteHddDiagnosticsFlag
) != 0) {
1511 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1514 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1515 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1519 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1520 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1521 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x80;
1523 UcdTable
->BbsTableEntryNumberForHddDiag
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1525 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1529 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1531 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_BEV
;
1534 if (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
)) != 0) {
1535 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1537 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1538 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1542 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1543 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1544 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x01;
1545 UcdTable
->BbsTableEntryNumberForBoot
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1546 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1549 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1551 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_FLOPPY
;
1554 // Build the BBS Device Path for this boot selection
1556 mBbsDevicePathNode
.Header
.Type
= BBS_DEVICE_PATH
;
1557 mBbsDevicePathNode
.Header
.SubType
= BBS_BBS_DP
;
1558 SetDevicePathNodeLength (&mBbsDevicePathNode
.Header
, sizeof (BBS_BBS_DEVICE_PATH
));
1559 mBbsDevicePathNode
.StatusFlag
= 0;
1560 mBbsDevicePathNode
.String
[0] = 0;
1562 Status
= GenericLegacyBoot (This
);
1567 Attempt to legacy boot the BootOption. If the EFI contexted has been
1568 compromised this function will not return.
1570 @param This Protocol instance pointer.
1571 @param BbsDevicePath EFI Device Path from BootXXXX variable.
1572 @param LoadOptionsSize Size of LoadOption in size.
1573 @param LoadOptions LoadOption from BootXXXX variable
1575 @retval EFI_SUCCESS Removable media not present
1580 LegacyBiosLegacyBoot (
1581 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1582 IN BBS_BBS_DEVICE_PATH
*BbsDevicePath
,
1583 IN UINT32 LoadOptionsSize
,
1584 IN VOID
*LoadOptions
1589 mBbsDevicePathPtr
= BbsDevicePath
;
1590 mLoadOptionsSize
= LoadOptionsSize
;
1591 mLoadOptions
= LoadOptions
;
1592 mBootMode
= BOOT_LEGACY_OS
;
1593 Status
= GenericLegacyBoot (This
);
1599 Convert EFI Memory Type to E820 Memory Type.
1601 @param Type EFI Memory Type
1603 @return ACPI Memory Type for EFI Memory Type
1606 EFI_ACPI_MEMORY_TYPE
1607 EfiMemoryTypeToE820Type (
1614 case EfiBootServicesCode
:
1615 case EfiBootServicesData
:
1616 case EfiConventionalMemory
:
1618 // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are
1619 // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept.
1620 // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData
1621 // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS.
1623 case EfiRuntimeServicesCode
:
1624 case EfiRuntimeServicesData
:
1625 return EfiAcpiAddressRangeMemory
;
1627 case EfiPersistentMemory
:
1628 return EfiAddressRangePersistentMemory
;
1630 case EfiACPIReclaimMemory
:
1631 return EfiAcpiAddressRangeACPI
;
1633 case EfiACPIMemoryNVS
:
1634 return EfiAcpiAddressRangeNVS
;
1637 // All other types map to reserved.
1638 // Adding the code just waists FLASH space.
1640 // case EfiReservedMemoryType:
1641 // case EfiUnusableMemory:
1642 // case EfiMemoryMappedIO:
1643 // case EfiMemoryMappedIOPortSpace:
1647 return EfiAcpiAddressRangeReserved
;
1652 Build the E820 table.
1654 @param Private Legacy BIOS Instance data
1655 @param Size Size of E820 Table
1657 @retval EFI_SUCCESS It should always work.
1661 LegacyBiosBuildE820 (
1662 IN LEGACY_BIOS_INSTANCE
*Private
,
1667 EFI_E820_ENTRY64
*E820Table
;
1668 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMap
;
1669 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMapEnd
;
1670 EFI_MEMORY_DESCRIPTOR
*EfiEntry
;
1671 EFI_MEMORY_DESCRIPTOR
*NextEfiEntry
;
1672 EFI_MEMORY_DESCRIPTOR TempEfiEntry
;
1673 UINTN EfiMemoryMapSize
;
1675 UINTN EfiDescriptorSize
;
1676 UINT32 EfiDescriptorVersion
;
1678 EFI_PEI_HOB_POINTERS Hob
;
1679 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
1682 UINTN TempNextIndex
;
1683 EFI_E820_ENTRY64 TempE820
;
1684 EFI_ACPI_MEMORY_TYPE TempType
;
1685 BOOLEAN ChangedFlag
;
1687 UINT64 MemoryBlockLength
;
1689 E820Table
= (EFI_E820_ENTRY64
*) Private
->E820Table
;
1692 // Get the EFI memory map.
1694 EfiMemoryMapSize
= 0;
1695 EfiMemoryMap
= NULL
;
1696 Status
= gBS
->GetMemoryMap (
1701 &EfiDescriptorVersion
1703 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1707 // Use size returned for the AllocatePool.
1708 // We don't just multiply by 2 since the "for" loop below terminates on
1709 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwise
1710 // we process bogus entries and create bogus E820 entries.
1712 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*) AllocatePool (EfiMemoryMapSize
);
1713 ASSERT (EfiMemoryMap
!= NULL
);
1714 Status
= gBS
->GetMemoryMap (
1719 &EfiDescriptorVersion
1721 if (EFI_ERROR (Status
)) {
1722 FreePool (EfiMemoryMap
);
1724 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1726 ASSERT_EFI_ERROR (Status
);
1729 // Punch in the E820 table for memory less than 1 MB.
1730 // Assume ZeroMem () has been done on data structure.
1733 // First entry is 0 to (640k - EBDA)
1736 E820Table
[0].BaseAddr
= 0;
1737 E820Table
[0].Length
= (UINT64
) ((*(UINT16
*) (UINTN
)0x40E) << 4);
1738 E820Table
[0].Type
= EfiAcpiAddressRangeMemory
;
1742 // Second entry is (640k - EBDA) to 640k
1744 E820Table
[1].BaseAddr
= E820Table
[0].Length
;
1745 E820Table
[1].Length
= (UINT64
) ((640 * 1024) - E820Table
[0].Length
);
1746 E820Table
[1].Type
= EfiAcpiAddressRangeReserved
;
1749 // Third Entry is legacy BIOS
1750 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1751 // to page in memory under 1MB.
1752 // Omit region from 0xE0000 to start of BIOS, if any. This can be
1753 // used for a multiple reasons including OPROMS.
1757 // The CSM binary image size is not the actually size that CSM binary used,
1758 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1760 E820Table
[2].BaseAddr
= 0xE0000;
1761 E820Table
[2].Length
= 0x20000;
1762 E820Table
[2].Type
= EfiAcpiAddressRangeReserved
;
1767 // Process the EFI map to produce E820 map;
1771 // Sort memory map from low to high
1773 EfiEntry
= EfiMemoryMap
;
1774 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1775 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1776 while (EfiEntry
< EfiMemoryMapEnd
) {
1777 while (NextEfiEntry
< EfiMemoryMapEnd
) {
1778 if (EfiEntry
->PhysicalStart
> NextEfiEntry
->PhysicalStart
) {
1779 CopyMem (&TempEfiEntry
, EfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1780 CopyMem (EfiEntry
, NextEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1781 CopyMem (NextEfiEntry
, &TempEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1784 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (NextEfiEntry
, EfiDescriptorSize
);
1787 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1788 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1791 EfiEntry
= EfiMemoryMap
;
1792 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1793 for (Index
= Above1MIndex
; (EfiEntry
< EfiMemoryMapEnd
) && (Index
< EFI_MAX_E820_ENTRY
- 1); ) {
1794 MemoryBlockLength
= (UINT64
) (LShiftU64 (EfiEntry
->NumberOfPages
, 12));
1795 if ((EfiEntry
->PhysicalStart
+ MemoryBlockLength
) < 0x100000) {
1797 // Skip the memory block if under 1MB
1800 if (EfiEntry
->PhysicalStart
< 0x100000) {
1802 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1804 MemoryBlockLength
-= 0x100000 - EfiEntry
->PhysicalStart
;
1805 EfiEntry
->PhysicalStart
= 0x100000;
1809 // Convert memory type to E820 type
1811 TempType
= EfiMemoryTypeToE820Type (EfiEntry
->Type
);
1813 if ((E820Table
[Index
].Type
== TempType
) && (EfiEntry
->PhysicalStart
== (E820Table
[Index
].BaseAddr
+ E820Table
[Index
].Length
))) {
1815 // Grow an existing entry
1817 E820Table
[Index
].Length
+= MemoryBlockLength
;
1823 E820Table
[Index
].BaseAddr
= EfiEntry
->PhysicalStart
;
1824 E820Table
[Index
].Length
= MemoryBlockLength
;
1825 E820Table
[Index
].Type
= TempType
;
1828 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1831 FreePool (EfiMemoryMap
);
1834 // Process the reserved memory map to produce E820 map ;
1836 for (Hob
.Raw
= GetHobList (); !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
1837 if (Hob
.Raw
!= NULL
&& GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
1838 ResourceHob
= Hob
.ResourceDescriptor
;
1839 if (((ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_MAPPED_IO
) ||
1840 (ResourceHob
->ResourceType
== EFI_RESOURCE_FIRMWARE_DEVICE
) ||
1841 (ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_RESERVED
) ) &&
1842 (ResourceHob
->PhysicalStart
> 0x100000) &&
1843 (Index
< EFI_MAX_E820_ENTRY
- 1)) {
1845 E820Table
[Index
].BaseAddr
= ResourceHob
->PhysicalStart
;
1846 E820Table
[Index
].Length
= ResourceHob
->ResourceLength
;
1847 E820Table
[Index
].Type
= EfiAcpiAddressRangeReserved
;
1853 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1854 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1855 Private
->NumberE820Entries
= (UINT32
)Index
;
1856 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1859 // Sort E820Table from low to high
1861 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1862 ChangedFlag
= FALSE
;
1863 for (TempNextIndex
= 1; TempNextIndex
< Index
- TempIndex
; TempNextIndex
++) {
1864 if (E820Table
[TempNextIndex
- 1].BaseAddr
> E820Table
[TempNextIndex
].BaseAddr
) {
1866 TempE820
.BaseAddr
= E820Table
[TempNextIndex
- 1].BaseAddr
;
1867 TempE820
.Length
= E820Table
[TempNextIndex
- 1].Length
;
1868 TempE820
.Type
= E820Table
[TempNextIndex
- 1].Type
;
1870 E820Table
[TempNextIndex
- 1].BaseAddr
= E820Table
[TempNextIndex
].BaseAddr
;
1871 E820Table
[TempNextIndex
- 1].Length
= E820Table
[TempNextIndex
].Length
;
1872 E820Table
[TempNextIndex
- 1].Type
= E820Table
[TempNextIndex
].Type
;
1874 E820Table
[TempNextIndex
].BaseAddr
= TempE820
.BaseAddr
;
1875 E820Table
[TempNextIndex
].Length
= TempE820
.Length
;
1876 E820Table
[TempNextIndex
].Type
= TempE820
.Type
;
1886 // Remove the overlap range
1888 for (TempIndex
= 1; TempIndex
< Index
; TempIndex
++) {
1889 if (E820Table
[TempIndex
- 1].BaseAddr
<= E820Table
[TempIndex
].BaseAddr
&&
1890 ((E820Table
[TempIndex
- 1].BaseAddr
+ E820Table
[TempIndex
- 1].Length
) >=
1891 (E820Table
[TempIndex
].BaseAddr
+E820Table
[TempIndex
].Length
))) {
1893 //Overlap range is found
1895 ASSERT (E820Table
[TempIndex
- 1].Type
== E820Table
[TempIndex
].Type
);
1897 if (TempIndex
== Index
- 1) {
1898 E820Table
[TempIndex
].BaseAddr
= 0;
1899 E820Table
[TempIndex
].Length
= 0;
1900 E820Table
[TempIndex
].Type
= (EFI_ACPI_MEMORY_TYPE
) 0;
1904 for (IndexSort
= TempIndex
; IndexSort
< Index
- 1; IndexSort
++) {
1905 E820Table
[IndexSort
].BaseAddr
= E820Table
[IndexSort
+ 1].BaseAddr
;
1906 E820Table
[IndexSort
].Length
= E820Table
[IndexSort
+ 1].Length
;
1907 E820Table
[IndexSort
].Type
= E820Table
[IndexSort
+ 1].Type
;
1916 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1917 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1918 Private
->NumberE820Entries
= (UINT32
)Index
;
1919 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1922 // Determine OS usable memory above 1MB
1924 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
= 0x0000;
1925 for (TempIndex
= Above1MIndex
; TempIndex
< Index
; TempIndex
++) {
1926 if (E820Table
[TempIndex
].BaseAddr
>= 0x100000 && E820Table
[TempIndex
].BaseAddr
< 0x100000000ULL
) { // not include above 4G memory
1928 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1930 if ((E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeMemory
) || (E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeACPI
)) {
1931 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
+= (UINT32
) (E820Table
[TempIndex
].Length
);
1933 break; // break at first not normal memory, because SMM may use reserved memory.
1938 Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
= Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
;
1941 // Print DEBUG information
1943 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1944 DEBUG((EFI_D_INFO
, "E820[%2d]: 0x%016lx - 0x%016lx, Type = %d\n",
1946 E820Table
[TempIndex
].BaseAddr
,
1947 (E820Table
[TempIndex
].BaseAddr
+ E820Table
[TempIndex
].Length
),
1948 E820Table
[TempIndex
].Type
1957 Fill in the standard BDA and EBDA stuff prior to legacy Boot
1959 @param Private Legacy BIOS Instance data
1961 @retval EFI_SUCCESS It should always work.
1965 LegacyBiosCompleteBdaBeforeBoot (
1966 IN LEGACY_BIOS_INSTANCE
*Private
1970 UINT16 MachineConfig
;
1971 DEVICE_PRODUCER_DATA_HEADER
*SioPtr
;
1973 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
1976 SioPtr
= &(Private
->IntThunk
->EfiToLegacy16BootTable
.SioData
);
1977 Bda
->Com1
= SioPtr
->Serial
[0].Address
;
1978 Bda
->Com2
= SioPtr
->Serial
[1].Address
;
1979 Bda
->Com3
= SioPtr
->Serial
[2].Address
;
1980 Bda
->Com4
= SioPtr
->Serial
[3].Address
;
1982 if (SioPtr
->Serial
[0].Address
!= 0x00) {
1983 MachineConfig
+= 0x200;
1986 if (SioPtr
->Serial
[1].Address
!= 0x00) {
1987 MachineConfig
+= 0x200;
1990 if (SioPtr
->Serial
[2].Address
!= 0x00) {
1991 MachineConfig
+= 0x200;
1994 if (SioPtr
->Serial
[3].Address
!= 0x00) {
1995 MachineConfig
+= 0x200;
1998 Bda
->Lpt1
= SioPtr
->Parallel
[0].Address
;
1999 Bda
->Lpt2
= SioPtr
->Parallel
[1].Address
;
2000 Bda
->Lpt3
= SioPtr
->Parallel
[2].Address
;
2002 if (SioPtr
->Parallel
[0].Address
!= 0x00) {
2003 MachineConfig
+= 0x4000;
2006 if (SioPtr
->Parallel
[1].Address
!= 0x00) {
2007 MachineConfig
+= 0x4000;
2010 if (SioPtr
->Parallel
[2].Address
!= 0x00) {
2011 MachineConfig
+= 0x4000;
2014 Bda
->NumberOfDrives
= (UINT8
) (Bda
->NumberOfDrives
+ Private
->IdeDriveCount
);
2015 if (SioPtr
->Floppy
.NumberOfFloppy
!= 0x00) {
2016 MachineConfig
= (UINT16
) (MachineConfig
+ 0x01 + (SioPtr
->Floppy
.NumberOfFloppy
- 1) * 0x40);
2017 Bda
->FloppyXRate
= 0x07;
2020 Bda
->Lpt1_2Timeout
= 0x1414;
2021 Bda
->Lpt3_4Timeout
= 0x1414;
2022 Bda
->Com1_2Timeout
= 0x0101;
2023 Bda
->Com3_4Timeout
= 0x0101;
2026 // Force VGA and Coprocessor, indicate 101/102 keyboard
2028 MachineConfig
= (UINT16
) (MachineConfig
+ 0x00 + 0x02 + (SioPtr
->MousePresent
* 0x04));
2029 Bda
->MachineConfig
= MachineConfig
;
2035 Fill in the standard BDA for Keyboard LEDs
2037 @param This Protocol instance pointer.
2038 @param Leds Current LED status
2040 @retval EFI_SUCCESS It should always work.
2045 LegacyBiosUpdateKeyboardLedStatus (
2046 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
2050 LEGACY_BIOS_INSTANCE
*Private
;
2053 EFI_IA32_REGISTER_SET Regs
;
2055 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
2058 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
2060 Bda
->LedStatus
= (UINT8
) ((Bda
->LedStatus
&~0x07) | LocalLeds
);
2061 LocalLeds
= (UINT8
) (LocalLeds
<< 4);
2062 Bda
->ShiftStatus
= (UINT8
) ((Bda
->ShiftStatus
&~0x70) | LocalLeds
);
2063 LocalLeds
= (UINT8
) (Leds
& 0x20);
2064 Bda
->KeyboardStatus
= (UINT8
) ((Bda
->KeyboardStatus
&~0x20) | LocalLeds
);
2068 // Call into Legacy16 code to allow it to do any processing
2070 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
2071 Regs
.X
.AX
= Legacy16SetKeyboardLeds
;
2074 Private
->LegacyBios
.FarCall86 (
2075 &Private
->LegacyBios
,
2076 Private
->Legacy16Table
->Compatibility16CallSegment
,
2077 Private
->Legacy16Table
->Compatibility16CallOffset
,
2088 Fill in the standard CMOS stuff prior to legacy Boot
2090 @param Private Legacy BIOS Instance data
2092 @retval EFI_SUCCESS It should always work.
2096 LegacyBiosCompleteStandardCmosBeforeBoot (
2097 IN LEGACY_BIOS_INSTANCE
*Private
2105 // Update CMOS locations
2107 // 12,19,1A - ignore as OS don't use them and there is no standard due
2108 // to large capacity drives
2109 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
2112 Bda
= (UINT8
)(*((UINT8
*)((UINTN
)0x410)) | BIT3
);
2116 // Force display enabled
2119 if ((Bda
& BIT0
) != 0) {
2124 // Check if 2.88MB floppy set
2126 if ((Bda
& (BIT7
| BIT6
)) != 0) {
2127 Floppy
= (UINT8
)(Floppy
| BIT1
);
2130 LegacyWriteStandardCmos (CMOS_10
, Floppy
);
2131 LegacyWriteStandardCmos (CMOS_14
, Bda
);
2134 // Force Status Register A to set rate selection bits and divider
2136 LegacyWriteStandardCmos (CMOS_0A
, 0x26);
2139 // redo memory size since it can change
2141 Size
= (15 * SIZE_1MB
) >> 10;
2142 if (Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
< (15 * SIZE_1MB
)) {
2143 Size
= Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
>> 10;
2146 LegacyWriteStandardCmos (CMOS_17
, (UINT8
)(Size
& 0xFF));
2147 LegacyWriteStandardCmos (CMOS_30
, (UINT8
)(Size
& 0xFF));
2148 LegacyWriteStandardCmos (CMOS_18
, (UINT8
)(Size
>> 8));
2149 LegacyWriteStandardCmos (CMOS_31
, (UINT8
)(Size
>> 8));
2151 LegacyCalculateWriteStandardCmosChecksum ();
2157 Relocate this image under 4G memory for IPF.
2159 @param ImageHandle Handle of driver image.
2160 @param SystemTable Pointer to system table.
2162 @retval EFI_SUCCESS Image successfully relocated.
2163 @retval EFI_ABORTED Failed to relocate image.
2167 RelocateImageUnder4GIfNeeded (
2168 IN EFI_HANDLE ImageHandle
,
2169 IN EFI_SYSTEM_TABLE
*SystemTable