/** * PROJECT: ExectOS * COPYRIGHT: See COPYING.md in the top level directory * FILE: xtldr/config.c * DESCRIPTION: XT Boot Loader Configuration * DEVELOPERS: Rafal Kupiec */ #include XTCDECL EFI_STATUS BlpLoadConfiguration() { EFI_STATUS Status; PLIST_ENTRY Configuration; PCHAR ConfigData; /* Initialize configuration pointer */ Configuration = NULL; /* Read data from configuration file */ Status = BlpReadConfigurationFile(L"\\EFI\\BOOT\\", L"XTLDR.INI", &ConfigData); if(Status != STATUS_EFI_SUCCESS) { /* Failed to load configuration */ BlDebugPrint(L"Failed to load configuration file (FS0:/EFI/BOOT/XTLDR.INI)\n"); return Status; } /* Parse configuration data */ Status = BlpParseConfigurationFile(ConfigData, Configuration); if(Status != STATUS_EFI_SUCCESS) { /* Failed to parse configuration */ BlDebugPrint(L"Failed to parse configuration file (FS0:/EFI/BOOT/XTLDR.INI)\n"); return Status; } /* Return success */ return STATUS_EFI_SUCCESS; } /** * Parses command line arguments and updates global configuration. * * @return This routine does not return any value. * * @since XT 1.0 */ XTCDECL VOID BlpParseCommandLine(VOID) { EFI_GUID LIPGuid = EFI_LOADED_IMAGE_PROTOCOL_GUID; PEFI_LOADED_IMAGE_PROTOCOL LoadedImage; EFI_STATUS Status; /* Handle loaded image protocol */ Status = EfiSystemTable->BootServices->HandleProtocol(EfiImageHandle, &LIPGuid, (PVOID *)&LoadedImage); if(Status == STATUS_EFI_SUCCESS) { /* Check if launched from UEFI shell */ if(LoadedImage && LoadedImage->LoadOptions) { /* Update global boot loader configuration */ BlpUpdateGlobalConfiguration(LoadedImage->LoadOptions); } } } XTCDECL EFI_STATUS BlpParseConfigurationFile(IN CONST PCHAR RawConfig, OUT PLIST_ENTRY Configuration) { SIZE_T SectionLength, KeyLength, ValueLength; PCHAR InputData, Key, SectionName, Value; PXTBL_INI_SECTION Section; PXTBL_INI_OPTION Option; EFI_STATUS Status; /* Initialize pointers */ InputData = RawConfig; Section = NULL; Option = NULL; SectionName = NULL; Key = NULL; Value = NULL; /* Analyze configuration data until end of file is reached */ while(*InputData != 0) { if(*InputData == ';' || *InputData == '#') { /* Skip comment until end of the line */ while(*InputData != 0 && *InputData != '\n') { /* Advance to the next character */ InputData++; } } else if(*InputData == ' ' || *InputData == '\t' || *InputData == '\r' || *InputData == '\n') { /* Skip whitespaces */ InputData++; } else if(*InputData == '[') { /* Skip leading bracket */ InputData++; /* Store section name */ SectionName = InputData; /* Find end of the section name */ while(*InputData != ']' && *InputData != 0 && *InputData != '\n') { /* Advance to the next character */ InputData++; } /* Check if end of the section name is reached */ if(*InputData != ']') { /* Section name does not end */ return STATUS_EFI_INVALID_PARAMETER; } /* Mark end of the section name and advance to the next character */ *InputData = 0; InputData++; /* Remove leading and trailing spaces from section name */ SectionName = RtlTrimString(SectionName); /* Find length of the section name */ SectionLength = RtlStringLength(SectionName, 0); /* Allocate memory for new section */ Status = BlMemoryAllocatePool(sizeof(XTBL_INI_SECTION), (PVOID*)&Section); if(Status == STATUS_EFI_SUCCESS) { /* Allocate more memory for section name */ Status = BlMemoryAllocatePool(sizeof(PWCHAR) * (SectionLength + 1), (PVOID*)&Section->SectionName); } if(Status != STATUS_EFI_SUCCESS) { /* Some memory allocation failed */ return Status; } /* Initialize new section and add it to the list */ RtlInitializeListHead(&Section->Options); RtlStringToWideString(Section->SectionName, &SectionName, SectionLength + 1); RtlInsertTailList(Configuration, &Section->Flink); } else { /* Store key */ Key = InputData; /* Find end of the key */ while(*InputData != '=' && *InputData != 0 && *InputData != '\n') { /* Advance to the next character */ InputData++; } /* Check if end of the key is reached */ if(*InputData != '=') { /* Key name does not end */ return STATUS_EFI_INVALID_PARAMETER; } /* Mark end of the key and advance to the next character */ *InputData = 0; InputData++; /* Skip all leading spaces in the value */ while(*InputData == ' ') { /* Advance to the next character */ InputData++; } /* Store value */ Value = InputData; /* Find end of the value */ while(*InputData != 0 && *InputData != '\n') { /* Advance to the next character */ InputData++; } /* Mark end of the value and advance to the next character */ *InputData = 0; InputData++; /* Remove leading and trailing spaces from key and value */ Key = RtlTrimString(Key); Value = RtlTrimString(Value); /* Find length of the key and its value */ KeyLength = RtlStringLength(Key, 0); ValueLength = RtlStringLength(Value, 0); /* Allocate memory for new option */ Status = BlMemoryAllocatePool(sizeof(XTBL_INI_OPTION), (PVOID*)&Option); if(Status == STATUS_EFI_SUCCESS) { /* Allocate more memory for option name */ Status = BlMemoryAllocatePool(sizeof(PWCHAR) * (KeyLength + 1), (PVOID*)&Option->Name); if(Status == STATUS_EFI_SUCCESS) { /* Allocate even more memory for option value */ Status = BlMemoryAllocatePool(sizeof(PWCHAR) * (ValueLength + 1), (PVOID*)&Option->Value); } } if(Status != STATUS_EFI_SUCCESS) { /* Some memory allocation failed */ return Status; } /* Initialize new option and add it to the list */ RtlStringToWideString(Option->Name, &Key, RtlStringLength(Key, 0) + 1); RtlStringToWideString(Option->Value, &Value, RtlStringLength(Value, 0) + 1); RtlInsertTailList(&Section->Options, &Option->Flink); } } /* Return success */ return STATUS_EFI_SUCCESS; } /** * Loads configuration file from the specified directory on the FS0:/ drive. * * @param ConfigDirectory * Specifies a path to the directory containing the configuration file. * * @param ConfigFile * Specifies the name of the configuration file. * * @param ConfigData * Provides a buffer to store the data read from the configuration file. * * @return This routine returns status code. * * @since XT 1.0 */ XTCDECL EFI_STATUS BlpReadConfigurationFile(IN CONST PWCHAR ConfigDirectory, IN CONST PWCHAR ConfigFile, OUT PCHAR *ConfigData) { PEFI_FILE_HANDLE DirHandle, FsHandle; EFI_HANDLE DiskHandle; EFI_STATUS Status; SIZE_T FileSize; /* Open EFI volume */ Status = BlOpenVolume(NULL, &DiskHandle, &FsHandle); if(Status != STATUS_EFI_SUCCESS) { /* Failed to open a volume */ return Status; } /* Open specified directory, containing the configuration file and close the FS immediately */ Status = FsHandle->Open(FsHandle, &DirHandle, ConfigDirectory, 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 configuration file */ Status = BlReadFile(DirHandle, ConfigFile, (PVOID *)ConfigData, &FileSize); /* Close EFI volume */ BlCloseVolume(DiskHandle); /* Return read status */ return Status; } /** * Updates XTLDR configuration based on provided options. * * @param Options * Supplies a formatted list of options to be processed and stored in global configuration. * * @return This routine does not return any value. * * @since XT 1.0 */ XTCDECL VOID BlpUpdateGlobalConfiguration(IN PWCHAR Options) { PWCHAR Argument, LastArg; SIZE_T Length; /* Tokenize provided options */ Argument = RtlTokenizeWideString(Options, L" ", &LastArg); /* Iterate over all arguments passed to boot loader */ while(Argument != NULL) { /* Check all provided parameters */ if(RtlCompareWideStringInsensitive(Argument, L"DEFAULT=", 8) == 0) { /* Skip to the argument value and calculate argument length */ Argument += 8; Length = RtlWideStringLength(Argument, 0); /* Save default OS parameter in global configuration */ BlMemoryAllocatePool(Length, (PVOID *)&BlpConfiguration.Default); RtlCopyMemory(BlpConfiguration.Default, Argument, (Length * sizeof(WCHAR))); BlpConfiguration.Default[Length] = '\0'; } else if(RtlCompareWideStringInsensitive(Argument, L"DEBUG=", 6) == 0) { /* Skip to the argument value */ Argument += 6; Length = RtlWideStringLength(Argument, 0); /* Store debug port configuration if not set already */ if(BlpConfiguration.Debug == NULL) { /* Save debug port in global configuration */ BlMemoryAllocatePool(Length, (PVOID *)&BlpConfiguration.Debug); RtlCopyMemory(BlpConfiguration.Debug, Argument, (Length * sizeof(WCHAR))); BlpConfiguration.Debug[Length] = '\0'; } } else if(RtlCompareWideStringInsensitive(Argument, L"SHELL", 5) == 0) { /* Force shell mode */ BlpConfiguration.Shell = TRUE; } else if(RtlCompareWideStringInsensitive(Argument, L"TIMEOUT=", 8) == 0) { /* Skip to the argument value */ Argument += 8; /* Zero the timeout */ BlpConfiguration.Timeout = 0; /* Read the timeout value and store it in global configuration */ while(*Argument >= '0' && *Argument <= '9') { BlpConfiguration.Timeout *= 10; BlpConfiguration.Timeout += *Argument - '0'; Argument++; } } else if(RtlCompareWideStringInsensitive(Argument, L"TUNE=", 5) == 0) { /* Skip to the argument value */ Argument += 5; Length = RtlWideStringLength(Argument, 0); /* Save theme in global configuration */ BlMemoryAllocatePool(Length, (PVOID *)&BlpConfiguration.Tune); RtlCopyMemory(BlpConfiguration.Tune, Argument, (Length * sizeof(WCHAR))); BlpConfiguration.Tune[Length] = '\0'; } /* Take next argument */ Argument = RtlTokenizeWideString(NULL, L" ", &LastArg); } }