From ea32946bbd23f18eda9d0948673ea6c2f42ef303 Mon Sep 17 00:00:00 2001 From: Rafal Kupiec Date: Sat, 30 Dec 2023 00:57:01 +0100 Subject: [PATCH] Initial modules support --- sdk/xtdk/bltypes.h | 9 + xtldr2/CMakeLists.txt | 3 + xtldr2/efiutils.c | 3 +- xtldr2/globals.c | 3 + xtldr2/includes/globals.h | 3 + xtldr2/modules/CMakeLists.txt | 2 + xtldr2/modules/dummy/CMakeLists.txt | 26 +++ xtldr2/modules/dummy/dummy.c | 36 ++++ xtldr2/modules/dummy2/CMakeLists.txt | 26 +++ xtldr2/modules/dummy2/dummy2.c | 34 +++ xtldr2/textui.c | 25 ++- xtldr2/xtldr.c | 303 +++++++++++++++++++++++++++ 12 files changed, 468 insertions(+), 5 deletions(-) create mode 100644 xtldr2/modules/CMakeLists.txt create mode 100644 xtldr2/modules/dummy/CMakeLists.txt create mode 100644 xtldr2/modules/dummy/dummy.c create mode 100644 xtldr2/modules/dummy2/CMakeLists.txt create mode 100644 xtldr2/modules/dummy2/dummy2.c diff --git a/sdk/xtdk/bltypes.h b/sdk/xtdk/bltypes.h index 3452655..f42ffc9 100644 --- a/sdk/xtdk/bltypes.h +++ b/sdk/xtdk/bltypes.h @@ -168,6 +168,15 @@ typedef struct _XTBL_LOADER_PROTOCOL } Util; } XTBL_LOADER_PROTOCOL, *PXTBL_LOADER_PROTOCOL; +/* XTLDR Module information data */ +typedef struct _XTBL_MODULE_INFO +{ + LIST_ENTRY Flink; + PWCHAR ModuleName; + PWCHAR ModuleDescription; + WCHAR Dependencies[1024]; +} XTBL_MODULE_INFO, *PXTBL_MODULE_INFO; + /* XTLDR Status data */ typedef struct _XTBL_STATUS { diff --git a/xtldr2/CMakeLists.txt b/xtldr2/CMakeLists.txt index e6a8237..2527989 100644 --- a/xtldr2/CMakeLists.txt +++ b/xtldr2/CMakeLists.txt @@ -1,6 +1,9 @@ # XT Boot Manager PROJECT(XTLDR) +# Build XTLDR modules +add_subdirectory(modules) + # Specify include directories include_directories( ${EXECTOS_SOURCE_DIR}/sdk/xtdk diff --git a/xtldr2/efiutils.c b/xtldr2/efiutils.c index 411cdcb..4b3733c 100644 --- a/xtldr2/efiutils.c +++ b/xtldr2/efiutils.c @@ -143,8 +143,9 @@ BlpInitializeEfiBootLoader() /* Print XTLDR version */ BlConsolePrint(L"XTLDR boot loader v%s\n", XTOS_VERSION); - /* Initialize XTLDR configuration list */ + /* Initialize XTLDR configuration and loaded modules lists */ RtlInitializeListHead(&BlpConfig); + RtlInitializeListHead(&BlpLoadedModules); /* Check if debug is enabled */ if(DEBUG) diff --git a/xtldr2/globals.c b/xtldr2/globals.c index 4b2a3b9..431c828 100644 --- a/xtldr2/globals.c +++ b/xtldr2/globals.c @@ -18,6 +18,9 @@ LIST_ENTRY BlpConfigSections; /* XT Boot Loader hex table */ STATIC PUINT16 BlpHexTable = L"0123456789ABCDEF"; +/* XT Boot Loader loaded modules list */ +LIST_ENTRY BlpLoadedModules; + /* XT Boot Loader menu list */ PLIST_ENTRY BlpMenuList = NULL; diff --git a/xtldr2/includes/globals.h b/xtldr2/includes/globals.h index dcdc804..5fe9363 100644 --- a/xtldr2/includes/globals.h +++ b/xtldr2/includes/globals.h @@ -21,6 +21,9 @@ EXTERN LIST_ENTRY BlpConfigSections; /* XT Boot Loader hex table */ EXTERN PUINT16 BlpHexTable; +/* XT Boot Loader loaded modules list */ +EXTERN LIST_ENTRY BlpLoadedModules; + /* XT Boot Loader menu list */ EXTERN PLIST_ENTRY BlpMenuList; diff --git a/xtldr2/modules/CMakeLists.txt b/xtldr2/modules/CMakeLists.txt new file mode 100644 index 0000000..5a3e917 --- /dev/null +++ b/xtldr2/modules/CMakeLists.txt @@ -0,0 +1,2 @@ +add_subdirectory(dummy) +add_subdirectory(dummy2) diff --git a/xtldr2/modules/dummy/CMakeLists.txt b/xtldr2/modules/dummy/CMakeLists.txt new file mode 100644 index 0000000..2108502 --- /dev/null +++ b/xtldr2/modules/dummy/CMakeLists.txt @@ -0,0 +1,26 @@ +# XT Boot Loader +PROJECT(XTLDR_DUMMY) + +# Specify include directories +include_directories( + ${EXECTOS_SOURCE_DIR}/sdk/xtdk + ${XTLDR_SOURCE_DIR}/includes + ${XTLDR_DUMMY_SOURCE_DIR}/includes) + +# Specify list of source code files +list(APPEND XTLDR_DUMMY_SOURCE + ${XTLDR_DUMMY_SOURCE_DIR}/dummy.c) + +# Link bootloader executable +add_executable(dummy ${XTLDR_DUMMY_SOURCE}) + +# Add linker libraries +target_link_libraries(dummy libxtldr libxtos) + +# Set proper binary name and install target +set_target_properties(dummy PROPERTIES SUFFIX .efi) +set_install_target(dummy efi/boot/xtldr/modules) + +# Set module entrypoint and subsystem +set_entrypoint(dummy "XtLdrModuleMain") +set_subsystem(dummy efi_boot_service_driver) diff --git a/xtldr2/modules/dummy/dummy.c b/xtldr2/modules/dummy/dummy.c new file mode 100644 index 0000000..0a78fde --- /dev/null +++ b/xtldr2/modules/dummy/dummy.c @@ -0,0 +1,36 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/dummy/dummy.c + * DESCRIPTION: Dummy XTLDR module + * DEVELOPERS: Rafal Kupiec + */ + +#include + +#define XTBL_MODDEP SEGMENT(".moddeps") CONST WCHAR XtBlpDeps[][8] +#define XTBL_MODINFO SEGMENT(".modinfo") CONST WCHAR XtBlpInfo[] + +XTBL_MODDEP = {L"dummy2", L"dummy2"}; +XTBL_MODINFO = L"Dummy XTLDR module"; + +/** + * This routine is the entry point of the XT EFI boot loader module. + * + * @param ImageHandle + * Firmware-allocated handle that identifies the image. + * + * @param SystemTable + * Provides the EFI system table. + * + * @return This routine returns status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtLdrModuleMain(IN EFI_HANDLE ImageHandle, + IN PEFI_SYSTEM_TABLE SystemTable) +{ + return STATUS_EFI_SUCCESS; +} diff --git a/xtldr2/modules/dummy2/CMakeLists.txt b/xtldr2/modules/dummy2/CMakeLists.txt new file mode 100644 index 0000000..b4e0328 --- /dev/null +++ b/xtldr2/modules/dummy2/CMakeLists.txt @@ -0,0 +1,26 @@ +# XT Boot Loader +PROJECT(XTLDR_DUMMY2) + +# Specify include directories +include_directories( + ${EXECTOS_SOURCE_DIR}/sdk/xtdk + ${XTLDR_SOURCE_DIR}/includes + ${XTLDR_DUMMY2_SOURCE_DIR}/includes) + +# Specify list of source code files +list(APPEND XTLDR_DUMMY2_SOURCE + ${XTLDR_DUMMY2_SOURCE_DIR}/dummy2.c) + +# Link bootloader executable +add_executable(dummy2 ${XTLDR_DUMMY2_SOURCE}) + +# Add linker libraries +target_link_libraries(dummy2 libxtldr libxtos) + +# Set proper binary name and install target +set_target_properties(dummy2 PROPERTIES SUFFIX .efi) +set_install_target(dummy2 efi/boot/xtldr/modules) + +# Set module entrypoint and subsystem +set_entrypoint(dummy2 "XtLdrModuleMain") +set_subsystem(dummy2 efi_boot_service_driver) diff --git a/xtldr2/modules/dummy2/dummy2.c b/xtldr2/modules/dummy2/dummy2.c new file mode 100644 index 0000000..f9a184a --- /dev/null +++ b/xtldr2/modules/dummy2/dummy2.c @@ -0,0 +1,34 @@ +/** + * PROJECT: ExectOS + * COPYRIGHT: See COPYING.md in the top level directory + * FILE: xtldr/modules/dummy/dummy.c + * DESCRIPTION: Dummy XTLDR module + * DEVELOPERS: Rafal Kupiec + */ + +#include + +#define XTBL_MODDEP SEGMENT(".moddeps") CONST WCHAR XtBlpDeps[][8] + +//XTBL_MODDEP = {L""}; + +/** + * This routine is the entry point of the XT EFI boot loader module. + * + * @param ImageHandle + * Firmware-allocated handle that identifies the image. + * + * @param SystemTable + * Provides the EFI system table. + * + * @return This routine returns status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +XtLdrModuleMain(IN EFI_HANDLE ImageHandle, + IN PEFI_SYSTEM_TABLE SystemTable) +{ + return STATUS_EFI_SUCCESS; +} diff --git a/xtldr2/textui.c b/xtldr2/textui.c index 51dfd1a..01fb4a1 100644 --- a/xtldr2/textui.c +++ b/xtldr2/textui.c @@ -963,6 +963,9 @@ BlDisplayInputDialog(IN PWCHAR Caption, +XTCDECL +EFI_STATUS +BlInvokeBootProtocol(IN PLIST_ENTRY Options); @@ -1075,10 +1078,17 @@ BlDisplayBootMenu() BlSetConsoleAttributes(Handle.DialogColor | Handle.TextColor); BlClearConsoleLine(Handle.PosY + Handle.Height + 4); BlSetCursorPosition(4, Handle.PosY + Handle.Height + 4); - BlConsolePrint(L"Booting '%S' now...", MenuEntries[HighligtedEntryId].EntryName); + BlConsolePrint(L"Booting '%S' now...\n", MenuEntries[HighligtedEntryId].EntryName); /* Boot the highlighted (chosen) OS */ - BlDisplayInfoDialog(L"XTLDR", L"Booting highlighted OS ..."); + Status = BlInvokeBootProtocol(MenuEntries[HighligtedEntryId].Options); + if(Status != STATUS_SUCCESS) + { + /* Failed to boot OS */ + BlDebugPrint(L"Failed to boot OS '%S' with status code: 0x%lx!\n", + MenuEntries[HighligtedEntryId].EntryName, Status); + BlDisplayErrorDialog(L"XTLDR", L"Failed to startup the selected Operating System."); + } /* Break from boot menu event loop to redraw whole boot menu */ break; @@ -1178,13 +1188,20 @@ BlDisplayBootMenu() BlSetConsoleAttributes(Handle.DialogColor | Handle.TextColor); BlClearConsoleLine(Handle.PosY + Handle.Height + 4); BlSetCursorPosition(4, Handle.PosY + Handle.Height + 4); - BlConsolePrint(L"Booting '%S' now...", MenuEntries[HighligtedEntryId].EntryName); + BlConsolePrint(L"Booting '%S' now...\n", MenuEntries[HighligtedEntryId].EntryName); /* Disable the timer just in case booting OS fails */ TimeOut = -1; /* Boot the highlighted (default) OS */ - BlDisplayInfoDialog(L"XTLDR", L"Booting highlighted OS ..."); + Status = BlInvokeBootProtocol(MenuEntries[HighligtedEntryId].Options); + if(Status != STATUS_SUCCESS) + { + /* Failed to boot OS */ + BlDebugPrint(L"Failed to boot OS '%S' with status code: 0x%lx!\n", + MenuEntries[HighligtedEntryId].EntryName, Status); + BlDisplayErrorDialog(L"XTLDR", L"Failed to startup the selected Operating System."); + } break; } } diff --git a/xtldr2/xtldr.c b/xtldr2/xtldr.c index 79e91af..dcc5109 100644 --- a/xtldr2/xtldr.c +++ b/xtldr2/xtldr.c @@ -9,6 +9,14 @@ #include +XTCDECL +EFI_STATUS +BlLoadModule(IN PWCHAR Module); + +XTCDECL +EFI_STATUS +BlLoadModules(IN PWCHAR ModulesList); + /** * Initializes a list of operating systems for XTLDR boot menu. * @@ -96,6 +104,266 @@ BlInitializeBootMenuList(OUT PXTBL_BOOTMENU_ITEM MenuEntries, MenuEntries = OsList; } +/** + * Loads all necessary modules and invokes boot protocol. + * + * @param OptionsList + * Supplies a pointer to list of options associated with chosen boot menu entry. + * + * @return This routine returns a status code. + * + * @since XT 1.0 + */ +XTCDECL +EFI_STATUS +BlInvokeBootProtocol(IN PLIST_ENTRY OptionsList) +{ + PWCHAR ModulesList, ProtocolName; + PLIST_ENTRY OptionsListEntry; + PXTBL_CONFIG_ENTRY Option; + EFI_STATUS Status; + + /* Set default values */ + ModulesList = NULL; + ProtocolName = NULL; + + /* Iterate through all options provided by boot menu entry */ + OptionsListEntry = OptionsList->Flink; + while(OptionsListEntry != OptionsList) + { + /* Get option */ + Option = CONTAIN_RECORD(OptionsListEntry, XTBL_CONFIG_ENTRY, Flink); + + /* Look for boot protocol and modules list */ + if(RtlCompareWideStringInsensitive(Option->Name, L"SYSTEMTYPE", 0) == 0) + { + /* Boot protocol found */ + ProtocolName = Option->Value; + } + else if(RtlCompareWideStringInsensitive(Option->Name, L"BOOTMODULES", 0) == 0) + { + /* Set protocol name */ + ModulesList = Option->Value; + } + + /* Move to the next option entry */ + OptionsListEntry = OptionsListEntry->Flink; + } + + /* Load all necessary modules */ + Status = BlLoadModules(ModulesList); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to load modules, print error message and return status code */ + BlDebugPrint(L"Failed to load XTLDR modules\n"); + return Status; + } + for(;;); + + /* This point should never be reached */ + return STATUS_EFI_SUCCESS; +} + +XTCDECL +EFI_STATUS +BlLoadModules(IN PWCHAR ModulesList) +{ + PWCHAR LastModule, Module; + EFI_STATUS Status; + + if(ModulesList != NULL) + { + /* Tokenize provided list of modules */ + Module = RtlTokenizeWideString(ModulesList, L" ", &LastModule); + + /* Iterate over all arguments passed to boot loader */ + while(Module != NULL) + { + Status = BlLoadModule(Module); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to load module, print error message and return status code */ + BlDebugPrint(L"Failed to load module '%S', status = 0x%lx\n", Module, Status); + // return Status; + } + + /* Take next module from the list */ + Module = RtlTokenizeWideString(NULL, L" ", &LastModule); + } + } + + /* Return success */ + return STATUS_EFI_SUCCESS; +} + +XTCDECL +EFI_STATUS +BlLoadModule(IN PWCHAR ModuleName) +{ + EFI_MEMMAP_DEVICE_PATH ModuleDevicePath[2]; + PEFI_FILE_HANDLE DirHandle, FsHandle; + EFI_HANDLE DiskHandle, ModuleHandle; + PPECOFF_IMAGE_SECTION_HEADER SectionHeader; + PPECOFF_IMAGE_DOS_HEADER DosHeader; + PPECOFF_IMAGE_PE_HEADER PeHeader; + PLIST_ENTRY ModuleListEntry; + WCHAR ModuleFileName[1024]; + USHORT SectionIndex; + SIZE_T ModuleSize; + EFI_STATUS Status; + PVOID ModuleData; + PWCHAR DepsData; + PXTBL_MODULE_INFO ModuleInfo; + + 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"Module '%S' already loaded\n", ModuleName); + return STATUS_EFI_SUCCESS; + } + + /* Move to the module */ + ModuleListEntry = ModuleListEntry->Flink; + } + + /* Print debug message */ + BlDebugPrint(L"Loading module '%S' ...\n", ModuleName); + + /* Set module path */ + RtlCopyMemory(ModuleFileName, ModuleName, sizeof(ModuleFileName) / sizeof(WCHAR)); + RtlConcatenateWideString(ModuleFileName, L".EFI", 0); + + /* Open EFI volume */ + Status = BlOpenVolume(NULL, &DiskHandle, &FsHandle); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to open a volume */ + return Status; + } + + /* Open XTLDR modules directory and close the FS immediately */ + Status = FsHandle->Open(FsHandle, &DirHandle, XTBL_MODULES_DIRECTORY_PATH, EFI_FILE_MODE_READ, 0); + FsHandle->Close(FsHandle); + + /* Check if directory opened successfully */ + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to open directory */ + BlCloseVolume(DiskHandle); + return Status; + } + + /* Read module file from disk and close EFI volume */ + Status = BlReadFile(DirHandle, ModuleFileName, &ModuleData, &ModuleSize); + BlCloseVolume(DiskHandle); + + /* Make sure module file was read successfully */ + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to read file */ + return Status; + } + + /* Allocate memory for new option */ + Status = BlMemoryAllocatePool(sizeof(XTBL_MODULE_INFO), (PVOID*)&ModuleInfo); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to allocate memory */ + return Status; + } + + RtlZeroMemory(ModuleInfo, sizeof(XTBL_MODULE_INFO)); + + /* Setup PE/COFF EFI image headers */ + DosHeader = (PPECOFF_IMAGE_DOS_HEADER)ModuleData; + PeHeader = (PPECOFF_IMAGE_PE_HEADER)(ModuleData + DosHeader->e_lfanew); + SectionHeader = (PPECOFF_IMAGE_SECTION_HEADER)((PUCHAR)&PeHeader->OptionalHeader + + PeHeader->FileHeader.SizeOfOptionalHeader); + + /* Look for .moddeps section */ + for(SectionIndex = 0; SectionIndex < PeHeader->FileHeader.NumberOfSections; SectionIndex++) + { + /* Check section name */ + if(RtlCompareString((PCHAR)SectionHeader[SectionIndex].Name, ".moddeps", 8) == 0) + { + /* Store address of .moddeps data segment */ + DepsData = ModuleData + SectionHeader[SectionIndex].PointerToRawData; + + /* Iterate over all dependencies stored */ + while(*DepsData != 0) + { + /* Load dependency module */ + BlDebugPrint(L"Module '%S' requires '%S' ...\n", ModuleName, DepsData); + Status = BlLoadModule(DepsData); + + 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 = 0x%lx\n", DepsData, Status); + return STATUS_EFI_UNSUPPORTED; + } + + /* Add dependency module name to the list */ + RtlConcatenateWideString(ModuleInfo->Dependencies, DepsData, RtlWideStringLength(DepsData, 0)); + RtlConcatenateWideString(ModuleInfo->Dependencies, L" ", 1); + + /* Get next dependency module name */ + DepsData += 8; + } + } + else if(RtlCompareString((PCHAR)SectionHeader[SectionIndex].Name, ".modinfo", 8) == 0) + { + /* Store module description */ + ModuleInfo->ModuleDescription = ModuleData + SectionHeader[SectionIndex].PointerToRawData; + } + } + + /* Store module name */ + ModuleInfo->ModuleName = ModuleName; + + /* 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 */ + Status = EfiSystemTable->BootServices->LoadImage(FALSE, EfiImageHandle, (PEFI_DEVICE_PATH_PROTOCOL)ModuleDevicePath, + ModuleData, ModuleSize, &ModuleHandle); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to load module image */ + return Status; + } + + /* Start EFI image */ + Status = EfiSystemTable->BootServices->StartImage(ModuleHandle, NULL, NULL); + if(Status != STATUS_EFI_SUCCESS) + { + /* Failed to start module image */ + return Status; + } + + /* Add module to the list of loaded modules */ + RtlInsertTailList(&BlpLoadedModules, &ModuleInfo->Flink); + + /* Return success */ + return STATUS_EFI_SUCCESS; +} + /** * This routine is the entry point of the XT EFI boot loader. * @@ -187,6 +455,41 @@ BlStartXtLoader(IN EFI_HANDLE ImageHandle, return Status; } + BlLoadModules(BlGetConfigValue(L"MODULES")); + + BlLoadModule(L"DUMMY"); + + + BlConsolePrint(L"\n\n\n\n\n\n\n\nList of loaded modules:"); + PLIST_ENTRY ModuleListEntry; + PXTBL_MODULE_INFO ModuleInfo; + + ModuleListEntry = BlpLoadedModules.Flink; + while(ModuleListEntry != &BlpLoadedModules) + { + /* Get module information */ + ModuleInfo = CONTAIN_RECORD(ModuleListEntry, XTBL_MODULE_INFO, Flink); + + /* Module already loaded */ + BlConsolePrint(L"\n%.8S", ModuleInfo->ModuleName); + if(ModuleInfo->ModuleDescription != 0) + { + BlConsolePrint(L" (%S)", ModuleInfo->ModuleDescription); + } + + if(ModuleInfo->Dependencies[0] != 0) + { + BlConsolePrint(L"\n - Uses: %S", ModuleInfo->Dependencies); + } + + /* Move to the module */ + ModuleListEntry = ModuleListEntry->Flink; + } + + BlConsolePrint(L"\n\n END OF LIST\n"); + + for(;;); + for(;;) { if(BlpStatus.BootMenu != NULL)