X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=IntelFrameworkModulePkg%2FCsm%2FLegacyBiosDxe%2FLegacyBios.c;h=fca08a8fa26d4be275576f8b6156290f96a9e5fc;hp=0381098c8a8f64b8679c1f4aed8b68ebacdfe462;hb=2ea3576e16a2af9e21e06ef4b759833989efced2;hpb=0f8b02980ed25b9a2310a4d2172de9a172c9262d diff --git a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c index 0381098c8a..fca08a8fa2 100644 --- a/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c +++ b/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c @@ -1,6 +1,6 @@ /** @file -Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.
+Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.
This program and the accompanying materials are licensed and made available under the terms and conditions @@ -29,6 +29,19 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. // LEGACY_BIOS_INSTANCE mPrivateData; +// +// The SMBIOS table in EfiRuntimeServicesData memory +// +VOID *mRuntimeSmbiosEntryPoint = NULL; + +// +// The SMBIOS table in EfiReservedMemoryType memory +// +EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0; +EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0; +UINTN mStructureTablePages = 0; +BOOLEAN mEndOfDxe = FALSE; + /** Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode memory. @@ -132,7 +145,7 @@ LegacyBiosGetLegacyRegion ( ); if (Regs.X.AX == 0) { - *LegacyMemoryAddress = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX); + *LegacyMemoryAddress = (VOID *) (((UINTN) Regs.X.DS << 4) + Regs.X.BX); Status = EFI_SUCCESS; } else { Status = EFI_OUT_OF_RESOURCES; @@ -661,6 +674,118 @@ GetPciInterfaceVersion ( return PciInterfaceVersion; } +/** + Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table. + SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path. + + @param Event Event whose notification function is being invoked. + @param Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +InstallSmbiosEventCallback ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + EFI_STATUS Status; + SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure; + + // + // Get SMBIOS table from EFI configuration table + // + Status = EfiGetSystemConfigurationTable ( + &gEfiSmbiosTableGuid, + &mRuntimeSmbiosEntryPoint + ); + if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) { + return; + } + + EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint; + + // + // Allocate memory for SMBIOS Entry Point Structure. + // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE. + // + if (mReserveSmbiosEntryPoint == 0) { + // + // Entrypoint structure with fixed size is allocated only once. + // + mReserveSmbiosEntryPoint = SIZE_4GB - 1; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)), + &mReserveSmbiosEntryPoint + ); + if (EFI_ERROR (Status)) { + mReserveSmbiosEntryPoint = 0; + return; + } + DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Entry Point Structure\n")); + } + + if ((mStructureTableAddress != 0) && + (mStructureTablePages < EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength))) { + // + // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate + // + gBS->FreePages (mStructureTableAddress, mStructureTablePages); + mStructureTableAddress = 0; + mStructureTablePages = 0; + DEBUG ((EFI_D_INFO, "Original size is not enough. Re-allocate the memory.\n")); + } + + if (mStructureTableAddress == 0) { + // + // Allocate reserved memory below 4GB. + // Smbios spec requires the structure table is below 4GB. + // + mStructureTableAddress = SIZE_4GB - 1; + mStructureTablePages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength); + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiReservedMemoryType, + mStructureTablePages, + &mStructureTableAddress + ); + if (EFI_ERROR (Status)) { + gBS->FreePages ( + mReserveSmbiosEntryPoint, + EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)) + ); + mReserveSmbiosEntryPoint = 0; + mStructureTableAddress = 0; + mStructureTablePages = 0; + return; + } + DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Structure Table\n")); + } +} + +/** + Callback function to toggle EndOfDxe status. NULL pointer detection needs + this status to decide if it's necessary to change attributes of page 0. + + @param Event Event whose notification function is being invoked. + @param Context The pointer to the notification function's context, + which is implementation-dependent. + +**/ +VOID +EFIAPI +ToggleEndOfDxeStatus ( + IN EFI_EVENT Event, + IN VOID *Context + ) +{ + mEndOfDxe = TRUE; + return; +} + /** Install Driver to produce Legacy BIOS protocol. @@ -682,6 +807,7 @@ LegacyBiosInstall ( LEGACY_BIOS_INSTANCE *Private; EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable; EFI_PHYSICAL_ADDRESS MemoryAddress; + EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress; VOID *MemoryPtr; EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB; UINTN Index; @@ -696,6 +822,8 @@ LegacyBiosInstall ( EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor; UINT64 Length; UINT8 *SecureBoot; + EFI_EVENT InstallSmbiosEvent; + EFI_EVENT EndOfDxeEvent; // // Load this driver's image to memory @@ -858,8 +986,10 @@ LegacyBiosInstall ( // Initialize region from 0x0000 to 4k. This initializes interrupt vector // range. // - gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K); - ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00); + ACCESS_PAGE0_CODE ( + gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K); + ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00); + ); // // Allocate pages for OPROM usage @@ -880,17 +1010,29 @@ LegacyBiosInstall ( // // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that // don't use PMM but look for zeroed memory. Note that various non-BBS - // SCSIs expect different areas to be free + // OpROMs expect different areas to be free + // + EbdaReservedBaseAddress = MemoryAddress; + MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase); + MemorySize = PcdGet32 (PcdOpromReservedMemorySize); + // + // Check if base address and size for reserved memory are 4KB aligned. + // + ASSERT ((MemoryAddress & 0xFFF) == 0); + ASSERT ((MemorySize & 0xFFF) == 0); + // + // Check if the reserved memory is below EBDA reserved range. // - for (MemStart = 0x60000; MemStart < 0x88000; MemStart += 0x1000) { + ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress)); + for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) { Status = AllocateLegacyMemory ( AllocateAddress, MemStart, 1, - &MemoryAddress + &StartAddress ); if (!EFI_ERROR (Status)) { - MemoryPtr = (VOID *) ((UINTN) MemoryAddress); + MemoryPtr = (VOID *) ((UINTN) StartAddress); ZeroMem (MemoryPtr, 0x1000); } else { DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart)); @@ -986,16 +1128,51 @@ LegacyBiosInstall ( // // Save Unexpected interrupt vector so can restore it just prior to boot // - BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); - Private->BiosUnexpectedInt = BaseVectorMaster[0]; - IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode; - for (Index = 0; Index < 8; Index++) { - BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4); - } + ACCESS_PAGE0_CODE ( + BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER); + Private->BiosUnexpectedInt = BaseVectorMaster[0]; + IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode; + for (Index = 0; Index < 8; Index++) { + BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4); + } + ); + // // Save EFI value // Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode)); + + // + // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists + // + InstallSmbiosEventCallback (NULL, NULL); + + // + // Create callback function to update the size of reserved memory after LegacyBiosDxe starts + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + InstallSmbiosEventCallback, + NULL, + &gEfiSmbiosTableGuid, + &InstallSmbiosEvent + ); + ASSERT_EFI_ERROR (Status); + + // + // Create callback to update status of EndOfDxe, which is needed by NULL + // pointer detection + // + Status = gBS->CreateEventEx ( + EVT_NOTIFY_SIGNAL, + TPL_NOTIFY, + ToggleEndOfDxeStatus, + NULL, + &gEfiEndOfDxeEventGroupGuid, + &EndOfDxeEvent + ); + ASSERT_EFI_ERROR (Status); // // Make a new handle and install the protocol