3 Copyright (c) 2006 - 2012, 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
;
39 @param BbsTable The BBS table.
45 IN BBS_TABLE
*BbsTable
52 DEBUG ((EFI_D_INFO
, "\n"));
53 DEBUG ((EFI_D_INFO
, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
54 DEBUG ((EFI_D_INFO
, "=================================================================\n"));
55 for (Index
= 0; Index
< MAX_BBS_ENTRIES
; Index
++) {
59 if (BbsTable
[Index
].BootPriority
== BBS_IGNORE_ENTRY
) {
65 " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
67 (UINTN
) BbsTable
[Index
].BootPriority
,
68 (UINTN
) BbsTable
[Index
].Bus
,
69 (UINTN
) BbsTable
[Index
].Device
,
70 (UINTN
) BbsTable
[Index
].Function
,
71 (UINTN
) BbsTable
[Index
].Class
,
72 (UINTN
) BbsTable
[Index
].SubClass
,
73 (UINTN
) BbsTable
[Index
].DeviceType
,
74 (UINTN
) * (UINT16
*) &BbsTable
[Index
].StatusFlags
78 " %04x:%04x %04x:%04x %04x:%04x",
79 (UINTN
) BbsTable
[Index
].BootHandlerSegment
,
80 (UINTN
) BbsTable
[Index
].BootHandlerOffset
,
81 (UINTN
) BbsTable
[Index
].MfgStringSegment
,
82 (UINTN
) BbsTable
[Index
].MfgStringOffset
,
83 (UINTN
) BbsTable
[Index
].DescStringSegment
,
84 (UINTN
) BbsTable
[Index
].DescStringOffset
90 String
= (CHAR8
*)(UINTN
)((BbsTable
[Index
].DescStringSegment
<< 4) + BbsTable
[Index
].DescStringOffset
);
92 DEBUG ((EFI_D_INFO
," ("));
93 for (SubIndex
= 0; String
[SubIndex
] != 0; SubIndex
++) {
94 DEBUG ((EFI_D_INFO
, "%c", String
[SubIndex
]));
96 DEBUG ((EFI_D_INFO
,")"));
98 DEBUG ((EFI_D_INFO
,"\n"));
101 DEBUG ((EFI_D_INFO
, "\n"));
109 @param HddInfo The HddInfo table.
120 DEBUG ((EFI_D_INFO
, "\n"));
121 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
122 DEBUG ((EFI_D_INFO
, "Index - %04x\n", Index
));
123 DEBUG ((EFI_D_INFO
, " Status - %04x\n", (UINTN
)HddInfo
[Index
].Status
));
124 DEBUG ((EFI_D_INFO
, " B/D/F - %02x/%02x/%02x\n", (UINTN
)HddInfo
[Index
].Bus
, (UINTN
)HddInfo
[Index
].Device
, (UINTN
)HddInfo
[Index
].Function
));
125 DEBUG ((EFI_D_INFO
, " Command - %04x\n", HddInfo
[Index
].CommandBaseAddress
));
126 DEBUG ((EFI_D_INFO
, " Control - %04x\n", HddInfo
[Index
].ControlBaseAddress
));
127 DEBUG ((EFI_D_INFO
, " BusMaster - %04x\n", HddInfo
[Index
].BusMasterAddress
));
128 DEBUG ((EFI_D_INFO
, " HddIrq - %02x\n", HddInfo
[Index
].HddIrq
));
129 DEBUG ((EFI_D_INFO
, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
130 DEBUG ((EFI_D_INFO
, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
133 DEBUG ((EFI_D_INFO
, "\n"));
139 Print the PCI Interrupt Line and Interrupt Pin registers.
142 PrintPciInterruptRegister (
150 EFI_PCI_IO_PROTOCOL
*PciIo
;
157 gBS
->LocateHandleBuffer (
159 &gEfiPciIoProtocolGuid
,
169 DEBUG ((EFI_D_INFO
, "\n"));
170 DEBUG ((EFI_D_INFO
, " bb/dd/ff interrupt line interrupt pin\n"));
171 DEBUG ((EFI_D_INFO
, "======================================\n"));
172 for (Index
= 0; Index
< HandleNum
; Index
++) {
173 Status
= gBS
->HandleProtocol (Handles
[Index
], &gEfiPciIoProtocolGuid
, (VOID
**) &PciIo
);
174 if (!EFI_ERROR (Status
)) {
175 Status
= PciIo
->Pci
.Read (
183 if (!EFI_ERROR (Status
)) {
184 Status
= PciIo
->GetLocation (
192 if (!EFI_ERROR (Status
)) {
193 DEBUG ((EFI_D_INFO
, " %02x/%02x/%02x 0x%02x 0x%02x\n",
194 Bus
, Device
, Function
, Interrupt
[0], Interrupt
[1]));
197 DEBUG ((EFI_D_INFO
, "\n"));
199 if (Handles
!= NULL
) {
205 Identify drive data must be updated to actual parameters before boot.
207 @param IdentifyDriveData ATA Identify Data
211 UpdateIdentifyDriveData (
212 IN UINT8
*IdentifyDriveData
218 @param Private Legacy BIOS Instance data
220 @retval EFI_SUCCESS Removable media not present
225 IN LEGACY_BIOS_INSTANCE
*Private
231 UINT8 LegacyInterrupts
[16];
232 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
233 UINTN RoutingTableEntries
;
234 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY
*IrqPriorityTable
;
235 UINTN NumberPriorityEntries
;
236 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
242 EFI_HANDLE
*HandleBuffer
;
243 EFI_ISA_IO_PROTOCOL
*IsaIo
;
248 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
249 LegacyBiosBuildSioData (Private
);
250 SetMem (LegacyInterrupts
, sizeof (LegacyInterrupts
), 0);
253 // Create list of legacy interrupts.
255 for (Index
= 0; Index
< 4; Index
++) {
256 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Serial
[Index
].Irq
;
259 for (Index
= 4; Index
< 7; Index
++) {
260 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Parallel
[Index
- 4].Irq
;
263 LegacyInterrupts
[7] = EfiToLegacy16BootTable
->SioData
.Floppy
.Irq
;
266 // Get Legacy Hdd IRQs. If native mode treat as PCI
268 for (Index
= 0; Index
< 2; Index
++) {
269 HddIrq
= EfiToLegacy16BootTable
->HddInfo
[Index
].HddIrq
;
270 if ((HddIrq
!= 0) && ((HddIrq
== 15) || (HddIrq
== 14))) {
271 LegacyInterrupts
[Index
+ 8] = HddIrq
;
275 Private
->LegacyBiosPlatform
->GetRoutingTable (
276 Private
->LegacyBiosPlatform
,
277 (VOID
*) &RoutingTable
,
278 &RoutingTableEntries
,
281 (VOID
**) &IrqPriorityTable
,
282 &NumberPriorityEntries
285 // Remove legacy interrupts from the list of PCI interrupts available.
287 for (Index
= 0; Index
<= 0x0b; Index
++) {
288 for (Index1
= 0; Index1
<= NumberPriorityEntries
; Index1
++) {
289 if (LegacyInterrupts
[Index
] != 0) {
290 LegacyInt
= (UINT16
) (LegacyInt
| (1 << LegacyInterrupts
[Index
]));
291 if (LegacyInterrupts
[Index
] == IrqPriorityTable
[Index1
].Irq
) {
292 IrqPriorityTable
[Index1
].Used
= LEGACY_USED
;
298 Private
->Legacy8259
->GetMask (
307 // Set SIO interrupts and disable mouse. Let mouse driver
310 LegMask
= (UINT16
) ((LegMask
&~LegacyInt
) | 0x1000);
311 Private
->Legacy8259
->SetMask (
320 // Disable mouse in keyboard controller
323 Status
= gBS
->LocateHandleBuffer (
325 &gEfiIsaIoProtocolGuid
,
330 if (EFI_ERROR (Status
)) {
334 for (Index
= 0; Index
< HandleCount
; Index
++) {
335 Status
= gBS
->HandleProtocol (
337 &gEfiIsaIoProtocolGuid
,
340 ASSERT_EFI_ERROR (Status
);
341 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, 0x64, 1, &Register
);
345 if (HandleBuffer
!= NULL
) {
346 FreePool (HandleBuffer
);
354 Identify drive data must be updated to actual parameters before boot.
355 This requires updating the checksum, if it exists.
357 @param IdentifyDriveData ATA Identify Data
358 @param Checksum checksum of the ATA Identify Data
360 @retval EFI_SUCCESS checksum calculated
361 @retval EFI_SECURITY_VIOLATION IdentifyData invalid
365 CalculateIdentifyDriveChecksum (
366 IN UINT8
*IdentifyDriveData
,
374 if (IdentifyDriveData
[510] != 0xA5) {
375 return EFI_SECURITY_VIOLATION
;
378 for (Index
= 0; Index
< 512; Index
++) {
379 LocalChecksum
= (UINT8
) (LocalChecksum
+ IdentifyDriveData
[Index
]);
382 *Checksum
= LocalChecksum
;
388 Identify drive data must be updated to actual parameters before boot.
390 @param IdentifyDriveData ATA Identify Data
395 UpdateIdentifyDriveData (
396 IN UINT8
*IdentifyDriveData
399 UINT16 NumberCylinders
;
401 UINT16 NumberSectorsTrack
;
402 UINT32 CapacityInSectors
;
403 UINT8 OriginalChecksum
;
406 ATAPI_IDENTIFY
*ReadInfo
;
409 // Status indicates if Integrity byte is correct. Checksum should be
412 ReadInfo
= (ATAPI_IDENTIFY
*) IdentifyDriveData
;
413 Status
= CalculateIdentifyDriveChecksum (IdentifyDriveData
, &OriginalChecksum
);
414 if (OriginalChecksum
!= 0) {
415 Status
= EFI_SECURITY_VIOLATION
;
418 // If NumberCylinders = 0 then do data(Controller present but don drive attached).
420 NumberCylinders
= ReadInfo
->Raw
[1];
421 if (NumberCylinders
!= 0) {
422 ReadInfo
->Raw
[54] = NumberCylinders
;
424 NumberHeads
= ReadInfo
->Raw
[3];
425 ReadInfo
->Raw
[55] = NumberHeads
;
427 NumberSectorsTrack
= ReadInfo
->Raw
[6];
428 ReadInfo
->Raw
[56] = NumberSectorsTrack
;
431 // Copy Multisector info and set valid bit.
433 ReadInfo
->Raw
[59] = (UINT16
) (ReadInfo
->Raw
[47] + 0x100);
434 CapacityInSectors
= (UINT32
) ((UINT32
) (NumberCylinders
) * (UINT32
) (NumberHeads
) * (UINT32
) (NumberSectorsTrack
));
435 ReadInfo
->Raw
[57] = (UINT16
) (CapacityInSectors
>> 16);
436 ReadInfo
->Raw
[58] = (UINT16
) (CapacityInSectors
& 0xffff);
437 if (Status
== EFI_SUCCESS
) {
439 // Forece checksum byte to 0 and get new checksum.
441 ReadInfo
->Raw
[255] &= 0xff;
442 CalculateIdentifyDriveChecksum (IdentifyDriveData
, &FinalChecksum
);
445 // Force new checksum such that sum is 0.
447 FinalChecksum
= (UINT8
) ((UINT8
)0 - FinalChecksum
);
448 ReadInfo
->Raw
[255] = (UINT16
) (ReadInfo
->Raw
[255] | (FinalChecksum
<< 8));
454 Identify drive data must be updated to actual parameters before boot.
457 @param Private Legacy BIOS Instance data
462 UpdateAllIdentifyDriveData (
463 IN LEGACY_BIOS_INSTANCE
*Private
469 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
471 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
473 // Each controller can have 2 devices. Update for each device
475 if ((HddInfo
[Index
].Status
& HDD_MASTER_IDE
) != 0) {
476 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
479 if ((HddInfo
[Index
].Status
& HDD_SLAVE_IDE
) != 0) {
480 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
486 Enable ide controller. This gets disabled when LegacyBoot.c is about
487 to run the Option ROMs.
489 @param Private Legacy BIOS Instance data
494 EnableIdeController (
495 IN LEGACY_BIOS_INSTANCE
*Private
498 EFI_PCI_IO_PROTOCOL
*PciIo
;
500 EFI_HANDLE IdeController
;
503 EFI_HANDLE
*HandleBuffer
;
505 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
506 Private
->LegacyBiosPlatform
,
507 EfiGetPlatformIdeHandle
,
513 if (!EFI_ERROR (Status
)) {
514 IdeController
= HandleBuffer
[0];
515 Status
= gBS
->HandleProtocol (
517 &gEfiPciIoProtocolGuid
,
521 if (!EFI_ERROR (Status
)) {
522 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x04, 1, &ByteBuffer
);
529 Enable ide controller. This gets disabled when LegacyBoot.c is about
530 to run the Option ROMs.
532 @param Private Legacy BIOS Instance data
537 EnableAllControllers (
538 IN LEGACY_BIOS_INSTANCE
*Private
542 EFI_HANDLE
*HandleBuffer
;
544 EFI_PCI_IO_PROTOCOL
*PciIo
;
545 PCI_TYPE01 PciConfigHeader
;
551 EnableIdeController (Private
);
554 // Assumption is table is built from low bus to high bus numbers.
556 Status
= gBS
->LocateHandleBuffer (
558 &gEfiPciIoProtocolGuid
,
563 ASSERT_EFI_ERROR (Status
);
565 for (Index
= 0; Index
< HandleCount
; Index
++) {
566 Status
= gBS
->HandleProtocol (
568 &gEfiPciIoProtocolGuid
,
571 ASSERT_EFI_ERROR (Status
);
577 sizeof (PciConfigHeader
) / sizeof (UINT32
),
582 // We do not enable PPB here. This is for HotPlug Consideration.
583 // The Platform HotPlug Driver is responsible for Padding enough hot plug
584 // resources. It is also responsible for enable this bridge. If it
585 // does not pad it. It will cause some early Windows fail to installation.
586 // If the platform driver does not pad resource for PPB, PPB should be in
587 // un-enabled state to let Windows know that this PPB is not configured by
588 // BIOS. So Windows will allocate default resource for PPB.
590 // The reason for why we enable the command register is:
591 // The CSM will use the IO bar to detect some IRQ status, if the command
592 // is disabled, the IO resource will be out of scope.
594 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
595 // comes up, the handle will check the IO space to identify is the
596 // controller generated the IRQ source.
597 // If the IO command is not enabled, the IRQ handler will has wrong
598 // information. It will cause IRQ storm when the correctly IRQ handler fails
601 if (!(IS_PCI_VGA (&PciConfigHeader
) ||
602 IS_PCI_OLD_VGA (&PciConfigHeader
) ||
603 IS_PCI_IDE (&PciConfigHeader
) ||
604 IS_PCI_P2P (&PciConfigHeader
) ||
605 IS_PCI_P2P_SUB (&PciConfigHeader
) ||
606 IS_PCI_LPC (&PciConfigHeader
) )) {
608 PciConfigHeader
.Hdr
.Command
|= 0x1f;
610 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 4, 1, &PciConfigHeader
.Hdr
.Command
);
616 The following routines are identical in operation, so combine
618 EfiGetPlatformBinaryGetMpTable
619 EfiGetPlatformBinaryGetOemIntData
620 EfiGetPlatformBinaryGetOem32Data
621 EfiGetPlatformBinaryGetOem16Data
623 @param This Protocol instance pointer.
624 @param Id Table/Data identifier
626 @retval EFI_SUCCESS Success
627 @retval EFI_INVALID_PARAMETER Invalid ID
628 @retval EFI_OUT_OF_RESOURCES no resource to get data or table
632 LegacyGetDataOrTable (
633 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
634 IN EFI_GET_PLATFORM_INFO_MODE Id
643 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
644 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
645 EFI_IA32_REGISTER_SET Regs
;
646 LEGACY_BIOS_INSTANCE
*Private
;
648 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
650 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
651 Legacy16Table
= Private
->Legacy16Table
;
654 // Phase 1 - get an address allocated in 16-bit code
658 case EfiGetPlatformBinaryMpTable
:
659 case EfiGetPlatformBinaryOemIntData
:
660 case EfiGetPlatformBinaryOem32Data
:
661 case EfiGetPlatformBinaryOem16Data
:
663 Status
= LegacyBiosPlatform
->GetPlatformInfo (
673 DEBUG ((EFI_D_INFO
, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN
)Id
, Status
));
674 DEBUG ((EFI_D_INFO
, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN
)Table
, (UINTN
)TableSize
, (UINTN
)Location
, (UINTN
)Alignment
));
680 return EFI_INVALID_PARAMETER
;
684 if (EFI_ERROR (Status
)) {
688 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
689 Regs
.X
.AX
= Legacy16GetTableAddress
;
690 Regs
.X
.CX
= (UINT16
) TableSize
;
691 Regs
.X
.BX
= (UINT16
) Location
;
692 Regs
.X
.DX
= (UINT16
) Alignment
;
693 Private
->LegacyBios
.FarCall86 (
695 Private
->Legacy16CallSegment
,
696 Private
->Legacy16CallOffset
,
702 if (Regs
.X
.AX
!= 0) {
703 DEBUG ((EFI_D_ERROR
, "Table ID %x length insufficient\n", Id
));
704 return EFI_OUT_OF_RESOURCES
;
710 // Phase 2 Call routine second time with address to allow address adjustment
712 Status
= LegacyBiosPlatform
->GetPlatformInfo (
723 case EfiGetPlatformBinaryMpTable
:
725 Legacy16Table
->MpTablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
726 Legacy16Table
->MpTableLength
= (UINT32
)TableSize
;
727 DEBUG ((EFI_D_INFO
, "MP table in legacy region - %x\n", (UINTN
)Legacy16Table
->MpTablePtr
));
731 case EfiGetPlatformBinaryOemIntData
:
734 Legacy16Table
->OemIntSegment
= Regs
.X
.DS
;
735 Legacy16Table
->OemIntOffset
= Regs
.X
.BX
;
736 DEBUG ((EFI_D_INFO
, "OemInt table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->OemIntSegment
, (UINTN
)Legacy16Table
->OemIntOffset
));
740 case EfiGetPlatformBinaryOem32Data
:
742 Legacy16Table
->Oem32Segment
= Regs
.X
.DS
;
743 Legacy16Table
->Oem32Offset
= Regs
.X
.BX
;
744 DEBUG ((EFI_D_INFO
, "Oem32 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem32Segment
, (UINTN
)Legacy16Table
->Oem32Offset
));
748 case EfiGetPlatformBinaryOem16Data
:
751 // Legacy16Table->Oem16Segment = Regs.X.DS;
752 // Legacy16Table->Oem16Offset = Regs.X.BX;
753 DEBUG ((EFI_D_INFO
, "Oem16 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem16Segment
, (UINTN
)Legacy16Table
->Oem16Offset
));
759 return EFI_INVALID_PARAMETER
;
763 if (EFI_ERROR (Status
)) {
767 // Phase 3 Copy table to final location
769 TablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
772 (VOID
*) (UINTN
)TablePtr
,
782 Assign drive number to legacy HDD drives prior to booting an EFI
783 aware OS so the OS can access drives without an EFI driver.
784 Note: BBS compliant drives ARE NOT available until this call by
787 @param This Protocol instance pointer.
789 @retval EFI_SUCCESS Drive numbers assigned
794 IN EFI_LEGACY_BIOS_PROTOCOL
*This
798 LEGACY_BIOS_INSTANCE
*Private
;
799 EFI_IA32_REGISTER_SET Regs
;
800 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
801 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
805 HDD_INFO
*LocalHddInfo
;
807 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
811 BBS_TABLE
*LocalBbsTable
;
812 UINT32
*BaseVectorMaster
;
815 EFI_HANDLE IdeController
;
817 EFI_HANDLE
*HandleBuffer
;
826 LocalBbsTable
= NULL
;
828 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
830 DEBUG ((EFI_D_ERROR
, "Start of legacy boot\n"));
833 Legacy16Table
= Private
->Legacy16Table
;
834 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
835 HddInfo
= &EfiToLegacy16BootTable
->HddInfo
[0];
837 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
839 EfiToLegacy16BootTable
->MajorVersion
= EFI_TO_LEGACY_MAJOR_VERSION
;
840 EfiToLegacy16BootTable
->MinorVersion
= EFI_TO_LEGACY_MINOR_VERSION
;
843 // If booting to a legacy OS then force HDD drives to the appropriate
844 // boot mode by calling GetIdeHandle.
845 // A reconnect -r can force all HDDs back to native mode.
847 IdeController
= NULL
;
848 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
849 Status
= LegacyBiosPlatform
->GetPlatformHandle (
850 Private
->LegacyBiosPlatform
,
851 EfiGetPlatformIdeHandle
,
857 if (!EFI_ERROR (Status
)) {
858 IdeController
= HandleBuffer
[0];
862 // Unlock the Legacy BIOS region
864 Private
->LegacyRegion
->UnLock (
865 Private
->LegacyRegion
,
872 // Reconstruct the Legacy16 boot memory map
874 LegacyBiosBuildE820 (Private
, &CopySize
);
875 if (CopySize
> Private
->Legacy16Table
->E820Length
) {
876 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
877 Regs
.X
.AX
= Legacy16GetTableAddress
;
878 Regs
.X
.CX
= (UINT16
) CopySize
;
879 Private
->LegacyBios
.FarCall86 (
880 &Private
->LegacyBios
,
881 Private
->Legacy16Table
->Compatibility16CallSegment
,
882 Private
->Legacy16Table
->Compatibility16CallOffset
,
888 Private
->Legacy16Table
->E820Pointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
889 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
890 if (Regs
.X
.AX
!= 0) {
891 DEBUG ((EFI_D_ERROR
, "Legacy16 E820 length insufficient\n"));
894 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
901 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
905 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
908 // Get SMBIOS and ACPI table pointers
911 EfiGetSystemConfigurationTable (
912 &gEfiSmbiosTableGuid
,
916 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
918 if (SmbiosTable
== NULL
) {
919 DEBUG ((EFI_D_INFO
, "Smbios table is not found!\n"));
921 EfiToLegacy16BootTable
->SmbiosTable
= (UINT32
)(UINTN
)SmbiosTable
;
924 Status
= EfiGetSystemConfigurationTable (
925 &gEfiAcpi20TableGuid
,
928 if (EFI_ERROR (Status
)) {
929 Status
= EfiGetSystemConfigurationTable (
930 &gEfiAcpi10TableGuid
,
935 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
937 if (AcpiTable
== NULL
) {
938 DEBUG ((EFI_D_INFO
, "ACPI table is not found!\n"));
940 EfiToLegacy16BootTable
->AcpiTable
= (UINT32
)(UINTN
)AcpiTable
;
943 // Get RSD Ptr table rev at offset 15 decimal
944 // Rev = 0 Length is 20 decimal
945 // Rev != 0 Length is UINT32 at offset 20 decimal
947 if (AcpiTable
!= NULL
) {
950 if (*((UINT8
*) AcpiPtr
+ 15) == 0) {
953 AcpiPtr
= ((UINT8
*) AcpiPtr
+ 20);
954 CopySize
= (*(UINT32
*) AcpiPtr
);
958 (VOID
*)(UINTN
) Private
->Legacy16Table
->AcpiRsdPtrPointer
,
964 // Make sure all PCI Interrupt Line register are programmed to match 8259
966 PciProgramAllInterruptLineRegisters (Private
);
969 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
972 Private
->LegacyRegion
->UnLock (
973 Private
->LegacyRegion
,
975 Private
->LegacyBiosImageSize
,
980 // Configure Legacy Device Magic
982 // Only do this code if booting legacy OS
984 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
985 UpdateSioData (Private
);
988 // Setup BDA and EBDA standard areas before Legacy Boot
990 LegacyBiosCompleteBdaBeforeBoot (Private
);
991 LegacyBiosCompleteStandardCmosBeforeBoot (Private
);
994 // We must build IDE data, if it hasn't been done, before PciShadowRoms
995 // to insure EFI drivers are connected.
997 LegacyBiosBuildIdeData (Private
, &HddInfo
, 1);
998 UpdateAllIdentifyDriveData (Private
);
1001 // Clear IO BAR, if IDE controller in legacy mode.
1003 InitLegacyIdeController (IdeController
);
1006 // Generate number of ticks since midnight for BDA. DOS requires this
1007 // for its time. We have to make assumptions as to how long following
1008 // code takes since after PciShadowRoms PciIo is gone. Place result in
1011 // Adjust value by 1 second.
1013 gRT
->GetTime (&BootTime
, NULL
);
1014 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
1018 // Multiply result by 18.2 for number of ticks since midnight.
1019 // Use 182/10 to avoid floating point math.
1021 LocalTime
= (LocalTime
* 182) / 10;
1022 BdaPtr
= (UINT32
*) (UINTN
)0x46C;
1023 *BdaPtr
= LocalTime
;
1026 // Shadow PCI ROMs. We must do this near the end since this will kick
1027 // of Native EFI drivers that may be needed to collect info for Legacy16
1029 // WARNING: PciIo is gone after this call.
1031 PciShadowRoms (Private
);
1034 // Shadow PXE base code, BIS etc.
1036 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xc0000, 0x40000, &Granularity
);
1037 ShadowAddress
= Private
->OptionRom
;
1038 Private
->LegacyBiosPlatform
->PlatformHooks (
1039 Private
->LegacyBiosPlatform
,
1040 EfiPlatformHookShadowServiceRoms
,
1047 Private
->OptionRom
= (UINT32
)ShadowAddress
;
1049 // Register Legacy SMI Handler
1051 LegacyBiosPlatform
->SmmInit (
1053 EfiToLegacy16BootTable
1057 // Let platform code know the boot options
1059 LegacyBiosGetBbsInfo (
1068 PrintPciInterruptRegister ();
1069 PrintBbsTable (LocalBbsTable
);
1070 PrintHddInfo (LocalHddInfo
);
1073 // If drive wasn't spun up then BuildIdeData may have found new drives.
1074 // Need to update BBS boot priority.
1076 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
1077 if ((LocalHddInfo
[Index
].IdentifyDrive
[0].Raw
[0] != 0) &&
1078 (LocalBbsTable
[2 * Index
+ 1].BootPriority
== BBS_IGNORE_ENTRY
)
1080 LocalBbsTable
[2 * Index
+ 1].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1083 if ((LocalHddInfo
[Index
].IdentifyDrive
[1].Raw
[0] != 0) &&
1084 (LocalBbsTable
[2 * Index
+ 2].BootPriority
== BBS_IGNORE_ENTRY
)
1086 LocalBbsTable
[2 * Index
+ 2].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1090 Private
->LegacyRegion
->UnLock (
1091 Private
->LegacyRegion
,
1097 LegacyBiosPlatform
->PrepareToBoot (
1103 (VOID
*) &Private
->IntThunk
->EfiToLegacy16BootTable
1107 // If no boot device return to BDS
1109 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1110 for (Index
= 0; Index
< BbsCount
; Index
++){
1111 if ((LocalBbsTable
[Index
].BootPriority
!= BBS_DO_NOT_BOOT_FROM
) &&
1112 (LocalBbsTable
[Index
].BootPriority
!= BBS_UNPRIORITIZED_ENTRY
) &&
1113 (LocalBbsTable
[Index
].BootPriority
!= BBS_IGNORE_ENTRY
)) {
1117 if (Index
== BbsCount
) {
1118 return EFI_DEVICE_ERROR
;
1122 // Let the Legacy16 code know the device path type for legacy boot
1124 EfiToLegacy16BootTable
->DevicePathType
= mBbsDevicePathPtr
->DeviceType
;
1127 // Copy MP table, if it exists.
1129 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryMpTable
);
1131 if (!Private
->LegacyBootEntered
) {
1133 // Copy OEM INT Data, if it exists. Note: This code treats any data
1134 // as a bag of bits and knows nothing of the contents nor cares.
1135 // Contents are IBV specific.
1137 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOemIntData
);
1140 // Copy OEM16 Data, if it exists.Note: This code treats any data
1141 // as a bag of bits and knows nothing of the contents nor cares.
1142 // Contents are IBV specific.
1144 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem16Data
);
1147 // Copy OEM32 Data, if it exists.Note: This code treats any data
1148 // as a bag of bits and knows nothing of the contents nor cares.
1149 // Contents are IBV specific.
1151 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem32Data
);
1155 // Call into Legacy16 code to prepare for INT 19h
1157 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1158 Regs
.X
.AX
= Legacy16PrepareToBoot
;
1161 // Pass in handoff data
1163 Regs
.X
.ES
= NORMALIZE_EFI_SEGMENT ((UINTN
)EfiToLegacy16BootTable
);
1164 Regs
.X
.BX
= NORMALIZE_EFI_OFFSET ((UINTN
)EfiToLegacy16BootTable
);
1166 Private
->LegacyBios
.FarCall86 (
1168 Private
->Legacy16CallSegment
,
1169 Private
->Legacy16CallOffset
,
1175 if (Regs
.X
.AX
!= 0) {
1176 return EFI_DEVICE_ERROR
;
1179 // Lock the Legacy BIOS region
1181 Private
->LegacyRegion
->Lock (
1182 Private
->LegacyRegion
,
1188 // Lock attributes of the Legacy Region if chipset supports
1190 Private
->LegacyRegion
->BootLock (
1191 Private
->LegacyRegion
,
1198 // Call into Legacy16 code to do the INT 19h
1200 EnableAllControllers (Private
);
1201 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1203 // Report Status Code to indicate legacy boot event will be signalled
1205 REPORT_STATUS_CODE (
1207 (EFI_SOFTWARE_DXE_BS_DRIVER
| EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT
)
1211 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
1213 EfiSignalEventLegacyBoot ();
1214 DEBUG ((EFI_D_INFO
, "Legacy INT19 Boot...\n"));
1217 // Disable DXE Timer while executing in real mode
1219 Private
->Timer
->SetTimerPeriod (Private
->Timer
, 0);
1222 // Save and disable interrupt of debug timer
1224 SaveAndSetDebugTimerInterrupt (FALSE
);
1228 // Put the 8259 into its legacy mode by reprogramming the vector bases
1230 Private
->Legacy8259
->SetVectorBase (Private
->Legacy8259
, LEGACY_MODE_BASE_VECTOR_MASTER
, LEGACY_MODE_BASE_VECTOR_SLAVE
);
1233 // The original PC used INT8-F for master PIC. Since these mapped over
1234 // processor exceptions TIANO moved the master PIC to INT68-6F.
1235 // We need to set these back to the Legacy16 unexpected interrupt(saved
1236 // in LegacyBios.c) since some OS see that these have values different from
1237 // what is expected and invoke them. Since the legacy OS corrupts EFI
1238 // memory, there is no handler for these interrupts and OS blows up.
1240 // We need to save the TIANO values for the rare case that the Legacy16
1241 // code cannot boot but knows memory hasn't been destroyed.
1243 // To compound the problem, video takes over one of these INTS and must be
1245 // @bug - determine if video hooks INT(in which case we must find new
1246 // set of TIANO vectors) or takes it over.
1249 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1250 for (Index
= 0; Index
< 8; Index
++) {
1251 Private
->ThunkSavedInt
[Index
] = BaseVectorMaster
[Index
];
1252 if (Private
->ThunkSeg
== (UINT16
) (BaseVectorMaster
[Index
] >> 16)) {
1253 BaseVectorMaster
[Index
] = (UINT32
) (Private
->BiosUnexpectedInt
);
1257 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1258 Regs
.X
.AX
= Legacy16Boot
;
1260 Private
->LegacyBios
.FarCall86 (
1262 Private
->Legacy16CallSegment
,
1263 Private
->Legacy16CallOffset
,
1269 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1270 for (Index
= 0; Index
< 8; Index
++) {
1271 BaseVectorMaster
[Index
] = Private
->ThunkSavedInt
[Index
];
1274 Private
->LegacyBootEntered
= TRUE
;
1275 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1277 // Should never return unless never passed control to 0:7c00(first stage
1278 // OS loader) and only then if no bootable device found.
1280 return EFI_DEVICE_ERROR
;
1283 // If boot to EFI then expect to return to caller
1291 Assign drive number to legacy HDD drives prior to booting an EFI
1292 aware OS so the OS can access drives without an EFI driver.
1293 Note: BBS compliant drives ARE NOT available until this call by
1294 either shell or EFI.
1296 @param This Protocol instance pointer.
1297 @param BbsCount Number of BBS_TABLE structures
1298 @param BbsTable List BBS entries
1300 @retval EFI_SUCCESS Drive numbers assigned
1305 LegacyBiosPrepareToBootEfi (
1306 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1307 OUT UINT16
*BbsCount
,
1308 OUT BBS_TABLE
**BbsTable
1312 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1313 LEGACY_BIOS_INSTANCE
*Private
;
1315 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1316 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1317 mBootMode
= BOOT_EFI_OS
;
1318 mBbsDevicePathPtr
= NULL
;
1319 Status
= GenericLegacyBoot (This
);
1320 *BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1321 *BbsCount
= (UINT16
) (sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
));
1326 To boot from an unconventional device like parties and/or execute HDD diagnostics.
1328 @param This Protocol instance pointer.
1329 @param Attributes How to interpret the other input parameters
1330 @param BbsEntry The 0-based index into the BbsTable for the parent
1332 @param BeerData Pointer to the 128 bytes of ram BEER data.
1333 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1334 caller must provide a pointer to the specific Service
1335 Area and not the start all Service Areas.
1337 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1342 LegacyBiosBootUnconventionalDevice (
1343 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1344 IN UDC_ATTRIBUTES Attributes
,
1347 IN VOID
*ServiceAreaData
1351 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1352 LEGACY_BIOS_INSTANCE
*Private
;
1355 UINT16 BootPriority
;
1356 BBS_TABLE
*BbsTable
;
1359 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1360 mBootMode
= BOOT_UNCONVENTIONAL_DEVICE
;
1361 mBbsDevicePathPtr
= &mBbsDevicePathNode
;
1362 mAttributes
= Attributes
;
1363 mBbsEntry
= BbsEntry
;
1364 mBeerData
= BeerData
, mServiceAreaData
= ServiceAreaData
;
1366 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1369 // Do input parameter checking
1371 if ((Attributes
.DirectoryServiceValidity
== 0) &&
1372 (Attributes
.RabcaUsedFlag
== 0) &&
1373 (Attributes
.ExecuteHddDiagnosticsFlag
== 0)
1375 return EFI_INVALID_PARAMETER
;
1378 if (((Attributes
.DirectoryServiceValidity
!= 0) && (ServiceAreaData
== NULL
)) ||
1379 (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
) != 0) && (BeerData
== NULL
))
1381 return EFI_INVALID_PARAMETER
;
1384 UcdTable
= (UD_TABLE
*) AllocatePool (
1387 if (NULL
== UcdTable
) {
1388 return EFI_OUT_OF_RESOURCES
;
1391 EfiToLegacy16BootTable
->UnconventionalDeviceTable
= (UINT32
)(UINTN
)UcdTable
;
1392 UcdTable
->Attributes
= Attributes
;
1393 UcdTable
->BbsTableEntryNumberForParentDevice
= (UINT8
) BbsEntry
;
1395 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1396 // to assign drive numbers but bot boot from. Only newly created entries
1399 BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1400 for (Index
= 0; Index
< EfiToLegacy16BootTable
->NumberBbsEntries
; Index
++) {
1401 BbsTable
[Index
].BootPriority
= BBS_DO_NOT_BOOT_FROM
;
1404 // If parent is onboard IDE then assign controller & device number
1407 if (BbsEntry
< MAX_IDE_CONTROLLER
* 2) {
1408 UcdTable
->DeviceNumber
= (UINT8
) ((BbsEntry
- 1) % 2);
1411 if (BeerData
!= NULL
) {
1413 (VOID
*) UcdTable
->BeerData
,
1419 if (ServiceAreaData
!= NULL
) {
1421 (VOID
*) UcdTable
->ServiceAreaData
,
1427 // For each new entry do the following:
1428 // 1. Increment current number of BBS entries
1429 // 2. Copy parent entry to new entry.
1430 // 3. Zero out BootHandler Offset & segment
1431 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1432 // and Floppy(0x01) for PARTIES boot.
1433 // 5. Assign new priority.
1435 if ((Attributes
.ExecuteHddDiagnosticsFlag
) != 0) {
1436 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1439 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1440 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1444 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1445 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1446 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x80;
1448 UcdTable
->BbsTableEntryNumberForHddDiag
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1450 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1454 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1456 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_BEV
;
1459 if (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
)) != 0) {
1460 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1462 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1463 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1467 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1468 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1469 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x01;
1470 UcdTable
->BbsTableEntryNumberForBoot
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1471 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1474 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1476 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_FLOPPY
;
1479 // Build the BBS Device Path for this boot selection
1481 mBbsDevicePathNode
.Header
.Type
= BBS_DEVICE_PATH
;
1482 mBbsDevicePathNode
.Header
.SubType
= BBS_BBS_DP
;
1483 SetDevicePathNodeLength (&mBbsDevicePathNode
.Header
, sizeof (BBS_BBS_DEVICE_PATH
));
1484 mBbsDevicePathNode
.StatusFlag
= 0;
1485 mBbsDevicePathNode
.String
[0] = 0;
1487 Status
= GenericLegacyBoot (This
);
1492 Attempt to legacy boot the BootOption. If the EFI contexted has been
1493 compromised this function will not return.
1495 @param This Protocol instance pointer.
1496 @param BbsDevicePath EFI Device Path from BootXXXX variable.
1497 @param LoadOptionsSize Size of LoadOption in size.
1498 @param LoadOptions LoadOption from BootXXXX variable
1500 @retval EFI_SUCCESS Removable media not present
1505 LegacyBiosLegacyBoot (
1506 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1507 IN BBS_BBS_DEVICE_PATH
*BbsDevicePath
,
1508 IN UINT32 LoadOptionsSize
,
1509 IN VOID
*LoadOptions
1514 mBbsDevicePathPtr
= BbsDevicePath
;
1515 mLoadOptionsSize
= LoadOptionsSize
;
1516 mLoadOptions
= LoadOptions
;
1517 mBootMode
= BOOT_LEGACY_OS
;
1518 Status
= GenericLegacyBoot (This
);
1524 Convert EFI Memory Type to E820 Memory Type.
1526 @param Type EFI Memory Type
1528 @return ACPI Memory Type for EFI Memory Type
1531 EFI_ACPI_MEMORY_TYPE
1532 EfiMemoryTypeToE820Type (
1539 case EfiBootServicesCode
:
1540 case EfiBootServicesData
:
1541 case EfiConventionalMemory
:
1542 case EfiRuntimeServicesCode
:
1543 case EfiRuntimeServicesData
:
1544 return EfiAcpiAddressRangeMemory
;
1546 case EfiACPIReclaimMemory
:
1547 return EfiAcpiAddressRangeACPI
;
1549 case EfiACPIMemoryNVS
:
1550 return EfiAcpiAddressRangeNVS
;
1553 // All other types map to reserved.
1554 // Adding the code just waists FLASH space.
1556 // case EfiReservedMemoryType:
1557 // case EfiUnusableMemory:
1558 // case EfiMemoryMappedIO:
1559 // case EfiMemoryMappedIOPortSpace:
1563 return EfiAcpiAddressRangeReserved
;
1568 Build the E820 table.
1570 @param Private Legacy BIOS Instance data
1571 @param Size Size of E820 Table
1573 @retval EFI_SUCCESS It should always work.
1577 LegacyBiosBuildE820 (
1578 IN LEGACY_BIOS_INSTANCE
*Private
,
1583 EFI_E820_ENTRY64
*E820Table
;
1584 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMap
;
1585 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMapEnd
;
1586 EFI_MEMORY_DESCRIPTOR
*EfiEntry
;
1587 EFI_MEMORY_DESCRIPTOR
*NextEfiEntry
;
1588 EFI_MEMORY_DESCRIPTOR TempEfiEntry
;
1589 UINTN EfiMemoryMapSize
;
1591 UINTN EfiDescriptorSize
;
1592 UINT32 EfiDescriptorVersion
;
1594 EFI_PEI_HOB_POINTERS Hob
;
1595 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
1598 UINTN TempNextIndex
;
1599 EFI_E820_ENTRY64 TempE820
;
1600 EFI_ACPI_MEMORY_TYPE TempType
;
1601 BOOLEAN ChangedFlag
;
1603 UINT64 MemoryBlockLength
;
1605 E820Table
= (EFI_E820_ENTRY64
*) Private
->E820Table
;
1608 // Get the EFI memory map.
1610 EfiMemoryMapSize
= 0;
1611 EfiMemoryMap
= NULL
;
1612 Status
= gBS
->GetMemoryMap (
1617 &EfiDescriptorVersion
1619 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1623 // Use size returned back plus 1 descriptor for the AllocatePool.
1624 // We don't just multiply by 2 since the "for" loop below terminates on
1625 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
1626 // we process bogus entries and create bogus E820 entries.
1628 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*) AllocatePool (EfiMemoryMapSize
);
1629 ASSERT (EfiMemoryMap
!= NULL
);
1630 Status
= gBS
->GetMemoryMap (
1635 &EfiDescriptorVersion
1637 if (EFI_ERROR (Status
)) {
1638 FreePool (EfiMemoryMap
);
1640 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1642 ASSERT_EFI_ERROR (Status
);
1645 // Punch in the E820 table for memory less than 1 MB.
1646 // Assume ZeroMem () has been done on data structure.
1649 // First entry is 0 to (640k - EBDA)
1651 E820Table
[0].BaseAddr
= 0;
1652 E820Table
[0].Length
= (UINT64
) ((*(UINT16
*) (UINTN
)0x40E) << 4);
1653 E820Table
[0].Type
= EfiAcpiAddressRangeMemory
;
1656 // Second entry is (640k - EBDA) to 640k
1658 E820Table
[1].BaseAddr
= E820Table
[0].Length
;
1659 E820Table
[1].Length
= (UINT64
) ((640 * 1024) - E820Table
[0].Length
);
1660 E820Table
[1].Type
= EfiAcpiAddressRangeReserved
;
1663 // Third Entry is legacy BIOS
1664 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1665 // to page in memory under 1MB.
1666 // Omit region from 0xE0000 to start of BIOS, if any. This can be
1667 // used for a multiple reasons including OPROMS.
1671 // The CSM binary image size is not the actually size that CSM binary used,
1672 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1674 E820Table
[2].BaseAddr
= 0xE0000;
1675 E820Table
[2].Length
= 0x20000;
1676 E820Table
[2].Type
= EfiAcpiAddressRangeReserved
;
1681 // Process the EFI map to produce E820 map;
1685 // Sort memory map from low to high
1687 EfiEntry
= EfiMemoryMap
;
1688 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1689 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1690 while (EfiEntry
< EfiMemoryMapEnd
) {
1691 while (NextEfiEntry
< EfiMemoryMapEnd
) {
1692 if (EfiEntry
->PhysicalStart
> NextEfiEntry
->PhysicalStart
) {
1693 CopyMem (&TempEfiEntry
, EfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1694 CopyMem (EfiEntry
, NextEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1695 CopyMem (NextEfiEntry
, &TempEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1698 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (NextEfiEntry
, EfiDescriptorSize
);
1701 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1702 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1705 EfiEntry
= EfiMemoryMap
;
1706 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1707 for (Index
= Above1MIndex
; (EfiEntry
< EfiMemoryMapEnd
) && (Index
< EFI_MAX_E820_ENTRY
- 1); ) {
1708 MemoryBlockLength
= (UINT64
) (LShiftU64 (EfiEntry
->NumberOfPages
, 12));
1709 if ((EfiEntry
->PhysicalStart
+ MemoryBlockLength
) < 0x100000) {
1711 // Skip the memory block is under 1MB
1714 if (EfiEntry
->PhysicalStart
< 0x100000) {
1716 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1718 MemoryBlockLength
-= 0x100000 - EfiEntry
->PhysicalStart
;
1719 EfiEntry
->PhysicalStart
= 0x100000;
1723 // Convert memory type to E820 type
1725 TempType
= EfiMemoryTypeToE820Type (EfiEntry
->Type
);
1727 if ((E820Table
[Index
].Type
== TempType
) && (EfiEntry
->PhysicalStart
== (E820Table
[Index
].BaseAddr
+ E820Table
[Index
].Length
))) {
1729 // Grow an existing entry
1731 E820Table
[Index
].Length
+= MemoryBlockLength
;
1737 E820Table
[Index
].BaseAddr
= EfiEntry
->PhysicalStart
;
1738 E820Table
[Index
].Length
= MemoryBlockLength
;
1739 E820Table
[Index
].Type
= TempType
;
1742 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1745 FreePool (EfiMemoryMap
);
1748 // Process the reserved memory map to produce E820 map ;
1750 for (Hob
.Raw
= GetHobList (); !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
1751 if (Hob
.Raw
!= NULL
&& GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
1752 ResourceHob
= Hob
.ResourceDescriptor
;
1753 if (((ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_MAPPED_IO
) ||
1754 (ResourceHob
->ResourceType
== EFI_RESOURCE_FIRMWARE_DEVICE
) ||
1755 (ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_RESERVED
) ) &&
1756 (ResourceHob
->PhysicalStart
> 0x100000) &&
1757 (Index
< EFI_MAX_E820_ENTRY
- 1)) {
1759 E820Table
[Index
].BaseAddr
= ResourceHob
->PhysicalStart
;
1760 E820Table
[Index
].Length
= ResourceHob
->ResourceLength
;
1761 E820Table
[Index
].Type
= EfiAcpiAddressRangeReserved
;
1767 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1768 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1769 Private
->NumberE820Entries
= (UINT32
)Index
;
1770 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1773 // Sort E820Table from low to high
1775 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1776 ChangedFlag
= FALSE
;
1777 for (TempNextIndex
= 1; TempNextIndex
< Index
- TempIndex
; TempNextIndex
++) {
1778 if (E820Table
[TempNextIndex
- 1].BaseAddr
> E820Table
[TempNextIndex
].BaseAddr
) {
1780 TempE820
.BaseAddr
= E820Table
[TempNextIndex
- 1].BaseAddr
;
1781 TempE820
.Length
= E820Table
[TempNextIndex
- 1].Length
;
1782 TempE820
.Type
= E820Table
[TempNextIndex
- 1].Type
;
1784 E820Table
[TempNextIndex
- 1].BaseAddr
= E820Table
[TempNextIndex
].BaseAddr
;
1785 E820Table
[TempNextIndex
- 1].Length
= E820Table
[TempNextIndex
].Length
;
1786 E820Table
[TempNextIndex
- 1].Type
= E820Table
[TempNextIndex
].Type
;
1788 E820Table
[TempNextIndex
].BaseAddr
= TempE820
.BaseAddr
;
1789 E820Table
[TempNextIndex
].Length
= TempE820
.Length
;
1790 E820Table
[TempNextIndex
].Type
= TempE820
.Type
;
1800 // Remove the overlap range
1802 for (TempIndex
= 1; TempIndex
< Index
; TempIndex
++) {
1803 if (E820Table
[TempIndex
- 1].BaseAddr
<= E820Table
[TempIndex
].BaseAddr
&&
1804 ((E820Table
[TempIndex
- 1].BaseAddr
+ E820Table
[TempIndex
- 1].Length
) >=
1805 (E820Table
[TempIndex
].BaseAddr
+E820Table
[TempIndex
].Length
))) {
1807 //Overlap range is found
1809 ASSERT (E820Table
[TempIndex
- 1].Type
== E820Table
[TempIndex
].Type
);
1811 if (TempIndex
== Index
- 1) {
1812 E820Table
[TempIndex
].BaseAddr
= 0;
1813 E820Table
[TempIndex
].Length
= 0;
1814 E820Table
[TempIndex
].Type
= (EFI_ACPI_MEMORY_TYPE
) 0;
1818 for (IndexSort
= TempIndex
; IndexSort
< Index
- 1; IndexSort
++) {
1819 E820Table
[IndexSort
].BaseAddr
= E820Table
[IndexSort
+ 1].BaseAddr
;
1820 E820Table
[IndexSort
].Length
= E820Table
[IndexSort
+ 1].Length
;
1821 E820Table
[IndexSort
].Type
= E820Table
[IndexSort
+ 1].Type
;
1830 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1831 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1832 Private
->NumberE820Entries
= (UINT32
)Index
;
1833 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1836 // Determine OS usable memory above 1Mb
1838 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
= 0x0000;
1839 for (TempIndex
= Above1MIndex
; TempIndex
< Index
; TempIndex
++) {
1840 if (E820Table
[TempIndex
].BaseAddr
>= 0x100000 && E820Table
[TempIndex
].BaseAddr
< 0x100000000ULL
) { // not include above 4G memory
1842 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1844 if ((E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeMemory
) || (E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeACPI
)) {
1845 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
+= (UINT32
) (E820Table
[TempIndex
].Length
);
1847 break; // break at first not normal memory, because SMM may use reserved memory.
1852 Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
= Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
;
1855 // Print DEBUG information
1857 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1858 DEBUG((EFI_D_INFO
, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
1860 E820Table
[TempIndex
].BaseAddr
,
1861 (E820Table
[TempIndex
].BaseAddr
+ E820Table
[TempIndex
].Length
),
1862 E820Table
[TempIndex
].Type
1871 Fill in the standard BDA and EBDA stuff prior to legacy Boot
1873 @param Private Legacy BIOS Instance data
1875 @retval EFI_SUCCESS It should always work.
1879 LegacyBiosCompleteBdaBeforeBoot (
1880 IN LEGACY_BIOS_INSTANCE
*Private
1884 UINT16 MachineConfig
;
1885 DEVICE_PRODUCER_DATA_HEADER
*SioPtr
;
1887 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
1890 SioPtr
= &(Private
->IntThunk
->EfiToLegacy16BootTable
.SioData
);
1891 Bda
->Com1
= SioPtr
->Serial
[0].Address
;
1892 Bda
->Com2
= SioPtr
->Serial
[1].Address
;
1893 Bda
->Com3
= SioPtr
->Serial
[2].Address
;
1894 Bda
->Com4
= SioPtr
->Serial
[3].Address
;
1896 if (SioPtr
->Serial
[0].Address
!= 0x00) {
1897 MachineConfig
+= 0x200;
1900 if (SioPtr
->Serial
[1].Address
!= 0x00) {
1901 MachineConfig
+= 0x200;
1904 if (SioPtr
->Serial
[2].Address
!= 0x00) {
1905 MachineConfig
+= 0x200;
1908 if (SioPtr
->Serial
[3].Address
!= 0x00) {
1909 MachineConfig
+= 0x200;
1912 Bda
->Lpt1
= SioPtr
->Parallel
[0].Address
;
1913 Bda
->Lpt2
= SioPtr
->Parallel
[1].Address
;
1914 Bda
->Lpt3
= SioPtr
->Parallel
[2].Address
;
1916 if (SioPtr
->Parallel
[0].Address
!= 0x00) {
1917 MachineConfig
+= 0x4000;
1920 if (SioPtr
->Parallel
[1].Address
!= 0x00) {
1921 MachineConfig
+= 0x4000;
1924 if (SioPtr
->Parallel
[2].Address
!= 0x00) {
1925 MachineConfig
+= 0x4000;
1928 Bda
->NumberOfDrives
= (UINT8
) (Bda
->NumberOfDrives
+ Private
->IdeDriveCount
);
1929 if (SioPtr
->Floppy
.NumberOfFloppy
!= 0x00) {
1930 MachineConfig
= (UINT16
) (MachineConfig
+ 0x01 + (SioPtr
->Floppy
.NumberOfFloppy
- 1) * 0x40);
1931 Bda
->FloppyXRate
= 0x07;
1934 Bda
->Lpt1_2Timeout
= 0x1414;
1935 Bda
->Lpt3_4Timeout
= 0x1414;
1936 Bda
->Com1_2Timeout
= 0x0101;
1937 Bda
->Com3_4Timeout
= 0x0101;
1940 // Force VGA and Coprocessor, indicate 101/102 keyboard
1942 MachineConfig
= (UINT16
) (MachineConfig
+ 0x00 + 0x02 + (SioPtr
->MousePresent
* 0x04));
1943 Bda
->MachineConfig
= MachineConfig
;
1949 Fill in the standard BDA for Keyboard LEDs
1951 @param This Protocol instance pointer.
1952 @param Leds Current LED status
1954 @retval EFI_SUCCESS It should always work.
1959 LegacyBiosUpdateKeyboardLedStatus (
1960 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1964 LEGACY_BIOS_INSTANCE
*Private
;
1967 EFI_IA32_REGISTER_SET Regs
;
1969 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
1971 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1973 Bda
->LedStatus
= (UINT8
) ((Bda
->LedStatus
&~0x07) | LocalLeds
);
1974 LocalLeds
= (UINT8
) (LocalLeds
<< 4);
1975 Bda
->ShiftStatus
= (UINT8
) ((Bda
->ShiftStatus
&~0x70) | LocalLeds
);
1976 LocalLeds
= (UINT8
) (Leds
& 0x20);
1977 Bda
->KeyboardStatus
= (UINT8
) ((Bda
->KeyboardStatus
&~0x20) | LocalLeds
);
1979 // Call into Legacy16 code to allow it to do any processing
1981 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1982 Regs
.X
.AX
= Legacy16SetKeyboardLeds
;
1985 Private
->LegacyBios
.FarCall86 (
1986 &Private
->LegacyBios
,
1987 Private
->Legacy16Table
->Compatibility16CallSegment
,
1988 Private
->Legacy16Table
->Compatibility16CallOffset
,
1999 Fill in the standard CMOS stuff prior to legacy Boot
2001 @param Private Legacy BIOS Instance data
2003 @retval EFI_SUCCESS It should always work.
2007 LegacyBiosCompleteStandardCmosBeforeBoot (
2008 IN LEGACY_BIOS_INSTANCE
*Private
2016 // Update CMOS locations
2018 // 12,19,1A - ignore as OS don't use them and there is no standard due
2019 // to large capacity drives
2020 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
2022 Bda
= (UINT8
)(*((UINT8
*)((UINTN
)0x410)) | BIT3
);
2025 // Force display enabled
2028 if ((Bda
& BIT0
) != 0) {
2033 // Check if 2.88MB floppy set
2035 if ((Bda
& (BIT7
| BIT6
)) != 0) {
2036 Floppy
= (UINT8
)(Floppy
| BIT1
);
2039 LegacyWriteStandardCmos (CMOS_10
, Floppy
);
2040 LegacyWriteStandardCmos (CMOS_14
, Bda
);
2043 // Force Status Register A to set rate selection bits and divider
2045 LegacyWriteStandardCmos (CMOS_0A
, 0x26);
2048 // redo memory size since it can change
2050 Size
= 15 * SIZE_1MB
;
2051 if (Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
< (15 * SIZE_1MB
)) {
2052 Size
= Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
>> 10;
2055 LegacyWriteStandardCmos (CMOS_17
, (UINT8
)(Size
& 0xFF));
2056 LegacyWriteStandardCmos (CMOS_30
, (UINT8
)(Size
& 0xFF));
2057 LegacyWriteStandardCmos (CMOS_18
, (UINT8
)(Size
>> 8));
2058 LegacyWriteStandardCmos (CMOS_31
, (UINT8
)(Size
>> 8));
2060 LegacyCalculateWriteStandardCmosChecksum ();
2066 Relocate this image under 4G memory for IPF.
2068 @param ImageHandle Handle of driver image.
2069 @param SystemTable Pointer to system table.
2071 @retval EFI_SUCCESS Image successfully relocated.
2072 @retval EFI_ABORTED Failed to relocate image.
2076 RelocateImageUnder4GIfNeeded (
2077 IN EFI_HANDLE ImageHandle
,
2078 IN EFI_SYSTEM_TABLE
*SystemTable