3 Copyright (c) 2006 - 2013, 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 SMBIOS table in EfiRuntimeServicesData memory
35 VOID
*mRuntimeSmbiosEntryPoint
= NULL
;
38 // The SMBIOS table in EfiReservedMemoryType memory
40 EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint
= 0;
41 EFI_PHYSICAL_ADDRESS mStructureTableAddress
= 0;
42 UINTN mStructureTablePages
= 0;
45 Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
48 @param AllocateType Allocated Legacy Memory Type
49 @param StartPageAddress Start address of range
50 @param Pages Number of pages to allocate
51 @param Result Result of allocation
53 @retval EFI_SUCCESS Legacy16 code loaded
54 @retval Other No protocol installed, unload driver.
58 AllocateLegacyMemory (
59 IN EFI_ALLOCATE_TYPE AllocateType
,
60 IN EFI_PHYSICAL_ADDRESS StartPageAddress
,
62 OUT EFI_PHYSICAL_ADDRESS
*Result
66 EFI_PHYSICAL_ADDRESS MemPage
;
69 // Allocate Pages of memory less <= StartPageAddress
71 MemPage
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) StartPageAddress
;
72 Status
= gBS
->AllocatePages (
79 // Do not ASSERT on Status error but let caller decide since some cases
80 // memory is already taken but that is ok.
82 if (!EFI_ERROR (Status
)) {
83 *Result
= (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemPage
;
86 // If reach here the status = EFI_SUCCESS
93 This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
96 Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
97 invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.
99 @param This Protocol instance pointer.
100 @param LegacyMemorySize Size of required region
101 @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
102 block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
104 @param Alignment Address alignment. Bit mapped. First non-zero
105 bit from right is alignment.
106 @param LegacyMemoryAddress Region Assigned
108 @retval EFI_SUCCESS Region assigned
109 @retval EFI_ACCESS_DENIED Procedure previously invoked
110 @retval Other Region not assigned
115 LegacyBiosGetLegacyRegion (
116 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
117 IN UINTN LegacyMemorySize
,
120 OUT VOID
**LegacyMemoryAddress
124 LEGACY_BIOS_INSTANCE
*Private
;
125 EFI_IA32_REGISTER_SET Regs
;
129 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
130 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
132 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
133 Regs
.X
.AX
= Legacy16GetTableAddress
;
134 Regs
.X
.BX
= (UINT16
) Region
;
135 Regs
.X
.CX
= (UINT16
) LegacyMemorySize
;
136 Regs
.X
.DX
= (UINT16
) Alignment
;
137 Private
->LegacyBios
.FarCall86 (
138 &Private
->LegacyBios
,
139 Private
->Legacy16CallSegment
,
140 Private
->Legacy16CallOffset
,
146 if (Regs
.X
.AX
== 0) {
147 *LegacyMemoryAddress
= (VOID
*) (UINTN
) ((Regs
.X
.DS
<< 4) + Regs
.X
.BX
);
148 Status
= EFI_SUCCESS
;
150 Status
= EFI_OUT_OF_RESOURCES
;
153 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
154 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
161 This function is called when copying data to the region assigned by
162 EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
164 @param This Protocol instance pointer.
165 @param LegacyMemorySize Size of data to copy
166 @param LegacyMemoryAddress Legacy Region destination address Note: must
167 be in region assigned by
168 LegacyBiosGetLegacyRegion
169 @param LegacyMemorySourceAddress Source of data
171 @retval EFI_SUCCESS The data was copied successfully.
172 @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.
176 LegacyBiosCopyLegacyRegion (
177 IN EFI_LEGACY_BIOS_PROTOCOL
*This
,
178 IN UINTN LegacyMemorySize
,
179 IN VOID
*LegacyMemoryAddress
,
180 IN VOID
*LegacyMemorySourceAddress
184 LEGACY_BIOS_INSTANCE
*Private
;
187 if ((LegacyMemoryAddress
< (VOID
*)(UINTN
)0xE0000 ) ||
188 ((UINTN
) LegacyMemoryAddress
+ LegacyMemorySize
> (UINTN
) 0x100000)
190 return EFI_ACCESS_DENIED
;
193 // There is no protection from writes over lapping if this function is
194 // called multiple times.
196 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
197 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
198 CopyMem (LegacyMemoryAddress
, LegacyMemorySourceAddress
, LegacyMemorySize
);
200 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate
);
201 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, 0xE0000, 0x20000, &Granularity
);
208 Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
209 the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
212 @param Private Legacy BIOS context data
214 @retval EFI_SUCCESS Legacy16 code loaded
215 @retval Other No protocol installed, unload driver.
219 ShadowAndStartLegacy16 (
220 IN LEGACY_BIOS_INSTANCE
*Private
227 EFI_COMPATIBILITY16_TABLE
*Table
;
229 EFI_IA32_REGISTER_SET Regs
;
230 EFI_TO_COMPATIBILITY16_INIT_TABLE
*EfiToLegacy16InitTable
;
231 EFI_TO_COMPATIBILITY16_BOOT_TABLE
*EfiToLegacy16BootTable
;
232 VOID
*LegacyBiosImage
;
233 UINTN LegacyBiosImageSize
;
237 LEGACY_EFI_HDD_TABLE
*LegacyEfiHddTable
;
240 VOID
*TpmBinaryImage
;
241 UINTN TpmBinaryImageSize
;
245 EFI_PHYSICAL_ADDRESS Address
;
249 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
255 // we allocate the C/D/E/F segment as RT code so no one will use it any more.
258 gDS
->GetMemorySpaceDescriptor (Address
, &Descriptor
);
259 if (Descriptor
.GcdMemoryType
== EfiGcdMemoryTypeSystemMemory
) {
261 // If it is already reserved, we should be safe, or else we allocate it.
263 Status
= gBS
->AllocatePages (
265 EfiRuntimeServicesCode
,
266 0x40000/EFI_PAGE_SIZE
,
269 if (EFI_ERROR (Status
)) {
271 // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
273 DEBUG ((DEBUG_ERROR
, "Failed to allocate the C/D/E/F segment Status = %r", Status
));
279 // GetTimerValue (&Ticker);
281 // gRT->SetVariable (L"StartLegacy",
282 // &gEfiGlobalVariableGuid,
283 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
289 EfiToLegacy16BootTable
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
290 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
291 Private
->LegacyBiosPlatform
,
292 EfiGetPlatformBinarySystemRom
,
294 &LegacyBiosImageSize
,
300 if (EFI_ERROR (Status
)) {
304 Private
->BiosStart
= (UINT32
) (0x100000 - LegacyBiosImageSize
);
305 Private
->OptionRom
= 0xc0000;
306 Private
->LegacyBiosImageSize
= (UINT32
) LegacyBiosImageSize
;
309 // Can only shadow into memory allocated for legacy useage.
311 ASSERT (Private
->BiosStart
> Private
->OptionRom
);
314 // Shadow Legacy BIOS. Turn on memory and copy image
316 Private
->LegacyRegion
->UnLock (Private
->LegacyRegion
, 0xc0000, 0x40000, &Granularity
);
318 ClearPtr
= (VOID
*) ((UINTN
) 0xc0000);
321 // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
322 // regions to be used by EMM386 etc.
324 SetMem ((VOID
*) ClearPtr
, (UINTN
) (0x40000 - LegacyBiosImageSize
), 0xff);
326 TempData
= Private
->BiosStart
;
331 (UINTN
) LegacyBiosImageSize
334 Private
->Cpu
->FlushDataCache (Private
->Cpu
, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate
);
337 // Search for Legacy16 table in Shadowed ROM
341 for (Ptr
= (UINT8
*) TempData
; Ptr
< (UINT8
*) ((UINTN
) 0x100000) && !Done
; Ptr
+= 0x10) {
342 if (*(UINT32
*) Ptr
== SIGNATURE_32 ('I', 'F', 'E', '$')) {
343 Table
= (EFI_COMPATIBILITY16_TABLE
*) Ptr
;
344 PtrEnd
= Ptr
+ Table
->TableLength
;
345 for (CheckSum
= 0; Ptr
< PtrEnd
; Ptr
++) {
346 CheckSum
= (UINT8
) (CheckSum
+*Ptr
);
354 DEBUG ((EFI_D_ERROR
, "No Legacy16 table found\n"));
355 return EFI_NOT_FOUND
;
360 // Legacy16 table header checksum error.
362 DEBUG ((EFI_D_ERROR
, "Legacy16 table found with bad talbe header checksum\n"));
366 // Remember location of the Legacy16 table
368 Private
->Legacy16Table
= Table
;
369 Private
->Legacy16CallSegment
= Table
->Compatibility16CallSegment
;
370 Private
->Legacy16CallOffset
= Table
->Compatibility16CallOffset
;
371 EfiToLegacy16InitTable
= &Private
->IntThunk
->EfiToLegacy16InitTable
;
372 Private
->Legacy16InitPtr
= EfiToLegacy16InitTable
;
373 Private
->Legacy16BootPtr
= &Private
->IntThunk
->EfiToLegacy16BootTable
;
374 Private
->InternalIrqRoutingTable
= NULL
;
375 Private
->NumberIrqRoutingEntries
= 0;
376 Private
->BbsTablePtr
= NULL
;
377 Private
->LegacyEfiHddTable
= NULL
;
378 Private
->DiskEnd
= 0;
379 Private
->Disk4075
= 0;
380 Private
->HddTablePtr
= &Private
->IntThunk
->EfiToLegacy16BootTable
.HddInfo
;
381 Private
->NumberHddControllers
= MAX_IDE_CONTROLLER
;
382 Private
->Dump
[0] = 'D';
383 Private
->Dump
[1] = 'U';
384 Private
->Dump
[2] = 'M';
385 Private
->Dump
[3] = 'P';
388 Private
->Legacy16BootPtr
,
389 sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE
)
393 // Store away a copy of the EFI System Table
395 Table
->EfiSystemTable
= (UINT32
) (UINTN
) gST
;
398 // IPF CSM integration -Bug
400 // Construct the Legacy16 boot memory map. This sets up number of
403 LegacyBiosBuildE820 (Private
, &E820Size
);
405 // Initialize BDA and EBDA standard values needed to load Legacy16 code
407 LegacyBiosInitBda (Private
);
408 LegacyBiosInitCmos (Private
);
411 // All legacy interrupt should be masked when do initialization work from legacy 16 code.
413 Private
->Legacy8259
->GetMask(Private
->Legacy8259
, &OldMask
, NULL
, NULL
, NULL
);
415 Private
->Legacy8259
->SetMask(Private
->Legacy8259
, &NewMask
, NULL
, NULL
, NULL
);
418 // Call into Legacy16 code to do an INIT
420 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
421 Regs
.X
.AX
= Legacy16InitializeYourself
;
422 Regs
.X
.ES
= EFI_SEGMENT (*((UINT32
*) &EfiToLegacy16InitTable
));
423 Regs
.X
.BX
= EFI_OFFSET (*((UINT32
*) &EfiToLegacy16InitTable
));
425 Private
->LegacyBios
.FarCall86 (
426 &Private
->LegacyBios
,
427 Table
->Compatibility16CallSegment
,
428 Table
->Compatibility16CallOffset
,
435 // Restore original legacy interrupt mask value
437 Private
->Legacy8259
->SetMask(Private
->Legacy8259
, &OldMask
, NULL
, NULL
, NULL
);
439 if (Regs
.X
.AX
!= 0) {
440 return EFI_DEVICE_ERROR
;
445 // GetTimerValue (&Ticker);
447 // gRT->SetVariable (L"BackFromInitYourself",
448 // &gEfiGlobalVariableGuid,
449 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
455 // Copy E820 table after InitializeYourself is completed
457 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
458 Regs
.X
.AX
= Legacy16GetTableAddress
;
459 Regs
.X
.CX
= (UINT16
) E820Size
;
461 Private
->LegacyBios
.FarCall86 (
462 &Private
->LegacyBios
,
463 Table
->Compatibility16CallSegment
,
464 Table
->Compatibility16CallOffset
,
470 Table
->E820Pointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
471 Table
->E820Length
= (UINT32
) E820Size
;
472 if (Regs
.X
.AX
!= 0) {
473 DEBUG ((EFI_D_ERROR
, "Legacy16 E820 length insufficient\n"));
475 TempData
= Table
->E820Pointer
;
476 CopyMem ((VOID
*) TempData
, Private
->E820Table
, E820Size
);
479 // Get PnPInstallationCheck Info.
481 Private
->PnPInstallationCheckSegment
= Table
->PnPInstallationCheckSegment
;
482 Private
->PnPInstallationCheckOffset
= Table
->PnPInstallationCheckOffset
;
485 // Check if PCI Express is supported. If yes, Save base address.
487 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
488 Private
->LegacyBiosPlatform
,
489 EfiGetPlatformPciExpressBase
,
497 if (!EFI_ERROR (Status
)) {
498 Private
->Legacy16Table
->PciExpressBase
= (UINT32
)Location
;
502 // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
503 // into, copy it and update pointer to binary image. This needs to be
504 // done prior to any OPROM for security purposes.
506 Status
= Private
->LegacyBiosPlatform
->GetPlatformInfo (
507 Private
->LegacyBiosPlatform
,
508 EfiGetPlatformBinaryTpmBinary
,
516 if (!EFI_ERROR (Status
)) {
518 ZeroMem (&Regs
, sizeof (EFI_IA32_REGISTER_SET
));
519 Regs
.X
.AX
= Legacy16GetTableAddress
;
520 Regs
.X
.CX
= (UINT16
) TpmBinaryImageSize
;
522 Private
->LegacyBios
.FarCall86 (
523 &Private
->LegacyBios
,
524 Table
->Compatibility16CallSegment
,
525 Table
->Compatibility16CallOffset
,
531 TpmPointer
= (UINT32
) (Regs
.X
.DS
* 16 + Regs
.X
.BX
);
532 if (Regs
.X
.AX
!= 0) {
533 DEBUG ((EFI_D_ERROR
, "TPM cannot be loaded\n"));
535 CopyMem ((VOID
*) (UINTN
)TpmPointer
, TpmBinaryImage
, TpmBinaryImageSize
);
536 Table
->TpmSegment
= Regs
.X
.DS
;
537 Table
->TpmOffset
= Regs
.X
.BX
;
542 // Lock the Legacy BIOS region
544 Private
->Cpu
->FlushDataCache (Private
->Cpu
, Private
->BiosStart
, (UINT32
) LegacyBiosImageSize
, EfiCpuFlushTypeWriteBackInvalidate
);
545 Private
->LegacyRegion
->Lock (Private
->LegacyRegion
, Private
->BiosStart
, (UINT32
) LegacyBiosImageSize
, &Granularity
);
548 // Get the BbsTable from LOW_MEMORY_THUNK
550 BbsTable
= (BBS_TABLE
*)(UINTN
)Private
->IntThunk
->BbsTable
;
551 ZeroMem ((VOID
*)BbsTable
, sizeof (Private
->IntThunk
->BbsTable
));
553 EfiToLegacy16BootTable
->BbsTable
= (UINT32
)(UINTN
)BbsTable
;
554 Private
->BbsTablePtr
= (VOID
*) BbsTable
;
556 // Skip Floppy and possible onboard IDE drives
558 EfiToLegacy16BootTable
->NumberBbsEntries
= 1 + 2 * MAX_IDE_CONTROLLER
;
560 for (Index
= 0; Index
< (sizeof (Private
->IntThunk
->BbsTable
) / sizeof (BBS_TABLE
)); Index
++) {
561 BbsTable
[Index
].BootPriority
= BBS_IGNORE_ENTRY
;
564 // Allocate space for Legacy HDD table
566 LegacyEfiHddTable
= (LEGACY_EFI_HDD_TABLE
*) AllocateZeroPool ((UINTN
) MAX_HDD_ENTRIES
* sizeof (LEGACY_EFI_HDD_TABLE
));
567 ASSERT (LegacyEfiHddTable
);
569 Private
->LegacyEfiHddTable
= LegacyEfiHddTable
;
570 Private
->LegacyEfiHddTableIndex
= 0x00;
574 // GetTimerValue (&Ticker);
576 // gRT->SetVariable (L"EndOfLoadFv",
577 // &gEfiGlobalVariableGuid,
578 // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
588 Shadow all legacy16 OPROMs that haven't been shadowed.
589 Warning: Use this with caution. This routine disconnects all EFI
590 drivers. If used externally then caller must re-connect EFI
593 @param This Protocol instance pointer.
595 @retval EFI_SUCCESS OPROMs shadowed
600 LegacyBiosShadowAllLegacyOproms (
601 IN EFI_LEGACY_BIOS_PROTOCOL
*This
604 LEGACY_BIOS_INSTANCE
*Private
;
607 // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
608 // EFI_LEGACY16_TABLE *Legacy16Table;
610 Private
= LEGACY_BIOS_INSTANCE_FROM_THIS (This
);
613 // LegacyBiosPlatform = Private->LegacyBiosPlatform;
614 // Legacy16Table = Private->Legacy16Table;
616 // Shadow PCI ROMs. We must do this near the end since this will kick
617 // of Native EFI drivers that may be needed to collect info for Legacy16
619 // WARNING: PciIo is gone after this call.
621 PciProgramAllInterruptLineRegisters (Private
);
623 PciShadowRoms (Private
);
626 // Shadow PXE base code, BIS etc.
628 // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
629 // &Private->OptionRom,
636 Get the PCI BIOS interface version.
638 @param Private Driver private data.
640 @return The PCI interface version number in Binary Coded Decimal (BCD) format.
641 E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
645 GetPciInterfaceVersion (
646 IN LEGACY_BIOS_INSTANCE
*Private
649 EFI_IA32_REGISTER_SET Reg
;
651 UINT16 PciInterfaceVersion
;
653 PciInterfaceVersion
= 0;
658 ThunkFailed
= Private
->LegacyBios
.Int86 (&Private
->LegacyBios
, 0x1A, &Reg
);
661 // From PCI Firmware 3.0 Specification:
662 // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
663 // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
664 // presence of the PCI function set. [BX] will further indicate the version level, with enough
665 // granularity to allow for incremental changes in the code that don't affect the function interface.
666 // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
667 // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
669 if ((Reg
.X
.Flags
.CF
== 0) && (Reg
.H
.AH
== 0) && (Reg
.E
.EDX
== SIGNATURE_32 ('P', 'C', 'I', ' '))) {
670 PciInterfaceVersion
= Reg
.X
.BX
;
673 return PciInterfaceVersion
;
677 Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table.
678 SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path.
680 @param Event Event whose notification function is being invoked.
681 @param Context The pointer to the notification function's context,
682 which is implementation-dependent.
687 InstallSmbiosEventCallback (
693 SMBIOS_TABLE_ENTRY_POINT
*EntryPointStructure
;
696 // Get SMBIOS table from EFI configuration table
698 Status
= EfiGetSystemConfigurationTable (
699 &gEfiSmbiosTableGuid
,
700 &mRuntimeSmbiosEntryPoint
702 if ((EFI_ERROR (Status
)) || (mRuntimeSmbiosEntryPoint
== NULL
)) {
706 EntryPointStructure
= (SMBIOS_TABLE_ENTRY_POINT
*) mRuntimeSmbiosEntryPoint
;
709 // Allocate memory for SMBIOS Entry Point Structure.
710 // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE.
712 if (mReserveSmbiosEntryPoint
== 0) {
714 // Entrypoint structure with fixed size is allocated only once.
716 mReserveSmbiosEntryPoint
= SIZE_4GB
- 1;
717 Status
= gBS
->AllocatePages (
719 EfiReservedMemoryType
,
720 EFI_SIZE_TO_PAGES ((UINTN
) (EntryPointStructure
->EntryPointLength
)),
721 &mReserveSmbiosEntryPoint
723 if (EFI_ERROR (Status
)) {
724 mReserveSmbiosEntryPoint
= 0;
727 DEBUG ((EFI_D_INFO
, "Allocate memory for Smbios Entry Point Structure\n"));
730 if ((mStructureTableAddress
!= 0) &&
731 (mStructureTablePages
< (UINTN
) EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
))) {
733 // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate
735 gBS
->FreePages (mStructureTableAddress
, mStructureTablePages
);
736 mStructureTableAddress
= 0;
737 mStructureTablePages
= 0;
738 DEBUG ((EFI_D_INFO
, "Original size is not enough. Re-allocate the memory.\n"));
741 if (mStructureTableAddress
== 0) {
743 // Allocate reserved memory below 4GB.
744 // Smbios spec requires the structure table is below 4GB.
746 mStructureTableAddress
= SIZE_4GB
- 1;
747 mStructureTablePages
= EFI_SIZE_TO_PAGES (EntryPointStructure
->TableLength
);
748 Status
= gBS
->AllocatePages (
750 EfiReservedMemoryType
,
751 mStructureTablePages
,
752 &mStructureTableAddress
754 if (EFI_ERROR (Status
)) {
756 mReserveSmbiosEntryPoint
,
757 EFI_SIZE_TO_PAGES ((UINTN
) (EntryPointStructure
->EntryPointLength
))
759 mReserveSmbiosEntryPoint
= 0;
760 mStructureTableAddress
= 0;
761 mStructureTablePages
= 0;
764 DEBUG ((EFI_D_INFO
, "Allocate memory for Smbios Structure Table\n"));
769 Install Driver to produce Legacy BIOS protocol.
771 @param ImageHandle Handle of driver image.
772 @param SystemTable Pointer to system table.
774 @retval EFI_SUCCESS Legacy BIOS protocol installed
775 @retval No protocol installed, unload driver.
781 IN EFI_HANDLE ImageHandle
,
782 IN EFI_SYSTEM_TABLE
*SystemTable
786 LEGACY_BIOS_INSTANCE
*Private
;
787 EFI_TO_COMPATIBILITY16_INIT_TABLE
*EfiToLegacy16InitTable
;
788 EFI_PHYSICAL_ADDRESS MemoryAddress
;
789 EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress
;
791 EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB
;
793 UINT32
*BaseVectorMaster
;
794 EFI_PHYSICAL_ADDRESS StartAddress
;
796 EFI_PHYSICAL_ADDRESS MemStart
;
801 EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor
;
804 EFI_EVENT InstallSmbiosEvent
;
807 // Load this driver's image to memory
809 Status
= RelocateImageUnder4GIfNeeded (ImageHandle
, SystemTable
);
810 if (EFI_ERROR (Status
)) {
815 // When UEFI Secure Boot is enabled, CSM module will not start any more.
818 GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME
, (VOID
**)&SecureBoot
, NULL
);
819 if ((SecureBoot
!= NULL
) && (*SecureBoot
== SECURE_BOOT_MODE_ENABLE
)) {
820 FreePool (SecureBoot
);
821 return EFI_SECURITY_VIOLATION
;
824 if (SecureBoot
!= NULL
) {
825 FreePool (SecureBoot
);
828 Private
= &mPrivateData
;
829 ZeroMem (Private
, sizeof (LEGACY_BIOS_INSTANCE
));
832 // Grab a copy of all the protocols we depend on. Any error would
833 // be a dispatcher bug!.
835 Status
= gBS
->LocateProtocol (&gEfiCpuArchProtocolGuid
, NULL
, (VOID
**) &Private
->Cpu
);
836 ASSERT_EFI_ERROR (Status
);
838 Status
= gBS
->LocateProtocol (&gEfiTimerArchProtocolGuid
, NULL
, (VOID
**) &Private
->Timer
);
839 ASSERT_EFI_ERROR (Status
);
841 Status
= gBS
->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyRegion
);
842 ASSERT_EFI_ERROR (Status
);
844 Status
= gBS
->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyBiosPlatform
);
845 ASSERT_EFI_ERROR (Status
);
847 Status
= gBS
->LocateProtocol (&gEfiLegacy8259ProtocolGuid
, NULL
, (VOID
**) &Private
->Legacy8259
);
848 ASSERT_EFI_ERROR (Status
);
850 Status
= gBS
->LocateProtocol (&gEfiLegacyInterruptProtocolGuid
, NULL
, (VOID
**) &Private
->LegacyInterrupt
);
851 ASSERT_EFI_ERROR (Status
);
854 // Locate Memory Test Protocol if exists
856 Status
= gBS
->LocateProtocol (
857 &gEfiGenericMemTestProtocolGuid
,
859 (VOID
**) &Private
->GenericMemoryTest
861 ASSERT_EFI_ERROR (Status
);
864 // Make sure all memory from 0-640K is tested
866 for (StartAddress
= 0; StartAddress
< 0xa0000; ) {
867 gDS
->GetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
868 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeReserved
) {
869 StartAddress
= Descriptor
.BaseAddress
+ Descriptor
.Length
;
872 Length
= MIN (Descriptor
.Length
, 0xa0000 - StartAddress
);
873 Private
->GenericMemoryTest
->CompatibleRangeTest (
874 Private
->GenericMemoryTest
,
878 StartAddress
= StartAddress
+ Length
;
881 // Make sure all memory from 1MB to 16MB is tested and added to memory map
883 for (StartAddress
= BASE_1MB
; StartAddress
< BASE_16MB
; ) {
884 gDS
->GetMemorySpaceDescriptor (StartAddress
, &Descriptor
);
885 if (Descriptor
.GcdMemoryType
!= EfiGcdMemoryTypeReserved
) {
886 StartAddress
= Descriptor
.BaseAddress
+ Descriptor
.Length
;
889 Length
= MIN (Descriptor
.Length
, BASE_16MB
- StartAddress
);
890 Private
->GenericMemoryTest
->CompatibleRangeTest (
891 Private
->GenericMemoryTest
,
895 StartAddress
= StartAddress
+ Length
;
898 Private
->Signature
= LEGACY_BIOS_INSTANCE_SIGNATURE
;
900 Private
->LegacyBios
.Int86
= LegacyBiosInt86
;
901 Private
->LegacyBios
.FarCall86
= LegacyBiosFarCall86
;
902 Private
->LegacyBios
.CheckPciRom
= LegacyBiosCheckPciRom
;
903 Private
->LegacyBios
.InstallPciRom
= LegacyBiosInstallPciRom
;
904 Private
->LegacyBios
.LegacyBoot
= LegacyBiosLegacyBoot
;
905 Private
->LegacyBios
.UpdateKeyboardLedStatus
= LegacyBiosUpdateKeyboardLedStatus
;
906 Private
->LegacyBios
.GetBbsInfo
= LegacyBiosGetBbsInfo
;
907 Private
->LegacyBios
.ShadowAllLegacyOproms
= LegacyBiosShadowAllLegacyOproms
;
908 Private
->LegacyBios
.PrepareToBootEfi
= LegacyBiosPrepareToBootEfi
;
909 Private
->LegacyBios
.GetLegacyRegion
= LegacyBiosGetLegacyRegion
;
910 Private
->LegacyBios
.CopyLegacyRegion
= LegacyBiosCopyLegacyRegion
;
911 Private
->LegacyBios
.BootUnconventionalDevice
= LegacyBiosBootUnconventionalDevice
;
913 Private
->ImageHandle
= ImageHandle
;
916 // Enable read attribute of legacy region.
919 Private
->LegacyRegion
->Decode (
920 Private
->LegacyRegion
,
927 // Set Cachebility for legacy region
928 // BUGBUG: Comments about this legacy region cacheability setting
929 // This setting will make D865GCHProduction CSM Unhappy
931 if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion
)) {
932 gDS
->SetMemorySpaceAttributes (
937 gDS
->SetMemorySpaceAttributes (
944 gDS
->SetMemorySpaceAttributes (
951 // Allocate 0 - 4K for real mode interupt vectors and BDA.
953 AllocateLegacyMemory (
959 ASSERT (MemoryAddress
== 0x000000000);
961 ClearPtr
= (VOID
*) ((UINTN
) 0x0000);
964 // Initialize region from 0x0000 to 4k. This initializes interrupt vector
967 gBS
->SetMem ((VOID
*) ClearPtr
, 0x400, INITIAL_VALUE_BELOW_1K
);
968 ZeroMem ((VOID
*) ((UINTN
)ClearPtr
+ 0x400), 0xC00);
971 // Allocate pages for OPROM usage
973 MemorySize
= PcdGet32 (PcdEbdaReservedMemorySize
);
974 ASSERT ((MemorySize
& 0xFFF) == 0);
976 Status
= AllocateLegacyMemory (
978 CONVENTIONAL_MEMORY_TOP
- MemorySize
,
979 EFI_SIZE_TO_PAGES (MemorySize
),
982 ASSERT_EFI_ERROR (Status
);
984 ZeroMem ((VOID
*) ((UINTN
) MemoryAddress
), MemorySize
);
987 // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
988 // don't use PMM but look for zeroed memory. Note that various non-BBS
989 // OpROMs expect different areas to be free
991 EbdaReservedBaseAddress
= MemoryAddress
;
992 MemoryAddress
= PcdGet32 (PcdOpromReservedMemoryBase
);
993 MemorySize
= PcdGet32 (PcdOpromReservedMemorySize
);
995 // Check if base address and size for reserved memory are 4KB aligned.
997 ASSERT ((MemoryAddress
& 0xFFF) == 0);
998 ASSERT ((MemorySize
& 0xFFF) == 0);
1000 // Check if the reserved memory is below EBDA reserved range.
1002 ASSERT ((MemoryAddress
< EbdaReservedBaseAddress
) && ((MemoryAddress
+ MemorySize
- 1) < EbdaReservedBaseAddress
));
1003 for (MemStart
= MemoryAddress
; MemStart
< MemoryAddress
+ MemorySize
; MemStart
+= 0x1000) {
1004 Status
= AllocateLegacyMemory (
1010 if (!EFI_ERROR (Status
)) {
1011 MemoryPtr
= (VOID
*) ((UINTN
) StartAddress
);
1012 ZeroMem (MemoryPtr
, 0x1000);
1014 DEBUG ((EFI_D_ERROR
, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart
));
1019 // Allocate low PMM memory and zero it out
1021 MemorySize
= PcdGet32 (PcdLowPmmMemorySize
);
1022 ASSERT ((MemorySize
& 0xFFF) == 0);
1023 Status
= AllocateLegacyMemory (
1025 CONVENTIONAL_MEMORY_TOP
,
1026 EFI_SIZE_TO_PAGES (MemorySize
),
1027 &MemoryAddressUnder1MB
1029 ASSERT_EFI_ERROR (Status
);
1031 ZeroMem ((VOID
*) ((UINTN
) MemoryAddressUnder1MB
), MemorySize
);
1034 // Allocate space for thunker and Init Thunker
1036 Status
= AllocateLegacyMemory (
1038 CONVENTIONAL_MEMORY_TOP
,
1039 (sizeof (LOW_MEMORY_THUNK
) / EFI_PAGE_SIZE
) + 2,
1042 ASSERT_EFI_ERROR (Status
);
1043 Private
->IntThunk
= (LOW_MEMORY_THUNK
*) (UINTN
) MemoryAddress
;
1044 EfiToLegacy16InitTable
= &Private
->IntThunk
->EfiToLegacy16InitTable
;
1045 EfiToLegacy16InitTable
->ThunkStart
= (UINT32
) (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemoryAddress
;
1046 EfiToLegacy16InitTable
->ThunkSizeInBytes
= (UINT32
) (sizeof (LOW_MEMORY_THUNK
));
1048 Status
= LegacyBiosInitializeThunk (Private
);
1049 ASSERT_EFI_ERROR (Status
);
1052 // Init the legacy memory map in memory < 1 MB.
1054 EfiToLegacy16InitTable
->BiosLessThan1MB
= (UINT32
) MemoryAddressUnder1MB
;
1055 EfiToLegacy16InitTable
->LowPmmMemory
= (UINT32
) MemoryAddressUnder1MB
;
1056 EfiToLegacy16InitTable
->LowPmmMemorySizeInBytes
= MemorySize
;
1058 MemorySize
= PcdGet32 (PcdHighPmmMemorySize
);
1059 ASSERT ((MemorySize
& 0xFFF) == 0);
1061 // Allocate high PMM Memory under 16 MB
1063 Status
= AllocateLegacyMemory (
1066 EFI_SIZE_TO_PAGES (MemorySize
),
1069 if (EFI_ERROR (Status
)) {
1071 // If it fails, allocate high PMM Memory under 4GB
1073 Status
= AllocateLegacyMemory (
1076 EFI_SIZE_TO_PAGES (MemorySize
),
1080 if (!EFI_ERROR (Status
)) {
1081 EfiToLegacy16InitTable
->HiPmmMemory
= (UINT32
) (EFI_PHYSICAL_ADDRESS
) (UINTN
) MemoryAddress
;
1082 EfiToLegacy16InitTable
->HiPmmMemorySizeInBytes
= MemorySize
;
1088 // Start the Legacy BIOS;
1090 Status
= ShadowAndStartLegacy16 (Private
);
1091 if (EFI_ERROR (Status
)) {
1095 // Initialize interrupt redirection code and entries;
1096 // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
1099 Private
->IntThunk
->InterruptRedirectionCode
,
1100 (VOID
*) (UINTN
) InterruptRedirectionTemplate
,
1101 sizeof (Private
->IntThunk
->InterruptRedirectionCode
)
1105 // Save Unexpected interrupt vector so can restore it just prior to boot
1107 BaseVectorMaster
= (UINT32
*) (sizeof (UINT32
) * PROTECTED_MODE_BASE_VECTOR_MASTER
);
1108 Private
->BiosUnexpectedInt
= BaseVectorMaster
[0];
1109 IntRedirCode
= (UINT32
) (UINTN
) Private
->IntThunk
->InterruptRedirectionCode
;
1110 for (Index
= 0; Index
< 8; Index
++) {
1111 BaseVectorMaster
[Index
] = (EFI_SEGMENT (IntRedirCode
+ Index
* 4) << 16) | EFI_OFFSET (IntRedirCode
+ Index
* 4);
1116 Private
->ThunkSeg
= (UINT16
) (EFI_SEGMENT (IntRedirCode
));
1119 // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists
1121 InstallSmbiosEventCallback (NULL
, NULL
);
1124 // Create callback function to update the size of reserved memory after LegacyBiosDxe starts
1126 Status
= gBS
->CreateEventEx (
1129 InstallSmbiosEventCallback
,
1131 &gEfiSmbiosTableGuid
,
1134 ASSERT_EFI_ERROR (Status
);
1137 // Make a new handle and install the protocol
1139 Private
->Handle
= NULL
;
1140 Status
= gBS
->InstallProtocolInterface (
1142 &gEfiLegacyBiosProtocolGuid
,
1143 EFI_NATIVE_INTERFACE
,
1144 &Private
->LegacyBios
1146 Private
->Csm16PciInterfaceVersion
= GetPciInterfaceVersion (Private
);
1148 DEBUG ((EFI_D_INFO
, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
1149 (UINT8
) (Private
->Csm16PciInterfaceVersion
>> 8),
1150 (UINT8
) Private
->Csm16PciInterfaceVersion
1152 ASSERT (Private
->Csm16PciInterfaceVersion
!= 0);