/** Load a binary file from BootMonFS. @param[in] FileHandle Handle of the file to load. @param[in] FileData Address of the file data in memory. @param[out] EntryPoint Will be filled with the ELF entry point address. @param[out] ImageSize Will be filled with the file size in memory. This will effectively be equal to the sum of the load region sizes. This function assumes the file is valid and supported as checked with BootMonFsCheckFile(). @retval EFI_SUCCESS on success. @retval EFI_INVALID_PARAMETER if the file is invalid. **/ EFI_STATUS BootMonFsLoadFile ( IN CONST EFI_FILE_HANDLE FileHandle, IN CONST VOID *FileData, OUT VOID **EntryPoint, OUT LIST_ENTRY *LoadList ) { EFI_STATUS Status; BOOTMON_FS_FILE_INFO Info; UINTN InfoSize; UINTN Index; UINTN ImageSize; RUNAXF_LOAD_LIST *LoadNode; ASSERT (FileHandle != NULL); ASSERT (FileData != NULL); ASSERT (EntryPoint != NULL); ASSERT (LoadList != NULL); ImageSize = 0; InfoSize = sizeof (Info); Status = FileHandle->GetInfo (FileHandle, &gArmBootMonFsFileInfoGuid, &InfoSize, &Info); if (!EFI_ERROR (Status)) { *EntryPoint = (VOID*)((UINTN)Info.EntryPoint); // Load all the regions to run-time memory for (Index = 0; Index < Info.RegionCount; Index++) { LoadNode = AllocateRuntimeZeroPool (sizeof (RUNAXF_LOAD_LIST)); if (LoadNode == NULL) { Status = EFI_OUT_OF_RESOURCES; break; } LoadNode->MemOffset = (UINTN)Info.Region[Index].LoadAddress; LoadNode->FileOffset = (UINTN)FileData + Info.Region[Index].Offset; LoadNode->Length = (UINTN)Info.Region[Index].Size; InsertTailList (LoadList, &LoadNode->Link); ImageSize += LoadNode->Length; } } if ((!EFI_ERROR (Status)) && (ImageSize == 0)) { Status = EFI_INVALID_PARAMETER; } return Status; }
INT32 ShvOsPrepareProcessor ( _In_ PSHV_VP_DATA VpData ) { PKGDTENTRY64 TssEntry, NewGdt; PKTSS64 Tss; KDESCRIPTOR Gdtr; // // Clear AC in case it's not been reset yet // __writeeflags(__readeflags() & ~EFLAGS_ALIGN_CHECK); // // Capture the current GDT // _sgdt(&Gdtr.Limit); // // Allocate a new GDT as big as the old one, or to cover selector 0x60 // NewGdt = AllocateRuntimeZeroPool(MAX(Gdtr.Limit + 1, KGDT64_SYS_TSS + sizeof(*TssEntry))); if (NewGdt == NULL) { return SHV_STATUS_NO_RESOURCES; } // // Copy the old GDT // CopyMem(NewGdt, Gdtr.Base, Gdtr.Limit + 1); // // Allocate a TSS // Tss = AllocateRuntimeZeroPool(sizeof(*Tss)); if (Tss == NULL) { FreePool(NewGdt); return SHV_STATUS_NO_RESOURCES; } // // Fill out the TSS Entry // TssEntry = (PKGDTENTRY64)((uintptr_t)NewGdt + KGDT64_SYS_TSS); TssEntry->BaseLow = (uintptr_t)Tss & 0xffff; TssEntry->Bits.BaseMiddle = ((uintptr_t)Tss >> 16) & 0xff; TssEntry->Bits.BaseHigh = ((uintptr_t)Tss >> 24) & 0xff; TssEntry->BaseUpper = (uintptr_t)Tss >> 32; TssEntry->LimitLow = sizeof(KTSS64) - 1; TssEntry->Bits.Type = AMD64_TSS; TssEntry->Bits.Dpl = 0; TssEntry->Bits.Present = 1; TssEntry->Bits.System = 0; TssEntry->Bits.LongMode = 0; TssEntry->Bits.DefaultBig = 0; TssEntry->Bits.Granularity = 0; TssEntry->MustBeZero = 0; // // Load the new GDT // Gdtr.Base = NewGdt; Gdtr.Limit = KGDT64_SYS_TSS + sizeof(*TssEntry) - 1; _lgdt(&Gdtr.Limit); // // Load the task register // _ltr(KGDT64_SYS_TSS); return SHV_STATUS_SUCCESS; }
/** Creates a general-purpose event structure @param Type The type of event to create and its mode and attributes @param NotifyTpl The task priority level of event notifications @param NotifyFunction Pointer to the events notification function @param NotifyContext Pointer to the notification functions context; corresponds to parameter "Context" in the notification function @param EventGroup GUID for EventGroup if NULL act the same as gBS->CreateEvent(). @param Event Pointer to the newly created event if the call succeeds; undefined otherwise @retval EFI_SUCCESS The event structure was created @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value @retval EFI_OUT_OF_RESOURCES The event could not be allocated **/ EFI_STATUS EFIAPI CoreCreateEventInternal ( IN UINT32 Type, IN EFI_TPL NotifyTpl, IN EFI_EVENT_NOTIFY NotifyFunction, OPTIONAL IN CONST VOID *NotifyContext, OPTIONAL IN CONST EFI_GUID *EventGroup, OPTIONAL OUT EFI_EVENT *Event ) { EFI_STATUS Status; IEVENT *IEvent; INTN Index; if (Event == NULL) { return EFI_INVALID_PARAMETER; } // // Check to make sure no reserved flags are set // Status = EFI_INVALID_PARAMETER; for (Index = 0; Index < (sizeof (mEventTable) / sizeof (UINT32)); Index++) { if (Type == mEventTable[Index]) { Status = EFI_SUCCESS; break; } } if(EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } // // Convert Event type for pre-defined Event groups // if (EventGroup != NULL) { // // For event group, type EVT_SIGNAL_EXIT_BOOT_SERVICES and EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE // are not valid // if ((Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) || (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE)) { return EFI_INVALID_PARAMETER; } if (CompareGuid (EventGroup, &gEfiEventExitBootServicesGuid)) { Type = EVT_SIGNAL_EXIT_BOOT_SERVICES; } else if (CompareGuid (EventGroup, &gEfiEventVirtualAddressChangeGuid)) { Type = EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE; } } else { // // Convert EFI 1.10 Events to their UEFI 2.0 CreateEventEx mapping // if (Type == EVT_SIGNAL_EXIT_BOOT_SERVICES) { EventGroup = &gEfiEventExitBootServicesGuid; } else if (Type == EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE) { EventGroup = &gEfiEventVirtualAddressChangeGuid; } } // // If it's a notify type of event, check its parameters // if ((Type & (EVT_NOTIFY_WAIT | EVT_NOTIFY_SIGNAL)) != 0) { // // Check for an invalid NotifyFunction or NotifyTpl // if ((NotifyFunction == NULL) || (NotifyTpl <= TPL_APPLICATION) || (NotifyTpl >= TPL_HIGH_LEVEL)) { return EFI_INVALID_PARAMETER; } } else { // // No notification needed, zero ignored values // NotifyTpl = 0; NotifyFunction = NULL; NotifyContext = NULL; } // // Allocate and initialize a new event structure. // if ((Type & EVT_RUNTIME) != 0) { IEvent = AllocateRuntimeZeroPool (sizeof (IEVENT)); } else { IEvent = AllocateZeroPool (sizeof (IEVENT)); } if (IEvent == NULL) { return EFI_OUT_OF_RESOURCES; } IEvent->Signature = EVENT_SIGNATURE; IEvent->Type = Type; IEvent->NotifyTpl = NotifyTpl; IEvent->NotifyFunction = NotifyFunction; IEvent->NotifyContext = (VOID *)NotifyContext; if (EventGroup != NULL) { CopyGuid (&IEvent->EventGroup, EventGroup); IEvent->ExFlag = TRUE; } *Event = IEvent; if ((Type & EVT_RUNTIME) != 0) { // // Keep a list of all RT events so we can tell the RT AP. // IEvent->RuntimeData.Type = Type; IEvent->RuntimeData.NotifyTpl = NotifyTpl; IEvent->RuntimeData.NotifyFunction = NotifyFunction; IEvent->RuntimeData.NotifyContext = (VOID *) NotifyContext; IEvent->RuntimeData.Event = (EFI_EVENT *) IEvent; InsertTailList (&gRuntime->EventHead, &IEvent->RuntimeData.Link); } CoreAcquireEventLock (); if ((Type & EVT_NOTIFY_SIGNAL) != 0x00000000) { // // The Event's NotifyFunction must be queued whenever the event is signaled // InsertHeadList (&gEventSignalQueue, &IEvent->SignalLink); } CoreReleaseEventLock (); // // Done // return EFI_SUCCESS; }
/** Build Gather list for a list of capsule images. @param[in] CapsuleBuffer An array of pointer to capsule images @param[in] FileSize An array of UINTN to capsule images size @param[in] CapsuleNum The count of capsule images @param[out] BlockDescriptors The block descriptors for the capsule images @retval EFI_SUCCESS The block descriptors for the capsule images are constructed. **/ EFI_STATUS BuildGatherList ( IN VOID **CapsuleBuffer, IN UINTN *FileSize, IN UINTN CapsuleNum, OUT EFI_CAPSULE_BLOCK_DESCRIPTOR **BlockDescriptors ) { EFI_STATUS Status; EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors1; EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptors2; EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorPre; EFI_CAPSULE_BLOCK_DESCRIPTOR *BlockDescriptorsHeader; EFI_CAPSULE_BLOCK_DESCRIPTOR *TempBlockPtr; UINT8 *TempDataPtr; UINTN SizeLeft; UINTN Size; INT32 Count; INT32 Number; UINTN Index; TempBlockPtr = NULL; BlockDescriptors1 = NULL; BlockDescriptors2 = NULL; BlockDescriptorPre = NULL; BlockDescriptorsHeader = NULL; for (Index = 0; Index < CapsuleNum; Index++) { // // Allocate memory for the descriptors. // if (NumberOfDescriptors == 1) { Count = 2; } else { Count = (INT32)(NumberOfDescriptors + 2) / 2; } Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); BlockDescriptors1 = AllocateRuntimeZeroPool (Size); if (BlockDescriptors1 == NULL) { Print (L"CapsuleApp: failed to allocate memory for descriptors\n"); Status = EFI_OUT_OF_RESOURCES; goto ERREXIT; } else { Print (L"CapsuleApp: creating capsule descriptors at 0x%X\n", (UINTN) BlockDescriptors1); Print (L"CapsuleApp: capsule data starts at 0x%X with size 0x%X\n", (UINTN) CapsuleBuffer[Index], FileSize[Index]); } // // Record descirptor header // if (Index == 0) { BlockDescriptorsHeader = BlockDescriptors1; } if (BlockDescriptorPre != NULL) { BlockDescriptorPre->Union.ContinuationPointer = (UINTN) BlockDescriptors1; BlockDescriptorPre->Length = 0; } // // Fill them in // TempBlockPtr = BlockDescriptors1; TempDataPtr = CapsuleBuffer[Index]; SizeLeft = FileSize[Index]; for (Number = 0; (Number < Count - 1) && (SizeLeft != 0); Number++) { // // Divide remaining data in half // if (NumberOfDescriptors != 1) { if (SizeLeft == 1) { Size = 1; } else { Size = SizeLeft / 2; } } else { Size = SizeLeft; } TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr; TempBlockPtr->Length = Size; Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size); SizeLeft -= Size; TempDataPtr += Size; TempBlockPtr++; } // // Allocate the second list, point the first block's last entry to point // to this one, and fill this one in. Worst case is that the previous // list only had one element that pointed here, so we need at least two // elements -- one to point to all the data, another to terminate the list. // if ((NumberOfDescriptors != 1) && (SizeLeft != 0)) { Count = (INT32)(NumberOfDescriptors + 2) - Count; if (Count == 1) { Count++; } Size = Count * sizeof (EFI_CAPSULE_BLOCK_DESCRIPTOR); BlockDescriptors2 = AllocateRuntimeZeroPool (Size); if (BlockDescriptors2 == NULL) { Print (L"CapsuleApp: failed to allocate memory for descriptors\n"); Status = EFI_OUT_OF_RESOURCES; goto ERREXIT; } // // Point the first list's last element to point to this second list. // TempBlockPtr->Union.ContinuationPointer = (UINTN) BlockDescriptors2; TempBlockPtr->Length = 0; TempBlockPtr = BlockDescriptors2; for (Number = 0; Number < Count - 1; Number++) { // // If second-to-last one, then dump rest to this element // if (Number == (Count - 2)) { Size = SizeLeft; } else { // // Divide remaining data in half // if (SizeLeft == 1) { Size = 1; } else { Size = SizeLeft / 2; } } TempBlockPtr->Union.DataBlock = (UINTN)TempDataPtr; TempBlockPtr->Length = Size; Print (L"CapsuleApp: capsule block/size 0x%X/0x%X\n", (UINTN) TempDataPtr, Size); SizeLeft -= Size; TempDataPtr += Size; TempBlockPtr++; if (SizeLeft == 0) { break; } } } BlockDescriptorPre = TempBlockPtr; BlockDescriptors1 = NULL; } // // Null-terminate. // if (TempBlockPtr != NULL) { TempBlockPtr->Union.ContinuationPointer = (UINTN)NULL; TempBlockPtr->Length = 0; *BlockDescriptors = BlockDescriptorsHeader; } return EFI_SUCCESS; ERREXIT: if (BlockDescriptors1 != NULL) { FreePool(BlockDescriptors1); } if (BlockDescriptors2 != NULL) { FreePool(BlockDescriptors2); } return Status; }
EFI_STATUS EFIAPI InstallPchSpi ( IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable ) /*++ Routine Description: Entry point for the SPI host controller driver. Arguments: ImageHandle Image handle of this driver. SystemTable Global system service table. Returns: EFI_SUCCESS Initialization complete. EFI_UNSUPPORTED The chipset is unsupported by this driver. EFI_OUT_OF_RESOURCES Do not have enough resources to initialize the driver. EFI_DEVICE_ERROR Device error, driver exits abnormally. --*/ { EFI_STATUS Status; UINT64 BaseAddress; UINT64 Length; EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdMemorySpaceDescriptor; UINT64 Attributes; EFI_EVENT Event; DEBUG ((DEBUG_INFO, "InstallPchSpi() Start\n")); // // Allocate Runtime memory for the SPI protocol instance. // mSpiInstance = AllocateRuntimeZeroPool (sizeof (SPI_INSTANCE)); if (mSpiInstance == NULL) { return EFI_OUT_OF_RESOURCES; } // // Initialize the SPI protocol instance // Status = SpiProtocolConstructor (mSpiInstance); if (EFI_ERROR (Status)) { return Status; } // // Install the EFI_SPI_PROTOCOL interface // Status = gBS->InstallMultipleProtocolInterfaces ( &(mSpiInstance->Handle), &gEfiSpiProtocolGuid, &(mSpiInstance->SpiProtocol), NULL ); if (EFI_ERROR (Status)) { FreePool (mSpiInstance); return EFI_DEVICE_ERROR; } // // Set RCBA space in GCD to be RUNTIME so that the range will be supported in // virtual address mode in EFI aware OS runtime. // It will assert if RCBA Memory Space is not allocated // The caller is responsible for the existence and allocation of the RCBA Memory Spaces // BaseAddress = (EFI_PHYSICAL_ADDRESS) (mSpiInstance->PchRootComplexBar); Length = PcdGet64 (PcdRcbaMmioSize); Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdMemorySpaceDescriptor); ASSERT_EFI_ERROR (Status); Attributes = GcdMemorySpaceDescriptor.Attributes | EFI_MEMORY_RUNTIME; Status = gDS->AddMemorySpace ( EfiGcdMemoryTypeMemoryMappedIo, BaseAddress, Length, EFI_MEMORY_RUNTIME | EFI_MEMORY_UC ); ASSERT_EFI_ERROR(Status); Status = gDS->SetMemorySpaceAttributes ( BaseAddress, Length, Attributes ); ASSERT_EFI_ERROR (Status); Status = gBS->CreateEventEx ( EVT_NOTIFY_SIGNAL, TPL_NOTIFY, PchSpiVirtualddressChangeEvent, NULL, &gEfiEventVirtualAddressChangeGuid, &Event ); ASSERT_EFI_ERROR (Status); DEBUG ((DEBUG_INFO, "InstallPchSpi() End\n")); return EFI_SUCCESS; }
/** The driver entry point for Firmware Volume Block Driver. The function does the necessary initialization work Firmware Volume Block Driver. @param[in] ImageHandle The firmware allocated handle for the UEFI image. @param[in] SystemTable A pointer to the EFI system table. @retval EFI_SUCCESS This funtion always return EFI_SUCCESS. It will ASSERT on errors. **/ EFI_STATUS FvbInitialize ( ) { EFI_FW_VOL_INSTANCE *FwhInstance; EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader; EFI_FIRMWARE_VOLUME_HEADER *FvHeader; EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry; EFI_PHYSICAL_ADDRESS BaseAddress; EFI_STATUS Status; UINTN BufferSize; UINTN TmpHeaderLength; UINTN Idx; UINT32 MaxLbaSize; BOOLEAN FvHeaderValid; UINTN FvFlashLinearAddress; EFI_BOOT_MODE BootMode; UINT32 Index; UINT32 PlatformFvBaseAddress[5]; UINT32 PlatformFvBaseAddressCount; UINT32 PlatformFvLockList[4]; UINT32 PlatformFvLockListCount; // // This platform driver knows there are 3 FVs on // FD, which are FvRecovery, FvMain and FvNvStorage. // BootMode = GetBootModeHob (); if (BootMode == BOOT_IN_RECOVERY_MODE) { // // On recovery boot, don't report any firmware FV images except payload, because their data can't be trusted. // PlatformFvBaseAddressCount = 2; PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashNvStorageVariableBase); PlatformFvBaseAddress[1] = PcdGet32 (PcdFlashPayloadBase); } else { PlatformFvBaseAddressCount = 5; PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashFvMainBase); PlatformFvBaseAddress[1] = PcdGet32 (PcdFlashNvStorageVariableBase); PlatformFvBaseAddress[2] = PcdGet32 (PcdFlashFvRecoveryBase); PlatformFvBaseAddress[3] = PcdGet32 (PcdFlashFvRecovery2Base); PlatformFvBaseAddress[4] = PcdGet32 (PcdFlashPayloadBase); } // // List of FVs that should be write protected on normal boots. // PlatformFvLockListCount = 4; PlatformFvLockList[0] = PcdGet32 (PcdFlashFvMainBase); PlatformFvLockList[1] = PcdGet32 (PcdFlashFvRecoveryBase); PlatformFvLockList[2] = PcdGet32 (PcdFlashFvRecovery2Base); PlatformFvLockList[3] = PcdGet32 (PcdFlashPayloadBase); // // Calculate the total size for all firmware volume block instances and // allocate a buffer to store them in. // BufferSize = 0; for (Idx = 0; Idx < PlatformFvBaseAddressCount; Idx++) { FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) PlatformFvBaseAddress[Idx]; if (FvHeader == NULL) { continue; } BufferSize += (FvHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER) ); } mFvbModuleGlobal.FvInstance = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize); ASSERT (NULL != mFvbModuleGlobal.FvInstance); // // Perform other variable initialization. // MaxLbaSize = 0; FwhInstance = mFvbModuleGlobal.FvInstance; mFvbModuleGlobal.NumFv = 0; for (Idx = 0; Idx < PlatformFvBaseAddressCount; Idx++) { if ((BootMode == BOOT_ASSUMING_NO_CONFIGURATION_CHANGES) && PlatformFvBaseAddress[Idx]!= PcdGet32 (PcdFlashNvStorageVariableBase) && PlatformFvBaseAddress[Idx]!= PcdGet32 (PcdFlashPayloadBase)) { continue; } // // Get base address information. // BaseAddress = PlatformFvBaseAddress[Idx]; FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress; if (FwVolHeader == NULL) { continue; } // // Find the flash linear address of the current FV. // FvFlashLinearAddress = (UINTN) FLASH_LINEAR_ADDRESS(BaseAddress); if (!IsFvHeaderValid (BaseAddress, FwVolHeader)) { FvHeaderValid = FALSE; // // If not valid, get FvbInfo from the information carried in // FVB driver. // DEBUG ((EFI_D_ERROR, "Fvb: FV header @ 0x%lx invalid\n", BaseAddress)); Status = GetFvbInfo (BaseAddress, &FwVolHeader); ASSERT_EFI_ERROR(Status); // // Write back a healthy FV header. // DEBUG ((EFI_D_INFO, "FwBlockService.c: Writing back healthy FV header\n")); mSpiDeviceProtocol->SpiLock (FvFlashLinearAddress, FwVolHeader->BlockMap->Length, FALSE); Status = mSpiDeviceProtocol->SpiErase (FvFlashLinearAddress, FwVolHeader->BlockMap->Length); TmpHeaderLength = (UINTN) FwVolHeader->HeaderLength; Status = mSpiDeviceProtocol->SpiWrite ( FvFlashLinearAddress, &TmpHeaderLength, (UINT8 *) FwVolHeader ); mSpiDeviceProtocol->SpiLock (FvFlashLinearAddress, FwVolHeader->BlockMap->Length, TRUE); WriteBackInvalidateDataCacheRange ( (VOID *) (UINTN) BaseAddress, FwVolHeader->BlockMap->Length ); } // // Copy FV header into local storage and assign base address. // CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength); FwVolHeader = &(FwhInstance->VolumeHeader); FwhInstance->FvBase = (UINTN)BaseAddress; FwhInstance->FvFlashLinearAddress = FvFlashLinearAddress; // // In some cases the Recovery and Main FVs should be considered locked from // write access by this protocol. Only in the case of flash updates and // configuration mode should they be left unlocked. // if (BootMode != BOOT_IN_RECOVERY_MODE && BootMode != BOOT_ON_FLASH_UPDATE) { for (Index = 0; Index < PlatformFvLockListCount; Index++) { if (FwhInstance->FvBase == PlatformFvLockList[Index]) { // // For all FVs in the lock list we need to clear the write status bit // and lock write status updates. This will make sure this protocol // will not attempt to write to the FV. // FwhInstance->VolumeHeader.Attributes &= (UINT64) ~EFI_FVB2_WRITE_STATUS; FwhInstance->VolumeHeader.Attributes |= (EFI_FVB2_LOCK_STATUS | EFI_FVB2_WRITE_LOCK_STATUS); } } } // // Process the block map for each FV // FwhInstance->NumOfBlocks = 0; for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { // // Get the maximum size of a block. // if (MaxLbaSize < PtrBlockMapEntry->Length) { MaxLbaSize = PtrBlockMapEntry->Length; } FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks; } // // Add a FVB Protocol Instance // mFvbModuleGlobal.NumFv++; InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1); // // Move on to the next FwhInstance // FwhInstance = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhInstance) + FwVolHeader->HeaderLength + (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))); } if ((PcdGet32 (PcdFlashNvStorageFtwWorkingBase) == 0) || (PcdGet32 (PcdFlashNvStorageFtwSpareBase) == 0)) { return EFI_SUCCESS; } // // Install FVB protocols for FTW spare space and FTW working space. // These is no FV header for these 2 spaces. // mFvbModuleGlobal.FvInstance = (EFI_FW_VOL_INSTANCE *) ReallocateRuntimePool ( BufferSize, BufferSize + (sizeof (EFI_FW_VOL_INSTANCE) + sizeof (EFI_FV_BLOCK_MAP_ENTRY)) * 2, mFvbModuleGlobal.FvInstance ); ASSERT (NULL != mFvbModuleGlobal.FvInstance); PlatformFvBaseAddress[0] = PcdGet32 (PcdFlashNvStorageFtwWorkingBase); PlatformFvBaseAddress[1] = PcdGet32 (PcdFlashNvStorageFtwSpareBase); for (Idx = 0; Idx < 2; Idx++) { BaseAddress = PlatformFvBaseAddress[Idx]; Status = GetFtwFvbInfo (BaseAddress, &FwVolHeader); ASSERT_EFI_ERROR(Status); // // Copy FV header into local storage and assign base address. // mFvbModuleGlobal.NumFv++; FwhInstance = GetFvbInstance (mFvbModuleGlobal.NumFv - 1); CopyMem (&(FwhInstance->VolumeHeader), FwVolHeader, FwVolHeader->HeaderLength); FwVolHeader = &(FwhInstance->VolumeHeader); // // Process the block map for each FV // FwhInstance->NumOfBlocks = 0; for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) { FwhInstance->NumOfBlocks += PtrBlockMapEntry->NumBlocks; } FwhInstance->FvBase = (UINTN)BaseAddress; FwhInstance->FvFlashLinearAddress = (UINTN) FLASH_LINEAR_ADDRESS(BaseAddress); InstallFvbProtocol (FwhInstance, mFvbModuleGlobal.NumFv - 1); } return EFI_SUCCESS; }
/** Load an ELF segment into memory. This function assumes the ELF file is valid. This function is meant to be called for PT_LOAD type segments only. **/ STATIC EFI_STATUS ElfLoadSegment ( IN CONST VOID *ElfImage, IN CONST VOID *PHdr, IN LIST_ENTRY *LoadList ) { VOID *FileSegment; VOID *MemSegment; UINTN ExtraZeroes; UINTN ExtraZeroesCount; RUNAXF_LOAD_LIST *LoadNode; #ifdef MDE_CPU_ARM Elf32_Phdr *ProgramHdr; ProgramHdr = (Elf32_Phdr *)PHdr; #elif defined(MDE_CPU_AARCH64) Elf64_Phdr *ProgramHdr; ProgramHdr = (Elf64_Phdr *)PHdr; #endif ASSERT (ElfImage != NULL); ASSERT (ProgramHdr != NULL); FileSegment = (VOID *)((UINTN)ElfImage + ProgramHdr->p_offset); MemSegment = (VOID *)ProgramHdr->p_vaddr; // If the segment's memory size p_memsz is larger than the file size p_filesz, // the "extra" bytes are defined to hold the value 0 and to follow the // segment's initialised area. // This is typically the case for the .bss segment. // The file size may not be larger than the memory size. if (ProgramHdr->p_filesz > ProgramHdr->p_memsz) { ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_RUNAXF_ELFBADFORMAT), gRunAxfHiiHandle); return EFI_INVALID_PARAMETER; } // Load the segment in memory. if (ProgramHdr->p_filesz != 0) { DEBUG ((EFI_D_INFO, "Loading segment from 0x%lx to 0x%lx (size = %ld)\n", FileSegment, MemSegment, ProgramHdr->p_filesz)); LoadNode = AllocateRuntimeZeroPool (sizeof (RUNAXF_LOAD_LIST)); if (LoadNode == NULL) { return EFI_OUT_OF_RESOURCES; } LoadNode->MemOffset = (UINTN)MemSegment; LoadNode->FileOffset = (UINTN)FileSegment; LoadNode->Length = (UINTN)ProgramHdr->p_filesz; InsertTailList (LoadList, &LoadNode->Link); } ExtraZeroes = ((UINTN)MemSegment + ProgramHdr->p_filesz); ExtraZeroesCount = ProgramHdr->p_memsz - ProgramHdr->p_filesz; DEBUG ((EFI_D_INFO, "Completing segment with %d zero bytes.\n", ExtraZeroesCount)); if (ExtraZeroesCount > 0) { // Extra Node to add the Zeroes. LoadNode = AllocateRuntimeZeroPool (sizeof (RUNAXF_LOAD_LIST)); if (LoadNode == NULL) { return EFI_OUT_OF_RESOURCES; } LoadNode->MemOffset = (UINTN)ExtraZeroes; LoadNode->Zeroes = TRUE; LoadNode->Length = ExtraZeroesCount; InsertTailList (LoadList, &LoadNode->Link); } return EFI_SUCCESS; }