1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110 |
- /*++
- Copyright (c) 2014 Minoca Corp.
- This file is licensed under the terms of the GNU General Public License
- version 3. Alternative licensing terms are available. Contact
- info@minocacorp.com for details. See the LICENSE file at the root of this
- project for complete licensing information.
- Module Name:
- image.c
- Abstract:
- This module implements UEFI core image services.
- Author:
- Evan Green 10-Mar-2014
- Environment:
- Firmware
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include "ueficore.h"
- #include "fileinfo.h"
- #include "hii.h"
- #include "imagep.h"
- #include "efiimg.h"
- #include "fv2.h"
- #include <minoca/uefi/protocol/loadfil.h>
- #include <minoca/uefi/protocol/loadfil2.h>
- #include <minoca/uefi/protocol/sfilesys.h>
- #include <minoca/kernel/hmod.h>
- #include <minoca/kernel/kdebug.h>
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- EFI_STATUS
- EfipCoreLoadImage (
- BOOLEAN BootPolicy,
- EFI_HANDLE ParentImageHandle,
- EFI_DEVICE_PATH_PROTOCOL *FilePath,
- VOID *SourceBuffer,
- UINTN SourceSize,
- EFI_PHYSICAL_ADDRESS DestinationBuffer,
- UINTN *PageCount,
- EFI_HANDLE *ImageHandle,
- EFI_PHYSICAL_ADDRESS *EntryPoint,
- UINT32 Attributes
- );
- EFIAPI
- VOID *
- EfipCoreGetFileBufferByFilePath (
- BOOLEAN BootPolicy,
- CONST EFI_DEVICE_PATH_PROTOCOL *FilePath,
- CHAR16 **FileName,
- UINTN *FileSize,
- UINT32 *AuthenticationStatus
- );
- EFI_STATUS
- EfipCoreLoadPeImage (
- BOOLEAN BootPolicy,
- VOID *PeHandle,
- PEFI_IMAGE_DATA Image,
- EFI_PHYSICAL_ADDRESS DestinationBuffer,
- EFI_PHYSICAL_ADDRESS *EntryPoint,
- UINT32 Attribute
- );
- VOID
- EfipCoreUnloadAndCloseImage (
- PEFI_IMAGE_DATA Image,
- BOOLEAN FreePages
- );
- PEFI_IMAGE_DATA
- EfipCoreGetImageDataFromHandle (
- EFI_HANDLE ImageHandle
- );
- EFIAPI
- EFI_STATUS
- EfipCoreReadImageFile (
- VOID *FileHandle,
- UINTN FileOffset,
- UINTN *ReadSize,
- VOID *Buffer
- );
- CHAR8 *
- EfipCoreConvertFileNameToAscii (
- CHAR16 *FileName,
- UINTN *AsciiNameSize
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PEFI_IMAGE_DATA EfiCurrentImage;
- EFI_IMAGE_DATA EfiFirmwareLoadedImage = {
- EFI_IMAGE_DATA_MAGIC,
- NULL,
- EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER,
- TRUE,
- (EFI_IMAGE_ENTRY_POINT)EfiCoreMain,
- {
- EFI_LOADED_IMAGE_INFORMATION_REVISION,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- 0,
- NULL,
- NULL,
- 0,
- EfiBootServicesCode,
- EfiBootServicesData
- },
- 0,
- 0,
- NULL,
- 0,
- EFI_SUCCESS,
- 0,
- NULL,
- NULL,
- NULL,
- 0,
- NULL,
- NULL,
- {0},
- EFI_SUCCESS
- };
- EFI_GUID EfiLoadedImageProtocolGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
- EFI_GUID EfiLoadFile2ProtocolGuid = EFI_LOAD_FILE2_PROTOCOL_GUID;
- EFI_GUID EfiLoadFileProtocolGuid = EFI_LOAD_FILE_PROTOCOL_GUID;
- EFI_GUID EfiLoadedImageDevicePathProtocolGuid =
- EFI_LOADED_IMAGE_DEVICE_PATH_PROTOCOL_GUID;
- EFI_GUID EfiHiiPackageListProtocolGuid = EFI_HII_PACKAGE_LIST_PROTOCOL_GUID;
- //
- // ------------------------------------------------------------------ Functions
- //
- EFIAPI
- EFI_STATUS
- EfiCoreLoadImage (
- BOOLEAN BootPolicy,
- EFI_HANDLE ParentImageHandle,
- EFI_DEVICE_PATH_PROTOCOL *DevicePath,
- VOID *SourceBuffer,
- UINTN SourceSize,
- EFI_HANDLE *ImageHandle
- )
- /*++
- Routine Description:
- This routine loads an EFI image into memory.
- Arguments:
- BootPolicy - Supplies a boolean indicating that the request originates
- from the boot manager, and that the boot manager is attempting to load
- the given file path as a boot selection. This is ignored if the source
- buffer is NULL.
- ParentImageHandle - Supplies the caller's image handle.
- DevicePath - Supplies a pointer to the device path from which the image is
- loaded.
- SourceBuffer - Supplies an optional pointer to the memory location
- containing a copy of the image to be loaded.
- SourceSize - Supplies the size in bytes of the source buffer.
- ImageHandle - Supplies a pointer where the loaded image handle will be
- returned on success.
- Return Value:
- EFI_SUCCESS on success.
- EFI_NOT_FOUND if both the source buffer and device path are NULL.
- EFI_INVALID_PARAMETER if one or more parameters are not valid.
- EFI_UNSUPPORTED if the image type is unsupported.
- EFI_OUT_OF_RESOURCES if an allocation failed.
- EFI_LOAD_ERROR if the image format was corrupt or not understood.
- EFI_DEVICE_ERROR if the underlying device returned a read error.
- EFI_ACCESS_DENIED if the platform policy prohibits the image from being
- loaded.
- EFI_SECURITY_VIOLATION if the image was successfully loaded, but the
- platform policy indicates the image should not be started.
- --*/
- {
- UINT32 Attributes;
- EFI_STATUS Status;
- Attributes =
- EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION |
- EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION;
- Status = EfipCoreLoadImage(BootPolicy,
- ParentImageHandle,
- DevicePath,
- SourceBuffer,
- SourceSize,
- (EFI_PHYSICAL_ADDRESS)(UINTN)NULL,
- NULL,
- ImageHandle,
- NULL,
- Attributes);
- return Status;
- }
- EFIAPI
- EFI_STATUS
- EfiCoreUnloadImage (
- EFI_HANDLE ImageHandle
- )
- /*++
- Routine Description:
- This routine unloads an image.
- Arguments:
- ImageHandle - Supplies the handle of the image to unload.
- ExitStatus - Supplies the exit code.
- ExitDataSize - Supplies the size of the exit data. This is ignored if the
- exit status code is EFI_SUCCESS.
- ExitData - Supplies an optional pointer where a pointer will be returned
- that includes a null-terminated string describing the reason the
- application exited, optionally followed by additional binary data. This
- buffer must be allocated from AllocatePool.
- Return Value:
- EFI_SUCCESS if the image was unloaded.
- EFI_INVALID_PARAMETER if the image handle is not valid.
- --*/
- {
- PEFI_IMAGE_DATA Image;
- EFI_STATUS Status;
- Image = EfipCoreGetImageDataFromHandle(ImageHandle);
- if (Image == NULL) {
- Status = EFI_INVALID_PARAMETER;
- goto CoreUnloadImageEnd;
- }
- //
- // If the image has been started, request that it unload.
- //
- if (Image->Started != FALSE) {
- Status = EFI_UNSUPPORTED;
- if (Image->Information.Unload != NULL) {
- Status = Image->Information.Unload(ImageHandle);
- }
- //
- // The image has not been started, so unloading it is always okay.
- //
- } else {
- Status = EFI_SUCCESS;
- }
- if (!EFI_ERROR(Status)) {
- EfipCoreUnloadAndCloseImage(Image, TRUE);
- }
- CoreUnloadImageEnd:
- return Status;
- }
- EFI_STATUS
- EfiCoreStartImage (
- EFI_HANDLE ImageHandle,
- UINTN *ExitDataSize,
- CHAR16 **ExitData
- )
- /*++
- Routine Description:
- This routine transfers control to a loaded image's entry point.
- Arguments:
- ImageHandle - Supplies the handle of the image to run.
- ExitDataSize - Supplies a pointer to the size, in bytes, of the exit data.
- ExitData - Supplies an optional pointer where a pointer will be returned
- that includes a null-terminated string, optionally followed by
- additional binary data.
- Return Value:
- EFI_INVALID_PARAMETER if the image handle is invalid or the image has
- already been started.
- EFI_SECURITY_VIOLATION if the platform policy specifies the image should
- not be started.
- Otherwise, returns the exit code from the image.
- --*/
- {
- UINT64 HandleDatabaseKey;
- PEFI_IMAGE_DATA Image;
- PEFI_IMAGE_DATA LastImage;
- UINTN SetJumpFlag;
- EFI_STATUS Status;
- Image = EfipCoreGetImageDataFromHandle(ImageHandle);
- if ((Image == NULL) || (Image->Started != FALSE)) {
- return EFI_INVALID_PARAMETER;
- }
- if (EFI_ERROR(Image->LoadImageStatus)) {
- return Image->LoadImageStatus;
- }
- if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Image->Machine)) {
- return EFI_UNSUPPORTED;
- }
- //
- // Push the current start image context, and link the current image to the
- // head. This is the only image that can call exit.
- //
- HandleDatabaseKey = EfipCoreGetHandleDatabaseKey();
- LastImage = EfiCurrentImage;
- EfiCurrentImage = Image;
- Image->Tpl = EfiCurrentTpl;
- //
- // Allocate the jump buffer and set the jump target. This is needed because
- // the caller may call Exit several functions in on the stack and
- // exit needs to get back here.
- //
- Image->JumpBuffer = EfiCoreAllocateBootPool(
- sizeof(EFI_JUMP_BUFFER) + EFI_JUMP_BUFFER_ALIGNMENT);
- if (Image->JumpBuffer == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- Image->JumpContext = ALIGN_POINTER(Image->JumpBuffer,
- EFI_JUMP_BUFFER_ALIGNMENT);
- SetJumpFlag = EfipArchSetJump(Image->JumpContext);
- //
- // The initial call to set jump always returns zero. Subsequent calls to
- // long jump cause a non-zero value to be returned here. The return
- // value of the set jump function is where exit jumps to.
- //
- if (SetJumpFlag == 0) {
- Image->Started = TRUE;
- Image->Status = Image->EntryPoint(ImageHandle,
- Image->Information.SystemTable);
- //
- // If the image returned, call exit for it.
- //
- EfiCoreExit(ImageHandle, Image->Status, 0, NULL);
- }
- //
- // The image has exited. Verify the TPL is the same.
- //
- ASSERT(Image->Tpl == EfiCurrentTpl);
- EfiCoreRestoreTpl(Image->Tpl);
- EfiCoreFreePool(Image->JumpBuffer);
- EfiCurrentImage = LastImage;
- EfipCoreConnectHandlesByKey(HandleDatabaseKey);
- //
- // Return the exit data to the caller, or discard it.
- //
- if ((ExitData != NULL) && (ExitDataSize != NULL)) {
- *ExitDataSize = Image->ExitDataSize;
- *ExitData = Image->ExitData;
- } else {
- EfiCoreFreePool(Image->ExitData);
- Image->ExitData = NULL;
- Image->ExitDataSize = 0;
- }
- //
- // If the image returned an error or the image is an application, unload it.
- //
- Status = Image->Status;
- if ((EFI_ERROR(Image->Status)) ||
- (Image->Type == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION)) {
- EfipCoreUnloadAndCloseImage(Image, TRUE);
- }
- return Status;
- }
- EFIAPI
- EFI_STATUS
- EfiCoreExit (
- EFI_HANDLE ImageHandle,
- EFI_STATUS ExitStatus,
- UINTN ExitDataSize,
- CHAR16 *ExitData
- )
- /*++
- Routine Description:
- This routine terminates an loaded EFI image and returns control to boot
- services.
- Arguments:
- ImageHandle - Supplies the handle of the image passed upon entry.
- ExitStatus - Supplies the exit code.
- ExitDataSize - Supplies the size of the exit data. This is ignored if the
- exit status code is EFI_SUCCESS.
- ExitData - Supplies an optional pointer where a pointer will be returned
- that includes a null-terminated string describing the reason the
- application exited, optionally followed by additional binary data. This
- buffer must be allocated from AllocatePool.
- Return Value:
- EFI_SUCCESS if the image was unloaded.
- EFI_INVALID_PARAMETER if the image has been loaded and started with
- LoadImage and StartImage, but the image is not currently executing.
- --*/
- {
- PEFI_IMAGE_DATA Image;
- EFI_TPL OldTpl;
- //
- // Prevent possible reentrance to this function for the same image handle.
- //
- OldTpl = EfiCoreRaiseTpl(TPL_NOTIFY);
- Image = EfipCoreGetImageDataFromHandle(ImageHandle);
- if (Image == NULL) {
- ExitStatus = EFI_INVALID_PARAMETER;
- goto CoreExitEnd;
- }
- //
- // If the image has not yet been started, just free its resources.
- //
- if (Image->Started == FALSE) {
- EfipCoreUnloadAndCloseImage(Image, TRUE);
- ExitStatus = EFI_SUCCESS;
- goto CoreExitEnd;
- }
- //
- // If the image has been started, verify it can exit.
- //
- if (Image != EfiCurrentImage) {
- RtlDebugPrint("Error: Image cannot exit while in the middle of "
- "starting another image.\n");
- ExitStatus = EFI_INVALID_PARAMETER;
- goto CoreExitEnd;
- }
- Image->Status = ExitStatus;
- if (ExitData != NULL) {
- Image->ExitDataSize = ExitDataSize;
- Image->ExitData = EfiCoreAllocateBootPool(Image->ExitDataSize);
- if (Image->ExitData == NULL) {
- ExitStatus = EFI_OUT_OF_RESOURCES;
- goto CoreExitEnd;
- }
- EfiCoreCopyMemory(Image->ExitData, ExitData, Image->ExitDataSize);
- }
- EfiCoreRestoreTpl(OldTpl);
- //
- // Return to the set jump in start image.
- //
- EfipArchLongJump(Image->JumpContext, -1);
- //
- // There should be no way to return from a long jump.
- //
- ASSERT(FALSE);
- ExitStatus = EFI_ACCESS_DENIED;
- CoreExitEnd:
- //
- // Something bizarre happened, return from the exit.
- //
- EfiCoreRestoreTpl(OldTpl);
- return ExitStatus;
- }
- EFI_STATUS
- EfiCoreInitializeImageServices (
- VOID *FirmwareBaseAddress,
- VOID *FirmwareLowestAddress,
- UINTN FirmwareSize
- )
- /*++
- Routine Description:
- This routine initializes image service support for the UEFI core.
- Arguments:
- FirmwareBaseAddress - Supplies the base address where the firmware was
- loaded into memory. Supply -1 to indicate that the image is loaded at
- its preferred base address and was not relocated.
- FirmwareLowestAddress - Supplies the lowest address where the firmware was
- loaded into memory.
- FirmwareSize - Supplies the size of the firmware image in memory, in bytes.
- Return Value:
- EFI Status code.
- --*/
- {
- PEFI_IMAGE_DATA Image;
- EFI_STATUS Status;
- //
- // Initialize the firmware image data.
- //
- Image = &EfiFirmwareLoadedImage;
- Image->ImageBasePage = (EFI_PHYSICAL_ADDRESS)(UINTN)FirmwareLowestAddress;
- Image->ImagePageCount = EFI_SIZE_TO_PAGES(FirmwareSize);
- Image->Tpl = EfiCurrentTpl;
- Image->Information.SystemTable = EfiSystemTable;
- Image->Information.ImageBase = FirmwareLowestAddress;
- Image->Information.ImageSize = FirmwareSize;
- //
- // Install the loaded image protocol on a new handle representing the
- // firmware image.
- //
- Image->Handle = NULL;
- Status = EfiCoreInstallProtocolInterface(&(Image->Handle),
- &EfiLoadedImageProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &(Image->Information));
- if (EFI_ERROR(Status)) {
- ASSERT(FALSE);
- return Status;
- }
- EfiFirmwareImageHandle = Image->Handle;
- return Status;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- EFI_STATUS
- EfipCoreLoadImage (
- BOOLEAN BootPolicy,
- EFI_HANDLE ParentImageHandle,
- EFI_DEVICE_PATH_PROTOCOL *FilePath,
- VOID *SourceBuffer,
- UINTN SourceSize,
- EFI_PHYSICAL_ADDRESS DestinationBuffer,
- UINTN *PageCount,
- EFI_HANDLE *ImageHandle,
- EFI_PHYSICAL_ADDRESS *EntryPoint,
- UINT32 Attributes
- )
- /*++
- Routine Description:
- This routine loads an EFI image into memory.
- Arguments:
- BootPolicy - Supplies a boolean indicating that the request originates
- from the boot manager, and that the boot manager is attempting to load
- the given file path as a boot selection. This is ignored if the source
- buffer is NULL.
- ParentImageHandle - Supplies the caller's image handle.
- FilePath - Supplies a pointer to the device path from which the image is
- loaded.
- SourceBuffer - Supplies an optional pointer to the memory location
- containing a copy of the image to be loaded.
- SourceSize - Supplies the size in bytes of the source buffer.
- DestinationBuffer - Supplies an optional address to load the image at.
- PageCount - Supplies a pointer that on input contains the size of the
- destination buffer in pages. On output, will contain the number of
- pages in the loaded image.
- ImageHandle - Supplies a pointer where the loaded image handle will be
- returned on success.
- EntryPoint - Supplies a pointer where the image entry point will be
- returned.
- Attributes - Supplies a bitfield of flags governing the behavior of the
- load. See EFI_LOAD_PE_IMAGE_ATTRIBUTE_* definitions.
- Return Value:
- EFI Status code.
- --*/
- {
- UINTN AllocationSize;
- CHAR8 *AsciiFileName;
- UINTN AsciiFileNameSize;
- UINT32 AuthenticationStatus;
- PDEBUG_MODULE DebuggerModule;
- EFI_HANDLE DeviceHandle;
- EFI_IMAGE_FILE_HANDLE FileHandle;
- CHAR16 *FileName;
- UINTN FilePathSize;
- BOOLEAN FreePage;
- EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
- PEFI_IMAGE_DATA Image;
- EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
- PEFI_IMAGE_DATA ParentImage;
- EFI_STATUS Status;
- ASSERT(EfiCurrentTpl < TPL_NOTIFY);
- ParentImage = NULL;
- if ((ImageHandle == NULL) || (ParentImageHandle == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- ParentImage = EfipCoreGetImageDataFromHandle(ParentImageHandle);
- if (ParentImage == NULL) {
- RtlDebugPrint("LoadImage: Invalid Parent image handle.\n");
- return EFI_INVALID_PARAMETER;
- }
- EfiCoreSetMemory(&FileHandle, 0, sizeof(EFI_IMAGE_FILE_HANDLE));
- FileHandle.Magic = EFI_IMAGE_FILE_HANDLE_MAGIC;
- FileName = NULL;
- OriginalFilePath = FilePath;
- HandleFilePath = FilePath;
- DeviceHandle = NULL;
- Status = EFI_SUCCESS;
- //
- // If the caller passed a copy of the file, then just use it.
- //
- if (SourceBuffer != NULL) {
- FileHandle.Source = SourceBuffer;
- FileHandle.SourceSize = SourceSize;
- Status = EfiCoreLocateDevicePath(&EfiDevicePathProtocolGuid,
- &HandleFilePath,
- &DeviceHandle);
- if (EFI_ERROR(Status)) {
- DeviceHandle = NULL;
- }
- if (SourceSize > 0) {
- Status = EFI_SUCCESS;
- } else {
- Status = EFI_LOAD_ERROR;
- }
- //
- // An image source was not supplied, go find it.
- //
- } else {
- if (FilePath == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- FileHandle.Source = EfipCoreGetFileBufferByFilePath(
- BootPolicy,
- FilePath,
- &FileName,
- &(FileHandle.SourceSize),
- &AuthenticationStatus);
- if (FileHandle.Source == NULL) {
- Status = EFI_NOT_FOUND;
- } else {
- FileHandle.FreeBuffer = TRUE;
- Status = EfiCoreLocateDevicePath(&EfiFirmwareVolume2ProtocolGuid,
- &HandleFilePath,
- &DeviceHandle);
- if (EFI_ERROR(Status)) {
- HandleFilePath = FilePath;
- Status = EfiCoreLocateDevicePath(
- &EfiSimpleFileSystemProtocolGuid,
- &HandleFilePath,
- &DeviceHandle);
- if (EFI_ERROR(Status)) {
- if (BootPolicy == FALSE) {
- Status = EfiCoreLocateDevicePath(
- &EfiLoadFile2ProtocolGuid,
- &HandleFilePath,
- &DeviceHandle);
- }
- if (EFI_ERROR(Status)) {
- HandleFilePath = FilePath;
- Status = EfiCoreLocateDevicePath(
- &EfiLoadFileProtocolGuid,
- &HandleFilePath,
- &DeviceHandle);
- }
- }
- }
- }
- }
- if (EFI_ERROR(Status)) {
- Image = NULL;
- goto CoreLoadImageEnd;
- }
- //
- // Allocate a new image data structure.
- //
- Image = EfiCoreAllocateBootPool(sizeof(EFI_IMAGE_DATA));
- if (Image == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CoreLoadImageEnd;
- }
- EfiCoreSetMemory(Image, sizeof(EFI_IMAGE_DATA), 0);
- //
- // Pull out just the file portion of the device path for the loaded image
- // file path.
- //
- FilePath = OriginalFilePath;
- if (DeviceHandle != NULL) {
- Status = EfiCoreHandleProtocol(DeviceHandle,
- &EfiDevicePathProtocolGuid,
- (VOID **)&HandleFilePath);
- if (!EFI_ERROR(Status)) {
- FilePathSize = EfiCoreGetDevicePathSize(HandleFilePath) -
- sizeof(EFI_DEVICE_PATH_PROTOCOL);
- FilePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)FilePath) +
- FilePathSize);
- }
- }
- Image->Magic = EFI_IMAGE_DATA_MAGIC;
- Image->Information.SystemTable = EfiSystemTable;
- Image->Information.DeviceHandle = DeviceHandle;
- Image->Information.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
- Image->Information.FilePath = EfiCoreDuplicateDevicePath(FilePath);
- Image->Information.ParentHandle = ParentImageHandle;
- if (PageCount != NULL) {
- Image->ImagePageCount = *PageCount;
- } else {
- Image->ImagePageCount = 0;
- }
- //
- // Install the protocol interfaces for this image, but don't fire the
- // notifications just yet.
- //
- Status = EfipCoreInstallProtocolInterfaceNotify(&(Image->Handle),
- &EfiLoadedImageProtocolGuid,
- EFI_NATIVE_INTERFACE,
- &(Image->Information),
- FALSE);
- if (EFI_ERROR(Status)) {
- goto CoreLoadImageEnd;
- }
- //
- // Load up the image.
- //
- Status = EfipCoreLoadPeImage(BootPolicy,
- &FileHandle,
- Image,
- DestinationBuffer,
- EntryPoint,
- Attributes);
- if (EFI_ERROR(Status)) {
- if ((Status == EFI_BUFFER_TOO_SMALL) ||
- (Status == EFI_OUT_OF_RESOURCES)) {
- if (PageCount != NULL) {
- *PageCount = Image->ImagePageCount;
- }
- }
- goto CoreLoadImageEnd;
- }
- if (PageCount != NULL) {
- *PageCount = Image->ImagePageCount;
- }
- //
- // Register the image with the debugger unless asked not to.
- //
- if (((Attributes &
- EFI_LOAD_PE_IMAGE_ATTRIBUTE_DEBUG_IMAGE_INFO_TABLE_REGISTRATION) !=
- 0) &&
- (FileName != NULL)) {
- AsciiFileName = EfipCoreConvertFileNameToAscii(FileName,
- &AsciiFileNameSize);
- if (AsciiFileName != NULL) {
- AllocationSize = sizeof(DEBUG_MODULE) + AsciiFileNameSize;
- DebuggerModule = EfiCoreAllocateBootPool(AllocationSize);
- if (DebuggerModule != NULL) {
- EfiSetMem(DebuggerModule, AllocationSize, 0);
- DebuggerModule->StructureSize = AllocationSize;
- DebuggerModule->LowestAddress =
- (PVOID)(UINTN)Image->ImageBasePage;
- DebuggerModule->Size = Image->ImagePageCount << EFI_PAGE_SHIFT;
- DebuggerModule->EntryPoint = Image->EntryPoint;
- RtlStringCopy(DebuggerModule->BinaryName,
- AsciiFileName,
- AsciiFileNameSize);
- Image->DebuggerData = DebuggerModule;
- KdReportModuleChange(DebuggerModule, TRUE);
- }
- EfiCoreFreePool(AsciiFileName);
- }
- }
- //
- // Reinstall the loaded image protocol to fire any notifications.
- //
- Status = EfiCoreReinstallProtocolInterface(Image->Handle,
- &EfiLoadedImageProtocolGuid,
- &(Image->Information),
- &(Image->Information));
- if (EFI_ERROR(Status)) {
- goto CoreLoadImageEnd;
- }
- //
- // If the device path parameter is not NULL, make a copy of the device
- // path. Otherwise the loaded image device path protocol is installed with
- // a NULL interface pointer.
- //
- if (OriginalFilePath != NULL) {
- Image->LoadedImageDevicePath =
- EfiCoreDuplicateDevicePath(OriginalFilePath);
- }
- //
- // Install the loaded image device path protocol.
- //
- Status = EfiCoreInstallProtocolInterface(
- &(Image->Handle),
- &EfiLoadedImageDevicePathProtocolGuid,
- EFI_NATIVE_INTERFACE,
- Image->LoadedImageDevicePath);
- if (EFI_ERROR(Status)) {
- goto CoreLoadImageEnd;
- }
- //
- // Install the HII package list protocol onto the image handle.
- //
- if (Image->ImageContext.HiiResourceData != 0) {
- Status = EfiCoreInstallProtocolInterface(
- &(Image->Handle),
- &EfiHiiPackageListProtocolGuid,
- EFI_NATIVE_INTERFACE,
- (VOID *)(UINTN)Image->ImageContext.HiiResourceData);
- if (EFI_ERROR(Status)) {
- goto CoreLoadImageEnd;
- }
- }
- *ImageHandle = Image->Handle;
- CoreLoadImageEnd:
- if (FileHandle.FreeBuffer != FALSE) {
- EfiCoreFreePool(FileHandle.Source);
- }
- if (FileName != NULL) {
- EfiCoreFreePool(FileName);
- }
- if (EFI_ERROR(Status)) {
- if (Image != NULL) {
- FreePage = FALSE;
- if (DestinationBuffer == 0) {
- FreePage = TRUE;
- }
- EfipCoreUnloadAndCloseImage(Image, FreePage);
- Image = NULL;
- }
- }
- //
- // Track the return status from this call.
- //
- if (Image != NULL) {
- Image->LoadImageStatus = Status;
- }
- return Status;
- }
- EFIAPI
- VOID *
- EfipCoreGetFileBufferByFilePath (
- BOOLEAN BootPolicy,
- CONST EFI_DEVICE_PATH_PROTOCOL *FilePath,
- CHAR16 **FileName,
- UINTN *FileSize,
- UINT32 *AuthenticationStatus
- )
- /*++
- Routine Description:
- This routine loads a file either from a firmware image, file system
- interface, or from the load file interface.
- Arguments:
- BootPolicy - Supplies the boot policy. if TRUE, indicates that the request
- originates from a boot manager trying to make a boot selection. If
- FALSE, the file path must match exactly with the file to be loaded.
- FilePath - Supplies a pointer to the device path of the file to load.
- FileName - Supplies a pointer where a pointer to the file name will be
- returned. The caller is responsible for freeing this buffer.
- FileSize - Supplies a pointer where the size of the loaded file buffer will
- be returned on success.
- AuthenticationStatus - Supplies a pointer to the authentication status.
- Return Value:
- Returns a pointer to the image contents. The caller is responsible for
- freeing this memory from pool.
- --*/
- {
- EFI_FV_FILE_ATTRIBUTES Attributes;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
- EFI_DEVICE_PATH_PROTOCOL *DevicePathNodeCopy;
- EFI_FILE_HANDLE FileHandle;
- EFI_FILE_INFO *FileInformation;
- UINTN FileInformationSize;
- UINTN FileNameSize;
- EFI_FIRMWARE_VOLUME2_PROTOCOL *FirmwareVolume;
- EFI_HANDLE Handle;
- UINT8 *ImageBuffer;
- UINTN ImageBufferSize;
- EFI_FILE_HANDLE LastHandle;
- EFI_LOAD_FILE_PROTOCOL *LoadFile;
- EFI_LOAD_FILE2_PROTOCOL *LoadFile2;
- EFI_GUID *NameGuid;
- EFI_DEVICE_PATH_PROTOCOL *OriginalDevicePathNode;
- EFI_SECTION_TYPE SectionType;
- EFI_STATUS Status;
- EFI_FV_FILETYPE Type;
- EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
- if ((FilePath == NULL) || (FileSize == NULL) ||
- (AuthenticationStatus == NULL)) {
- return NULL;
- }
- DevicePathNodeCopy = NULL;
- NameGuid = NULL;
- FileInformation = NULL;
- FileHandle = NULL;
- ImageBuffer = NULL;
- ImageBufferSize = 0;
- *AuthenticationStatus = 0;
- *FileName = NULL;
- OriginalDevicePathNode = EfiCoreDuplicateDevicePath(FilePath);
- if (OriginalDevicePathNode == NULL) {
- return NULL;
- }
- //
- // See if the device path supports the Firmware Volume 2 protocol.
- //
- DevicePathNode = OriginalDevicePathNode;
- Status = EfiLocateDevicePath(&EfiFirmwareVolume2ProtocolGuid,
- &DevicePathNode,
- &Handle);
- if (!EFI_ERROR(Status)) {
- NameGuid = EfiCoreGetNameGuidFromFirmwareVolumeDevicePathNode(
- (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)DevicePathNode);
- if (NameGuid == NULL) {
- Status = EFI_INVALID_PARAMETER;
- } else {
- //
- // Read the image from the firmware file.
- //
- Status = EfiHandleProtocol(Handle,
- &EfiFirmwareVolume2ProtocolGuid,
- (VOID **)&FirmwareVolume);
- if (!EFI_ERROR(Status)) {
- SectionType = EFI_SECTION_PE32;
- ImageBuffer = NULL;
- Status = FirmwareVolume->ReadSection(FirmwareVolume,
- NameGuid,
- SectionType,
- 0,
- (VOID **)&ImageBuffer,
- &ImageBufferSize,
- AuthenticationStatus);
- //
- // If that succeeded, try to read the UI description out as
- // well.
- //
- if (!EFI_ERROR(Status)) {
- FirmwareVolume->ReadSection(FirmwareVolume,
- NameGuid,
- EFI_SECTION_USER_INTERFACE,
- 0,
- (VOID **)FileName,
- &FileNameSize,
- AuthenticationStatus);
- //
- // Null terminate the string just to be safe.
- //
- if (FileNameSize / sizeof(CHAR16) != 0) {
- (*FileName)[(FileNameSize / sizeof(CHAR16)) - 1] =
- L'\0';
- }
- //
- // If reading the PE32 section failed, try a raw file type.
- //
- } else {
- if (ImageBuffer != NULL) {
- EfiCoreFreePool(ImageBuffer);
- *AuthenticationStatus = 0;
- ImageBuffer = NULL;
- }
- Status = FirmwareVolume->ReadFile(FirmwareVolume,
- NameGuid,
- (VOID **)&ImageBuffer,
- &ImageBufferSize,
- &Type,
- &Attributes,
- AuthenticationStatus);
- }
- }
- }
- if (!EFI_ERROR(Status)) {
- goto CoreGetFileBufferByFilePathEnd;
- }
- }
- //
- // Try to access the file via a file system interface.
- //
- DevicePathNode = OriginalDevicePathNode;
- Status = EfiLocateDevicePath(&EfiSimpleFileSystemProtocolGuid,
- &DevicePathNode,
- &Handle);
- if (!EFI_ERROR(Status)) {
- Status = EfiHandleProtocol(Handle,
- &EfiSimpleFileSystemProtocolGuid,
- (VOID **)&Volume);
- if (!EFI_ERROR(Status)) {
- //
- // Open the volume to get the file system handle.
- //
- Status = Volume->OpenVolume(Volume, &FileHandle);
- if (!EFI_ERROR(Status)) {
- //
- // Duplicate the device path to avoid access to an unaligned
- // device path node.
- //
- DevicePathNodeCopy = EfiCoreDuplicateDevicePath(DevicePathNode);
- if (DevicePathNodeCopy == NULL) {
- FileHandle->Close(FileHandle);
- Status = EFI_OUT_OF_RESOURCES;
- }
- DevicePathNode = DevicePathNodeCopy;
- while ((!EFI_ERROR(Status)) &&
- (EfiCoreIsDevicePathEnd(DevicePathNode) == FALSE)) {
- if ((EfiCoreGetDevicePathType(DevicePathNode) !=
- MEDIA_DEVICE_PATH) ||
- (EfiCoreGetDevicePathSubType(DevicePathNode) !=
- MEDIA_FILEPATH_DP)) {
- Status = EFI_UNSUPPORTED;
- break;
- }
- LastHandle = FileHandle;
- FileHandle = NULL;
- Status = LastHandle->Open(
- LastHandle,
- &FileHandle,
- ((FILEPATH_DEVICE_PATH *)DevicePathNode)->PathName,
- EFI_FILE_MODE_READ,
- 0);
- LastHandle->Close(LastHandle);
- DevicePathNode =
- EfiCoreGetNextDevicePathNode(DevicePathNode);
- }
- //
- // If no error occurred, then the file was found. Load the
- // file.
- //
- if (!EFI_ERROR(Status)) {
- FileInformation = NULL;
- FileInformationSize = 0;
- Status = FileHandle->GetInfo(FileHandle,
- &EfiFileInformationGuid,
- &FileInformationSize,
- FileInformation);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- FileInformation =
- EfiCoreAllocateBootPool(FileInformationSize);
- if (FileInformation == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- } else {
- Status = FileHandle->GetInfo(
- FileHandle,
- &EfiFileInformationGuid,
- &FileInformationSize,
- FileInformation);
- }
- }
- if ((!EFI_ERROR(Status)) && (FileInformation != NULL)) {
- //
- // Fail if it's a directory.
- //
- if ((FileInformation->Attribute & EFI_FILE_DIRECTORY) !=
- 0) {
- Status = EFI_LOAD_ERROR;
- //
- // Allocate space for the file and read it in.
- //
- } else {
- ImageBuffer = EfiCoreAllocateBootPool(
- (UINTN)(FileInformation->FileSize));
- if (ImageBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- } else {
- ImageBufferSize = FileInformation->FileSize;
- Status = FileHandle->Read(FileHandle,
- &ImageBufferSize,
- ImageBuffer);
- if (!EFI_ERROR(Status)) {
- //
- // Also read in the file name.
- //
- FileNameSize = EfiCoreStringLength(
- FileInformation->FileName);
- FileNameSize = (FileNameSize + 1) *
- sizeof(CHAR16);
- *FileName = EfiCoreAllocateBootPool(
- FileNameSize);
- if (*FileName != NULL) {
- EfiCopyMem(*FileName,
- FileInformation->FileName,
- FileNameSize);
- }
- }
- }
- }
- }
- }
- if (FileInformation != NULL) {
- EfiCoreFreePool(FileInformation);
- }
- if (FileHandle != NULL) {
- FileHandle->Close(FileHandle);
- }
- if (DevicePathNodeCopy != NULL) {
- EfiCoreFreePool(DevicePathNodeCopy);
- }
- }
- }
- if (!EFI_ERROR(Status)) {
- goto CoreGetFileBufferByFilePathEnd;
- }
- }
- //
- // Attempt to access the file using the Load File 2 protocol.
- //
- if (BootPolicy == FALSE) {
- DevicePathNode = OriginalDevicePathNode;
- Status = EfiLocateDevicePath(&EfiLoadFile2ProtocolGuid,
- &DevicePathNode,
- &Handle);
- if (!EFI_ERROR(Status)) {
- Status = EfiHandleProtocol(Handle,
- &EfiLoadFile2ProtocolGuid,
- (VOID **)&LoadFile2);
- if (!EFI_ERROR(Status)) {
- //
- // Call once to figure out the buffer size.
- //
- ImageBufferSize = 0;
- ImageBuffer = NULL;
- Status = LoadFile2->LoadFile(LoadFile2,
- DevicePathNode,
- FALSE,
- &ImageBufferSize,
- ImageBuffer);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- ImageBuffer = EfiCoreAllocateBootPool(ImageBufferSize);
- if (ImageBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- } else {
- Status = LoadFile2->LoadFile(LoadFile2,
- DevicePathNode,
- FALSE,
- &ImageBufferSize,
- ImageBuffer);
- }
- }
- }
- }
- if (!EFI_ERROR(Status)) {
- goto CoreGetFileBufferByFilePathEnd;
- }
- }
- //
- // Attempt to access the file using the Load File protocol.
- //
- if (BootPolicy == FALSE) {
- DevicePathNode = OriginalDevicePathNode;
- Status = EfiLocateDevicePath(&EfiLoadFileProtocolGuid,
- &DevicePathNode,
- &Handle);
- if (!EFI_ERROR(Status)) {
- Status = EfiHandleProtocol(Handle,
- &EfiLoadFileProtocolGuid,
- (VOID **)&LoadFile);
- if (!EFI_ERROR(Status)) {
- //
- // Call once to figure out the buffer size.
- //
- ImageBufferSize = 0;
- ImageBuffer = NULL;
- Status = LoadFile->LoadFile(LoadFile,
- DevicePathNode,
- FALSE,
- &ImageBufferSize,
- ImageBuffer);
- if (Status == EFI_BUFFER_TOO_SMALL) {
- ImageBuffer = EfiCoreAllocateBootPool(ImageBufferSize);
- if (ImageBuffer == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- } else {
- Status = LoadFile->LoadFile(LoadFile,
- DevicePathNode,
- FALSE,
- &ImageBufferSize,
- ImageBuffer);
- }
- }
- }
- }
- if (!EFI_ERROR(Status)) {
- goto CoreGetFileBufferByFilePathEnd;
- }
- }
- CoreGetFileBufferByFilePathEnd:
- if (EFI_ERROR(Status)) {
- if (ImageBuffer != NULL) {
- EfiCoreFreePool(ImageBuffer);
- ImageBuffer = NULL;
- }
- ImageBufferSize = 0;
- }
- *FileSize = ImageBufferSize;
- EfiCoreFreePool(OriginalDevicePathNode);
- return ImageBuffer;
- }
- EFI_STATUS
- EfipCoreLoadPeImage (
- BOOLEAN BootPolicy,
- VOID *PeHandle,
- PEFI_IMAGE_DATA Image,
- EFI_PHYSICAL_ADDRESS DestinationBuffer,
- EFI_PHYSICAL_ADDRESS *EntryPoint,
- UINT32 Attribute
- )
- /*++
- Routine Description:
- This routine loads, relocates, and invokes a PE/COFF image.
- Arguments:
- BootPolicy - Supplies the boot policy. if TRUE, indicates that the request
- originates from a boot manager trying to make a boot selection. If
- FALSE, the file path must match exactly with the file to be loaded.
- PeHandle - Supplies the handle of the PE image.
- Image - Supplies the PE image to be loaded.
- DestinationBuffer - Supplies the buffer to store the image at.
- EntryPoint - Supplies a pointer where the entry point of the image will
- be returned.
- Attribute - Supplies the bitmask of attributes governing the load process.
- Return Value:
- EFI_SUCCESS if the image was loaded, relocated, and invoked.
- EFI_OUT_OF_RESOURCES on allocation failure.
- EFI_INVALID_PARAMETER on invalid parameter.
- EFI_BUFFER_TOO_SMALL if the buffer for the image is too small.
- --*/
- {
- BOOLEAN DestinationAllocated;
- UINTN NeededPages;
- UINTN Size;
- EFI_STATUS Status;
- EfiCoreSetMemory(&(Image->ImageContext), sizeof(Image->ImageContext), 0);
- Image->ImageContext.Handle = PeHandle;
- Image->ImageContext.ImageRead = EfipCoreReadImageFile;
- //
- // Get information about the image being loaded.
- //
- Status = EfiPeLoaderGetImageInfo(&(Image->ImageContext));
- if (EFI_ERROR(Status)) {
- return Status;
- }
- if (!EFI_IMAGE_MACHINE_TYPE_SUPPORTED(Image->ImageContext.Machine)) {
- RtlDebugPrint("Image Type 0x%x can't be loaded.\n",
- Image->ImageContext.Machine);
- return EFI_UNSUPPORTED;
- }
- //
- // Set the memory type based on the image type.
- //
- switch (Image->ImageContext.ImageType) {
- case EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION:
- Image->ImageContext.ImageCodeMemoryType = EfiLoaderCode;
- Image->ImageContext.ImageDataMemoryType = EfiLoaderData;
- break;
- case EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER:
- Image->ImageContext.ImageCodeMemoryType = EfiBootServicesCode;
- Image->ImageContext.ImageDataMemoryType = EfiBootServicesData;
- break;
- case EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER:
- case EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER:
- Image->ImageContext.ImageCodeMemoryType = EfiRuntimeServicesCode;
- Image->ImageContext.ImageDataMemoryType = EfiRuntimeServicesData;
- break;
- default:
- Image->ImageContext.ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
- return EFI_UNSUPPORTED;
- }
- //
- // Allocate memory of the correct type aligned on the required image
- // boundary.
- //
- DestinationAllocated = FALSE;
- if (DestinationBuffer == 0) {
- Size = (UINTN)Image->ImageContext.ImageSize;
- if (Image->ImageContext.SectionAlignment > EFI_PAGE_SIZE) {
- Size += Image->ImageContext.SectionAlignment;
- }
- Image->ImagePageCount = EFI_SIZE_TO_PAGES(Size);
- //
- // If image relocations have not been stripped, then load at any
- // address. Otherwise, load at the address the image was linked at.
- //
- Status = EFI_OUT_OF_RESOURCES;
- if (Image->ImageContext.RelocationsStripped != FALSE) {
- Status = EfiCoreAllocatePages(
- AllocateAddress,
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
- Image->ImagePageCount,
- &(Image->ImageContext.ImageAddress));
- }
- if ((EFI_ERROR(Status)) &&
- (Image->ImageContext.RelocationsStripped == FALSE)) {
- Status = EfiCoreAllocatePages(
- AllocateAnyPages,
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType),
- Image->ImagePageCount,
- &(Image->ImageContext.ImageAddress));
- }
- if (EFI_ERROR(Status)) {
- return Status;
- }
- DestinationAllocated = TRUE;
- //
- // The caller provided a destination buffer.
- //
- } else {
- if ((Image->ImageContext.RelocationsStripped != FALSE) &&
- (Image->ImageContext.ImageAddress != DestinationBuffer)) {
- RtlDebugPrint("Image must be loaded at 0x%x.\n",
- (UINTN)Image->ImageContext.ImageAddress);
- return EFI_INVALID_PARAMETER;
- }
- Size = (UINTN)Image->ImageContext.ImageSize +
- Image->ImageContext.SectionAlignment;
- NeededPages = EFI_SIZE_TO_PAGES(Size);
- if ((Image->ImagePageCount != 0) &&
- (Image->ImagePageCount < NeededPages)) {
- return EFI_BUFFER_TOO_SMALL;
- }
- Image->ImagePageCount = NeededPages;
- Image->ImageContext.ImageAddress = DestinationBuffer;
- }
- Image->ImageBasePage = Image->ImageContext.ImageAddress;
- if (Image->ImageContext.IsTeImage == FALSE) {
- Image->ImageContext.ImageAddress =
- ALIGN_VALUE(Image->ImageContext.ImageAddress,
- Image->ImageContext.SectionAlignment);
- }
- //
- // Load the image from the file.
- //
- Status = EfiPeLoaderLoadImage(&(Image->ImageContext));
- if (EFI_ERROR(Status)) {
- goto CoreLoadPeImageEnd;
- }
- //
- // If this is a runtime driver, allocate memory for the fixup data used to
- // relocate the image when SetVirtualAddressMap is called.
- //
- if (((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) &&
- (Image->ImageContext.ImageType ==
- EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {
- Image->ImageContext.FixupData = EfiCoreAllocateRuntimePool(
- (UINTN)Image->ImageContext.FixupDataSize);
- if (Image->ImageContext.FixupData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CoreLoadPeImageEnd;
- }
- }
- //
- // Relocate the image in memory.
- //
- Status = EfiPeLoaderRelocateImage(&(Image->ImageContext));
- if (EFI_ERROR(Status)) {
- goto CoreLoadPeImageEnd;
- }
- EfiCoreInvalidateInstructionCacheRange(
- (VOID *)(UINTN)(Image->ImageContext.ImageAddress),
- (UINTN)(Image->ImageContext.ImageSize));
- Image->Machine = Image->ImageContext.Machine;
- //
- // Get the image entry point.
- //
- Image->EntryPoint =
- (EFI_IMAGE_ENTRY_POINT)(UINTN)(Image->ImageContext.EntryPoint);
- //
- // Fill in the image information for the Loaded Image Protocol.
- //
- Image->Type = Image->ImageContext.ImageType;
- Image->Information.ImageBase =
- (VOID *)(UINTN)(Image->ImageContext.ImageAddress);
- Image->Information.ImageSize = Image->ImageContext.ImageSize;
- Image->Information.ImageCodeType =
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageCodeMemoryType);
- Image->Information.ImageDataType =
- (EFI_MEMORY_TYPE)(Image->ImageContext.ImageDataMemoryType);
- //
- // Create the runtime image entry as well if needed.
- //
- if (((Attribute & EFI_LOAD_PE_IMAGE_ATTRIBUTE_RUNTIME_REGISTRATION) != 0) &&
- (Image->ImageContext.ImageType ==
- EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER)) {
- Image->RuntimeData = EfiCoreAllocateRuntimePool(
- sizeof(EFI_RUNTIME_IMAGE_ENTRY));
- if (Image->RuntimeData == NULL) {
- Status = EFI_OUT_OF_RESOURCES;
- goto CoreLoadPeImageEnd;
- }
- Image->RuntimeData->ImageBase = Image->Information.ImageBase;
- Image->RuntimeData->ImageSize = Image->Information.ImageSize;
- Image->RuntimeData->RelocationData = Image->ImageContext.FixupData;
- Image->RuntimeData->Handle = Image->Handle;
- INSERT_BEFORE(&(Image->RuntimeData->ListEntry),
- &(EfiRuntimeProtocol->ImageListHead));
- }
- if (EntryPoint != NULL) {
- *EntryPoint = Image->ImageContext.EntryPoint;
- }
- Status = EFI_SUCCESS;
- CoreLoadPeImageEnd:
- if (EFI_ERROR(Status)) {
- if (DestinationAllocated != FALSE) {
- EfiCoreFreePages(Image->ImageContext.ImageAddress,
- Image->ImagePageCount);
- }
- if (Image->ImageContext.FixupData != NULL) {
- EfiCoreFreePool(Image->ImageContext.FixupData);
- }
- }
- return Status;
- }
- VOID
- EfipCoreUnloadAndCloseImage (
- PEFI_IMAGE_DATA Image,
- BOOLEAN FreePages
- )
- /*++
- Routine Description:
- This routine unloads an EFI image from memory.
- Arguments:
- Image - Supplies a pointer to the image data.
- FreePages - Supplies a boolean indicating whether or not to free the
- allocated pages.
- Return Value:
- None.
- --*/
- {
- UINTN ArrayCount;
- EFI_HANDLE *HandleBuffer;
- UINTN HandleCount;
- UINTN HandleIndex;
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInformation;
- UINTN OpenInformationCount;
- EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInformationEntry;
- UINTN OpenInformationIndex;
- EFI_GUID **ProtocolGuidArray;
- UINTN ProtocolIndex;
- EFI_STATUS Status;
- ASSERT(Image->Magic == EFI_IMAGE_DATA_MAGIC);
- EfiPeLoaderUnloadImage(&(Image->ImageContext));
- //
- // Free references to the image handle.
- //
- if (Image->Handle != NULL) {
- Status = EfiCoreLocateHandleBuffer(AllHandles,
- NULL,
- NULL,
- &HandleCount,
- &HandleBuffer);
- if (!EFI_ERROR(Status)) {
- for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex += 1) {
- Status = EfiCoreProtocolsPerHandle(HandleBuffer[HandleIndex],
- &ProtocolGuidArray,
- &ArrayCount);
- if (!EFI_ERROR(Status)) {
- for (ProtocolIndex = 0;
- ProtocolIndex < ArrayCount;
- ProtocolIndex += 1) {
- Status = EfiCoreOpenProtocolInformation(
- HandleBuffer[HandleIndex],
- ProtocolGuidArray[ProtocolIndex],
- &OpenInformation,
- &OpenInformationCount);
- if (!EFI_ERROR(Status)) {
- for (OpenInformationIndex = 0;
- OpenInformationIndex < OpenInformationCount;
- OpenInformationIndex += 1) {
- OpenInformationEntry =
- &(OpenInformation[OpenInformationIndex]);
- if (OpenInformationEntry->AgentHandle ==
- Image->Handle) {
- EfiCoreCloseProtocol(
- HandleBuffer[HandleIndex],
- ProtocolGuidArray[ProtocolIndex],
- Image->Handle,
- OpenInformationEntry->ControllerHandle);
- }
- }
- if (OpenInformation != NULL) {
- EfiCoreFreePool(OpenInformation);
- }
- }
- }
- if (ProtocolGuidArray != NULL) {
- EfiCoreFreePool(ProtocolGuidArray);
- }
- }
- }
- if (HandleBuffer != NULL) {
- EfiCoreFreePool(HandleBuffer);
- }
- }
- //
- // Let the debugger know the image is being unloaded.
- //
- if (Image->DebuggerData != NULL) {
- KdReportModuleChange(Image->DebuggerData, FALSE);
- EfiCoreFreePool(Image->DebuggerData);
- }
- EfiCoreUninstallProtocolInterface(Image->Handle,
- &EfiLoadedImageDevicePathProtocolGuid,
- Image->LoadedImageDevicePath);
- EfiCoreUninstallProtocolInterface(Image->Handle,
- &EfiLoadedImageProtocolGuid,
- &(Image->Information));
- if (Image->ImageContext.HiiResourceData != 0) {
- EfiCoreUninstallProtocolInterface(
- Image->Handle,
- &EfiHiiPackageListProtocolGuid,
- (VOID *)(UINTN)Image->ImageContext.HiiResourceData);
- }
- }
- if (Image->RuntimeData != NULL) {
- if (Image->RuntimeData->ListEntry.Next != NULL) {
- LIST_REMOVE(&(Image->RuntimeData->ListEntry));
- }
- EfiCoreFreePool(Image->RuntimeData);
- }
- //
- // Free the image from memory.
- //
- if ((Image->ImageBasePage != 0) && (FreePages != FALSE)) {
- EfiCoreFreePages(Image->ImageBasePage, Image->ImagePageCount);
- }
- if (Image->Information.FilePath != NULL) {
- EfiCoreFreePool(Image->Information.FilePath);
- }
- if (Image->LoadedImageDevicePath != NULL) {
- EfiCoreFreePool(Image->LoadedImageDevicePath);
- }
- if (Image->FixupData != NULL) {
- EfiCoreFreePool(Image->FixupData);
- }
- Image->Magic = 0;
- EfiCoreFreePool(Image);
- return;
- }
- PEFI_IMAGE_DATA
- EfipCoreGetImageDataFromHandle (
- EFI_HANDLE ImageHandle
- )
- /*++
- Routine Description:
- This routine returns the private image data from a handle.
- Arguments:
- ImageHandle - Supplies the image handle.
- Return Value:
- Returns a pointer to the private image data.
- --*/
- {
- PEFI_IMAGE_DATA Image;
- EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
- EFI_STATUS Status;
- Status = EfiCoreHandleProtocol(ImageHandle,
- &EfiLoadedImageProtocolGuid,
- (VOID **)&LoadedImage);
- if (!EFI_ERROR(Status)) {
- Image = PARENT_STRUCTURE(LoadedImage, EFI_IMAGE_DATA, Information);
- ASSERT(Image->Magic == EFI_IMAGE_DATA_MAGIC);
- } else {
- ASSERT(FALSE);
- Image = NULL;
- }
- return Image;
- }
- EFIAPI
- EFI_STATUS
- EfipCoreReadImageFile (
- VOID *FileHandle,
- UINTN FileOffset,
- UINTN *ReadSize,
- VOID *Buffer
- )
- /*++
- Routine Description:
- This routine reads contents of the PE/COFF image file.
- Arguments:
- FileHandle - Supplies a pointer to the file handle to read from.
- FileOffset - Supplies an offset in bytes from the beginning of the file to
- read.
- ReadSize - Supplies a pointer that on input contains the number of bytes to
- read. On output, returns the number of bytes read.
- Buffer - Supplies the buffer where the read data will be returned.
- Return Value:
- EFI status code.
- --*/
- {
- UINTN EndPosition;
- PEFI_IMAGE_FILE_HANDLE ImageHandle;
- if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
- if (MAX_ADDRESS - FileOffset < *ReadSize) {
- return EFI_INVALID_PARAMETER;
- }
- ImageHandle = (EFI_IMAGE_FILE_HANDLE *)FileHandle;
- ASSERT(ImageHandle->Magic == EFI_IMAGE_FILE_HANDLE_MAGIC);
- EndPosition = FileOffset + *ReadSize;
- if (EndPosition > ImageHandle->SourceSize) {
- *ReadSize = (UINT32)(ImageHandle->SourceSize - FileOffset);
- }
- if (FileOffset >= ImageHandle->SourceSize) {
- *ReadSize = 0;
- }
- if (*ReadSize != 0) {
- EfiCoreCopyMemory(Buffer,
- (CHAR8 *)ImageHandle->Source + FileOffset,
- *ReadSize);
- }
- return EFI_SUCCESS;
- }
- CHAR8 *
- EfipCoreConvertFileNameToAscii (
- CHAR16 *FileName,
- UINTN *AsciiNameSize
- )
- /*++
- Routine Description:
- This routine creates an ASCII version of the given wide string.
- Arguments:
- FileName - Supplies a pointer to the wide string.
- AsciiNameSize - Supplies a pointer where the size of the ASCII string in
- bytes including the NULL terminator will be returned.
- Return Value:
- Returns a pointer to the ASCII string. The caller is responsible for
- freeing this memory.
- NULL on allocation failure.
- --*/
- {
- CHAR8 *AsciiCharacter;
- CHAR8 *AsciiString;
- UINTN StringSize;
- StringSize = EfiCoreStringLength(FileName) + 1;
- AsciiString = EfiCoreAllocateBootPool(StringSize);
- if (AsciiString == NULL) {
- *AsciiNameSize = 0;
- return NULL;
- }
- AsciiCharacter = AsciiString;
- while (TRUE) {
- *AsciiCharacter = *FileName;
- if (*AsciiCharacter == '\0') {
- break;
- }
- FileName += 1;
- AsciiCharacter += 1;
- }
- *AsciiNameSize = StringSize;
- return AsciiString;
- }
|