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"
18 #define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
21 // define maximum number of HDD system supports
23 #define MAX_HDD_ENTRIES 0x30
27 // Since this driver will only ever produce one instance of the Private Data
28 // protocol you are not required to dynamically allocate the PrivateData.
30 LEGACY_BIOS_INSTANCE mPrivateData
;
33 // The end of OPROM shadow address
35 UINTN mEndOpromShadowAddress
= 0;
38 Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
41 @param AllocateType Allocated Legacy Memory Type
42 @param StartPageAddress Start address of range
43 @param Pages Number of pages to allocate
44 @param Result Result of allocation
46 @retval EFI_SUCCESS Legacy16 code loaded
47 @retval Other No protocol installed, unload driver.
51 AllocateLegacyMemory (
52 IN EFI_ALLOCATE_TYPE AllocateType
,
53 IN EFI_PHYSICAL_ADDRESS StartPageAddress
,
55 OUT EFI_PHYSICAL_ADDRESS
*Result
59 EFI_PHYSICAL_ADDRESS MemPage
;
62 // Allocate Pages of memory less <= StartPageAddress
64 MemPage
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartPageAddress
;
65 Status
= gBS
->AllocatePages (
72 // Do not ASSERT on Status error but let caller decide since some cases
73 // memory is already taken but that is ok.
75 if (!EFI_ERROR (Status
)) {
76 *Result
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemPage
;
79 // If reach here the status = EFI_SUCCESS
86 This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
89 Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
90 invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.
92 @param This Protocol instance pointer.
93 @param LegacyMemorySize Size of required region
94 @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
95 block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
97 @param Alignment Address alignment. Bit mapped. First non-zero
98 bit from right is alignment.
99 @param LegacyMemoryAddress Region Assigned
101 @retval EFI_SUCCESS Region assigned
102 @retval EFI_ACCESS_DENIED Procedure previously invoked
103 @retval Other Region not assigned
108 LegacyBiosGetLegacyRegion (
109 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
110 IN UINTN LegacyMemorySize
,
113 OUT VOID
**LegacyMemoryAddress
117 LEGACY_BIOS_INSTANCE
*Private
;
118 EFI_IA32_REGISTER_SET Regs
;
122 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
123 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
125 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
126 Regs
.X
.AX
= Legacy16GetTableAddress
;
127 Regs
.X
.BX
= (UINT16
) Region
;
128 Regs
.X
.CX
= (UINT16
) LegacyMemorySize
;
129 Regs
.X
.DX
= (UINT16
) Alignment
;
130 Private
->LegacyBios
.FarCall86 (
131 &Private
->LegacyBios
,
132 Private
->Legacy16CallSegment
,
133 Private
->Legacy16CallOffset
,
139 if (Regs
.X
.AX
== 0) {
140 *LegacyMemoryAddress
= (VOID
*) (UINTN
) ((Regs
.X
.DS
<< 4) + Regs
.X
.BX
);
141 Status
= EFI_SUCCESS
;
143 Status
= EFI_OUT_OF_RESOURCES
;
146 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
147 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
154 This function is called when copying data to the region assigned by
155 EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
157 @param This Protocol instance pointer.
158 @param LegacyMemorySize Size of data to copy
159 @param LegacyMemoryAddress Legacy Region destination address Note: must
160 be in region assigned by
161 LegacyBiosGetLegacyRegion
162 @param LegacyMemorySourceAddress Source of data
164 @retval EFI_SUCCESS The data was copied successfully.
165 @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.
169 LegacyBiosCopyLegacyRegion (
170 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
171 IN UINTN LegacyMemorySize
,
172 IN VOID
*LegacyMemoryAddress
,
173 IN VOID
*LegacyMemorySourceAddress
177 LEGACY_BIOS_INSTANCE
*Private
;
180 if ((LegacyMemoryAddress
< (VOID
*)(UINTN
)0xE0000 ) ||
181 ((UINTN
) LegacyMemoryAddress
+ LegacyMemorySize
> (UINTN
) 0x100000)
183 return EFI_ACCESS_DENIED
;
186 // There is no protection from writes over lapping if this function is
187 // called multiple times.
189 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
190 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
191 CopyMem (LegacyMemoryAddress
, LegacyMemorySourceAddress
, LegacyMemorySize
);
193 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
194 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
201 Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
202 the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
205 @param Private Legacy BIOS context data
207 @retval EFI_SUCCESS Legacy16 code loaded
208 @retval Other No protocol installed, unload driver.
212 ShadowAndStartLegacy16 (
213 IN LEGACY_BIOS_INSTANCE
*Private
220 EFI_COMPATIBILITY16_TABLE
*Table
;
222 EFI_IA32_REGISTER_SET Regs
;
223 EFI_TO_COMPATIBILITY16_INIT_TABLE
*EfiToLegacy16InitTable
;
224 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
225 VOID
*LegacyBiosImage
;
226 UINTN LegacyBiosImageSize
;
230 LEGACY_EFI_HDD_TABLE
*LegacyEfiHddTable
;
233 VOID
*TpmBinaryImage
;
234 UINTN TpmBinaryImageSize
;
238 EFI_PHYSICAL_ADDRESS Address
;
242 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
248 // we allocate the C/D/E/F segment as RT code so no one will use it any more.
251 gDS
->GetMemorySpaceDescriptor (Address
, &Descriptor
);
252 if (Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeSystemMemory
) {
254 // If it is already reserved, we should be safe, or else we allocate it.
256 Status
= gBS
->AllocatePages (
258 EfiRuntimeServicesCode
,
259 0x40000/EFI_PAGE_SIZE
,
262 if (EFI_ERROR (Status
)) {
264 // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
266 DEBUG ((DEBUG_ERROR
, "Failed to allocate the C/D/E/F segment Status = %r", Status
));
272 // GetTimerValue (&Ticker);
274 // gRT->SetVariable (L"StartLegacy",
275 // &gEfiGlobalVariableGuid,
276 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
282 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
283 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
284 Private
->LegacyBiosPlatform
,
285 EfiGetPlatformBinarySystemRom
,
287 &LegacyBiosImageSize
,
293 if (EFI_ERROR (Status
)) {
297 Private
->BiosStart
= (UINT32
) (0x100000 - LegacyBiosImageSize
);
298 Private
->OptionRom
= 0xc0000;
299 Private
->LegacyBiosImageSize
= (UINT32
) LegacyBiosImageSize
;
302 // Can only shadow into memory allocated for legacy useage.
304 ASSERT (Private
->BiosStart
> Private
->OptionRom
);
307 // Shadow Legacy BIOS. Turn on memory and copy image
309 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xc0000, 0x40000, &Granularity
);
311 ClearPtr
= (VOID
*) ((UINTN
) 0xc0000);
314 // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
315 // regions to be used by EMM386 etc.
317 SetMem ((VOID
*) ClearPtr
, (UINTN
) (0x40000 - LegacyBiosImageSize
), 0xff);
319 TempData
= Private
->BiosStart
;
324 (UINTN
) LegacyBiosImageSize
327 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate
);
330 // Search for Legacy16 table in Shadowed ROM
334 for (Ptr
= (UINT8
*) TempData
; Ptr
< (UINT8
*) ((UINTN
) 0x100000) && !Done
; Ptr
+= 0x10) {
335 if (*(UINT32
*) Ptr
== SIGNATURE_32 ('I', 'F', 'E', '$')) {
336 Table
= (EFI_COMPATIBILITY16_TABLE
*) Ptr
;
337 PtrEnd
= Ptr
+ Table
->TableLength
;
338 for (CheckSum
= 0; Ptr
< PtrEnd
; Ptr
++) {
339 CheckSum
= (UINT8
) (CheckSum
+*Ptr
);
347 DEBUG ((EFI_D_ERROR
, "No Legacy16 table found\n"));
348 return EFI_NOT_FOUND
;
353 // Legacy16 table header checksum error.
355 DEBUG ((EFI_D_ERROR
, "Legacy16 table found with bad talbe header checksum\n"));
359 // Remember location of the Legacy16 table
361 Private
->Legacy16Table
= Table
;
362 Private
->Legacy16CallSegment
= Table
->Compatibility16CallSegment
;
363 Private
->Legacy16CallOffset
= Table
->Compatibility16CallOffset
;
364 EfiToLegacy16InitTable
= &Private
->IntThunk
->EfiToLegacy16InitTable
;
365 Private
->Legacy16InitPtr
= EfiToLegacy16InitTable
;
366 Private
->Legacy16BootPtr
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
367 Private
->InternalIrqRoutingTable
= NULL
;
368 Private
->NumberIrqRoutingEntries
= 0;
369 Private
->BbsTablePtr
= NULL
;
370 Private
->LegacyEfiHddTable
= NULL
;
371 Private
->DiskEnd
= 0;
372 Private
->Disk4075
= 0;
373 Private
->HddTablePtr
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
;
374 Private
->NumberHddControllers
= MAX_IDE_CONTROLLER
;
375 Private
->Dump
[0] = 'D';
376 Private
->Dump
[1] = 'U';
377 Private
->Dump
[2] = 'M';
378 Private
->Dump
[3] = 'P';
381 Private
->Legacy16BootPtr
,
382 sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE
)
386 // Store away a copy of the EFI System Table
388 Table
->EfiSystemTable
= (UINT32
) (UINTN
) gST
;
391 // Get the end of OPROM shadow address
393 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
394 Private
->LegacyBiosPlatform
,
395 EfiGetPlatformEndOpromShadowAddr
,
398 &mEndOpromShadowAddress
,
403 if (EFI_ERROR (Status
)) {
404 mEndOpromShadowAddress
= 0xDFFFF;
408 // IPF CSM integration -Bug
410 // Construct the Legacy16 boot memory map. This sets up number of
413 LegacyBiosBuildE820 (Private
, &E820Size
);
415 // Initialize BDA and EBDA standard values needed to load Legacy16 code
417 LegacyBiosInitBda (Private
);
418 LegacyBiosInitCmos (Private
);
421 // All legacy interrupt should be masked when do initialization work from legacy 16 code.
423 Private
->Legacy8259
->GetMask(Private
->Legacy8259
, &OldMask
, NULL
, NULL
, NULL
);
425 Private
->Legacy8259
->SetMask(Private
->Legacy8259
, &NewMask
, NULL
, NULL
, NULL
);
428 // Call into Legacy16 code to do an INIT
430 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
431 Regs
.X
.AX
= Legacy16InitializeYourself
;
432 Regs
.X
.ES
= EFI_SEGMENT (*((UINT32
*) &EfiToLegacy16InitTable
));
433 Regs
.X
.BX
= EFI_OFFSET (*((UINT32
*) &EfiToLegacy16InitTable
));
435 Private
->LegacyBios
.FarCall86 (
436 &Private
->LegacyBios
,
437 Table
->Compatibility16CallSegment
,
438 Table
->Compatibility16CallOffset
,
445 // Restore original legacy interrupt mask value
447 Private
->Legacy8259
->SetMask(Private
->Legacy8259
, &OldMask
, NULL
, NULL
, NULL
);
449 if (Regs
.X
.AX
!= 0) {
450 return EFI_DEVICE_ERROR
;
455 // GetTimerValue (&Ticker);
457 // gRT->SetVariable (L"BackFromInitYourself",
458 // &gEfiGlobalVariableGuid,
459 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
465 // Copy E820 table after InitializeYourself is completed
467 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
468 Regs
.X
.AX
= Legacy16GetTableAddress
;
469 Regs
.X
.CX
= (UINT16
) E820Size
;
471 Private
->LegacyBios
.FarCall86 (
472 &Private
->LegacyBios
,
473 Table
->Compatibility16CallSegment
,
474 Table
->Compatibility16CallOffset
,
480 Table
->E820Pointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
481 Table
->E820Length
= (UINT32
) E820Size
;
482 if (Regs
.X
.AX
!= 0) {
483 DEBUG ((EFI_D_ERROR
, "Legacy16 E820 length insufficient\n"));
485 TempData
= Table
->E820Pointer
;
486 CopyMem ((VOID
*) TempData
, Private
->E820Table
, E820Size
);
489 // Get PnPInstallationCheck Info.
491 Private
->PnPInstallationCheckSegment
= Table
->PnPInstallationCheckSegment
;
492 Private
->PnPInstallationCheckOffset
= Table
->PnPInstallationCheckOffset
;
495 // Check if PCI Express is supported. If yes, Save base address.
497 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
498 Private
->LegacyBiosPlatform
,
499 EfiGetPlatformPciExpressBase
,
507 if (!EFI_ERROR (Status
)) {
508 Private
->Legacy16Table
->PciExpressBase
= (UINT32
)Location
;
512 // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
513 // into, copy it and update pointer to binary image. This needs to be
514 // done prior to any OPROM for security purposes.
516 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
517 Private
->LegacyBiosPlatform
,
518 EfiGetPlatformBinaryTpmBinary
,
526 if (!EFI_ERROR (Status
)) {
528 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
529 Regs
.X
.AX
= Legacy16GetTableAddress
;
530 Regs
.X
.CX
= (UINT16
) TpmBinaryImageSize
;
532 Private
->LegacyBios
.FarCall86 (
533 &Private
->LegacyBios
,
534 Table
->Compatibility16CallSegment
,
535 Table
->Compatibility16CallOffset
,
541 TpmPointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
542 if (Regs
.X
.AX
!= 0) {
543 DEBUG ((EFI_D_ERROR
, "TPM cannot be loaded\n"));
545 CopyMem ((VOID
*) (UINTN
)TpmPointer
, TpmBinaryImage
, TpmBinaryImageSize
);
546 Table
->TpmSegment
= Regs
.X
.DS
;
547 Table
->TpmOffset
= Regs
.X
.BX
;
552 // Lock the Legacy BIOS region
554 Private
->Cpu
->FlushDataCache (Private
->Cpu
, Private
->BiosStart
, (UINT32
) LegacyBiosImageSize
, EfiCpuFlushTypeWriteBackInvalidate
);
555 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, Private
->BiosStart
, (UINT32
) LegacyBiosImageSize
, &Granularity
);
558 // Get the BbsTable from LOW_MEMORY_THUNK
560 BbsTable
= (BBS_TABLE
*)(UINTN
)Private
->IntThunk
->BbsTable
;
561 ZeroMem ((VOID
*)BbsTable
, sizeof (Private
->IntThunk
->BbsTable
));
563 EfiToLegacy16BootTable
->BbsTable
= (UINT32
)(UINTN
)BbsTable
;
564 Private
->BbsTablePtr
= (VOID
*) BbsTable
;
566 // Skip Floppy and possible onboard IDE drives
568 EfiToLegacy16BootTable
->NumberBbsEntries
= 1 + 2 * MAX_IDE_CONTROLLER
;
570 for (Index
= 0; Index
< (sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
)); Index
++) {
571 BbsTable
[Index
].BootPriority
= BBS_IGNORE_ENTRY
;
574 // Allocate space for Legacy HDD table
576 LegacyEfiHddTable
= (LEGACY_EFI_HDD_TABLE
*) AllocateZeroPool ((UINTN
) MAX_HDD_ENTRIES
* sizeof (LEGACY_EFI_HDD_TABLE
));
577 ASSERT (LegacyEfiHddTable
);
579 Private
->LegacyEfiHddTable
= LegacyEfiHddTable
;
580 Private
->LegacyEfiHddTableIndex
= 0x00;
584 // GetTimerValue (&Ticker);
586 // gRT->SetVariable (L"EndOfLoadFv",
587 // &gEfiGlobalVariableGuid,
588 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
598 Shadow all legacy16 OPROMs that haven't been shadowed.
599 Warning: Use this with caution. This routine disconnects all EFI
600 drivers. If used externally then caller must re-connect EFI
603 @param This Protocol instance pointer.
605 @retval EFI_SUCCESS OPROMs shadowed
610 LegacyBiosShadowAllLegacyOproms (
611 IN EFI_LEGACY_BIOS_PROTOCOL
*This
614 LEGACY_BIOS_INSTANCE
*Private
;
617 // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
618 // EFI_LEGACY16_TABLE *Legacy16Table;
620 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
623 // LegacyBiosPlatform = Private->LegacyBiosPlatform;
624 // Legacy16Table = Private->Legacy16Table;
626 // Shadow PCI ROMs. We must do this near the end since this will kick
627 // of Native EFI drivers that may be needed to collect info for Legacy16
629 // WARNING: PciIo is gone after this call.
631 PciProgramAllInterruptLineRegisters (Private
);
633 PciShadowRoms (Private
);
636 // Shadow PXE base code, BIS etc.
638 // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
639 // &Private->OptionRom,
646 Get the PCI BIOS interface version.
648 @param Private Driver private data.
650 @return The PCI interface version number in Binary Coded Decimal (BCD) format.
651 E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
655 GetPciInterfaceVersion (
656 IN LEGACY_BIOS_INSTANCE
*Private
659 EFI_IA32_REGISTER_SET Reg
;
661 UINT16 PciInterfaceVersion
;
663 PciInterfaceVersion
= 0;
668 ThunkFailed
= Private
->LegacyBios
.Int86 (&Private
->LegacyBios
, 0x1A, &Reg
);
671 // From PCI Firmware 3.0 Specification:
672 // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
673 // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
674 // presence of the PCI function set. [BX] will further indicate the version level, with enough
675 // granularity to allow for incremental changes in the code that don't affect the function interface.
676 // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
677 // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
679 if ((Reg
.X
.Flags
.CF
== 0) && (Reg
.H
.AH
== 0) && (Reg
.E
.EDX
== SIGNATURE_32 ('P', 'C', 'I', ' '))) {
680 PciInterfaceVersion
= Reg
.X
.BX
;
683 return PciInterfaceVersion
;
687 Install Driver to produce Legacy BIOS protocol.
689 @param ImageHandle Handle of driver image.
690 @param SystemTable Pointer to system table.
692 @retval EFI_SUCCESS Legacy BIOS protocol installed
693 @retval No protocol installed, unload driver.
699 IN EFI_HANDLE ImageHandle
,
700 IN EFI_SYSTEM_TABLE
*SystemTable
704 LEGACY_BIOS_INSTANCE
*Private
;
705 EFI_TO_COMPATIBILITY16_INIT_TABLE
*EfiToLegacy16InitTable
;
706 EFI_PHYSICAL_ADDRESS MemoryAddress
;
708 EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB
;
710 UINT32
*BaseVectorMaster
;
711 EFI_PHYSICAL_ADDRESS StartAddress
;
713 EFI_PHYSICAL_ADDRESS MemStart
;
718 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
722 // Load this driver's image to memory
724 Status
= RelocateImageUnder4GIfNeeded (ImageHandle
, SystemTable
);
725 if (EFI_ERROR (Status
)) {
729 Private
= &mPrivateData
;
730 ZeroMem (Private
, sizeof (LEGACY_BIOS_INSTANCE
));
733 // Grab a copy of all the protocols we depend on. Any error would
734 // be a dispatcher bug!.
736 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &Private
->Cpu
);
737 ASSERT_EFI_ERROR (Status
);
739 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**) &Private
->Timer
);
740 ASSERT_EFI_ERROR (Status
);
742 Status
= gBS
->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyRegion
);
743 ASSERT_EFI_ERROR (Status
);
745 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyBiosPlatform
);
746 ASSERT_EFI_ERROR (Status
);
748 Status
= gBS
->LocateProtocol (&gEfiLegacy8259ProtocolGuid
, NULL
, (VOID
**) &Private
->Legacy8259
);
749 ASSERT_EFI_ERROR (Status
);
751 Status
= gBS
->LocateProtocol (&gEfiLegacyInterruptProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyInterrupt
);
752 ASSERT_EFI_ERROR (Status
);
755 // Locate Memory Test Protocol if exists
757 Status
= gBS
->LocateProtocol (
758 &gEfiGenericMemTestProtocolGuid
,
760 (VOID
**) &Private
->GenericMemoryTest
762 ASSERT_EFI_ERROR (Status
);
765 // Make sure all memory from 0-640K is tested
767 for (StartAddress
= 0; StartAddress
< 0xa0000; ) {
768 gDS
->GetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
769 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeReserved
) {
770 StartAddress
= Descriptor
.BaseAddress
+ Descriptor
.Length
;
773 Length
= MIN (Descriptor
.Length
, 0xa0000 - StartAddress
);
774 Private
->GenericMemoryTest
->CompatibleRangeTest (
775 Private
->GenericMemoryTest
,
779 StartAddress
= StartAddress
+ Length
;
782 // Make sure all memory from 1MB to 16MB is tested and added to memory map
784 for (StartAddress
= BASE_1MB
; StartAddress
< BASE_16MB
; ) {
785 gDS
->GetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
786 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeReserved
) {
787 StartAddress
= Descriptor
.BaseAddress
+ Descriptor
.Length
;
790 Length
= MIN (Descriptor
.Length
, BASE_16MB
- StartAddress
);
791 Private
->GenericMemoryTest
->CompatibleRangeTest (
792 Private
->GenericMemoryTest
,
796 StartAddress
= StartAddress
+ Length
;
799 Private
->Signature
= LEGACY_BIOS_INSTANCE_SIGNATURE
;
801 Private
->LegacyBios
.Int86
= LegacyBiosInt86
;
802 Private
->LegacyBios
.FarCall86
= LegacyBiosFarCall86
;
803 Private
->LegacyBios
.CheckPciRom
= LegacyBiosCheckPciRom
;
804 Private
->LegacyBios
.InstallPciRom
= LegacyBiosInstallPciRom
;
805 Private
->LegacyBios
.LegacyBoot
= LegacyBiosLegacyBoot
;
806 Private
->LegacyBios
.UpdateKeyboardLedStatus
= LegacyBiosUpdateKeyboardLedStatus
;
807 Private
->LegacyBios
.GetBbsInfo
= LegacyBiosGetBbsInfo
;
808 Private
->LegacyBios
.ShadowAllLegacyOproms
= LegacyBiosShadowAllLegacyOproms
;
809 Private
->LegacyBios
.PrepareToBootEfi
= LegacyBiosPrepareToBootEfi
;
810 Private
->LegacyBios
.GetLegacyRegion
= LegacyBiosGetLegacyRegion
;
811 Private
->LegacyBios
.CopyLegacyRegion
= LegacyBiosCopyLegacyRegion
;
812 Private
->LegacyBios
.BootUnconventionalDevice
= LegacyBiosBootUnconventionalDevice
;
814 Private
->ImageHandle
= ImageHandle
;
817 // Enable read attribute of legacy region.
820 Private
->LegacyRegion
->Decode (
821 Private
->LegacyRegion
,
828 // Set Cachebility for legacy region
829 // BUGBUG: Comments about this legacy region cacheability setting
830 // This setting will make D865GCHProduction CSM Unhappy
832 if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion
)) {
833 gDS
->SetMemorySpaceAttributes (
838 gDS
->SetMemorySpaceAttributes (
845 gDS
->SetMemorySpaceAttributes (
852 // Allocate 0 - 4K for real mode interupt vectors and BDA.
854 AllocateLegacyMemory (
860 ASSERT (MemoryAddress
== 0x000000000);
862 ClearPtr
= (VOID
*) ((UINTN
) 0x0000);
865 // Initialize region from 0x0000 to 4k. This initializes interrupt vector
868 gBS
->SetMem ((VOID
*) ClearPtr
, 0x400, INITIAL_VALUE_BELOW_1K
);
869 ZeroMem ((VOID
*) ((UINTN
)ClearPtr
+ 0x400), 0xC00);
872 // Allocate pages for OPROM usage
874 MemorySize
= PcdGet32 (PcdEbdaReservedMemorySize
);
875 ASSERT ((MemorySize
& 0xFFF) == 0);
877 Status
= AllocateLegacyMemory (
879 CONVENTIONAL_MEMORY_TOP
- MemorySize
,
880 EFI_SIZE_TO_PAGES (MemorySize
),
883 ASSERT_EFI_ERROR (Status
);
885 ZeroMem ((VOID
*) ((UINTN
) MemoryAddress
), MemorySize
);
888 // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
889 // don't use PMM but look for zeroed memory. Note that various non-BBS
890 // SCSIs expect different areas to be free
892 for (MemStart
= 0x60000; MemStart
< 0x88000; MemStart
+= 0x1000) {
893 Status
= AllocateLegacyMemory (
899 if (!EFI_ERROR (Status
)) {
900 MemoryPtr
= (VOID
*) ((UINTN
) MemoryAddress
);
901 ZeroMem (MemoryPtr
, 0x1000);
903 DEBUG ((EFI_D_ERROR
, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart
));
908 // Allocate a 64k area (16 4k pages) for 16-bit code for scratch pad and zero it out
910 Status
= AllocateLegacyMemory (
912 CONVENTIONAL_MEMORY_TOP
,
914 &MemoryAddressUnder1MB
916 ASSERT_EFI_ERROR (Status
);
918 ZeroMem ((VOID
*) ((UINTN
) MemoryAddressUnder1MB
), 0x10000);
921 // Allocate space for thunker and Init Thunker
923 Status
= AllocateLegacyMemory (
925 CONVENTIONAL_MEMORY_TOP
,
926 (sizeof (LOW_MEMORY_THUNK
) / EFI_PAGE_SIZE
) + 2,
929 ASSERT_EFI_ERROR (Status
);
930 Private
->IntThunk
= (LOW_MEMORY_THUNK
*) (UINTN
) MemoryAddress
;
931 EfiToLegacy16InitTable
= &Private
->IntThunk
->EfiToLegacy16InitTable
;
932 EfiToLegacy16InitTable
->ThunkStart
= (UINT32
) (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemoryAddress
;
933 EfiToLegacy16InitTable
->ThunkSizeInBytes
= (UINT32
) (sizeof (LOW_MEMORY_THUNK
));
935 Status
= LegacyBiosInitializeThunk (Private
);
936 ASSERT_EFI_ERROR (Status
);
939 // Init the legacy memory map in memory < 1 MB.
941 EfiToLegacy16InitTable
->BiosLessThan1MB
= (UINT32
) MemoryAddressUnder1MB
;
942 EfiToLegacy16InitTable
->LowPmmMemory
= (UINT32
) MemoryAddressUnder1MB
;
943 EfiToLegacy16InitTable
->LowPmmMemorySizeInBytes
= 0x10000;
946 // Allocate 4 MB of PMM Memory under 16 MB
948 Status
= AllocateLegacyMemory (
954 if (!EFI_ERROR (Status
)) {
955 EfiToLegacy16InitTable
->HiPmmMemory
= (UINT32
) (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemoryAddress
;
956 EfiToLegacy16InitTable
->HiPmmMemorySizeInBytes
= PMM_MEMORY_SIZE
;
962 // Start the Legacy BIOS;
964 Status
= ShadowAndStartLegacy16 (Private
);
965 if (EFI_ERROR (Status
)) {
969 // Initialize interrupt redirection code and entries;
970 // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
973 Private
->IntThunk
->InterruptRedirectionCode
,
974 (VOID
*) (UINTN
) InterruptRedirectionTemplate
,
975 sizeof (Private
->IntThunk
->InterruptRedirectionCode
)
979 // Save Unexpected interrupt vector so can restore it just prior to boot
981 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
982 Private
->BiosUnexpectedInt
= BaseVectorMaster
[0];
983 IntRedirCode
= (UINT32
) (UINTN
) Private
->IntThunk
->InterruptRedirectionCode
;
984 for (Index
= 0; Index
< 8; Index
++) {
985 BaseVectorMaster
[Index
] = (EFI_SEGMENT (IntRedirCode
+ Index
* 4) << 16) | EFI_OFFSET (IntRedirCode
+ Index
* 4);
990 Private
->ThunkSeg
= (UINT16
) (EFI_SEGMENT (IntRedirCode
));
993 // Make a new handle and install the protocol
995 Private
->Handle
= NULL
;
996 Status
= gBS
->InstallProtocolInterface (
998 &gEfiLegacyBiosProtocolGuid
,
999 EFI_NATIVE_INTERFACE
,
1000 &Private
->LegacyBios
1002 Private
->Csm16PciInterfaceVersion
= GetPciInterfaceVersion (Private
);
1004 DEBUG ((EFI_D_INFO
, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
1005 (UINT8
) (Private
->Csm16PciInterfaceVersion
>> 8),
1006 (UINT8
) Private
->Csm16PciInterfaceVersion
1008 ASSERT (Private
->Csm16PciInterfaceVersion
!= 0);