/** * PROJECT: ExectOS * COPYRIGHT: See COPYING.md in the top level directory * FILE: xtldr/xtldr.c * DESCRIPTION: XTOS UEFI Boot Loader * DEVELOPERS: Rafal Kupiec */ #include /** * Initializes a list of operating systems for XTLDR boot menu. * * @param MenuEntries * Supplies a pointer to memory area where operating systems list will be stored. * * @param EntriesCount * Supplies a pointer to memory area where number of menu entries will be stored. * * @param DefaultId * Supplies a pointer to memory area where ID of default menu entry will be stored. * * @return This routine does not return any value. * * @since XT 1.0 */ XTCDECL VOID BlInitializeBootMenuList(OUT PXTBL_BOOTMENU_ITEM MenuEntries, OUT PULONG EntriesCount, OUT PULONG DefaultId) { PWCHAR DefaultMenuEntry, MenuEntryName; PLIST_ENTRY MenuEntrySectionList, MenuEntryList; PXTBL_CONFIG_SECTION MenuEntrySection; PXTBL_CONFIG_ENTRY MenuEntryOption; PXTBL_BOOTMENU_ITEM OsList; ULONG DefaultOS, NumberOfEntries; /* Set default values */ DefaultOS = 0; NumberOfEntries = 0; OsList = NULL; /* Get default menu entry from configuration */ DefaultMenuEntry = BlGetConfigValue(L"DEFAULT"); /* Iterate through all menu sections */ MenuEntrySectionList = BlpMenuList->Flink; while(MenuEntrySectionList != BlpMenuList) { /* NULLify menu entry name */ MenuEntryName = NULL; /* Get menu section */ MenuEntrySection = CONTAIN_RECORD(MenuEntrySectionList, XTBL_CONFIG_SECTION, Flink); /* Check if this is the default menu entry */ if(RtlCompareWideStringInsensitive(MenuEntrySection->SectionName, DefaultMenuEntry, 0) == 0) { /* Set default OS ID */ DefaultOS = NumberOfEntries; } /* Iterate through all entry parameters */ MenuEntryList = MenuEntrySection->Options.Flink; while(MenuEntryList != &MenuEntrySection->Options) { /* Get menu entry parameter */ MenuEntryOption = CONTAIN_RECORD(MenuEntryList, XTBL_CONFIG_ENTRY, Flink); /* Check if this is the menu entry display name */ if(RtlCompareWideStringInsensitive(MenuEntryOption->Name, L"SYSTEMNAME", 0) == 0) { /* Set menu entry display name */ MenuEntryName = MenuEntryOption->Value; } /* Get next parameter for this menu entry */ MenuEntryList = MenuEntryList->Flink; } /* Add OS to the boot menu list */ OsList[NumberOfEntries].EntryName = MenuEntryName; OsList[NumberOfEntries].Options = &MenuEntrySection->Options; /* Get next menu entry */ MenuEntrySectionList = MenuEntrySectionList->Flink; NumberOfEntries++; } /* Set return values */ *DefaultId = DefaultOS; *EntriesCount = NumberOfEntries; 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; SIZE_T ModuleListLength; EFI_STATUS Status; /* Set default values */ 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) { /* Check a length of modules list */ ModuleListLength = RtlWideStringLength(Option->Value, 0); Status = BlMemoryAllocatePool(sizeof(PWCHAR) * ModuleListLength, (PVOID *)&ModulesList); if(Status != STATUS_EFI_SUCCESS) { /* Failed to allocate memory, print error message and return status code */ BlDebugPrint(L"ERROR: Memory allocation failure (Status Code: 0x%lx)\n"); return STATUS_EFI_OUT_OF_RESOURCES; } /* Make a copy of modules list */ RtlCopyMemory(ModulesList, Option->Value, sizeof(PWCHAR) * ModuleListLength); } /* 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"ERROR: Failed to load XTLDR modules\n"); return STATUS_EFI_NOT_READY; } // TODO: Add support for boot protocol and invoke it for(;;); /* This point should never be reached */ return STATUS_EFI_SUCCESS; } /** * This routine is the entry point of the XT EFI boot loader. * * @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 BlStartXtLoader(IN EFI_HANDLE ImageHandle, IN PEFI_SYSTEM_TABLE SystemTable) { EFI_STATUS Status; /* Set the system table and image handle */ EfiImageHandle = ImageHandle; EfiSystemTable = SystemTable; /* Initialize XTLDR and */ BlpInitializeEfiBootLoader(); /* Parse configuration options passed from UEFI shell */ Status = BlpParseCommandLine(); if(Status != STATUS_EFI_SUCCESS) { /* Failed to parse command line options */ BlDisplayErrorDialog(L"XTLDR", L"Failed to parse command line parameters."); } /* Attempt to early initialize debug console */ if(DEBUG) { Status = BlpInitializeDebugConsole(); if(Status != STATUS_EFI_SUCCESS) { /* Initialization failed, notify user on stdout */ BlDisplayErrorDialog(L"XTLDR", L"Failed to initialize debug console."); } } /* Load XTLDR configuration file */ Status = BlpLoadConfiguration(); if(Status != STATUS_EFI_SUCCESS) { /* Failed to load/parse config file */ BlDisplayErrorDialog(L"XTLDR", L"Failed to load and parse configuration file."); } /* Reinitialize debug console if it was not initialized earlier */ if(DEBUG) { Status = BlpInitializeDebugConsole(); if(Status != STATUS_EFI_SUCCESS) { /* Initialization failed, notify user on stdout */ BlDisplayErrorDialog(L"XTLDR", L"Failed to initialize debug console."); } } /* Disable watchdog timer */ Status = EfiSystemTable->BootServices->SetWatchdogTimer(0, 0x10000, 0, NULL); if(Status != STATUS_EFI_SUCCESS) { /* Failed to disable the timer, print message */ BlDebugPrint(L"WARNING: Failed to disable watchdog timer\n"); } /* Register loader protocol */ Status = BlpRegisterXtLoaderProtocol(); if(Status != STATUS_EFI_SUCCESS) { /* Failed to register loader protocol */ BlDebugPrint(L"ERROR: Failed to register XTLDR boot protocol\n"); return Status; } /* Discover and enumerate EFI block devices */ Status = BlEnumerateBlockDevices(); if(Status != STATUS_EFI_SUCCESS) { /* Failed to enumerate block devices */ BlDebugPrint(L"ERROR: Failed to discover and enumerate block devices\n"); 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%S", ModuleInfo->ModuleName); if(ModuleInfo->ModuleDescription != 0) { BlConsolePrint(L" (%S)", ModuleInfo->ModuleDescription); } PLIST_ENTRY DepsListEntry; PXTBL_MODULE_DEPS DepsInfo; BlConsolePrint(L"\n - Uses: "); DepsListEntry = ModuleInfo->Dependencies.Flink; while(DepsListEntry != &ModuleInfo->Dependencies) { DepsInfo = CONTAIN_RECORD(DepsListEntry, XTBL_MODULE_DEPS, Flink); BlConsolePrint(L"%S ", DepsInfo->ModuleName); DepsListEntry = DepsListEntry->Flink; } /* Move to the module */ ModuleListEntry = ModuleListEntry->Flink; } BlConsolePrint(L"\n\n END OF LIST\n"); for(;;) { if(BlpStatus.BootMenu != NULL) { /* Display alternative boot menu */ BlpStatus.BootMenu(); } else { /* Display default boot menu */ BlDisplayBootMenu(); } } /* This point should be never reached, if this happen return error code */ return STATUS_EFI_LOAD_ERROR; }