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"
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 Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
36 @param AllocateType Allocated Legacy Memory Type
37 @param StartPageAddress Start address of range
38 @param Pages Number of pages to allocate
39 @param Result Result of allocation
41 @retval EFI_SUCCESS Legacy16 code loaded
42 @retval Other No protocol installed, unload driver.
46 AllocateLegacyMemory (
47 IN EFI_ALLOCATE_TYPE AllocateType
,
48 IN EFI_PHYSICAL_ADDRESS StartPageAddress
,
50 OUT EFI_PHYSICAL_ADDRESS
*Result
54 EFI_PHYSICAL_ADDRESS MemPage
;
57 // Allocate Pages of memory less <= StartPageAddress
59 MemPage
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartPageAddress
;
60 Status
= gBS
->AllocatePages (
67 // Do not ASSERT on Status error but let caller decide since some cases
68 // memory is already taken but that is ok.
70 if (!EFI_ERROR (Status
)) {
71 *Result
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemPage
;
74 // If reach here the status = EFI_SUCCESS
81 This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
84 Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
85 invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.
87 @param This Protocol instance pointer.
88 @param LegacyMemorySize Size of required region
89 @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
90 block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
92 @param Alignment Address alignment. Bit mapped. First non-zero
93 bit from right is alignment.
94 @param LegacyMemoryAddress Region Assigned
96 @retval EFI_SUCCESS Region assigned
97 @retval EFI_ACCESS_DENIED Procedure previously invoked
98 @retval Other Region not assigned
103 LegacyBiosGetLegacyRegion (
104 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
105 IN UINTN LegacyMemorySize
,
108 OUT VOID
**LegacyMemoryAddress
112 LEGACY_BIOS_INSTANCE
*Private
;
113 EFI_IA32_REGISTER_SET Regs
;
117 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
118 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
120 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
121 Regs
.X
.AX
= Legacy16GetTableAddress
;
122 Regs
.X
.BX
= (UINT16
) Region
;
123 Regs
.X
.CX
= (UINT16
) LegacyMemorySize
;
124 Regs
.X
.DX
= (UINT16
) Alignment
;
125 Private
->LegacyBios
.FarCall86 (
126 &Private
->LegacyBios
,
127 Private
->Legacy16CallSegment
,
128 Private
->Legacy16CallOffset
,
134 if (Regs
.X
.AX
== 0) {
135 *LegacyMemoryAddress
= (VOID
*) (UINTN
) ((Regs
.X
.DS
<< 4) + Regs
.X
.BX
);
136 Status
= EFI_SUCCESS
;
138 Status
= EFI_OUT_OF_RESOURCES
;
141 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
142 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
149 This function is called when copying data to the region assigned by
150 EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
152 @param This Protocol instance pointer.
153 @param LegacyMemorySize Size of data to copy
154 @param LegacyMemoryAddress Legacy Region destination address Note: must
155 be in region assigned by
156 LegacyBiosGetLegacyRegion
157 @param LegacyMemorySourceAddress Source of data
159 @retval EFI_SUCCESS The data was copied successfully.
160 @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.
164 LegacyBiosCopyLegacyRegion (
165 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
166 IN UINTN LegacyMemorySize
,
167 IN VOID
*LegacyMemoryAddress
,
168 IN VOID
*LegacyMemorySourceAddress
172 LEGACY_BIOS_INSTANCE
*Private
;
175 if ((LegacyMemoryAddress
< (VOID
*)(UINTN
)0xE0000 ) ||
176 ((UINTN
) LegacyMemoryAddress
+ LegacyMemorySize
> (UINTN
) 0x100000)
178 return EFI_ACCESS_DENIED
;
181 // There is no protection from writes over lapping if this function is
182 // called multiple times.
184 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
185 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
186 CopyMem (LegacyMemoryAddress
, LegacyMemorySourceAddress
, LegacyMemorySize
);
188 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
189 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
196 Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
197 the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
200 @param Private Legacy BIOS context data
202 @retval EFI_SUCCESS Legacy16 code loaded
203 @retval Other No protocol installed, unload driver.
207 ShadowAndStartLegacy16 (
208 IN LEGACY_BIOS_INSTANCE
*Private
215 EFI_COMPATIBILITY16_TABLE
*Table
;
217 EFI_IA32_REGISTER_SET Regs
;
218 EFI_TO_COMPATIBILITY16_INIT_TABLE
*EfiToLegacy16InitTable
;
219 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
220 VOID
*LegacyBiosImage
;
221 UINTN LegacyBiosImageSize
;
225 LEGACY_EFI_HDD_TABLE
*LegacyEfiHddTable
;
228 VOID
*TpmBinaryImage
;
229 UINTN TpmBinaryImageSize
;
233 EFI_PHYSICAL_ADDRESS Address
;
237 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
243 // we allocate the C/D/E/F segment as RT code so no one will use it any more.
246 gDS
->GetMemorySpaceDescriptor (Address
, &Descriptor
);
247 if (Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeSystemMemory
) {
249 // If it is already reserved, we should be safe, or else we allocate it.
251 Status
= gBS
->AllocatePages (
253 EfiRuntimeServicesCode
,
254 0x40000/EFI_PAGE_SIZE
,
257 if (EFI_ERROR (Status
)) {
259 // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
261 DEBUG ((DEBUG_ERROR
, "Failed to allocate the C/D/E/F segment Status = %r", Status
));
267 // GetTimerValue (&Ticker);
269 // gRT->SetVariable (L"StartLegacy",
270 // &gEfiGlobalVariableGuid,
271 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
277 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
278 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
279 Private
->LegacyBiosPlatform
,
280 EfiGetPlatformBinarySystemRom
,
282 &LegacyBiosImageSize
,
288 if (EFI_ERROR (Status
)) {
292 Private
->BiosStart
= (UINT32
) (0x100000 - LegacyBiosImageSize
);
293 Private
->OptionRom
= 0xc0000;
294 Private
->LegacyBiosImageSize
= (UINT32
) LegacyBiosImageSize
;
297 // Can only shadow into memory allocated for legacy useage.
299 ASSERT (Private
->BiosStart
> Private
->OptionRom
);
302 // Shadow Legacy BIOS. Turn on memory and copy image
304 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xc0000, 0x40000, &Granularity
);
306 ClearPtr
= (VOID
*) ((UINTN
) 0xc0000);
309 // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
310 // regions to be used by EMM386 etc.
312 SetMem ((VOID
*) ClearPtr
, (UINTN
) (0x40000 - LegacyBiosImageSize
), 0xff);
314 TempData
= Private
->BiosStart
;
319 (UINTN
) LegacyBiosImageSize
322 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate
);
325 // Search for Legacy16 table in Shadowed ROM
329 for (Ptr
= (UINT8
*) TempData
; Ptr
< (UINT8
*) ((UINTN
) 0x100000) && !Done
; Ptr
+= 0x10) {
330 if (*(UINT32
*) Ptr
== SIGNATURE_32 ('I', 'F', 'E', '$')) {
331 Table
= (EFI_COMPATIBILITY16_TABLE
*) Ptr
;
332 PtrEnd
= Ptr
+ Table
->TableLength
;
333 for (CheckSum
= 0; Ptr
< PtrEnd
; Ptr
++) {
334 CheckSum
= (UINT8
) (CheckSum
+*Ptr
);
342 DEBUG ((EFI_D_ERROR
, "No Legacy16 table found\n"));
343 return EFI_NOT_FOUND
;
348 // Legacy16 table header checksum error.
350 DEBUG ((EFI_D_ERROR
, "Legacy16 table found with bad talbe header checksum\n"));
354 // Remember location of the Legacy16 table
356 Private
->Legacy16Table
= Table
;
357 Private
->Legacy16CallSegment
= Table
->Compatibility16CallSegment
;
358 Private
->Legacy16CallOffset
= Table
->Compatibility16CallOffset
;
359 EfiToLegacy16InitTable
= &Private
->IntThunk
->EfiToLegacy16InitTable
;
360 Private
->Legacy16InitPtr
= EfiToLegacy16InitTable
;
361 Private
->Legacy16BootPtr
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
362 Private
->InternalIrqRoutingTable
= NULL
;
363 Private
->NumberIrqRoutingEntries
= 0;
364 Private
->BbsTablePtr
= NULL
;
365 Private
->LegacyEfiHddTable
= NULL
;
366 Private
->DiskEnd
= 0;
367 Private
->Disk4075
= 0;
368 Private
->HddTablePtr
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
;
369 Private
->NumberHddControllers
= MAX_IDE_CONTROLLER
;
370 Private
->Dump
[0] = 'D';
371 Private
->Dump
[1] = 'U';
372 Private
->Dump
[2] = 'M';
373 Private
->Dump
[3] = 'P';
376 Private
->Legacy16BootPtr
,
377 sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE
)
381 // Store away a copy of the EFI System Table
383 Table
->EfiSystemTable
= (UINT32
) (UINTN
) gST
;
386 // IPF CSM integration -Bug
388 // Construct the Legacy16 boot memory map. This sets up number of
391 LegacyBiosBuildE820 (Private
, &E820Size
);
393 // Initialize BDA and EBDA standard values needed to load Legacy16 code
395 LegacyBiosInitBda (Private
);
396 LegacyBiosInitCmos (Private
);
399 // All legacy interrupt should be masked when do initialization work from legacy 16 code.
401 Private
->Legacy8259
->GetMask(Private
->Legacy8259
, &OldMask
, NULL
, NULL
, NULL
);
403 Private
->Legacy8259
->SetMask(Private
->Legacy8259
, &NewMask
, NULL
, NULL
, NULL
);
406 // Call into Legacy16 code to do an INIT
408 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
409 Regs
.X
.AX
= Legacy16InitializeYourself
;
410 Regs
.X
.ES
= EFI_SEGMENT (*((UINT32
*) &EfiToLegacy16InitTable
));
411 Regs
.X
.BX
= EFI_OFFSET (*((UINT32
*) &EfiToLegacy16InitTable
));
413 Private
->LegacyBios
.FarCall86 (
414 &Private
->LegacyBios
,
415 Table
->Compatibility16CallSegment
,
416 Table
->Compatibility16CallOffset
,
423 // Restore original legacy interrupt mask value
425 Private
->Legacy8259
->SetMask(Private
->Legacy8259
, &OldMask
, NULL
, NULL
, NULL
);
427 if (Regs
.X
.AX
!= 0) {
428 return EFI_DEVICE_ERROR
;
433 // GetTimerValue (&Ticker);
435 // gRT->SetVariable (L"BackFromInitYourself",
436 // &gEfiGlobalVariableGuid,
437 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
443 // Copy E820 table after InitializeYourself is completed
445 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
446 Regs
.X
.AX
= Legacy16GetTableAddress
;
447 Regs
.X
.CX
= (UINT16
) E820Size
;
449 Private
->LegacyBios
.FarCall86 (
450 &Private
->LegacyBios
,
451 Table
->Compatibility16CallSegment
,
452 Table
->Compatibility16CallOffset
,
458 Table
->E820Pointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
459 Table
->E820Length
= (UINT32
) E820Size
;
460 if (Regs
.X
.AX
!= 0) {
461 DEBUG ((EFI_D_ERROR
, "Legacy16 E820 length insufficient\n"));
463 TempData
= Table
->E820Pointer
;
464 CopyMem ((VOID
*) TempData
, Private
->E820Table
, E820Size
);
467 // Get PnPInstallationCheck Info.
469 Private
->PnPInstallationCheckSegment
= Table
->PnPInstallationCheckSegment
;
470 Private
->PnPInstallationCheckOffset
= Table
->PnPInstallationCheckOffset
;
473 // Check if PCI Express is supported. If yes, Save base address.
475 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
476 Private
->LegacyBiosPlatform
,
477 EfiGetPlatformPciExpressBase
,
485 if (!EFI_ERROR (Status
)) {
486 Private
->Legacy16Table
->PciExpressBase
= (UINT32
)Location
;
490 // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
491 // into, copy it and update pointer to binary image. This needs to be
492 // done prior to any OPROM for security purposes.
494 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
495 Private
->LegacyBiosPlatform
,
496 EfiGetPlatformBinaryTpmBinary
,
504 if (!EFI_ERROR (Status
)) {
506 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
507 Regs
.X
.AX
= Legacy16GetTableAddress
;
508 Regs
.X
.CX
= (UINT16
) TpmBinaryImageSize
;
510 Private
->LegacyBios
.FarCall86 (
511 &Private
->LegacyBios
,
512 Table
->Compatibility16CallSegment
,
513 Table
->Compatibility16CallOffset
,
519 TpmPointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
520 if (Regs
.X
.AX
!= 0) {
521 DEBUG ((EFI_D_ERROR
, "TPM cannot be loaded\n"));
523 CopyMem ((VOID
*) (UINTN
)TpmPointer
, TpmBinaryImage
, TpmBinaryImageSize
);
524 Table
->TpmSegment
= Regs
.X
.DS
;
525 Table
->TpmOffset
= Regs
.X
.BX
;
530 // Lock the Legacy BIOS region
532 Private
->Cpu
->FlushDataCache (Private
->Cpu
, Private
->BiosStart
, (UINT32
) LegacyBiosImageSize
, EfiCpuFlushTypeWriteBackInvalidate
);
533 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, Private
->BiosStart
, (UINT32
) LegacyBiosImageSize
, &Granularity
);
536 // Get the BbsTable from LOW_MEMORY_THUNK
538 BbsTable
= (BBS_TABLE
*)(UINTN
)Private
->IntThunk
->BbsTable
;
539 ZeroMem ((VOID
*)BbsTable
, sizeof (Private
->IntThunk
->BbsTable
));
541 EfiToLegacy16BootTable
->BbsTable
= (UINT32
)(UINTN
)BbsTable
;
542 Private
->BbsTablePtr
= (VOID
*) BbsTable
;
544 // Skip Floppy and possible onboard IDE drives
546 EfiToLegacy16BootTable
->NumberBbsEntries
= 1 + 2 * MAX_IDE_CONTROLLER
;
548 for (Index
= 0; Index
< (sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
)); Index
++) {
549 BbsTable
[Index
].BootPriority
= BBS_IGNORE_ENTRY
;
552 // Allocate space for Legacy HDD table
554 LegacyEfiHddTable
= (LEGACY_EFI_HDD_TABLE
*) AllocateZeroPool ((UINTN
) MAX_HDD_ENTRIES
* sizeof (LEGACY_EFI_HDD_TABLE
));
555 ASSERT (LegacyEfiHddTable
);
557 Private
->LegacyEfiHddTable
= LegacyEfiHddTable
;
558 Private
->LegacyEfiHddTableIndex
= 0x00;
562 // GetTimerValue (&Ticker);
564 // gRT->SetVariable (L"EndOfLoadFv",
565 // &gEfiGlobalVariableGuid,
566 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
576 Shadow all legacy16 OPROMs that haven't been shadowed.
577 Warning: Use this with caution. This routine disconnects all EFI
578 drivers. If used externally then caller must re-connect EFI
581 @param This Protocol instance pointer.
583 @retval EFI_SUCCESS OPROMs shadowed
588 LegacyBiosShadowAllLegacyOproms (
589 IN EFI_LEGACY_BIOS_PROTOCOL
*This
592 LEGACY_BIOS_INSTANCE
*Private
;
595 // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
596 // EFI_LEGACY16_TABLE *Legacy16Table;
598 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
601 // LegacyBiosPlatform = Private->LegacyBiosPlatform;
602 // Legacy16Table = Private->Legacy16Table;
604 // Shadow PCI ROMs. We must do this near the end since this will kick
605 // of Native EFI drivers that may be needed to collect info for Legacy16
607 // WARNING: PciIo is gone after this call.
609 PciProgramAllInterruptLineRegisters (Private
);
611 PciShadowRoms (Private
);
614 // Shadow PXE base code, BIS etc.
616 // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
617 // &Private->OptionRom,
624 Get the PCI BIOS interface version.
626 @param Private Driver private data.
628 @return The PCI interface version number in Binary Coded Decimal (BCD) format.
629 E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
633 GetPciInterfaceVersion (
634 IN LEGACY_BIOS_INSTANCE
*Private
637 EFI_IA32_REGISTER_SET Reg
;
639 UINT16 PciInterfaceVersion
;
641 PciInterfaceVersion
= 0;
646 ThunkFailed
= Private
->LegacyBios
.Int86 (&Private
->LegacyBios
, 0x1A, &Reg
);
649 // From PCI Firmware 3.0 Specification:
650 // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
651 // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
652 // presence of the PCI function set. [BX] will further indicate the version level, with enough
653 // granularity to allow for incremental changes in the code that don't affect the function interface.
654 // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
655 // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
657 if ((Reg
.X
.Flags
.CF
== 0) && (Reg
.H
.AH
== 0) && (Reg
.E
.EDX
== SIGNATURE_32 ('P', 'C', 'I', ' '))) {
658 PciInterfaceVersion
= Reg
.X
.BX
;
661 return PciInterfaceVersion
;
665 Install Driver to produce Legacy BIOS protocol.
667 @param ImageHandle Handle of driver image.
668 @param SystemTable Pointer to system table.
670 @retval EFI_SUCCESS Legacy BIOS protocol installed
671 @retval No protocol installed, unload driver.
677 IN EFI_HANDLE ImageHandle
,
678 IN EFI_SYSTEM_TABLE
*SystemTable
682 LEGACY_BIOS_INSTANCE
*Private
;
683 EFI_TO_COMPATIBILITY16_INIT_TABLE
*EfiToLegacy16InitTable
;
684 EFI_PHYSICAL_ADDRESS MemoryAddress
;
686 EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB
;
688 UINT32
*BaseVectorMaster
;
689 EFI_PHYSICAL_ADDRESS StartAddress
;
691 EFI_PHYSICAL_ADDRESS MemStart
;
696 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
701 // Load this driver's image to memory
703 Status
= RelocateImageUnder4GIfNeeded (ImageHandle
, SystemTable
);
704 if (EFI_ERROR (Status
)) {
709 // When UEFI Secure Boot is enabled, CSM module will not start any more.
712 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME
, (VOID
**)&SecureBoot
, NULL
);
713 if ((SecureBoot
!= NULL
) && (*SecureBoot
== SECURE_BOOT_MODE_ENABLE
)) {
714 FreePool (SecureBoot
);
715 return EFI_SECURITY_VIOLATION
;
718 if (SecureBoot
!= NULL
) {
719 FreePool (SecureBoot
);
722 Private
= &mPrivateData
;
723 ZeroMem (Private
, sizeof (LEGACY_BIOS_INSTANCE
));
726 // Grab a copy of all the protocols we depend on. Any error would
727 // be a dispatcher bug!.
729 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &Private
->Cpu
);
730 ASSERT_EFI_ERROR (Status
);
732 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**) &Private
->Timer
);
733 ASSERT_EFI_ERROR (Status
);
735 Status
= gBS
->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyRegion
);
736 ASSERT_EFI_ERROR (Status
);
738 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyBiosPlatform
);
739 ASSERT_EFI_ERROR (Status
);
741 Status
= gBS
->LocateProtocol (&gEfiLegacy8259ProtocolGuid
, NULL
, (VOID
**) &Private
->Legacy8259
);
742 ASSERT_EFI_ERROR (Status
);
744 Status
= gBS
->LocateProtocol (&gEfiLegacyInterruptProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyInterrupt
);
745 ASSERT_EFI_ERROR (Status
);
748 // Locate Memory Test Protocol if exists
750 Status
= gBS
->LocateProtocol (
751 &gEfiGenericMemTestProtocolGuid
,
753 (VOID
**) &Private
->GenericMemoryTest
755 ASSERT_EFI_ERROR (Status
);
758 // Make sure all memory from 0-640K is tested
760 for (StartAddress
= 0; StartAddress
< 0xa0000; ) {
761 gDS
->GetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
762 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeReserved
) {
763 StartAddress
= Descriptor
.BaseAddress
+ Descriptor
.Length
;
766 Length
= MIN (Descriptor
.Length
, 0xa0000 - StartAddress
);
767 Private
->GenericMemoryTest
->CompatibleRangeTest (
768 Private
->GenericMemoryTest
,
772 StartAddress
= StartAddress
+ Length
;
775 // Make sure all memory from 1MB to 16MB is tested and added to memory map
777 for (StartAddress
= BASE_1MB
; StartAddress
< BASE_16MB
; ) {
778 gDS
->GetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
779 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeReserved
) {
780 StartAddress
= Descriptor
.BaseAddress
+ Descriptor
.Length
;
783 Length
= MIN (Descriptor
.Length
, BASE_16MB
- StartAddress
);
784 Private
->GenericMemoryTest
->CompatibleRangeTest (
785 Private
->GenericMemoryTest
,
789 StartAddress
= StartAddress
+ Length
;
792 Private
->Signature
= LEGACY_BIOS_INSTANCE_SIGNATURE
;
794 Private
->LegacyBios
.Int86
= LegacyBiosInt86
;
795 Private
->LegacyBios
.FarCall86
= LegacyBiosFarCall86
;
796 Private
->LegacyBios
.CheckPciRom
= LegacyBiosCheckPciRom
;
797 Private
->LegacyBios
.InstallPciRom
= LegacyBiosInstallPciRom
;
798 Private
->LegacyBios
.LegacyBoot
= LegacyBiosLegacyBoot
;
799 Private
->LegacyBios
.UpdateKeyboardLedStatus
= LegacyBiosUpdateKeyboardLedStatus
;
800 Private
->LegacyBios
.GetBbsInfo
= LegacyBiosGetBbsInfo
;
801 Private
->LegacyBios
.ShadowAllLegacyOproms
= LegacyBiosShadowAllLegacyOproms
;
802 Private
->LegacyBios
.PrepareToBootEfi
= LegacyBiosPrepareToBootEfi
;
803 Private
->LegacyBios
.GetLegacyRegion
= LegacyBiosGetLegacyRegion
;
804 Private
->LegacyBios
.CopyLegacyRegion
= LegacyBiosCopyLegacyRegion
;
805 Private
->LegacyBios
.BootUnconventionalDevice
= LegacyBiosBootUnconventionalDevice
;
807 Private
->ImageHandle
= ImageHandle
;
810 // Enable read attribute of legacy region.
813 Private
->LegacyRegion
->Decode (
814 Private
->LegacyRegion
,
821 // Set Cachebility for legacy region
822 // BUGBUG: Comments about this legacy region cacheability setting
823 // This setting will make D865GCHProduction CSM Unhappy
825 if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion
)) {
826 gDS
->SetMemorySpaceAttributes (
831 gDS
->SetMemorySpaceAttributes (
838 gDS
->SetMemorySpaceAttributes (
845 // Allocate 0 - 4K for real mode interupt vectors and BDA.
847 AllocateLegacyMemory (
853 ASSERT (MemoryAddress
== 0x000000000);
855 ClearPtr
= (VOID
*) ((UINTN
) 0x0000);
858 // Initialize region from 0x0000 to 4k. This initializes interrupt vector
861 gBS
->SetMem ((VOID
*) ClearPtr
, 0x400, INITIAL_VALUE_BELOW_1K
);
862 ZeroMem ((VOID
*) ((UINTN
)ClearPtr
+ 0x400), 0xC00);
865 // Allocate pages for OPROM usage
867 MemorySize
= PcdGet32 (PcdEbdaReservedMemorySize
);
868 ASSERT ((MemorySize
& 0xFFF) == 0);
870 Status
= AllocateLegacyMemory (
872 CONVENTIONAL_MEMORY_TOP
- MemorySize
,
873 EFI_SIZE_TO_PAGES (MemorySize
),
876 ASSERT_EFI_ERROR (Status
);
878 ZeroMem ((VOID
*) ((UINTN
) MemoryAddress
), MemorySize
);
881 // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
882 // don't use PMM but look for zeroed memory. Note that various non-BBS
883 // SCSIs expect different areas to be free
885 for (MemStart
= 0x60000; MemStart
< 0x88000; MemStart
+= 0x1000) {
886 Status
= AllocateLegacyMemory (
892 if (!EFI_ERROR (Status
)) {
893 MemoryPtr
= (VOID
*) ((UINTN
) MemoryAddress
);
894 ZeroMem (MemoryPtr
, 0x1000);
896 DEBUG ((EFI_D_ERROR
, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart
));
901 // Allocate low PMM memory and zero it out
903 MemorySize
= PcdGet32 (PcdLowPmmMemorySize
);
904 ASSERT ((MemorySize
& 0xFFF) == 0);
905 Status
= AllocateLegacyMemory (
907 CONVENTIONAL_MEMORY_TOP
,
908 EFI_SIZE_TO_PAGES (MemorySize
),
909 &MemoryAddressUnder1MB
911 ASSERT_EFI_ERROR (Status
);
913 ZeroMem ((VOID
*) ((UINTN
) MemoryAddressUnder1MB
), MemorySize
);
916 // Allocate space for thunker and Init Thunker
918 Status
= AllocateLegacyMemory (
920 CONVENTIONAL_MEMORY_TOP
,
921 (sizeof (LOW_MEMORY_THUNK
) / EFI_PAGE_SIZE
) + 2,
924 ASSERT_EFI_ERROR (Status
);
925 Private
->IntThunk
= (LOW_MEMORY_THUNK
*) (UINTN
) MemoryAddress
;
926 EfiToLegacy16InitTable
= &Private
->IntThunk
->EfiToLegacy16InitTable
;
927 EfiToLegacy16InitTable
->ThunkStart
= (UINT32
) (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemoryAddress
;
928 EfiToLegacy16InitTable
->ThunkSizeInBytes
= (UINT32
) (sizeof (LOW_MEMORY_THUNK
));
930 Status
= LegacyBiosInitializeThunk (Private
);
931 ASSERT_EFI_ERROR (Status
);
934 // Init the legacy memory map in memory < 1 MB.
936 EfiToLegacy16InitTable
->BiosLessThan1MB
= (UINT32
) MemoryAddressUnder1MB
;
937 EfiToLegacy16InitTable
->LowPmmMemory
= (UINT32
) MemoryAddressUnder1MB
;
938 EfiToLegacy16InitTable
->LowPmmMemorySizeInBytes
= MemorySize
;
940 MemorySize
= PcdGet32 (PcdHighPmmMemorySize
);
941 ASSERT ((MemorySize
& 0xFFF) == 0);
943 // Allocate high PMM Memory under 16 MB
945 Status
= AllocateLegacyMemory (
948 EFI_SIZE_TO_PAGES (MemorySize
),
951 if (EFI_ERROR (Status
)) {
953 // If it fails, allocate high PMM Memory under 4GB
955 Status
= AllocateLegacyMemory (
958 EFI_SIZE_TO_PAGES (MemorySize
),
962 if (!EFI_ERROR (Status
)) {
963 EfiToLegacy16InitTable
->HiPmmMemory
= (UINT32
) (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemoryAddress
;
964 EfiToLegacy16InitTable
->HiPmmMemorySizeInBytes
= MemorySize
;
970 // Start the Legacy BIOS;
972 Status
= ShadowAndStartLegacy16 (Private
);
973 if (EFI_ERROR (Status
)) {
977 // Initialize interrupt redirection code and entries;
978 // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
981 Private
->IntThunk
->InterruptRedirectionCode
,
982 (VOID
*) (UINTN
) InterruptRedirectionTemplate
,
983 sizeof (Private
->IntThunk
->InterruptRedirectionCode
)
987 // Save Unexpected interrupt vector so can restore it just prior to boot
989 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
990 Private
->BiosUnexpectedInt
= BaseVectorMaster
[0];
991 IntRedirCode
= (UINT32
) (UINTN
) Private
->IntThunk
->InterruptRedirectionCode
;
992 for (Index
= 0; Index
< 8; Index
++) {
993 BaseVectorMaster
[Index
] = (EFI_SEGMENT (IntRedirCode
+ Index
* 4) << 16) | EFI_OFFSET (IntRedirCode
+ Index
* 4);
998 Private
->ThunkSeg
= (UINT16
) (EFI_SEGMENT (IntRedirCode
));
1001 // Make a new handle and install the protocol
1003 Private
->Handle
= NULL
;
1004 Status
= gBS
->InstallProtocolInterface (
1006 &gEfiLegacyBiosProtocolGuid
,
1007 EFI_NATIVE_INTERFACE
,
1008 &Private
->LegacyBios
1010 Private
->Csm16PciInterfaceVersion
= GetPciInterfaceVersion (Private
);
1012 DEBUG ((EFI_D_INFO
, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
1013 (UINT8
) (Private
->Csm16PciInterfaceVersion
>> 8),
1014 (UINT8
) Private
->Csm16PciInterfaceVersion
1016 ASSERT (Private
->Csm16PciInterfaceVersion
!= 0);