Migrate XTLDR to C++
This commit is contained in:
938
xtldr/protocol.cc
Normal file
938
xtldr/protocol.cc
Normal file
@@ -0,0 +1,938 @@
|
||||
/**
|
||||
* PROJECT: ExectOS
|
||||
* COPYRIGHT: See COPYING.md in the top level directory
|
||||
* FILE: xtldr/protocol.cc
|
||||
* DESCRIPTION: XT Boot Loader protocol support
|
||||
* DEVELOPERS: Rafal Kupiec <belliash@codingworkshop.eu.org>
|
||||
*/
|
||||
|
||||
#include <xtldr.h>
|
||||
|
||||
|
||||
/**
|
||||
* Closes a protocol on a provided handle.
|
||||
*
|
||||
* @param Handle
|
||||
* Supplies a handle for the protocol interface that was previously opened.
|
||||
*
|
||||
* @param ProtocolGuid
|
||||
* Supplies a unique protocol GUID.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlCloseProtocol(IN PEFI_HANDLE Handle,
|
||||
IN PEFI_GUID ProtocolGuid)
|
||||
{
|
||||
return EfiSystemTable->BootServices->CloseProtocol(Handle, ProtocolGuid, EfiImageHandle, NULLPTR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds a boot protocol for specified system type.
|
||||
*
|
||||
* @param SystemType
|
||||
* Specifies the system type to search for.
|
||||
*
|
||||
* @param BootProtocolGuid
|
||||
* Receives the GUID of the registered boot protocol, that supports specified system.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlFindBootProtocol(IN PCWSTR SystemType,
|
||||
OUT PEFI_GUID BootProtocolGuid)
|
||||
{
|
||||
PXTBL_KNOWN_BOOT_PROTOCOL ProtocolEntry;
|
||||
PLIST_ENTRY ProtocolListEntry;
|
||||
|
||||
ProtocolListEntry = BlpBootProtocols.Flink;
|
||||
while(ProtocolListEntry != &BlpBootProtocols)
|
||||
{
|
||||
/* Get boot protocol entry */
|
||||
ProtocolEntry = CONTAIN_RECORD(ProtocolListEntry, XTBL_KNOWN_BOOT_PROTOCOL, Flink);
|
||||
|
||||
/* Check if this boot protocol supports specified system */
|
||||
if(RtlCompareWideStringInsensitive(ProtocolEntry->SystemType, SystemType, 0) == 0)
|
||||
{
|
||||
/* Boot protocol matched, return success */
|
||||
*BootProtocolGuid = ProtocolEntry->Guid;
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/* Move to the next registered boot protocol */
|
||||
ProtocolListEntry = ProtocolListEntry->Flink;
|
||||
}
|
||||
|
||||
/* Boot protocol not found, return error */
|
||||
return STATUS_EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a linked list of all loaded modules.
|
||||
*
|
||||
* @return This routine returns a pointer to a linked list of all loaded modules.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*
|
||||
* @todo This is a temporary solution and it should be replaced by a complex API allowing to map modules.
|
||||
*/
|
||||
XTCDECL
|
||||
PLIST_ENTRY
|
||||
BlGetModulesList()
|
||||
{
|
||||
/* Return a pointer to a list of all loaded modules */
|
||||
return &BlpLoadedModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Installs XTLDR protocol interface.
|
||||
*
|
||||
* @param Guid
|
||||
* Specifies a unique protocol GUID.
|
||||
*
|
||||
* @param Interface
|
||||
* Supplies a pointer to the protocol interface, or NULLPTR if there is no structure associated.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlInstallProtocol(IN PVOID Interface,
|
||||
IN PEFI_GUID Guid)
|
||||
{
|
||||
EFI_HANDLE Handle = NULLPTR;
|
||||
|
||||
/* Install protocol interface */
|
||||
return EfiSystemTable->BootServices->InstallProtocolInterface(&Handle, Guid, EFI_NATIVE_INTERFACE, Interface);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a specified XTLDR module from disk.
|
||||
*
|
||||
* @param ModuleName
|
||||
* Specifies the name of the module to load.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlLoadModule(IN PWCHAR ModuleName)
|
||||
{
|
||||
EFI_GUID LIPGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||
PLIST_ENTRY DepsListEntry, ModuleListEntry;
|
||||
EFI_MEMMAP_DEVICE_PATH ModuleDevicePath[2];
|
||||
PEFI_LOADED_IMAGE_PROTOCOL LoadedImage;
|
||||
PEFI_FILE_HANDLE DirHandle, FsHandle;
|
||||
EFI_HANDLE DiskHandle, ModuleHandle;
|
||||
PPECOFF_IMAGE_SECTION_HEADER SectionHeader;
|
||||
PPECOFF_IMAGE_DOS_HEADER DosHeader;
|
||||
PPECOFF_IMAGE_PE_HEADER PeHeader;
|
||||
PXTBL_MODULE_DEPS ModuleDependency;
|
||||
PXTBL_MODULE_INFO ModuleInfo;
|
||||
WCHAR ModuleFileName[24];
|
||||
USHORT SectionIndex;
|
||||
PWCHAR SectionData;
|
||||
SIZE_T ModuleSize;
|
||||
EFI_STATUS Status;
|
||||
PVOID ModuleData;
|
||||
|
||||
ModuleListEntry = BlpLoadedModules.Flink;
|
||||
while(ModuleListEntry != &BlpLoadedModules)
|
||||
{
|
||||
/* Get module information */
|
||||
ModuleInfo = CONTAIN_RECORD(ModuleListEntry, XTBL_MODULE_INFO, Flink);
|
||||
|
||||
if(RtlCompareWideStringInsensitive(ModuleInfo->ModuleName, ModuleName, 0) == 0)
|
||||
{
|
||||
/* Module already loaded */
|
||||
BlDebugPrint(L"WARNING: Module '%S' already loaded!\n", ModuleName);
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/* Move to next module */
|
||||
ModuleListEntry = ModuleListEntry->Flink;
|
||||
}
|
||||
|
||||
/* Print debug message */
|
||||
BlDebugPrint(L"Loading module '%S' ...\n", ModuleName);
|
||||
|
||||
/* Set module path */
|
||||
RtlCopyMemory(ModuleFileName, ModuleName, (RtlWideStringLength(ModuleName, 0) + 1) * sizeof(WCHAR));
|
||||
RtlConcatenateWideString(ModuleFileName, (PWCHAR)L".EFI", 0);
|
||||
|
||||
/* Open EFI volume */
|
||||
Status = BlOpenVolume(NULLPTR, &DiskHandle, &FsHandle);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to open a volume */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Open XTLDR modules common directory */
|
||||
Status = FsHandle->Open(FsHandle, &DirHandle, (PWCHAR)XTBL_MODULES_DIRECTORY_PATH, EFI_FILE_MODE_READ, 0);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Modules directory not found, attempt to open XTLDR architecture specific modules directory */
|
||||
Status = FsHandle->Open(FsHandle, &DirHandle, (PWCHAR)XTBL_ARCH_MODULES_DIRECTORY_PATH, EFI_FILE_MODE_READ, 0);
|
||||
}
|
||||
|
||||
/* Close FS handle */
|
||||
FsHandle->Close(FsHandle);
|
||||
|
||||
/* Check if modules directory opened successfully */
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to open directory */
|
||||
BlCloseVolume(&DiskHandle);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Read module file from disk and close directory and EFI volume */
|
||||
Status = BlReadFile(DirHandle, ModuleFileName, &ModuleData, &ModuleSize);
|
||||
DirHandle->Close(DirHandle);
|
||||
BlCloseVolume(&DiskHandle);
|
||||
|
||||
/* Make sure module file was read successfully */
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to read file */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Allocate memory for module information block */
|
||||
Status = BlAllocateMemoryPool(sizeof(XTBL_MODULE_INFO), (PVOID*)&ModuleInfo);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to allocate memory */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Zero module information block */
|
||||
RtlZeroMemory(ModuleInfo, sizeof(XTBL_MODULE_INFO));
|
||||
|
||||
/* Setup PE/COFF EFI image headers */
|
||||
DosHeader = (PPECOFF_IMAGE_DOS_HEADER)ModuleData;
|
||||
PeHeader = (PPECOFF_IMAGE_PE_HEADER)((PUCHAR)ModuleData + DosHeader->PeHeaderOffset);
|
||||
|
||||
/* Check PE/COFF image type*/
|
||||
if(PeHeader->OptionalHeader32.Magic == PECOFF_IMAGE_PE_OPTIONAL_HDR64_MAGIC)
|
||||
{
|
||||
/* Get PE32+ (64-bit) image section headers */
|
||||
SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&PeHeader->OptionalHeader64 +
|
||||
PeHeader->FileHeader.SizeOfOptionalHeader);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get PE32 (32-bit) image section headers */
|
||||
SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&PeHeader->OptionalHeader32 +
|
||||
PeHeader->FileHeader.SizeOfOptionalHeader);
|
||||
}
|
||||
|
||||
/* Look for .modinfo section */
|
||||
for(SectionIndex = 0; SectionIndex < PeHeader->FileHeader.NumberOfSections; SectionIndex++)
|
||||
{
|
||||
if(RtlCompareString((PCHAR)SectionHeader[SectionIndex].Name, ".modinfo", 8) == 0)
|
||||
{
|
||||
/* Module information section found */
|
||||
SectionData = (PWCHAR)((PUCHAR)ModuleData + SectionHeader[SectionIndex].PointerToRawData);
|
||||
|
||||
/* Get module information */
|
||||
Status = BlpGetModuleInformation(SectionData, SectionHeader[SectionIndex].SizeOfRawData, ModuleInfo);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to read module information */
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Iterate through module dependencies */
|
||||
DepsListEntry = ModuleInfo->Dependencies.Flink;
|
||||
while(DepsListEntry != &ModuleInfo->Dependencies)
|
||||
{
|
||||
/* Get module dependency information */
|
||||
ModuleDependency = CONTAIN_RECORD(DepsListEntry, XTBL_MODULE_DEPS, Flink);
|
||||
|
||||
/* Make sure dependency list contains a valid module name */
|
||||
if(ModuleDependency->ModuleName == NULLPTR || ModuleDependency->ModuleName[0] == L'\0')
|
||||
{
|
||||
/* Invalid module name found, just skip this step */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Load dependency module */
|
||||
BlDebugPrint(L"Module '%S' requires '%S' ...\n", ModuleName, ModuleDependency->ModuleName);
|
||||
Status = BlLoadModule(ModuleDependency->ModuleName);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to load module, print error message and return status code */
|
||||
BlDebugPrint(L"Failed to load dependency module '%S' (Status Code: 0x%zX)\n", ModuleDependency->ModuleName, Status);
|
||||
return STATUS_EFI_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/* Move to the next dependency */
|
||||
DepsListEntry = DepsListEntry->Flink;
|
||||
}
|
||||
|
||||
/* Setup module device path */
|
||||
ModuleDevicePath[0].Header.Length[0] = sizeof(EFI_MEMMAP_DEVICE_PATH);
|
||||
ModuleDevicePath[0].Header.Length[1] = sizeof(EFI_MEMMAP_DEVICE_PATH) >> 8;
|
||||
ModuleDevicePath[0].Header.Type = EFI_HARDWARE_DEVICE_PATH;
|
||||
ModuleDevicePath[0].Header.SubType = EFI_HARDWARE_MEMMAP_DP;
|
||||
ModuleDevicePath[0].MemoryType = EfiLoaderData;
|
||||
ModuleDevicePath[0].StartingAddress = (UINT_PTR)ModuleData;
|
||||
ModuleDevicePath[0].EndingAddress = (UINT_PTR)ModuleData + ModuleSize;
|
||||
ModuleDevicePath[1].Header.Length[0] = sizeof(EFI_DEVICE_PATH_PROTOCOL);
|
||||
ModuleDevicePath[1].Header.Length[1] = sizeof(EFI_DEVICE_PATH_PROTOCOL) >> 8;
|
||||
ModuleDevicePath[1].Header.Type = EFI_END_DEVICE_PATH;
|
||||
ModuleDevicePath[1].Header.SubType = EFI_END_ENTIRE_DP;
|
||||
|
||||
/* Load EFI image */
|
||||
BlDebugPrint(L"Starting module '%S' ...\n", ModuleName);
|
||||
Status = BlLoadEfiImage((PEFI_DEVICE_PATH_PROTOCOL)ModuleDevicePath, ModuleData, ModuleSize, &ModuleHandle);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Check if caused by secure boot */
|
||||
if(Status == STATUS_EFI_ACCESS_DENIED && BlpStatus.SecureBoot >= 1)
|
||||
{
|
||||
/* SecureBoot signature validation failed */
|
||||
BlDebugPrint(L"ERROR: SecureBoot signature validation failed, module '%S' will not be loaded\n", ModuleName);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Failed to load module */
|
||||
BlDebugPrint(L"ERROR: Unable to load module '%S' (Status Code: 0x%zX)\n", ModuleName, Status);
|
||||
}
|
||||
|
||||
/* Return error status code */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Access module interface for further module type check */
|
||||
Status = EfiSystemTable->BootServices->OpenProtocol(ModuleHandle, &LIPGuid, (PVOID *)&LoadedImage,
|
||||
EfiImageHandle, NULLPTR, EFI_OPEN_PROTOCOL_GET_PROTOCOL);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to open LoadedImage protocol */
|
||||
BlDebugPrint(L"ERROR: Unable to access module interface (Status Code: 0x%zX)\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Some firmwares do not allow to start drivers which are not of 'boot system driver' type, so check it */
|
||||
if(LoadedImage->ImageCodeType != EfiBootServicesCode)
|
||||
{
|
||||
/* Different type set, probably 'runtime driver', refuse to load it */
|
||||
BlDebugPrint(L"ERROR: Loaded module is not a boot system driver\n");
|
||||
|
||||
/* Close protocol and skip module */
|
||||
EfiSystemTable->BootServices->CloseProtocol(LoadedImage, &LIPGuid, LoadedImage, NULLPTR);
|
||||
}
|
||||
|
||||
/* Save additional module information, not found in '.modinfo' section */
|
||||
ModuleInfo->ModuleName = ModuleName;
|
||||
ModuleInfo->ModuleBase = LoadedImage->ImageBase;
|
||||
ModuleInfo->ModuleSize = LoadedImage->ImageSize;
|
||||
ModuleInfo->Revision = LoadedImage->Revision;
|
||||
ModuleInfo->UnloadModule = LoadedImage->Unload;
|
||||
|
||||
/* Close loaded image protocol */
|
||||
EfiSystemTable->BootServices->CloseProtocol(LoadedImage, &LIPGuid, LoadedImage, NULLPTR);
|
||||
|
||||
/* Start EFI image */
|
||||
Status = BlStartEfiImage(ModuleHandle);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to start module image */
|
||||
BlDebugPrint(L"ERROR: Failed to start module '%S' (Status Code: 0x%zX)\n", ModuleName, Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Add module to the list of loaded modules */
|
||||
RtlInsertTailList(&BlpLoadedModules, &ModuleInfo->Flink);
|
||||
|
||||
/* Return success */
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper routine to load all modules supplied in the configuration file.
|
||||
*
|
||||
* @param ModulesList
|
||||
* Supplies a space separated list of XTLDR modules to load (mostly read from configuration file).
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlLoadModules(IN PWCHAR ModulesList)
|
||||
{
|
||||
PWCHAR LastModule, Module;
|
||||
EFI_STATUS ReturnStatus, Status;
|
||||
|
||||
/* Set default return value */
|
||||
ReturnStatus = STATUS_EFI_SUCCESS;
|
||||
|
||||
if(ModulesList != NULLPTR)
|
||||
{
|
||||
/* Tokenize provided list of modules */
|
||||
Module = RtlTokenizeWideString(ModulesList, L" ", &LastModule);
|
||||
|
||||
/* Iterate over all arguments passed to boot loader */
|
||||
while(Module != NULLPTR)
|
||||
{
|
||||
Status = BlLoadModule(Module);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to load module, print error message and set new return value */
|
||||
BlDebugPrint(L"ERROR: Failed to load module '%S' (Status Code: 0x%zX)\n", Module, Status);
|
||||
ReturnStatus = STATUS_EFI_LOAD_ERROR;
|
||||
}
|
||||
|
||||
/* Take next module from the list */
|
||||
Module = RtlTokenizeWideString(NULLPTR, L" ", &LastModule);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return ReturnStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of handles that support the requested protocol.
|
||||
*
|
||||
* @param Handles
|
||||
* Supplies the address where a pointer to all handles found for the protocol interface.
|
||||
*
|
||||
* @param Count
|
||||
* Provides a number of the returned handles.
|
||||
*
|
||||
* @param ProtocolGuid
|
||||
* Supplies a pointer to the unique protocol GUID.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlLocateProtocolHandles(OUT PEFI_HANDLE *Handles,
|
||||
OUT PUINT_PTR Count,
|
||||
IN PEFI_GUID ProtocolGuid)
|
||||
{
|
||||
return EfiSystemTable->BootServices->LocateHandleBuffer(ByProtocol, ProtocolGuid, NULLPTR, Count, Handles);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locates and opens the requested XT Boot Loader or EFI protocol.
|
||||
*
|
||||
* @param Handle
|
||||
* Supplies the address where a pointer to the handle for the protocol interface.
|
||||
*
|
||||
* @param ProtocolHandler
|
||||
* Supplies the address where a pointer to the opened protocol is returned.
|
||||
*
|
||||
* @param ProtocolGuid
|
||||
* Supplies a pointer to the unique protocol GUID.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlOpenProtocol(OUT PEFI_HANDLE Handle,
|
||||
OUT PVOID *ProtocolHandler,
|
||||
IN PEFI_GUID ProtocolGuid)
|
||||
{
|
||||
PEFI_HANDLE Handles = NULLPTR;
|
||||
EFI_STATUS Status;
|
||||
UINT_PTR Count;
|
||||
UINT Index;
|
||||
|
||||
/* Try to locate the handles */
|
||||
Status = BlLocateProtocolHandles(&Handles, &Count, ProtocolGuid);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Unable to get handles */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Check if any handles returned */
|
||||
if(Count > 0)
|
||||
{
|
||||
/* Iterate through all given handles */
|
||||
for(Index = 0; Index < Count; Index++)
|
||||
{
|
||||
/* Try to open protocol */
|
||||
Status = BlOpenProtocolHandle(Handles[Index], ProtocolHandler, ProtocolGuid);
|
||||
|
||||
/* Check if successfully opened the loader protocol */
|
||||
if(Status == STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Protocol found and successfully opened */
|
||||
*Handle = Handles[Index];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Free handles */
|
||||
EfiSystemTable->BootServices->FreePool(Handles);
|
||||
|
||||
/* Make sure the loaded protocol has been found */
|
||||
if(*ProtocolHandler == NULLPTR)
|
||||
{
|
||||
/* Protocol not found */
|
||||
return STATUS_EFI_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens the requested XT Boot Loader or EFI protocol, if it is supported by the handle.
|
||||
*
|
||||
* @param Handle
|
||||
* Supplies a handle for the protocol interface that is being opened.
|
||||
*
|
||||
* @param ProtocolHandler
|
||||
* Supplies the address where a pointer to the opened protocol is returned.
|
||||
*
|
||||
* @param ProtocolGuid
|
||||
* Supplies a pointer to the unique protocol GUID.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlOpenProtocolHandle(IN EFI_HANDLE Handle,
|
||||
OUT PVOID *ProtocolHandler,
|
||||
IN PEFI_GUID ProtocolGuid)
|
||||
{
|
||||
return EfiSystemTable->BootServices->OpenProtocol(Handle, ProtocolGuid, ProtocolHandler, EfiImageHandle,
|
||||
NULLPTR, EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a boot menu callback routine, that will be used to display alternative boot menu.
|
||||
*
|
||||
* @param BootMenuRoutine
|
||||
* Supplies a pointer to the boot menu callback routine.
|
||||
*
|
||||
* @return This routine does not return any value.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
VOID
|
||||
BlRegisterBootMenu(IN PVOID BootMenuRoutine)
|
||||
{
|
||||
/* Set boot menu routine */
|
||||
BlpStatus.BootMenu = (PBL_XT_BOOT_MENU)BootMenuRoutine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a known boot protocol for a specified OS.
|
||||
*
|
||||
* @param SystemType
|
||||
* Supplies the type of the OS, such as "LINUX", "XTOS", etc. that is supported by the boot protocol.
|
||||
*
|
||||
* @param BootProtocolGuid
|
||||
* Supplies a pointer to the unique protocol GUID.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlRegisterBootProtocol(IN PCWSTR SystemType,
|
||||
IN PEFI_GUID BootProtocolGuid)
|
||||
{
|
||||
PXTBL_KNOWN_BOOT_PROTOCOL ProtocolEntry;
|
||||
PLIST_ENTRY ProtocolListEntry;
|
||||
EFI_STATUS Status;
|
||||
|
||||
ProtocolListEntry = BlpBootProtocols.Flink;
|
||||
while(ProtocolListEntry != &BlpBootProtocols)
|
||||
{
|
||||
/* Get boot protocol entry */
|
||||
ProtocolEntry = CONTAIN_RECORD(ProtocolListEntry, XTBL_KNOWN_BOOT_PROTOCOL, Flink);
|
||||
|
||||
/* Check if boot protocol already registered for specified system */
|
||||
if(RtlCompareWideStringInsensitive(ProtocolEntry->SystemType, SystemType, 0) == 0)
|
||||
{
|
||||
/* Boot protocol already registered */
|
||||
return STATUS_EFI_ABORTED;
|
||||
}
|
||||
|
||||
/* Move to the next registered boot protocol */
|
||||
ProtocolListEntry = ProtocolListEntry->Flink;
|
||||
}
|
||||
|
||||
/* Create new boot protocol entry */
|
||||
Status = BlAllocateMemoryPool(sizeof(XTBL_BOOT_PROTOCOL), (PVOID *)&ProtocolEntry);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure */
|
||||
return STATUS_EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
/* Set protocol properties and add it to the list */
|
||||
ProtocolEntry->SystemType = (PWCHAR)SystemType;
|
||||
ProtocolEntry->Guid = *BootProtocolGuid;
|
||||
RtlInsertTailList(&BlpBootProtocols, &ProtocolEntry->Flink);
|
||||
|
||||
/* Return success */
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads information from the '.modinfo' section and populates the module information structure.
|
||||
*
|
||||
* @param SectionData
|
||||
* Supplies a pointer to the module's information section data.
|
||||
*
|
||||
* @param SectionSize
|
||||
* Supplies an expected size of the section data.
|
||||
*
|
||||
* @param ModuleInfo
|
||||
* Supplies a pointer to the module information structure that will be filled by data from module's info section.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlpGetModuleInformation(IN PWCHAR SectionData,
|
||||
IN ULONG SectionSize,
|
||||
OUT PXTBL_MODULE_INFO ModuleInfo)
|
||||
{
|
||||
PXTBL_MODULE_DEPS ModuleDependencies;
|
||||
PXTBL_MODULE_AUTHORS ModuleAuthors;
|
||||
PWCHAR Dependency, Key, LastStr;
|
||||
ULONG Index, Count;
|
||||
EFI_STATUS Status;
|
||||
PWCHAR *Strings;
|
||||
|
||||
/* Initialize authors and dependencies lists */
|
||||
RtlInitializeListHead(&ModuleInfo->Authors);
|
||||
RtlInitializeListHead(&ModuleInfo->Dependencies);
|
||||
|
||||
/* Get information strings from '.modinfo' section */
|
||||
Status = BlpGetModuleInfoStrings(SectionData, SectionSize, &Strings, &Count);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to get information strings */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Parse information strings */
|
||||
for(Index = 0; Index < Count; Index++)
|
||||
{
|
||||
/* Store the key */
|
||||
Key = Strings[Index];
|
||||
|
||||
/* Find the end of the key and the beginning of the value */
|
||||
while(*Strings[Index] != L'=' && *Strings[Index] != L'\0' && *Strings[Index] != L'\n')
|
||||
{
|
||||
/* Move to the next character */
|
||||
Strings[Index]++;
|
||||
}
|
||||
|
||||
/* Make sure value is NULL-terminated */
|
||||
*Strings[Index] = L'\0';
|
||||
Strings[Index]++;
|
||||
|
||||
/* Parse information string key */
|
||||
if(RtlCompareWideString(Key, L"author", 6) == 0)
|
||||
{
|
||||
/* Allocate memory for module author */
|
||||
Status = BlAllocateMemoryPool(sizeof(XTBL_MODULE_AUTHORS), (PVOID*)&ModuleAuthors);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Store module's author */
|
||||
ModuleAuthors->AuthorName = Strings[Index];
|
||||
RtlInsertTailList(&ModuleInfo->Authors, &ModuleAuthors->Flink);
|
||||
}
|
||||
else if(RtlCompareWideString(Key, L"description", 11) == 0)
|
||||
{
|
||||
/* Store module's description */
|
||||
ModuleInfo->ModuleDescription = Strings[Index];
|
||||
}
|
||||
else if(RtlCompareWideString(Key, L"license", 7) == 0)
|
||||
{
|
||||
/* Store module's license */
|
||||
ModuleInfo->License = Strings[Index];
|
||||
}
|
||||
else if(RtlCompareWideString(Key, L"softdeps", 6) == 0)
|
||||
{
|
||||
/* Tokenize value to get module's single dependency */
|
||||
Dependency = RtlTokenizeWideString(Strings[Index], L" ", &LastStr);
|
||||
while(Dependency != NULLPTR)
|
||||
{
|
||||
/* Allocate memory for module dependency */
|
||||
Status = BlAllocateMemoryPool(sizeof(XTBL_MODULE_DEPS), (PVOID*)&ModuleDependencies);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Memory allocation failure */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Store module's dependency */
|
||||
ModuleDependencies->ModuleName = Dependency;
|
||||
RtlInsertTailList(&ModuleInfo->Dependencies, &ModuleDependencies->Flink);
|
||||
|
||||
/* Get next dependency from single value if available */
|
||||
Dependency = RtlTokenizeWideString(NULLPTR, L" ", &LastStr);
|
||||
}
|
||||
}
|
||||
else if(RtlCompareWideString(Key, L"version", 7) == 0)
|
||||
{
|
||||
/* Store module's version */
|
||||
ModuleInfo->Version = Strings[Index];
|
||||
}
|
||||
}
|
||||
|
||||
/* Return success */
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads raw data from the '.modinfo' section and populates an array of strings.
|
||||
*
|
||||
* @param SectionData
|
||||
* Supplies a pointer to the module's information section data.
|
||||
*
|
||||
* @param SectionSize
|
||||
* Supplies an expected size of the section data.
|
||||
*
|
||||
* @param ModInfo
|
||||
* Supplies a pointer to memory area, where an array of strings read from the section will be stored.
|
||||
*
|
||||
* @param InfoCount
|
||||
* Supplies a pointer to variable that will receive the number of strings found in the section.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlpGetModuleInfoStrings(IN PWCHAR SectionData,
|
||||
IN ULONG SectionSize,
|
||||
OUT PWCHAR **ModInfo,
|
||||
OUT PULONG InfoCount)
|
||||
{
|
||||
ULONG Count, Index, ArrayIndex;
|
||||
PCWSTR InfoStrings;
|
||||
EFI_STATUS Status;
|
||||
PWCHAR *Array;
|
||||
PWCHAR String;
|
||||
ULONG DataSize;
|
||||
|
||||
/* Check input parameters */
|
||||
InfoStrings = SectionData;
|
||||
if(!InfoStrings || !SectionSize)
|
||||
{
|
||||
/* Invalid input parameters */
|
||||
*ModInfo = NULLPTR;
|
||||
*InfoCount = 0;
|
||||
return STATUS_EFI_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Calculate the size of the data based on the size of the section */
|
||||
DataSize = SectionSize / sizeof(WCHAR);
|
||||
|
||||
/* Skip zero padding at the beginning */
|
||||
while(DataSize > 0 && *InfoStrings == L'\0')
|
||||
{
|
||||
InfoStrings++;
|
||||
DataSize--;
|
||||
}
|
||||
|
||||
/* Make sure there is at least one string available */
|
||||
if(DataSize < 1)
|
||||
{
|
||||
/* No strings found */
|
||||
*ModInfo = NULLPTR;
|
||||
*InfoCount = 0;
|
||||
return STATUS_EFI_END_OF_FILE;
|
||||
}
|
||||
|
||||
/* Count number of strings */
|
||||
Index = 0;
|
||||
Count = 0;
|
||||
while(Index < DataSize)
|
||||
{
|
||||
/* Found start of a new string */
|
||||
Count++;
|
||||
|
||||
/* Go to the end of the string */
|
||||
while(Index < DataSize && InfoStrings[Index] != L'\0')
|
||||
{
|
||||
Index++;
|
||||
}
|
||||
/* Skip all NULL terminators */
|
||||
while(Index < DataSize && InfoStrings[Index] == L'\0')
|
||||
{
|
||||
Index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate memory for the pointer array and the string data */
|
||||
Status = BlAllocateMemoryPool(sizeof(PWCHAR) * (Count + 1) + (DataSize + 1) * sizeof(WCHAR), (PVOID *)&Array);
|
||||
if(Status != STATUS_EFI_SUCCESS)
|
||||
{
|
||||
/* Failed to allocate memory */
|
||||
return STATUS_EFI_OUT_OF_RESOURCES;
|
||||
}
|
||||
|
||||
/* The string buffer is located right after the pointer array */
|
||||
String = (PWCHAR)(Array + Count + 1);
|
||||
|
||||
/* Copy the raw string data */
|
||||
RtlCopyMemory(String, InfoStrings, DataSize * sizeof(WCHAR));
|
||||
|
||||
/* Ensure the entire buffer is NULL-terminated for safety */
|
||||
String[DataSize] = L'\0';
|
||||
|
||||
/* Set the last element of the pointer array to NULLPTR */
|
||||
Array[Count] = NULLPTR;
|
||||
|
||||
/* Populate the array with pointers to the strings within the buffer */
|
||||
Index = 0;
|
||||
ArrayIndex = 0;
|
||||
while(Index < DataSize && ArrayIndex < Count)
|
||||
{
|
||||
/* Set pointer to the beginning of the string */
|
||||
Array[ArrayIndex++] = &String[Index];
|
||||
|
||||
/* Find the end of the current string */
|
||||
while(Index < DataSize && String[Index] != L'\0')
|
||||
{
|
||||
Index++;
|
||||
}
|
||||
|
||||
/* Skip all NULL terminators to find the beginning of the next string */
|
||||
while(Index < DataSize && String[Index] == L'\0')
|
||||
{
|
||||
Index++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return array of strings and its size */
|
||||
*ModInfo = Array;
|
||||
*InfoCount = Count;
|
||||
|
||||
/* Return success */
|
||||
return STATUS_EFI_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine installs XTLDR protocol for further usage by modules.
|
||||
*
|
||||
* @return This routine returns a status code.
|
||||
*
|
||||
* @since XT 1.0
|
||||
*/
|
||||
XTCDECL
|
||||
EFI_STATUS
|
||||
BlpInstallXtLoaderProtocol()
|
||||
{
|
||||
EFI_GUID Guid = XT_BOOT_LOADER_PROTOCOL_GUID;
|
||||
|
||||
/* Set all routines available via loader protocol */
|
||||
BlpLdrProtocol.Boot.FindProtocol = BlFindBootProtocol;
|
||||
BlpLdrProtocol.Boot.InitializeMenuList = BlInitializeBootMenuList;
|
||||
BlpLdrProtocol.Boot.InvokeProtocol = BlInvokeBootProtocol;
|
||||
BlpLdrProtocol.Boot.RegisterMenu = BlRegisterBootMenu;
|
||||
BlpLdrProtocol.Boot.RegisterProtocol = BlRegisterBootProtocol;
|
||||
BlpLdrProtocol.BootUtil.GetBooleanParameter = BlGetBooleanParameter;
|
||||
BlpLdrProtocol.Config.GetBooleanValue = BlGetConfigBooleanValue;
|
||||
BlpLdrProtocol.Config.GetBootOptionValue = BlGetBootOptionValue;
|
||||
BlpLdrProtocol.Config.GetEditableOptions = BlGetEditableOptions;
|
||||
BlpLdrProtocol.Config.GetValue = BlGetConfigValue;
|
||||
BlpLdrProtocol.Config.SetBootOptionValue = BlSetBootOptionValue;
|
||||
BlpLdrProtocol.Console.ClearLine = BlClearConsoleLine;
|
||||
BlpLdrProtocol.Console.ClearScreen = BlClearConsoleScreen;
|
||||
BlpLdrProtocol.Console.DisableCursor = BlDisableConsoleCursor;
|
||||
BlpLdrProtocol.Console.EnableCursor = BlEnableConsoleCursor;
|
||||
BlpLdrProtocol.Console.Print = BlConsolePrint;
|
||||
BlpLdrProtocol.Console.QueryMode = BlQueryConsoleMode;
|
||||
BlpLdrProtocol.Console.ReadKeyStroke = BlReadKeyStroke;
|
||||
BlpLdrProtocol.Console.ResetInputBuffer = BlResetConsoleInputBuffer;
|
||||
BlpLdrProtocol.Console.SetAttributes = BlSetConsoleAttributes;
|
||||
BlpLdrProtocol.Console.SetCursorPosition = BlSetCursorPosition;
|
||||
BlpLdrProtocol.Console.Write = BlConsoleWrite;
|
||||
BlpLdrProtocol.Debug.Print = BlDebugPrint;
|
||||
BlpLdrProtocol.Disk.CloseVolume = BlCloseVolume;
|
||||
BlpLdrProtocol.Disk.OpenVolume = BlOpenVolume;
|
||||
BlpLdrProtocol.Disk.ReadFile = BlReadFile;
|
||||
BlpLdrProtocol.Memory.AllocatePages = BlAllocateMemoryPages;
|
||||
BlpLdrProtocol.Memory.AllocatePool = BlAllocateMemoryPool;
|
||||
BlpLdrProtocol.Memory.BuildPageMap = BlBuildPageMap;
|
||||
BlpLdrProtocol.Memory.CopyMemory = RtlCopyMemory;
|
||||
BlpLdrProtocol.Memory.FreePages = BlFreeMemoryPages;
|
||||
BlpLdrProtocol.Memory.FreePool = BlFreeMemoryPool;
|
||||
BlpLdrProtocol.Memory.GetMappingsCount = BlGetMappingsCount;
|
||||
BlpLdrProtocol.Memory.GetMemoryMap = BlGetMemoryMap;
|
||||
BlpLdrProtocol.Memory.GetVirtualAddress = BlGetVirtualAddress;
|
||||
BlpLdrProtocol.Memory.InitializePageMap = BlInitializePageMap;
|
||||
BlpLdrProtocol.Memory.MapEfiMemory = BlMapEfiMemory;
|
||||
BlpLdrProtocol.Memory.MapPage = BlMapPage;
|
||||
BlpLdrProtocol.Memory.MapVirtualMemory = BlMapVirtualMemory;
|
||||
BlpLdrProtocol.Memory.PhysicalAddressToVirtual = BlPhysicalAddressToVirtual;
|
||||
BlpLdrProtocol.Memory.PhysicalListToVirtual = BlPhysicalListToVirtual;
|
||||
BlpLdrProtocol.Memory.SetMemory = RtlSetMemory;
|
||||
BlpLdrProtocol.Memory.ZeroMemory = RtlZeroMemory;
|
||||
BlpLdrProtocol.Protocol.Close = BlCloseProtocol;
|
||||
BlpLdrProtocol.Protocol.GetModulesList = BlGetModulesList;
|
||||
BlpLdrProtocol.Protocol.Install = BlInstallProtocol;
|
||||
BlpLdrProtocol.Protocol.LocateHandles = BlLocateProtocolHandles;
|
||||
BlpLdrProtocol.Protocol.Open = BlOpenProtocol;
|
||||
BlpLdrProtocol.Protocol.OpenHandle = BlOpenProtocolHandle;
|
||||
BlpLdrProtocol.Tui.DisplayErrorDialog = BlDisplayErrorDialog;
|
||||
BlpLdrProtocol.Tui.DisplayInfoDialog = BlDisplayInfoDialog;
|
||||
BlpLdrProtocol.Tui.DisplayInputDialog = BlDisplayInputDialog;
|
||||
BlpLdrProtocol.Tui.DisplayProgressDialog = BlDisplayProgressDialog;
|
||||
BlpLdrProtocol.Tui.UpdateProgressBar = BlUpdateProgressBar;
|
||||
BlpLdrProtocol.Util.EnterFirmwareSetup = BlEnterFirmwareSetup;
|
||||
BlpLdrProtocol.Util.ExitBootServices = BlExitBootServices;
|
||||
BlpLdrProtocol.Util.GetConfigurationTable = BlGetConfigurationTable;
|
||||
BlpLdrProtocol.Util.GetEfiVariable = BlGetEfiVariable;
|
||||
BlpLdrProtocol.Util.GetRandomValue = BlGetRandomValue;
|
||||
BlpLdrProtocol.Util.GetSecureBootStatus = BlGetSecureBootStatus;
|
||||
BlpLdrProtocol.Util.InitializeEntropy = BlInitializeEntropy;
|
||||
BlpLdrProtocol.Util.LoadEfiImage = BlLoadEfiImage;
|
||||
BlpLdrProtocol.Util.RebootSystem = BlRebootSystem;
|
||||
BlpLdrProtocol.Util.SetEfiVariable = BlSetEfiVariable;
|
||||
BlpLdrProtocol.Util.ShutdownSystem = BlShutdownSystem;
|
||||
BlpLdrProtocol.Util.SleepExecution = BlSleepExecution;
|
||||
BlpLdrProtocol.Util.StartEfiImage = BlStartEfiImage;
|
||||
BlpLdrProtocol.Util.WaitForEfiEvent = BlWaitForEfiEvent;
|
||||
|
||||
/* Register XTLDR loader protocol */
|
||||
BlDebugPrint(L"Registering XT loader protocol\n");
|
||||
return BlInstallProtocol(&BlpLdrProtocol, &Guid);
|
||||
}
|
Reference in New Issue
Block a user