EFI_STATUS EFIAPI PeimInitializeFlashMap ( IN EFI_PEI_FILE_HANDLE FileHandle, IN CONST EFI_PEI_SERVICES **PeiServices ) /*++ Routine Description: Build GUIDed HOBs for platform specific flash map Arguments: FfsHeader - A pointer to the EFI_FFS_FILE_HEADER structure. PeiServices - General purpose services available to every PEIM. Returns: EFI_STATUS **/ { EFI_STATUS Status; EMU_THUNK_PPI *Thunk; EFI_PEI_PPI_DESCRIPTOR *PpiDescriptor; EFI_PHYSICAL_ADDRESS FdBase; EFI_PHYSICAL_ADDRESS FdFixUp; UINT64 FdSize; DEBUG ((EFI_D_ERROR, "EmulatorPkg Flash Map PEIM Loaded\n")); // // Get the Fwh Information PPI // Status = PeiServicesLocatePpi ( &gEmuThunkPpiGuid, // GUID 0, // INSTANCE &PpiDescriptor, // EFI_PEI_PPI_DESCRIPTOR (VOID **)&Thunk // PPI ); ASSERT_EFI_ERROR (Status); // // Assume that FD0 contains the Flash map. // Status = Thunk->FirmwareDevices (0, &FdBase, &FdSize, &FdFixUp); if (EFI_ERROR (Status)) { return Status; } PcdSet64 (PcdFlashNvStorageVariableBase64, PcdGet64 (PcdEmuFlashNvStorageVariableBase) + FdFixUp); PcdSet64 (PcdFlashNvStorageFtwWorkingBase64, PcdGet64 (PcdEmuFlashNvStorageFtwWorkingBase) + FdFixUp); PcdSet64 (PcdFlashNvStorageFtwSpareBase64, PcdGet64 (PcdEmuFlashNvStorageFtwSpareBase) + FdFixUp); return EFI_SUCCESS; }
EFI_STATUS EFIAPI VisitingFileSystemInstance ( IN EFI_HANDLE Handle, IN VOID *Instance, IN VOID *Context ) { EFI_STATUS Status; STATIC BOOLEAN ConnectedToFileSystem = FALSE; if (ConnectedToFileSystem) { return EFI_ALREADY_STARTED; } Status = ConnectNvVarsToFileSystem (Handle); if (EFI_ERROR (Status)) { return Status; } ConnectedToFileSystem = TRUE; mEmuVariableEvent = EfiCreateProtocolNotifyEvent ( &gEfiDevicePathProtocolGuid, TPL_CALLBACK, EmuVariablesUpdatedCallback, NULL, &mEmuVariableEventReg ); PcdSet64 (PcdEmuVariableEvent, (UINT64)(UINTN) mEmuVariableEvent); return EFI_SUCCESS; }
VOID ReserveEmuVariableNvStore ( ) { EFI_PHYSICAL_ADDRESS VariableStore; // // Allocate storage for NV variables early on so it will be // at a consistent address. Since VM memory is preserved // across reboots, this allows the NV variable storage to survive // a VM reboot. // VariableStore = (EFI_PHYSICAL_ADDRESS)(UINTN) AllocateAlignedRuntimePages ( EFI_SIZE_TO_PAGES (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)), PcdGet32 (PcdFlashNvStorageFtwSpareSize) ); DEBUG ((EFI_D_INFO, "Reserved variable store memory: 0x%lX; size: %dkb\n", VariableStore, (2 * PcdGet32 (PcdFlashNvStorageFtwSpareSize)) / 1024 )); PcdSet64 (PcdEmuVariableNvStoreReserved, VariableStore); }
/** This function initialize basic context for FRM. **/ VOID InitBasicContext ( VOID ) { UINT32 RegEax; mHostContextCommon.CpuNum = GetCpuNumFromAcpi (); GetPciExpressInfoFromAcpi (&mHostContextCommon.PciExpressBaseAddress, &mHostContextCommon.PciExpressLength); PcdSet64 (PcdPciExpressBaseAddress, mHostContextCommon.PciExpressBaseAddress); if (mHostContextCommon.PciExpressBaseAddress == 0) { CpuDeadLoop (); } mHostContextCommon.AcpiTimerIoPortBaseAddress = GetAcpiTimerPort (&mHostContextCommon.AcpiTimerWidth); PcdSet16 (PcdAcpiTimerIoPortBaseAddress, mHostContextCommon.AcpiTimerIoPortBaseAddress); PcdSet8 (PcdAcpiTimerWidth, mHostContextCommon.AcpiTimerWidth); if (mHostContextCommon.AcpiTimerIoPortBaseAddress == 0) { CpuDeadLoop (); } mHostContextCommon.ResetIoPortBaseAddress = GetAcpiResetPort (); mHostContextCommon.AcpiPmControlIoPortBaseAddress = GetAcpiPmControlPort (); if (mHostContextCommon.AcpiPmControlIoPortBaseAddress == 0) { CpuDeadLoop (); } mHostContextCommon.HostContextPerCpu = AllocatePages (FRM_SIZE_TO_PAGES(sizeof(FRM_HOST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum); mGuestContextCommon.GuestContextPerCpu = AllocatePages (FRM_SIZE_TO_PAGES(sizeof(FRM_GUEST_CONTEXT_PER_CPU)) * mHostContextCommon.CpuNum); mHostContextCommon.LowMemoryBase = mCommunicationData.LowMemoryBase; mHostContextCommon.LowMemorySize = mCommunicationData.LowMemorySize; mHostContextCommon.LowMemoryBackupBase = (UINT64)(UINTN)AllocatePages (FRM_SIZE_TO_PAGES ((UINTN)mCommunicationData.LowMemorySize)); // // Save current context // mBspIndex = ApicToIndex (ReadLocalApicId ()); mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr0 = AsmReadCr0 (); mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr3 = AsmReadCr3 (); mGuestContextCommon.GuestContextPerCpu[mBspIndex].Cr4 = AsmReadCr4 (); AsmReadGdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Gdtr); AsmReadIdtr (&mGuestContextCommon.GuestContextPerCpu[mBspIndex].Idtr); AsmCpuid (CPUID_EXTENDED_INFORMATION, &RegEax, NULL, NULL, NULL); if (RegEax >= CPUID_EXTENDED_ADDRESS_SIZE) { AsmCpuid (CPUID_EXTENDED_ADDRESS_SIZE, &RegEax, NULL, NULL, NULL); mHostContextCommon.PhysicalAddressBits = (UINT8)RegEax; } else { mHostContextCommon.PhysicalAddressBits = 36; } }
/** *--------------------------------------------------------------------------------------- * PlatInitPeiEntryPoint * * Description: * Entry point of the PlatInit PEI module. * * Control flow: * Query platform parameters via ISCP. * * Parameters: * @param[in] FfsHeader EFI_PEI_FILE_HANDLE * @param[in] **PeiServices Pointer to the PEI Services Table. * * @return EFI_STATUS * *--------------------------------------------------------------------------------------- */ EFI_STATUS EFIAPI PlatInitPeiEntryPoint ( IN EFI_PEI_FILE_HANDLE FfsHeader, IN CONST EFI_PEI_SERVICES **PeiServices ) { EFI_STATUS Status = EFI_SUCCESS; AMD_MEMORY_RANGE_DESCRIPTOR IscpMemDescriptor = {0}; ISCP_FUSE_INFO IscpFuseInfo = {0}; ISCP_CPU_RESET_INFO CpuResetInfo = {0}; #if DO_XGBE == 1 ISCP_MAC_INFO MacAddrInfo = {0}; UINT64 MacAddr0, MacAddr1; #endif UINTN CpuCoreCount, CpuMap, CpuMapSize; UINTN Index, CoreNum; UINT32 *CpuIdReg = (UINT32 *)FixedPcdGet32 (PcdCpuIdRegister); DEBUG ((EFI_D_ERROR, "PlatInit PEIM Loaded\n")); // CPUID PcdSet32 (PcdSocCpuId, *CpuIdReg); DEBUG ((EFI_D_ERROR, "SocCpuId = 0x%X\n", PcdGet32 (PcdSocCpuId))); // Update core count based on PCD option if (mAmdCoreCount > PcdGet32 (PcdSocCoreCount)) { mAmdCoreCount = PcdGet32 (PcdSocCoreCount); } if (FixedPcdGetBool (PcdIscpSupport)) { Status = PeiServicesLocatePpi (&gPeiIscpPpiGuid, 0, NULL, (VOID**)&PeiIscpPpi); ASSERT_EFI_ERROR (Status); // Get fuse information from ISCP Status = PeiIscpPpi->ExecuteFuseTransaction (PeiServices, &IscpFuseInfo); ASSERT_EFI_ERROR (Status); CpuMap = IscpFuseInfo.SocConfiguration.CpuMap; CpuCoreCount = IscpFuseInfo.SocConfiguration.CpuCoreCount; CpuMapSize = sizeof (IscpFuseInfo.SocConfiguration.CpuMap) * 8; ASSERT (CpuMap != 0); ASSERT (CpuCoreCount != 0); ASSERT (CpuCoreCount <= CpuMapSize); // Update core count based on fusing if (mAmdCoreCount > CpuCoreCount) { mAmdCoreCount = CpuCoreCount; } } // // Update per-core information from ISCP // if (!FixedPcdGetBool (PcdIscpSupport)) { DEBUG ((EFI_D_ERROR, "Warning: Could not get CPU info via ISCP, using default values.\n")); } else { // // Walk CPU map to enumerate active cores // for (CoreNum = 0, Index = 0; CoreNum < CpuMapSize && Index < mAmdCoreCount; ++CoreNum) { if (CpuMap & 1) { CpuResetInfo.CoreNum = CoreNum; Status = PeiIscpPpi->ExecuteCpuRetrieveIdTransaction ( PeiServices, &CpuResetInfo ); ASSERT_EFI_ERROR (Status); ASSERT (CpuResetInfo.CoreStatus.Status != CPU_CORE_DISABLED); ASSERT (CpuResetInfo.CoreStatus.Status != CPU_CORE_UNDEFINED); mAmdMpCoreInfoTable[Index].ClusterId = CpuResetInfo.CoreStatus.ClusterId; mAmdMpCoreInfoTable[Index].CoreId = CpuResetInfo.CoreStatus.CoreId; DEBUG ((EFI_D_ERROR, "Core[%d]: ClusterId = %d CoreId = %d\n", Index, mAmdMpCoreInfoTable[Index].ClusterId, mAmdMpCoreInfoTable[Index].CoreId)); // Next core in Table ++Index; } // Next core in Map CpuMap >>= 1; } // Update core count based on CPU map if (mAmdCoreCount > Index) { mAmdCoreCount = Index; } } // Update SocCoreCount on Dynamic PCD if (PcdGet32 (PcdSocCoreCount) != mAmdCoreCount) { PcdSet32 (PcdSocCoreCount, mAmdCoreCount); } DEBUG ((EFI_D_ERROR, "SocCoreCount = %d\n", PcdGet32 (PcdSocCoreCount))); // Build AmdMpCoreInfo HOB BuildGuidDataHob (&gAmdStyxMpCoreInfoGuid, mAmdMpCoreInfoTable, sizeof (ARM_CORE_INFO) * mAmdCoreCount); // Get SystemMemorySize from ISCP IscpMemDescriptor.Size0 = 0; if (FixedPcdGetBool (PcdIscpSupport)) { Status = PeiIscpPpi->ExecuteMemoryTransaction (PeiServices, &IscpMemDescriptor); ASSERT_EFI_ERROR (Status); // Update SystemMemorySize on Dynamic PCD if (IscpMemDescriptor.Size0) { PcdSet64 (PcdSystemMemorySize, IscpMemDescriptor.Size0); } } if (IscpMemDescriptor.Size0 == 0) { DEBUG ((EFI_D_ERROR, "Warning: Could not get SystemMemorySize via ISCP, using default value.\n")); } DEBUG ((EFI_D_ERROR, "SystemMemorySize = %ld\n", PcdGet64 (PcdSystemMemorySize))); #if DO_XGBE == 1 // Get MAC Address from ISCP if (FixedPcdGetBool (PcdIscpSupport)) { Status = PeiIscpPpi->ExecuteGetMacAddressTransaction ( PeiServices, &MacAddrInfo ); ASSERT_EFI_ERROR (Status); MacAddr0 = MacAddr1 = 0; for (Index = 0; Index < 6; ++Index) { MacAddr0 |= (UINT64)MacAddrInfo.MacAddress0[Index] << (Index * 8); MacAddr1 |= (UINT64)MacAddrInfo.MacAddress1[Index] << (Index * 8); } PcdSet64 (PcdEthMacA, MacAddr0); PcdSet64 (PcdEthMacB, MacAddr1); } DEBUG ((EFI_D_ERROR, "EthMacA = 0x%lX\n", PcdGet64 (PcdEthMacA))); DEBUG ((EFI_D_ERROR, "EthMacB = 0x%lX\n", PcdGet64 (PcdEthMacB))); #endif // Let other PEI modules know we're done! Status = (*PeiServices)->InstallPpi (PeiServices, &mPlatInitPpiDescriptor); ASSERT_EFI_ERROR (Status); return Status; }
/** Initialize the system (or sometimes called permanent) memory This memory is generally represented by the DRAM. This function is called from InitializeMemory() in MemoryInitPeim, in the PEI phase. **/ VOID ArmPlatformInitializeSystemMemory ( VOID ) { VOID *DeviceTreeBase; INT32 Node, Prev; UINT64 NewBase; UINT64 NewSize; CONST CHAR8 *Type; INT32 Len; CONST UINT64 *RegProp; NewBase = 0; NewSize = 0; DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress); ASSERT (DeviceTreeBase != NULL); // // Make sure we have a valid device tree blob // ASSERT (fdt_check_header (DeviceTreeBase) == 0); // // Look for a memory node // for (Prev = 0;; Prev = Node) { Node = fdt_next_node (DeviceTreeBase, Prev, NULL); if (Node < 0) { break; } // // Check for memory node // Type = fdt_getprop (DeviceTreeBase, Node, "device_type", &Len); if (Type && AsciiStrnCmp (Type, "memory", Len) == 0) { // // Get the 'reg' property of this node. For now, we will assume // two 8 byte quantities for base and size, respectively. // RegProp = fdt_getprop (DeviceTreeBase, Node, "reg", &Len); if (RegProp != 0 && Len == (2 * sizeof (UINT64))) { NewBase = fdt64_to_cpu (ReadUnaligned64 (RegProp)); NewSize = fdt64_to_cpu (ReadUnaligned64 (RegProp + 1)); // // Make sure the start of DRAM matches our expectation // ASSERT (FixedPcdGet64 (PcdSystemMemoryBase) == NewBase); PcdSet64 (PcdSystemMemorySize, NewSize); DEBUG ((EFI_D_INFO, "%a: System RAM @ 0x%lx - 0x%lx\n", __FUNCTION__, NewBase, NewBase + NewSize - 1)); } else { DEBUG ((EFI_D_ERROR, "%a: Failed to parse FDT memory node\n", __FUNCTION__)); } break; } } // // We need to make sure that the machine we are running on has at least // 128 MB of memory configured, and is currently executing this binary from // NOR flash. This prevents a device tree image in DRAM from getting // clobbered when our caller installs permanent PEI RAM, before we have a // chance of marking its location as reserved or copy it to a freshly // allocated block in the permanent PEI RAM in the platform PEIM. // ASSERT (NewSize >= SIZE_128MB); ASSERT ( (((UINT64)PcdGet64 (PcdFdBaseAddress) + (UINT64)PcdGet32 (PcdFdSize)) <= NewBase) || ((UINT64)PcdGet64 (PcdFdBaseAddress) >= (NewBase + NewSize))); }
VOID MemMapInitialization ( VOID ) { // // Create Memory Type Information HOB // BuildGuidDataHob ( &gEfiMemoryTypeInformationGuid, mDefaultMemoryTypeInformation, sizeof(mDefaultMemoryTypeInformation) ); // // Add PCI IO Port space available for PCI resource allocations. // BuildResourceDescriptorHob ( EFI_RESOURCE_IO, EFI_RESOURCE_ATTRIBUTE_PRESENT | EFI_RESOURCE_ATTRIBUTE_INITIALIZED, PcdGet64 (PcdPciIoBase), PcdGet64 (PcdPciIoSize) ); // // Video memory + Legacy BIOS region // AddIoMemoryRangeHob (0x0A0000, BASE_1MB); if (!mXen) { UINT32 TopOfLowRam; UINT64 PciExBarBase; UINT32 PciBase; UINT32 PciSize; TopOfLowRam = GetSystemMemorySizeBelow4gb (); PciExBarBase = 0; if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { // // The MMCONFIG area is expected to fall between the top of low RAM and // the base of the 32-bit PCI host aperture. // PciExBarBase = FixedPcdGet64 (PcdPciExpressBaseAddress); ASSERT (TopOfLowRam <= PciExBarBase); ASSERT (PciExBarBase <= MAX_UINT32 - SIZE_256MB); PciBase = (UINT32)(PciExBarBase + SIZE_256MB); } else { PciBase = (TopOfLowRam < BASE_2GB) ? BASE_2GB : TopOfLowRam; } // // address purpose size // ------------ -------- ------------------------- // max(top, 2g) PCI MMIO 0xFC000000 - max(top, 2g) // 0xFC000000 gap 44 MB // 0xFEC00000 IO-APIC 4 KB // 0xFEC01000 gap 1020 KB // 0xFED00000 HPET 1 KB // 0xFED00400 gap 111 KB // 0xFED1C000 gap (PIIX4) / RCRB (ICH9) 16 KB // 0xFED20000 gap 896 KB // 0xFEE00000 LAPIC 1 MB // PciSize = 0xFC000000 - PciBase; AddIoMemoryBaseSizeHob (PciBase, PciSize); PcdSet64 (PcdPciMmio32Base, PciBase); PcdSet64 (PcdPciMmio32Size, PciSize); AddIoMemoryBaseSizeHob (0xFEC00000, SIZE_4KB); AddIoMemoryBaseSizeHob (0xFED00000, SIZE_1KB); if (mHostBridgeDevId == INTEL_Q35_MCH_DEVICE_ID) { AddIoMemoryBaseSizeHob (ICH9_ROOT_COMPLEX_BASE, SIZE_16KB); // // Note: there should be an // // AddIoMemoryBaseSizeHob (PciExBarBase, SIZE_256MB); // // call below, just like the one above for RCBA. However, Linux insists // that the MMCONFIG area be marked in the E820 or UEFI memory map as // "reserved memory" -- Linux does not content itself with a simple gap // in the memory map wherever the MCFG ACPI table points to. // // This appears to be a safety measure. The PCI Firmware Specification // (rev 3.1) says in 4.1.2. "MCFG Table Description": "The resources can // *optionally* be returned in [...] EFIGetMemoryMap as reserved memory // [...]". (Emphasis added here.) // // Normally we add memory resource descriptor HOBs in // QemuInitializeRam(), and pre-allocate from those with memory // allocation HOBs in InitializeRamRegions(). However, the MMCONFIG area // is most definitely not RAM; so, as an exception, cover it with // uncacheable reserved memory right here. // AddReservedMemoryBaseSizeHob (PciExBarBase, SIZE_256MB, FALSE); BuildMemoryAllocationHob (PciExBarBase, SIZE_256MB, EfiReservedMemoryType); } AddIoMemoryBaseSizeHob (PcdGet32(PcdCpuLocalApicBaseAddress), SIZE_1MB); } }
/** Main entry point. @param[in] ImageHandle The firmware allocated handle for the EFI image. @param[in] SystemTable A pointer to the EFI System Table. @retval EFI_SUCCESS Successfully initialized. **/ EFI_STATUS EFIAPI FvbInitialize ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { EFI_STATUS Status; VOID *Ptr; VOID *SubPtr; BOOLEAN Initialize; EFI_HANDLE Handle; EFI_PHYSICAL_ADDRESS Address; DEBUG ((EFI_D_INFO, "EMU Variable FVB Started\n")); // // Verify that the PCD's are set correctly. // if ( (PcdGet32 (PcdVariableStoreSize) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) ) > EMU_FVB_BLOCK_SIZE ) { DEBUG ((EFI_D_ERROR, "EMU Variable invalid PCD sizes\n")); return EFI_INVALID_PARAMETER; } if (PcdGet64 (PcdFlashNvStorageVariableBase64) != 0) { DEBUG ((EFI_D_INFO, "Disabling EMU Variable FVB since " "flash variables appear to be supported.\n")); return EFI_ABORTED; } // // By default we will initialize the FV contents. But, if // PcdEmuVariableNvStoreReserved is non-zero, then we will // use this location for our buffer. // // If this location does not have a proper FV header, then // we will initialize it. // Initialize = TRUE; if (PcdGet64 (PcdEmuVariableNvStoreReserved) != 0) { Ptr = (VOID*)(UINTN) PcdGet64 (PcdEmuVariableNvStoreReserved); DEBUG (( EFI_D_INFO, "EMU Variable FVB: Using pre-reserved block at %p\n", Ptr )); Status = ValidateFvHeader (Ptr); if (!EFI_ERROR (Status)) { DEBUG ((EFI_D_INFO, "EMU Variable FVB: Found valid pre-existing FV\n")); Initialize = FALSE; } } else { Ptr = AllocateAlignedRuntimePages ( EFI_SIZE_TO_PAGES (EMU_FVB_SIZE), SIZE_64KB ); } mEmuVarsFvb.BufferPtr = Ptr; // // Initialize the main FV header and variable store header // if (Initialize) { SetMem (Ptr, EMU_FVB_SIZE, ERASED_UINT8); InitializeFvAndVariableStoreHeaders (Ptr); } PcdSet64 (PcdFlashNvStorageVariableBase64, (UINT32)(UINTN) Ptr); // // Initialize the Fault Tolerant Write data area // SubPtr = (VOID*) ((UINT8*) Ptr + PcdGet32 (PcdVariableStoreSize)); PcdSet32 (PcdFlashNvStorageFtwWorkingBase, (UINT32)(UINTN) SubPtr); // // Initialize the Fault Tolerant Write spare block // SubPtr = (VOID*) ((UINT8*) Ptr + EMU_FVB_BLOCK_SIZE); PcdSet32 (PcdFlashNvStorageFtwSpareBase, (UINT32)(UINTN) SubPtr); // // Setup FVB device path // Address = (EFI_PHYSICAL_ADDRESS)(UINTN) Ptr; mEmuVarsFvb.DevicePath.MemMapDevPath.StartingAddress = Address; mEmuVarsFvb.DevicePath.MemMapDevPath.EndingAddress = Address + EMU_FVB_SIZE - 1; // // Install the protocols // DEBUG ((EFI_D_INFO, "Installing FVB for EMU Variable support\n")); Handle = 0; Status = gBS->InstallMultipleProtocolInterfaces ( &Handle, &gEfiFirmwareVolumeBlock2ProtocolGuid, &mEmuVarsFvb.FwVolBlockInstance, &gEfiDevicePathProtocolGuid, &mEmuVarsFvb.DevicePath, NULL ); ASSERT_EFI_ERROR (Status); // // Register for the virtual address change event // Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, FvbVirtualAddressChangeEvent, NULL, &gEfiEventVirtualAddressChangeGuid, &mEmuVarsFvbAddrChangeEvent ); ASSERT_EFI_ERROR (Status); return EFI_SUCCESS; }
/** This routine is entry point of ScriptSave driver. @param ImageHandle Handle for this drivers loaded image protocol. @param SystemTable EFI system table. @retval EFI_OUT_OF_RESOURCES No enough resource @retval EFI_SUCCESS Succesfully installed the ScriptSave driver. @retval other Errors occured. **/ EFI_STATUS EFIAPI InitializeScriptSaveOnS3SaveState ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) { UINT8 *Buffer; UINTN BufferSize; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; BOOT_SCRIPT_THUNK_DATA *BootScriptThunkData; EFI_STATUS Status; VOID *DevicePath; EFI_PHYSICAL_ADDRESS MemoryAddress; UINTN PageNumber; EFI_HANDLE NewImageHandle; // // Test if the gEfiCallerIdGuid of this image is already installed. if not, the entry // point is loaded by DXE code which is the first time loaded. or else, it is already // be reloaded be itself.This is a work-around // Status = gBS->LocateProtocol (&gEfiCallerIdGuid, NULL, &DevicePath); if (EFI_ERROR (Status)) { // // This is the first-time loaded by DXE core. reload itself to RESERVED mem // // // A workaround: Here we install a dummy handle // NewImageHandle = NULL; Status = gBS->InstallProtocolInterface ( &NewImageHandle, &gEfiCallerIdGuid, EFI_NATIVE_INTERFACE, NULL ); ASSERT_EFI_ERROR (Status); Status = GetSectionFromAnyFv ( &gEfiCallerIdGuid, EFI_SECTION_PE32, 0, (VOID **) &Buffer, &BufferSize ); ASSERT_EFI_ERROR (Status); ImageContext.Handle = Buffer; ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory; // // Get information about the image being loaded // Status = PeCoffLoaderGetImageInfo (&ImageContext); ASSERT_EFI_ERROR (Status); MemoryAddress = SIZE_4GB - 1; if (ImageContext.SectionAlignment > EFI_PAGE_SIZE) { PageNumber = EFI_SIZE_TO_PAGES ((UINTN) (ImageContext.ImageSize + ImageContext.SectionAlignment)); } else { PageNumber = EFI_SIZE_TO_PAGES ((UINTN) ImageContext.ImageSize); } Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, PageNumber, &MemoryAddress ); ASSERT_EFI_ERROR (Status); ImageContext.ImageAddress = (PHYSICAL_ADDRESS)(UINTN)MemoryAddress; // // Align buffer on section boundry // ImageContext.ImageAddress += ImageContext.SectionAlignment - 1; ImageContext.ImageAddress &= ~(ImageContext.SectionAlignment - 1); // // Load the image to our new buffer // Status = PeCoffLoaderLoadImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Relocate the image in our new buffer // Status = PeCoffLoaderRelocateImage (&ImageContext); ASSERT_EFI_ERROR (Status); // // Free the buffer allocated by ReadSection since the image has been relocated in the new buffer // gBS->FreePool (Buffer); // // Flush the instruction cache so the image data is written before we execute it // InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize); RegisterMemoryProfileImage ( &gEfiCallerIdGuid, ImageContext.ImageAddress, ImageContext.ImageSize, EFI_FV_FILETYPE_DRIVER ); Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable); ASSERT_EFI_ERROR (Status); // // Additional step for BootScriptThunk integrity // // // Allocate BootScriptThunkData // BootScriptThunkData = AllocatePool (sizeof (BOOT_SCRIPT_THUNK_DATA)); ASSERT (BootScriptThunkData != NULL); BootScriptThunkData->BootScriptThunkBase = ImageContext.ImageAddress; BootScriptThunkData->BootScriptThunkLength = ImageContext.ImageSize; // // Set BootScriptThunkData // PcdSet64 (BootScriptThunkDataPtr, (UINT64)(UINTN)BootScriptThunkData); return EFI_SUCCESS; } else { // // the entry point is invoked after reloading. following code only run in RESERVED mem // // // Locate and cache PI S3 Save State Protocol. // Status = gBS->LocateProtocol ( &gEfiS3SaveStateProtocolGuid, NULL, (VOID **) &mS3SaveState ); ASSERT_EFI_ERROR (Status); return gBS->InstallProtocolInterface ( &mHandle, &gEfiBootScriptSaveProtocolGuid, EFI_NATIVE_INTERFACE, &mS3ScriptSave ); } }