3 Copyright (c) 2006 - 2011, 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 Identify drive data must be updated to actual parameters before boot.
141 @param IdentifyDriveData ATA Identify Data
145 UpdateIdentifyDriveData (
146 IN UINT8
*IdentifyDriveData
152 @param Private Legacy BIOS Instance data
154 @retval EFI_SUCCESS Removable media not present
159 IN LEGACY_BIOS_INSTANCE
*Private
165 UINT8 LegacyInterrupts
[16];
166 EFI_LEGACY_IRQ_ROUTING_ENTRY
*RoutingTable
;
167 UINTN RoutingTableEntries
;
168 EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY
*IrqPriorityTable
;
169 UINTN NumberPriorityEntries
;
170 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
176 EFI_HANDLE
*HandleBuffer
;
177 EFI_ISA_IO_PROTOCOL
*IsaIo
;
182 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
183 LegacyBiosBuildSioData (Private
);
184 SetMem (LegacyInterrupts
, sizeof (LegacyInterrupts
), 0);
187 // Create list of legacy interrupts.
189 for (Index
= 0; Index
< 4; Index
++) {
190 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Serial
[Index
].Irq
;
193 for (Index
= 4; Index
< 7; Index
++) {
194 LegacyInterrupts
[Index
] = EfiToLegacy16BootTable
->SioData
.Parallel
[Index
- 4].Irq
;
197 LegacyInterrupts
[7] = EfiToLegacy16BootTable
->SioData
.Floppy
.Irq
;
200 // Get Legacy Hdd IRQs. If native mode treat as PCI
202 for (Index
= 0; Index
< 2; Index
++) {
203 HddIrq
= EfiToLegacy16BootTable
->HddInfo
[Index
].HddIrq
;
204 if ((HddIrq
!= 0) && ((HddIrq
== 15) || (HddIrq
== 14))) {
205 LegacyInterrupts
[Index
+ 8] = HddIrq
;
209 Private
->LegacyBiosPlatform
->GetRoutingTable (
210 Private
->LegacyBiosPlatform
,
211 (VOID
*) &RoutingTable
,
212 &RoutingTableEntries
,
215 (VOID
**) &IrqPriorityTable
,
216 &NumberPriorityEntries
219 // Remove legacy interrupts from the list of PCI interrupts available.
221 for (Index
= 0; Index
<= 0x0b; Index
++) {
222 for (Index1
= 0; Index1
<= NumberPriorityEntries
; Index1
++) {
223 if (LegacyInterrupts
[Index
] != 0) {
224 LegacyInt
= (UINT16
) (LegacyInt
| (1 << LegacyInterrupts
[Index
]));
225 if (LegacyInterrupts
[Index
] == IrqPriorityTable
[Index1
].Irq
) {
226 IrqPriorityTable
[Index1
].Used
= LEGACY_USED
;
232 Private
->Legacy8259
->GetMask (
241 // Set SIO interrupts and disable mouse. Let mouse driver
244 LegMask
= (UINT16
) ((LegMask
&~LegacyInt
) | 0x1000);
245 Private
->Legacy8259
->SetMask (
254 // Disable mouse in keyboard controller
257 Status
= gBS
->LocateHandleBuffer (
259 &gEfiIsaIoProtocolGuid
,
264 if (EFI_ERROR (Status
)) {
268 for (Index
= 0; Index
< HandleCount
; Index
++) {
269 Status
= gBS
->HandleProtocol (
271 &gEfiIsaIoProtocolGuid
,
274 ASSERT_EFI_ERROR (Status
);
275 IsaIo
->Io
.Write (IsaIo
, EfiIsaIoWidthUint8
, 0x64, 1, &Register
);
279 if (HandleBuffer
!= NULL
) {
280 FreePool (HandleBuffer
);
288 Identify drive data must be updated to actual parameters before boot.
289 This requires updating the checksum, if it exists.
291 @param IdentifyDriveData ATA Identify Data
292 @param Checksum checksum of the ATA Identify Data
294 @retval EFI_SUCCESS checksum calculated
295 @retval EFI_SECURITY_VIOLATION IdentifyData invalid
299 CalculateIdentifyDriveChecksum (
300 IN UINT8
*IdentifyDriveData
,
308 if (IdentifyDriveData
[510] != 0xA5) {
309 return EFI_SECURITY_VIOLATION
;
312 for (Index
= 0; Index
< 512; Index
++) {
313 LocalChecksum
= (UINT8
) (LocalChecksum
+ IdentifyDriveData
[Index
]);
316 *Checksum
= LocalChecksum
;
322 Identify drive data must be updated to actual parameters before boot.
324 @param IdentifyDriveData ATA Identify Data
329 UpdateIdentifyDriveData (
330 IN UINT8
*IdentifyDriveData
333 UINT16 NumberCylinders
;
335 UINT16 NumberSectorsTrack
;
336 UINT32 CapacityInSectors
;
337 UINT8 OriginalChecksum
;
340 ATAPI_IDENTIFY
*ReadInfo
;
343 // Status indicates if Integrity byte is correct. Checksum should be
346 ReadInfo
= (ATAPI_IDENTIFY
*) IdentifyDriveData
;
347 Status
= CalculateIdentifyDriveChecksum (IdentifyDriveData
, &OriginalChecksum
);
348 if (OriginalChecksum
!= 0) {
349 Status
= EFI_SECURITY_VIOLATION
;
352 // If NumberCylinders = 0 then do data(Controller present but don drive attached).
354 NumberCylinders
= ReadInfo
->Raw
[1];
355 if (NumberCylinders
!= 0) {
356 ReadInfo
->Raw
[54] = NumberCylinders
;
358 NumberHeads
= ReadInfo
->Raw
[3];
359 ReadInfo
->Raw
[55] = NumberHeads
;
361 NumberSectorsTrack
= ReadInfo
->Raw
[6];
362 ReadInfo
->Raw
[56] = NumberSectorsTrack
;
365 // Copy Multisector info and set valid bit.
367 ReadInfo
->Raw
[59] = (UINT16
) (ReadInfo
->Raw
[47] + 0x100);
368 CapacityInSectors
= (UINT32
) ((UINT32
) (NumberCylinders
) * (UINT32
) (NumberHeads
) * (UINT32
) (NumberSectorsTrack
));
369 ReadInfo
->Raw
[57] = (UINT16
) (CapacityInSectors
>> 16);
370 ReadInfo
->Raw
[58] = (UINT16
) (CapacityInSectors
& 0xffff);
371 if (Status
== EFI_SUCCESS
) {
373 // Forece checksum byte to 0 and get new checksum.
375 ReadInfo
->Raw
[255] &= 0xff;
376 CalculateIdentifyDriveChecksum (IdentifyDriveData
, &FinalChecksum
);
379 // Force new checksum such that sum is 0.
381 FinalChecksum
= (UINT8
) ((UINT8
)0 - FinalChecksum
);
382 ReadInfo
->Raw
[255] = (UINT16
) (ReadInfo
->Raw
[255] | (FinalChecksum
<< 8));
388 Identify drive data must be updated to actual parameters before boot.
391 @param Private Legacy BIOS Instance data
396 UpdateAllIdentifyDriveData (
397 IN LEGACY_BIOS_INSTANCE
*Private
403 HddInfo
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
[0];
405 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
407 // Each controller can have 2 devices. Update for each device
409 if ((HddInfo
[Index
].Status
& HDD_MASTER_IDE
) != 0) {
410 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[0].Raw
[0]));
413 if ((HddInfo
[Index
].Status
& HDD_SLAVE_IDE
) != 0) {
414 UpdateIdentifyDriveData ((UINT8
*) (&HddInfo
[Index
].IdentifyDrive
[1].Raw
[0]));
420 Enable ide controller. This gets disabled when LegacyBoot.c is about
421 to run the Option ROMs.
423 @param Private Legacy BIOS Instance data
428 EnableIdeController (
429 IN LEGACY_BIOS_INSTANCE
*Private
432 EFI_PCI_IO_PROTOCOL
*PciIo
;
434 EFI_HANDLE IdeController
;
437 EFI_HANDLE
*HandleBuffer
;
439 Status
= Private
->LegacyBiosPlatform
->GetPlatformHandle (
440 Private
->LegacyBiosPlatform
,
441 EfiGetPlatformIdeHandle
,
447 if (!EFI_ERROR (Status
)) {
448 IdeController
= HandleBuffer
[0];
449 Status
= gBS
->HandleProtocol (
451 &gEfiPciIoProtocolGuid
,
455 if (!EFI_ERROR (Status
)) {
456 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint8
, 0x04, 1, &ByteBuffer
);
463 Enable ide controller. This gets disabled when LegacyBoot.c is about
464 to run the Option ROMs.
466 @param Private Legacy BIOS Instance data
471 EnableAllControllers (
472 IN LEGACY_BIOS_INSTANCE
*Private
476 EFI_HANDLE
*HandleBuffer
;
478 EFI_PCI_IO_PROTOCOL
*PciIo
;
479 PCI_TYPE01 PciConfigHeader
;
485 EnableIdeController (Private
);
488 // Assumption is table is built from low bus to high bus numbers.
490 Status
= gBS
->LocateHandleBuffer (
492 &gEfiPciIoProtocolGuid
,
497 ASSERT_EFI_ERROR (Status
);
499 for (Index
= 0; Index
< HandleCount
; Index
++) {
500 Status
= gBS
->HandleProtocol (
502 &gEfiPciIoProtocolGuid
,
505 ASSERT_EFI_ERROR (Status
);
511 sizeof (PciConfigHeader
) / sizeof (UINT32
),
516 // We do not enable PPB here. This is for HotPlug Consideration.
517 // The Platform HotPlug Driver is responsible for Padding enough hot plug
518 // resources. It is also responsible for enable this bridge. If it
519 // does not pad it. It will cause some early Windows fail to installation.
520 // If the platform driver does not pad resource for PPB, PPB should be in
521 // un-enabled state to let Windows know that this PPB is not configured by
522 // BIOS. So Windows will allocate default resource for PPB.
524 // The reason for why we enable the command register is:
525 // The CSM will use the IO bar to detect some IRQ status, if the command
526 // is disabled, the IO resource will be out of scope.
528 // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
529 // comes up, the handle will check the IO space to identify is the
530 // controller generated the IRQ source.
531 // If the IO command is not enabled, the IRQ handler will has wrong
532 // information. It will cause IRQ storm when the correctly IRQ handler fails
535 if (!(IS_PCI_VGA (&PciConfigHeader
) ||
536 IS_PCI_OLD_VGA (&PciConfigHeader
) ||
537 IS_PCI_IDE (&PciConfigHeader
) ||
538 IS_PCI_P2P (&PciConfigHeader
) ||
539 IS_PCI_P2P_SUB (&PciConfigHeader
) ||
540 IS_PCI_LPC (&PciConfigHeader
) )) {
542 PciConfigHeader
.Hdr
.Command
|= 0x1f;
544 PciIo
->Pci
.Write (PciIo
, EfiPciIoWidthUint32
, 4, 1, &PciConfigHeader
.Hdr
.Command
);
550 The following routines are identical in operation, so combine
552 EfiGetPlatformBinaryGetMpTable
553 EfiGetPlatformBinaryGetOemIntData
554 EfiGetPlatformBinaryGetOem32Data
555 EfiGetPlatformBinaryGetOem16Data
557 @param This Protocol instance pointer.
558 @param Id Table/Data identifier
560 @retval EFI_SUCCESS Success
561 @retval EFI_INVALID_PARAMETER Invalid ID
562 @retval EFI_OUT_OF_RESOURCES no resource to get data or table
566 LegacyGetDataOrTable (
567 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
568 IN EFI_GET_PLATFORM_INFO_MODE Id
577 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
578 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
579 EFI_IA32_REGISTER_SET Regs
;
580 LEGACY_BIOS_INSTANCE
*Private
;
582 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
584 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
585 Legacy16Table
= Private
->Legacy16Table
;
588 // Phase 1 - get an address allocated in 16-bit code
592 case EfiGetPlatformBinaryMpTable
:
593 case EfiGetPlatformBinaryOemIntData
:
594 case EfiGetPlatformBinaryOem32Data
:
595 case EfiGetPlatformBinaryOem16Data
:
597 Status
= LegacyBiosPlatform
->GetPlatformInfo (
607 DEBUG ((EFI_D_INFO
, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN
)Id
, Status
));
608 DEBUG ((EFI_D_INFO
, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN
)Table
, (UINTN
)TableSize
, (UINTN
)Location
, (UINTN
)Alignment
));
614 return EFI_INVALID_PARAMETER
;
618 if (EFI_ERROR (Status
)) {
622 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
623 Regs
.X
.AX
= Legacy16GetTableAddress
;
624 Regs
.X
.CX
= (UINT16
) TableSize
;
625 Regs
.X
.BX
= (UINT16
) Location
;
626 Regs
.X
.DX
= (UINT16
) Alignment
;
627 Private
->LegacyBios
.FarCall86 (
629 Private
->Legacy16CallSegment
,
630 Private
->Legacy16CallOffset
,
636 if (Regs
.X
.AX
!= 0) {
637 DEBUG ((EFI_D_ERROR
, "Table ID %x length insufficient\n", Id
));
638 return EFI_OUT_OF_RESOURCES
;
644 // Phase 2 Call routine second time with address to allow address adjustment
646 Status
= LegacyBiosPlatform
->GetPlatformInfo (
657 case EfiGetPlatformBinaryMpTable
:
659 Legacy16Table
->MpTablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
660 Legacy16Table
->MpTableLength
= (UINT32
)TableSize
;
661 DEBUG ((EFI_D_INFO
, "MP table in legacy region - %x\n", (UINTN
)Legacy16Table
->MpTablePtr
));
665 case EfiGetPlatformBinaryOemIntData
:
668 Legacy16Table
->OemIntSegment
= Regs
.X
.DS
;
669 Legacy16Table
->OemIntOffset
= Regs
.X
.BX
;
670 DEBUG ((EFI_D_INFO
, "OemInt table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->OemIntSegment
, (UINTN
)Legacy16Table
->OemIntOffset
));
674 case EfiGetPlatformBinaryOem32Data
:
676 Legacy16Table
->Oem32Segment
= Regs
.X
.DS
;
677 Legacy16Table
->Oem32Offset
= Regs
.X
.BX
;
678 DEBUG ((EFI_D_INFO
, "Oem32 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem32Segment
, (UINTN
)Legacy16Table
->Oem32Offset
));
682 case EfiGetPlatformBinaryOem16Data
:
685 // Legacy16Table->Oem16Segment = Regs.X.DS;
686 // Legacy16Table->Oem16Offset = Regs.X.BX;
687 DEBUG ((EFI_D_INFO
, "Oem16 table in legacy region - %04x:%04x\n", (UINTN
)Legacy16Table
->Oem16Segment
, (UINTN
)Legacy16Table
->Oem16Offset
));
693 return EFI_INVALID_PARAMETER
;
697 if (EFI_ERROR (Status
)) {
701 // Phase 3 Copy table to final location
703 TablePtr
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
706 (VOID
*) (UINTN
)TablePtr
,
716 Assign drive number to legacy HDD drives prior to booting an EFI
717 aware OS so the OS can access drives without an EFI driver.
718 Note: BBS compliant drives ARE NOT available until this call by
721 @param This Protocol instance pointer.
723 @retval EFI_SUCCESS Drive numbers assigned
728 IN EFI_LEGACY_BIOS_PROTOCOL
*This
732 LEGACY_BIOS_INSTANCE
*Private
;
733 EFI_IA32_REGISTER_SET Regs
;
734 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
735 EFI_LEGACY_BIOS_PLATFORM_PROTOCOL
*LegacyBiosPlatform
;
739 HDD_INFO
*LocalHddInfo
;
741 EFI_COMPATIBILITY16_TABLE
*Legacy16Table
;
745 BBS_TABLE
*LocalBbsTable
;
746 UINT32
*BaseVectorMaster
;
749 EFI_HANDLE IdeController
;
751 EFI_HANDLE
*HandleBuffer
;
756 EFI_TIMER_ARCH_PROTOCOL
*Timer
;
762 LocalBbsTable
= NULL
;
765 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
767 DEBUG ((EFI_D_ERROR
, "Start of legacy boot\n"));
770 Legacy16Table
= Private
->Legacy16Table
;
771 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
772 HddInfo
= &EfiToLegacy16BootTable
->HddInfo
[0];
774 LegacyBiosPlatform
= Private
->LegacyBiosPlatform
;
776 EfiToLegacy16BootTable
->MajorVersion
= EFI_TO_LEGACY_MAJOR_VERSION
;
777 EfiToLegacy16BootTable
->MinorVersion
= EFI_TO_LEGACY_MINOR_VERSION
;
780 // Before starting the Legacy boot check the system ticker.
782 Status
= gBS
->LocateProtocol (
783 &gEfiTimerArchProtocolGuid
,
787 if (EFI_ERROR (Status
)) {
791 Status
= Timer
->GetTimerPeriod (
795 if (EFI_ERROR (Status
)) {
799 if (TimerPeriod
!= DEFAULT_LAGACY_TIMER_TICK_DURATION
) {
800 Status
= Timer
->SetTimerPeriod (
802 DEFAULT_LAGACY_TIMER_TICK_DURATION
804 if (EFI_ERROR (Status
)) {
810 // If booting to a legacy OS then force HDD drives to the appropriate
811 // boot mode by calling GetIdeHandle.
812 // A reconnect -r can force all HDDs back to native mode.
814 IdeController
= NULL
;
815 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
816 Status
= LegacyBiosPlatform
->GetPlatformHandle (
817 Private
->LegacyBiosPlatform
,
818 EfiGetPlatformIdeHandle
,
824 if (!EFI_ERROR (Status
)) {
825 IdeController
= HandleBuffer
[0];
829 // Unlock the Legacy BIOS region
831 Private
->LegacyRegion
->UnLock (
832 Private
->LegacyRegion
,
839 // Reconstruct the Legacy16 boot memory map
841 LegacyBiosBuildE820 (Private
, &CopySize
);
842 if (CopySize
> Private
->Legacy16Table
->E820Length
) {
843 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
844 Regs
.X
.AX
= Legacy16GetTableAddress
;
845 Regs
.X
.CX
= (UINT16
) CopySize
;
846 Private
->LegacyBios
.FarCall86 (
847 &Private
->LegacyBios
,
848 Private
->Legacy16Table
->Compatibility16CallSegment
,
849 Private
->Legacy16Table
->Compatibility16CallOffset
,
855 Private
->Legacy16Table
->E820Pointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
856 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
857 if (Regs
.X
.AX
!= 0) {
858 DEBUG ((EFI_D_ERROR
, "Legacy16 E820 length insufficient\n"));
861 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
868 (VOID
*)(UINTN
) Private
->Legacy16Table
->E820Pointer
,
872 Private
->Legacy16Table
->E820Length
= (UINT32
) CopySize
;
875 // Get SMBIOS and ACPI table pointers
878 EfiGetSystemConfigurationTable (
879 &gEfiSmbiosTableGuid
,
883 // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
885 if (SmbiosTable
== NULL
) {
886 DEBUG ((EFI_D_INFO
, "Smbios table is not found!\n"));
888 EfiToLegacy16BootTable
->SmbiosTable
= (UINT32
)(UINTN
)SmbiosTable
;
891 Status
= EfiGetSystemConfigurationTable (
892 &gEfiAcpi20TableGuid
,
895 if (EFI_ERROR (Status
)) {
896 Status
= EfiGetSystemConfigurationTable (
897 &gEfiAcpi10TableGuid
,
902 // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
904 if (AcpiTable
== NULL
) {
905 DEBUG ((EFI_D_INFO
, "ACPI table is not found!\n"));
907 EfiToLegacy16BootTable
->AcpiTable
= (UINT32
)(UINTN
)AcpiTable
;
910 // Get RSD Ptr table rev at offset 15 decimal
911 // Rev = 0 Length is 20 decimal
912 // Rev != 0 Length is UINT32 at offset 20 decimal
914 if (AcpiTable
!= NULL
) {
917 if (*((UINT8
*) AcpiPtr
+ 15) == 0) {
920 AcpiPtr
= ((UINT8
*) AcpiPtr
+ 20);
921 CopySize
= (*(UINT32
*) AcpiPtr
);
925 (VOID
*)(UINTN
) Private
->Legacy16Table
->AcpiRsdPtrPointer
,
931 // Make sure all PCI Interrupt Line register are programmed to match 8259
933 PciProgramAllInterruptLineRegisters (Private
);
936 // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
939 Private
->LegacyRegion
->UnLock (
940 Private
->LegacyRegion
,
942 Private
->LegacyBiosImageSize
,
947 // Configure Legacy Device Magic
949 // Only do this code if booting legacy OS
951 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
952 UpdateSioData (Private
);
955 // Setup BDA and EBDA standard areas before Legacy Boot
957 LegacyBiosCompleteBdaBeforeBoot (Private
);
958 LegacyBiosCompleteStandardCmosBeforeBoot (Private
);
961 // We must build IDE data, if it hasn't been done, before PciShadowRoms
962 // to insure EFI drivers are connected.
964 LegacyBiosBuildIdeData (Private
, &HddInfo
, 1);
965 UpdateAllIdentifyDriveData (Private
);
968 // Clear IO BAR, if IDE controller in legacy mode.
970 InitLegacyIdeController (IdeController
);
973 // Generate number of ticks since midnight for BDA. DOS requires this
974 // for its time. We have to make assumptions as to how long following
975 // code takes since after PciShadowRoms PciIo is gone. Place result in
978 // Adjust value by 1 second.
980 gRT
->GetTime (&BootTime
, NULL
);
981 LocalTime
= BootTime
.Hour
* 3600 + BootTime
.Minute
* 60 + BootTime
.Second
;
985 // Multiply result by 18.2 for number of ticks since midnight.
986 // Use 182/10 to avoid floating point math.
988 LocalTime
= (LocalTime
* 182) / 10;
989 BdaPtr
= (UINT32
*) (UINTN
)0x46C;
993 // Shadow PCI ROMs. We must do this near the end since this will kick
994 // of Native EFI drivers that may be needed to collect info for Legacy16
996 // WARNING: PciIo is gone after this call.
998 PciShadowRoms (Private
);
1001 // Shadow PXE base code, BIS etc.
1003 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xc0000, 0x40000, &Granularity
);
1004 ShadowAddress
= Private
->OptionRom
;
1005 Private
->LegacyBiosPlatform
->PlatformHooks (
1006 Private
->LegacyBiosPlatform
,
1007 EfiPlatformHookShadowServiceRoms
,
1014 Private
->OptionRom
= (UINT32
)ShadowAddress
;
1016 // Register Legacy SMI Handler
1018 LegacyBiosPlatform
->SmmInit (
1020 EfiToLegacy16BootTable
1024 // Let platform code know the boot options
1026 LegacyBiosGetBbsInfo (
1034 PrintBbsTable (LocalBbsTable
);
1035 PrintHddInfo (LocalHddInfo
);
1038 // If drive wasn't spun up then BuildIdeData may have found new drives.
1039 // Need to update BBS boot priority.
1041 for (Index
= 0; Index
< MAX_IDE_CONTROLLER
; Index
++) {
1042 if ((LocalHddInfo
[Index
].IdentifyDrive
[0].Raw
[0] != 0) &&
1043 (LocalBbsTable
[2 * Index
+ 1].BootPriority
== BBS_IGNORE_ENTRY
)
1045 LocalBbsTable
[2 * Index
+ 1].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1048 if ((LocalHddInfo
[Index
].IdentifyDrive
[1].Raw
[0] != 0) &&
1049 (LocalBbsTable
[2 * Index
+ 2].BootPriority
== BBS_IGNORE_ENTRY
)
1051 LocalBbsTable
[2 * Index
+ 2].BootPriority
= BBS_UNPRIORITIZED_ENTRY
;
1055 Private
->LegacyRegion
->UnLock (
1056 Private
->LegacyRegion
,
1062 LegacyBiosPlatform
->PrepareToBoot (
1068 (VOID
*) &Private
->IntThunk
->EfiToLegacy16BootTable
1072 // If no boot device return to BDS
1074 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1075 for (Index
= 0; Index
< BbsCount
; Index
++){
1076 if ((LocalBbsTable
[Index
].BootPriority
!= BBS_DO_NOT_BOOT_FROM
) &&
1077 (LocalBbsTable
[Index
].BootPriority
!= BBS_UNPRIORITIZED_ENTRY
) &&
1078 (LocalBbsTable
[Index
].BootPriority
!= BBS_IGNORE_ENTRY
)) {
1082 if (Index
== BbsCount
) {
1083 return EFI_DEVICE_ERROR
;
1087 // Let the Legacy16 code know the device path type for legacy boot
1089 EfiToLegacy16BootTable
->DevicePathType
= mBbsDevicePathPtr
->DeviceType
;
1092 // Copy MP table, if it exists.
1094 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryMpTable
);
1096 if (!Private
->LegacyBootEntered
) {
1098 // Copy OEM INT Data, if it exists. Note: This code treats any data
1099 // as a bag of bits and knows nothing of the contents nor cares.
1100 // Contents are IBV specific.
1102 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOemIntData
);
1105 // Copy OEM16 Data, if it exists.Note: This code treats any data
1106 // as a bag of bits and knows nothing of the contents nor cares.
1107 // Contents are IBV specific.
1109 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem16Data
);
1112 // Copy OEM32 Data, if it exists.Note: This code treats any data
1113 // as a bag of bits and knows nothing of the contents nor cares.
1114 // Contents are IBV specific.
1116 LegacyGetDataOrTable (This
, EfiGetPlatformBinaryOem32Data
);
1120 // Call into Legacy16 code to prepare for INT 19h
1122 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1123 Regs
.X
.AX
= Legacy16PrepareToBoot
;
1126 // Pass in handoff data
1128 Regs
.X
.ES
= EFI_SEGMENT ((UINTN
)EfiToLegacy16BootTable
);
1129 Regs
.X
.BX
= EFI_OFFSET ((UINTN
)EfiToLegacy16BootTable
);
1131 Private
->LegacyBios
.FarCall86 (
1133 Private
->Legacy16CallSegment
,
1134 Private
->Legacy16CallOffset
,
1140 if (Regs
.X
.AX
!= 0) {
1141 return EFI_DEVICE_ERROR
;
1144 // Lock the Legacy BIOS region
1146 Private
->LegacyRegion
->Lock (
1147 Private
->LegacyRegion
,
1153 // Lock attributes of the Legacy Region if chipset supports
1155 Private
->LegacyRegion
->BootLock (
1156 Private
->LegacyRegion
,
1163 // Call into Legacy16 code to do the INT 19h
1165 EnableAllControllers (Private
);
1166 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1168 // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
1170 EfiSignalEventLegacyBoot ();
1171 DEBUG ((EFI_D_INFO
, "Legacy INT19 Boot...\n"));
1173 // Raise TPL to high level to disable CPU interrupts
1175 gBS
->RaiseTPL (TPL_HIGH_LEVEL
);
1178 // Put the 8259 into its legacy mode by reprogramming the vector bases
1180 Private
->Legacy8259
->SetVectorBase (Private
->Legacy8259
, LEGACY_MODE_BASE_VECTOR_MASTER
, LEGACY_MODE_BASE_VECTOR_SLAVE
);
1183 // The original PC used INT8-F for master PIC. Since these mapped over
1184 // processor exceptions TIANO moved the master PIC to INT68-6F.
1185 // We need to set these back to the Legacy16 unexpected interrupt(saved
1186 // in LegacyBios.c) since some OS see that these have values different from
1187 // what is expected and invoke them. Since the legacy OS corrupts EFI
1188 // memory, there is no handler for these interrupts and OS blows up.
1190 // We need to save the TIANO values for the rare case that the Legacy16
1191 // code cannot boot but knows memory hasn't been destroyed.
1193 // To compound the problem, video takes over one of these INTS and must be
1195 // @bug - determine if video hooks INT(in which case we must find new
1196 // set of TIANO vectors) or takes it over.
1199 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1200 for (Index
= 0; Index
< 8; Index
++) {
1201 Private
->ThunkSavedInt
[Index
] = BaseVectorMaster
[Index
];
1202 if (Private
->ThunkSeg
== (UINT16
) (BaseVectorMaster
[Index
] >> 16)) {
1203 BaseVectorMaster
[Index
] = (UINT32
) (Private
->BiosUnexpectedInt
);
1207 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1208 Regs
.X
.AX
= Legacy16Boot
;
1210 Private
->LegacyBios
.FarCall86 (
1212 Private
->Legacy16CallSegment
,
1213 Private
->Legacy16CallOffset
,
1219 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1220 for (Index
= 0; Index
< 8; Index
++) {
1221 BaseVectorMaster
[Index
] = Private
->ThunkSavedInt
[Index
];
1224 Private
->LegacyBootEntered
= TRUE
;
1225 if ((mBootMode
== BOOT_LEGACY_OS
) || (mBootMode
== BOOT_UNCONVENTIONAL_DEVICE
)) {
1227 // Should never return unless never passed control to 0:7c00(first stage
1228 // OS loader) and only then if no bootable device found.
1230 return EFI_DEVICE_ERROR
;
1233 // If boot to EFI then expect to return to caller
1241 Assign drive number to legacy HDD drives prior to booting an EFI
1242 aware OS so the OS can access drives without an EFI driver.
1243 Note: BBS compliant drives ARE NOT available until this call by
1244 either shell or EFI.
1246 @param This Protocol instance pointer.
1247 @param BbsCount Number of BBS_TABLE structures
1248 @param BbsTable List BBS entries
1250 @retval EFI_SUCCESS Drive numbers assigned
1255 LegacyBiosPrepareToBootEfi (
1256 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1257 OUT UINT16
*BbsCount
,
1258 OUT BBS_TABLE
**BbsTable
1262 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1263 LEGACY_BIOS_INSTANCE
*Private
;
1265 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1266 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1267 mBootMode
= BOOT_EFI_OS
;
1268 mBbsDevicePathPtr
= NULL
;
1269 Status
= GenericLegacyBoot (This
);
1270 *BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1271 *BbsCount
= (UINT16
) (sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
));
1276 To boot from an unconventional device like parties and/or execute HDD diagnostics.
1278 @param This Protocol instance pointer.
1279 @param Attributes How to interpret the other input parameters
1280 @param BbsEntry The 0-based index into the BbsTable for the parent
1282 @param BeerData Pointer to the 128 bytes of ram BEER data.
1283 @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
1284 caller must provide a pointer to the specific Service
1285 Area and not the start all Service Areas.
1287 @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
1292 LegacyBiosBootUnconventionalDevice (
1293 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1294 IN UDC_ATTRIBUTES Attributes
,
1297 IN VOID
*ServiceAreaData
1301 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
1302 LEGACY_BIOS_INSTANCE
*Private
;
1305 UINT16 BootPriority
;
1306 BBS_TABLE
*BbsTable
;
1309 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1310 mBootMode
= BOOT_UNCONVENTIONAL_DEVICE
;
1311 mBbsDevicePathPtr
= &mBbsDevicePathNode
;
1312 mAttributes
= Attributes
;
1313 mBbsEntry
= BbsEntry
;
1314 mBeerData
= BeerData
, mServiceAreaData
= ServiceAreaData
;
1316 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
1319 // Do input parameter checking
1321 if ((Attributes
.DirectoryServiceValidity
== 0) &&
1322 (Attributes
.RabcaUsedFlag
== 0) &&
1323 (Attributes
.ExecuteHddDiagnosticsFlag
== 0)
1325 return EFI_INVALID_PARAMETER
;
1328 if (((Attributes
.DirectoryServiceValidity
!= 0) && (ServiceAreaData
== NULL
)) ||
1329 (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
) != 0) && (BeerData
== NULL
))
1331 return EFI_INVALID_PARAMETER
;
1334 UcdTable
= (UD_TABLE
*) AllocatePool (
1337 if (NULL
== UcdTable
) {
1338 return EFI_OUT_OF_RESOURCES
;
1341 EfiToLegacy16BootTable
->UnconventionalDeviceTable
= (UINT32
)(UINTN
)UcdTable
;
1342 UcdTable
->Attributes
= Attributes
;
1343 UcdTable
->BbsTableEntryNumberForParentDevice
= (UINT8
) BbsEntry
;
1345 // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
1346 // to assign drive numbers but bot boot from. Only newly created entries
1349 BbsTable
= (BBS_TABLE
*)(UINTN
)EfiToLegacy16BootTable
->BbsTable
;
1350 for (Index
= 0; Index
< EfiToLegacy16BootTable
->NumberBbsEntries
; Index
++) {
1351 BbsTable
[Index
].BootPriority
= BBS_DO_NOT_BOOT_FROM
;
1354 // If parent is onboard IDE then assign controller & device number
1357 if (BbsEntry
< MAX_IDE_CONTROLLER
* 2) {
1358 UcdTable
->DeviceNumber
= (UINT8
) ((BbsEntry
- 1) % 2);
1361 if (BeerData
!= NULL
) {
1363 (VOID
*) UcdTable
->BeerData
,
1369 if (ServiceAreaData
!= NULL
) {
1371 (VOID
*) UcdTable
->ServiceAreaData
,
1377 // For each new entry do the following:
1378 // 1. Increment current number of BBS entries
1379 // 2. Copy parent entry to new entry.
1380 // 3. Zero out BootHandler Offset & segment
1381 // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
1382 // and Floppy(0x01) for PARTIES boot.
1383 // 5. Assign new priority.
1385 if ((Attributes
.ExecuteHddDiagnosticsFlag
) != 0) {
1386 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1389 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1390 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1394 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1395 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1396 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x80;
1398 UcdTable
->BbsTableEntryNumberForHddDiag
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1400 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1404 // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
1406 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_BEV
;
1409 if (((Attributes
.DirectoryServiceValidity
| Attributes
.RabcaUsedFlag
)) != 0) {
1410 EfiToLegacy16BootTable
->NumberBbsEntries
+= 1;
1412 (VOID
*) &BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
,
1413 (VOID
*) &BbsTable
[BbsEntry
].BootPriority
,
1417 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerOffset
= 0;
1418 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootHandlerSegment
= 0;
1419 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].DeviceType
= 0x01;
1420 UcdTable
->BbsTableEntryNumberForBoot
= (UINT8
) (EfiToLegacy16BootTable
->NumberBbsEntries
- 1);
1421 BbsTable
[EfiToLegacy16BootTable
->NumberBbsEntries
].BootPriority
= BootPriority
;
1424 // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
1426 mBbsDevicePathNode
.DeviceType
= BBS_TYPE_FLOPPY
;
1429 // Build the BBS Device Path for this boot selection
1431 mBbsDevicePathNode
.Header
.Type
= BBS_DEVICE_PATH
;
1432 mBbsDevicePathNode
.Header
.SubType
= BBS_BBS_DP
;
1433 SetDevicePathNodeLength (&mBbsDevicePathNode
.Header
, sizeof (BBS_BBS_DEVICE_PATH
));
1434 mBbsDevicePathNode
.StatusFlag
= 0;
1435 mBbsDevicePathNode
.String
[0] = 0;
1437 Status
= GenericLegacyBoot (This
);
1442 Attempt to legacy boot the BootOption. If the EFI contexted has been
1443 compromised this function will not return.
1445 @param This Protocol instance pointer.
1446 @param BbsDevicePath EFI Device Path from BootXXXX variable.
1447 @param LoadOptionsSize Size of LoadOption in size.
1448 @param LoadOptions LoadOption from BootXXXX variable
1450 @retval EFI_SUCCESS Removable media not present
1455 LegacyBiosLegacyBoot (
1456 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1457 IN BBS_BBS_DEVICE_PATH
*BbsDevicePath
,
1458 IN UINT32 LoadOptionsSize
,
1459 IN VOID
*LoadOptions
1464 mBbsDevicePathPtr
= BbsDevicePath
;
1465 mLoadOptionsSize
= LoadOptionsSize
;
1466 mLoadOptions
= LoadOptions
;
1467 mBootMode
= BOOT_LEGACY_OS
;
1468 Status
= GenericLegacyBoot (This
);
1474 Convert EFI Memory Type to E820 Memory Type.
1476 @param Type EFI Memory Type
1478 @return ACPI Memory Type for EFI Memory Type
1481 EFI_ACPI_MEMORY_TYPE
1482 EfiMemoryTypeToE820Type (
1489 case EfiBootServicesCode
:
1490 case EfiBootServicesData
:
1491 case EfiConventionalMemory
:
1492 case EfiRuntimeServicesCode
:
1493 case EfiRuntimeServicesData
:
1494 return EfiAcpiAddressRangeMemory
;
1496 case EfiACPIReclaimMemory
:
1497 return EfiAcpiAddressRangeACPI
;
1499 case EfiACPIMemoryNVS
:
1500 return EfiAcpiAddressRangeNVS
;
1503 // All other types map to reserved.
1504 // Adding the code just waists FLASH space.
1506 // case EfiReservedMemoryType:
1507 // case EfiUnusableMemory:
1508 // case EfiMemoryMappedIO:
1509 // case EfiMemoryMappedIOPortSpace:
1513 return EfiAcpiAddressRangeReserved
;
1518 Build the E820 table.
1520 @param Private Legacy BIOS Instance data
1521 @param Size Size of E820 Table
1523 @retval EFI_SUCCESS It should always work.
1527 LegacyBiosBuildE820 (
1528 IN LEGACY_BIOS_INSTANCE
*Private
,
1533 EFI_E820_ENTRY64
*E820Table
;
1534 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMap
;
1535 EFI_MEMORY_DESCRIPTOR
*EfiMemoryMapEnd
;
1536 EFI_MEMORY_DESCRIPTOR
*EfiEntry
;
1537 EFI_MEMORY_DESCRIPTOR
*NextEfiEntry
;
1538 EFI_MEMORY_DESCRIPTOR TempEfiEntry
;
1539 UINTN EfiMemoryMapSize
;
1541 UINTN EfiDescriptorSize
;
1542 UINT32 EfiDescriptorVersion
;
1544 EFI_PEI_HOB_POINTERS Hob
;
1545 EFI_HOB_RESOURCE_DESCRIPTOR
*ResourceHob
;
1548 UINTN TempNextIndex
;
1549 EFI_E820_ENTRY64 TempE820
;
1550 EFI_ACPI_MEMORY_TYPE TempType
;
1551 BOOLEAN ChangedFlag
;
1553 UINT64 MemoryBlockLength
;
1555 E820Table
= (EFI_E820_ENTRY64
*) Private
->E820Table
;
1558 // Get the EFI memory map.
1560 EfiMemoryMapSize
= 0;
1561 EfiMemoryMap
= NULL
;
1562 Status
= gBS
->GetMemoryMap (
1567 &EfiDescriptorVersion
1569 ASSERT (Status
== EFI_BUFFER_TOO_SMALL
);
1573 // Use size returned back plus 1 descriptor for the AllocatePool.
1574 // We don't just multiply by 2 since the "for" loop below terminates on
1575 // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
1576 // we process bogus entries and create bogus E820 entries.
1578 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*) AllocatePool (EfiMemoryMapSize
);
1579 ASSERT (EfiMemoryMap
!= NULL
);
1580 Status
= gBS
->GetMemoryMap (
1585 &EfiDescriptorVersion
1587 if (EFI_ERROR (Status
)) {
1588 FreePool (EfiMemoryMap
);
1590 } while (Status
== EFI_BUFFER_TOO_SMALL
);
1592 ASSERT_EFI_ERROR (Status
);
1595 // Punch in the E820 table for memory less than 1 MB.
1596 // Assume ZeroMem () has been done on data structure.
1599 // First entry is 0 to (640k - EBDA)
1601 E820Table
[0].BaseAddr
= 0;
1602 E820Table
[0].Length
= (UINT64
) ((*(UINT16
*) (UINTN
)0x40E) << 4);
1603 E820Table
[0].Type
= EfiAcpiAddressRangeMemory
;
1606 // Second entry is (640k - EBDA) to 640k
1608 E820Table
[1].BaseAddr
= E820Table
[0].Length
;
1609 E820Table
[1].Length
= (UINT64
) ((640 * 1024) - E820Table
[0].Length
);
1610 E820Table
[1].Type
= EfiAcpiAddressRangeReserved
;
1613 // Third Entry is legacy BIOS
1614 // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
1615 // to page in memory under 1MB.
1616 // Omit region from 0xE0000 to start of BIOS, if any. This can be
1617 // used for a multiple reasons including OPROMS.
1621 // The CSM binary image size is not the actually size that CSM binary used,
1622 // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
1624 E820Table
[2].BaseAddr
= 0xE0000;
1625 E820Table
[2].Length
= 0x20000;
1626 E820Table
[2].Type
= EfiAcpiAddressRangeReserved
;
1631 // Process the EFI map to produce E820 map;
1635 // Sort memory map from low to high
1637 EfiEntry
= EfiMemoryMap
;
1638 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1639 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1640 while (EfiEntry
< EfiMemoryMapEnd
) {
1641 while (NextEfiEntry
< EfiMemoryMapEnd
) {
1642 if (EfiEntry
->PhysicalStart
> NextEfiEntry
->PhysicalStart
) {
1643 CopyMem (&TempEfiEntry
, EfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1644 CopyMem (EfiEntry
, NextEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1645 CopyMem (NextEfiEntry
, &TempEfiEntry
, sizeof (EFI_MEMORY_DESCRIPTOR
));
1648 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (NextEfiEntry
, EfiDescriptorSize
);
1651 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1652 NextEfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1655 EfiEntry
= EfiMemoryMap
;
1656 EfiMemoryMapEnd
= (EFI_MEMORY_DESCRIPTOR
*) ((UINT8
*) EfiMemoryMap
+ EfiMemoryMapSize
);
1657 for (Index
= Above1MIndex
; (EfiEntry
< EfiMemoryMapEnd
) && (Index
< EFI_MAX_E820_ENTRY
- 1); ) {
1658 MemoryBlockLength
= (UINT64
) (LShiftU64 (EfiEntry
->NumberOfPages
, 12));
1659 if ((EfiEntry
->PhysicalStart
+ MemoryBlockLength
) < 0x100000) {
1661 // Skip the memory block is under 1MB
1664 if (EfiEntry
->PhysicalStart
< 0x100000) {
1666 // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
1668 MemoryBlockLength
-= 0x100000 - EfiEntry
->PhysicalStart
;
1669 EfiEntry
->PhysicalStart
= 0x100000;
1673 // Convert memory type to E820 type
1675 TempType
= EfiMemoryTypeToE820Type (EfiEntry
->Type
);
1677 if ((E820Table
[Index
].Type
== TempType
) && (EfiEntry
->PhysicalStart
== (E820Table
[Index
].BaseAddr
+ E820Table
[Index
].Length
))) {
1679 // Grow an existing entry
1681 E820Table
[Index
].Length
+= MemoryBlockLength
;
1687 E820Table
[Index
].BaseAddr
= EfiEntry
->PhysicalStart
;
1688 E820Table
[Index
].Length
= MemoryBlockLength
;
1689 E820Table
[Index
].Type
= TempType
;
1692 EfiEntry
= NEXT_MEMORY_DESCRIPTOR (EfiEntry
, EfiDescriptorSize
);
1695 FreePool (EfiMemoryMap
);
1698 // Process the reserved memory map to produce E820 map ;
1700 for (Hob
.Raw
= GetHobList (); !END_OF_HOB_LIST (Hob
); Hob
.Raw
= GET_NEXT_HOB (Hob
)) {
1701 if (Hob
.Raw
!= NULL
&& GET_HOB_TYPE (Hob
) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR
) {
1702 ResourceHob
= Hob
.ResourceDescriptor
;
1703 if (((ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_MAPPED_IO
) ||
1704 (ResourceHob
->ResourceType
== EFI_RESOURCE_FIRMWARE_DEVICE
) ||
1705 (ResourceHob
->ResourceType
== EFI_RESOURCE_MEMORY_RESERVED
) ) &&
1706 (ResourceHob
->PhysicalStart
> 0x100000) &&
1707 (Index
< EFI_MAX_E820_ENTRY
- 1)) {
1709 E820Table
[Index
].BaseAddr
= ResourceHob
->PhysicalStart
;
1710 E820Table
[Index
].Length
= ResourceHob
->ResourceLength
;
1711 E820Table
[Index
].Type
= EfiAcpiAddressRangeReserved
;
1717 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1718 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1719 Private
->NumberE820Entries
= (UINT32
)Index
;
1720 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1723 // Sort E820Table from low to high
1725 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1726 ChangedFlag
= FALSE
;
1727 for (TempNextIndex
= 1; TempNextIndex
< Index
- TempIndex
; TempNextIndex
++) {
1728 if (E820Table
[TempNextIndex
- 1].BaseAddr
> E820Table
[TempNextIndex
].BaseAddr
) {
1730 TempE820
.BaseAddr
= E820Table
[TempNextIndex
- 1].BaseAddr
;
1731 TempE820
.Length
= E820Table
[TempNextIndex
- 1].Length
;
1732 TempE820
.Type
= E820Table
[TempNextIndex
- 1].Type
;
1734 E820Table
[TempNextIndex
- 1].BaseAddr
= E820Table
[TempNextIndex
].BaseAddr
;
1735 E820Table
[TempNextIndex
- 1].Length
= E820Table
[TempNextIndex
].Length
;
1736 E820Table
[TempNextIndex
- 1].Type
= E820Table
[TempNextIndex
].Type
;
1738 E820Table
[TempNextIndex
].BaseAddr
= TempE820
.BaseAddr
;
1739 E820Table
[TempNextIndex
].Length
= TempE820
.Length
;
1740 E820Table
[TempNextIndex
].Type
= TempE820
.Type
;
1750 // Remove the overlap range
1752 for (TempIndex
= 1; TempIndex
< Index
; TempIndex
++) {
1753 if (E820Table
[TempIndex
- 1].BaseAddr
<= E820Table
[TempIndex
].BaseAddr
&&
1754 ((E820Table
[TempIndex
- 1].BaseAddr
+ E820Table
[TempIndex
- 1].Length
) >=
1755 (E820Table
[TempIndex
].BaseAddr
+E820Table
[TempIndex
].Length
))) {
1757 //Overlap range is found
1759 ASSERT (E820Table
[TempIndex
- 1].Type
== E820Table
[TempIndex
].Type
);
1761 if (TempIndex
== Index
- 1) {
1762 E820Table
[TempIndex
].BaseAddr
= 0;
1763 E820Table
[TempIndex
].Length
= 0;
1764 E820Table
[TempIndex
].Type
= (EFI_ACPI_MEMORY_TYPE
) 0;
1768 for (IndexSort
= TempIndex
; IndexSort
< Index
- 1; IndexSort
++) {
1769 E820Table
[IndexSort
].BaseAddr
= E820Table
[IndexSort
+ 1].BaseAddr
;
1770 E820Table
[IndexSort
].Length
= E820Table
[IndexSort
+ 1].Length
;
1771 E820Table
[IndexSort
].Type
= E820Table
[IndexSort
+ 1].Type
;
1780 Private
->IntThunk
->EfiToLegacy16InitTable
.NumberE820Entries
= (UINT32
)Index
;
1781 Private
->IntThunk
->EfiToLegacy16BootTable
.NumberE820Entries
= (UINT32
)Index
;
1782 Private
->NumberE820Entries
= (UINT32
)Index
;
1783 *Size
= (UINTN
) (Index
* sizeof (EFI_E820_ENTRY64
));
1786 // Determine OS usable memory above 1Mb
1788 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
= 0x0000;
1789 for (TempIndex
= Above1MIndex
; TempIndex
< Index
; TempIndex
++) {
1790 if (E820Table
[TempIndex
].BaseAddr
>= 0x100000 && E820Table
[TempIndex
].BaseAddr
< 0x100000000ULL
) { // not include above 4G memory
1792 // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
1794 if ((E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeMemory
) || (E820Table
[TempIndex
].Type
== EfiAcpiAddressRangeACPI
)) {
1795 Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
+= (UINT32
) (E820Table
[TempIndex
].Length
);
1797 break; // break at first not normal memory, because SMM may use reserved memory.
1802 Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
= Private
->IntThunk
->EfiToLegacy16BootTable
.OsMemoryAbove1Mb
;
1805 // Print DEBUG information
1807 for (TempIndex
= 0; TempIndex
< Index
; TempIndex
++) {
1808 DEBUG((EFI_D_INFO
, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
1810 E820Table
[TempIndex
].BaseAddr
,
1811 (E820Table
[TempIndex
].BaseAddr
+ E820Table
[TempIndex
].Length
),
1812 E820Table
[TempIndex
].Type
1821 Fill in the standard BDA and EBDA stuff prior to legacy Boot
1823 @param Private Legacy BIOS Instance data
1825 @retval EFI_SUCCESS It should always work.
1829 LegacyBiosCompleteBdaBeforeBoot (
1830 IN LEGACY_BIOS_INSTANCE
*Private
1834 UINT16 MachineConfig
;
1835 DEVICE_PRODUCER_DATA_HEADER
*SioPtr
;
1837 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
1840 SioPtr
= &(Private
->IntThunk
->EfiToLegacy16BootTable
.SioData
);
1841 Bda
->Com1
= SioPtr
->Serial
[0].Address
;
1842 Bda
->Com2
= SioPtr
->Serial
[1].Address
;
1843 Bda
->Com3
= SioPtr
->Serial
[2].Address
;
1844 Bda
->Com4
= SioPtr
->Serial
[3].Address
;
1846 if (SioPtr
->Serial
[0].Address
!= 0x00) {
1847 MachineConfig
+= 0x200;
1850 if (SioPtr
->Serial
[1].Address
!= 0x00) {
1851 MachineConfig
+= 0x200;
1854 if (SioPtr
->Serial
[2].Address
!= 0x00) {
1855 MachineConfig
+= 0x200;
1858 if (SioPtr
->Serial
[3].Address
!= 0x00) {
1859 MachineConfig
+= 0x200;
1862 Bda
->Lpt1
= SioPtr
->Parallel
[0].Address
;
1863 Bda
->Lpt2
= SioPtr
->Parallel
[1].Address
;
1864 Bda
->Lpt3
= SioPtr
->Parallel
[2].Address
;
1866 if (SioPtr
->Parallel
[0].Address
!= 0x00) {
1867 MachineConfig
+= 0x4000;
1870 if (SioPtr
->Parallel
[1].Address
!= 0x00) {
1871 MachineConfig
+= 0x4000;
1874 if (SioPtr
->Parallel
[2].Address
!= 0x00) {
1875 MachineConfig
+= 0x4000;
1878 Bda
->NumberOfDrives
= (UINT8
) (Bda
->NumberOfDrives
+ Private
->IdeDriveCount
);
1879 if (SioPtr
->Floppy
.NumberOfFloppy
!= 0x00) {
1880 MachineConfig
= (UINT16
) (MachineConfig
+ 0x01 + (SioPtr
->Floppy
.NumberOfFloppy
- 1) * 0x40);
1881 Bda
->FloppyXRate
= 0x07;
1884 Bda
->Lpt1_2Timeout
= 0x1414;
1885 Bda
->Lpt3_4Timeout
= 0x1414;
1886 Bda
->Com1_2Timeout
= 0x0101;
1887 Bda
->Com3_4Timeout
= 0x0101;
1890 // Force VGA and Coprocessor, indicate 101/102 keyboard
1892 MachineConfig
= (UINT16
) (MachineConfig
+ 0x00 + 0x02 + (SioPtr
->MousePresent
* 0x04));
1893 Bda
->MachineConfig
= MachineConfig
;
1899 Fill in the standard BDA for Keyboard LEDs
1901 @param This Protocol instance pointer.
1902 @param Leds Current LED status
1904 @retval EFI_SUCCESS It should always work.
1909 LegacyBiosUpdateKeyboardLedStatus (
1910 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
1914 LEGACY_BIOS_INSTANCE
*Private
;
1917 EFI_IA32_REGISTER_SET Regs
;
1919 Bda
= (BDA_STRUC
*) ((UINTN
) 0x400);
1921 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
1923 Bda
->LedStatus
= (UINT8
) ((Bda
->LedStatus
&~0x07) | LocalLeds
);
1924 LocalLeds
= (UINT8
) (LocalLeds
<< 4);
1925 Bda
->ShiftStatus
= (UINT8
) ((Bda
->ShiftStatus
&~0x70) | LocalLeds
);
1926 LocalLeds
= (UINT8
) (Leds
& 0x20);
1927 Bda
->KeyboardStatus
= (UINT8
) ((Bda
->KeyboardStatus
&~0x20) | LocalLeds
);
1929 // Call into Legacy16 code to allow it to do any processing
1931 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
1932 Regs
.X
.AX
= Legacy16SetKeyboardLeds
;
1935 Private
->LegacyBios
.FarCall86 (
1936 &Private
->LegacyBios
,
1937 Private
->Legacy16Table
->Compatibility16CallSegment
,
1938 Private
->Legacy16Table
->Compatibility16CallOffset
,
1949 Fill in the standard CMOS stuff prior to legacy Boot
1951 @param Private Legacy BIOS Instance data
1953 @retval EFI_SUCCESS It should always work.
1957 LegacyBiosCompleteStandardCmosBeforeBoot (
1958 IN LEGACY_BIOS_INSTANCE
*Private
1966 // Update CMOS locations
1968 // 12,19,1A - ignore as OS don't use them and there is no standard due
1969 // to large capacity drives
1970 // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
1972 Bda
= (UINT8
)(*((UINT8
*)((UINTN
)0x410)) | BIT3
);
1975 // Force display enabled
1978 if ((Bda
& BIT0
) != 0) {
1983 // Check if 2.88MB floppy set
1985 if ((Bda
& (BIT7
| BIT6
)) != 0) {
1986 Floppy
= (UINT8
)(Floppy
| BIT1
);
1989 LegacyWriteStandardCmos (CMOS_10
, Floppy
);
1990 LegacyWriteStandardCmos (CMOS_14
, Bda
);
1993 // Force Status Register A to set rate selection bits and divider
1995 LegacyWriteStandardCmos (CMOS_0A
, 0x26);
1998 // redo memory size since it can change
2000 Size
= 15 * SIZE_1MB
;
2001 if (Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
< (15 * SIZE_1MB
)) {
2002 Size
= Private
->IntThunk
->EfiToLegacy16InitTable
.OsMemoryAbove1Mb
>> 10;
2005 LegacyWriteStandardCmos (CMOS_17
, (UINT8
)(Size
& 0xFF));
2006 LegacyWriteStandardCmos (CMOS_30
, (UINT8
)(Size
& 0xFF));
2007 LegacyWriteStandardCmos (CMOS_18
, (UINT8
)(Size
>> 8));
2008 LegacyWriteStandardCmos (CMOS_31
, (UINT8
)(Size
>> 8));
2010 LegacyCalculateWriteStandardCmosChecksum ();
2016 Relocate this image under 4G memory for IPF.
2018 @param ImageHandle Handle of driver image.
2019 @param SystemTable Pointer to system table.
2021 @retval EFI_SUCCESS Image successfully relocated.
2022 @retval EFI_ABORTED Failed to relocate image.
2026 RelocateImageUnder4GIfNeeded (
2027 IN EFI_HANDLE ImageHandle
,
2028 IN EFI_SYSTEM_TABLE
*SystemTable