155 lines
5.7 KiB
C
155 lines
5.7 KiB
C
// Kernel boot configuration parser. This file intentionally implements only the boot.ini settings the kernel owns.
|
|
|
|
#include <kernel/ke_boot_config.h>
|
|
|
|
#include <ntlite/ddk/debug.h>
|
|
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
|
|
// Returns whether one character is horizontal configuration whitespace.
|
|
static bool KiBootConfigSpace(char c) {
|
|
return c == ' ' || c == '\t' || c == '\r';
|
|
}
|
|
|
|
// Trims horizontal whitespace from one immutable line span.
|
|
static void KiBootConfigTrim(const char** begin, const char** end) {
|
|
while (*begin < *end && KiBootConfigSpace(**begin))
|
|
++*begin;
|
|
while (*end > *begin && KiBootConfigSpace((*end)[-1]))
|
|
--*end;
|
|
}
|
|
|
|
// Returns whether one immutable span exactly matches a NUL-terminated string.
|
|
static bool KiBootConfigSpanEquals(const char* begin, const char* end, const char* text) {
|
|
while (begin < end && *text) {
|
|
if (*begin++ != *text++)
|
|
return false;
|
|
}
|
|
return begin == end && *text == '\0';
|
|
}
|
|
|
|
// Parses one unsigned decimal or 0x-prefixed hexadecimal value without accepting trailing junk.
|
|
static KSTATUS KiBootConfigParseUInt32(const char* begin, const char* end, uint32_t* valueOut) {
|
|
KiBootConfigTrim(&begin, &end);
|
|
if (begin == end || !valueOut)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
uint32_t base = 10;
|
|
if (end - begin >= 2 && begin[0] == '0' && (begin[1] == 'x' || begin[1] == 'X')) {
|
|
base = 16;
|
|
begin += 2;
|
|
if (begin == end)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
uint32_t value = 0;
|
|
for (const char* p = begin; p < end; ++p) {
|
|
uint32_t digit;
|
|
if (*p >= '0' && *p <= '9') digit = (uint32_t)(*p - '0');
|
|
else if (*p >= 'a' && *p <= 'f') digit = (uint32_t)(10 + *p - 'a');
|
|
else if (*p >= 'A' && *p <= 'F') digit = (uint32_t)(10 + *p - 'A');
|
|
else return NTLSTATUS_INVALID_PARAMETER;
|
|
if (digit >= base || value > (UINT32_MAX - digit) / base)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
value = value * base + digit;
|
|
}
|
|
|
|
*valueOut = value;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Copies one trimmed configuration value into a fixed kernel-owned string.
|
|
static KSTATUS KiBootConfigCopyString(const char* begin, const char* end, char* buffer, size_t bufferSize) {
|
|
KiBootConfigTrim(&begin, &end);
|
|
size_t length = (size_t)(end - begin);
|
|
if (!buffer || bufferSize == 0 || length >= bufferSize)
|
|
return NTLSTATUS_BUFFER_TOO_SMALL;
|
|
memcpy(buffer, begin, length);
|
|
buffer[length] = '\0';
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|
|
|
|
// Parses the kernel-owned boot.ini settings from the raw bootloader string.
|
|
KSTATUS KeParseBootConfiguration(const char* text, size_t length, KE_BOOT_CONFIG* configOut) {
|
|
if (!text || !configOut)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
KE_BOOT_CONFIG config = {0};
|
|
bool systemVolumeSeen = false;
|
|
char section[32] = {0};
|
|
size_t offset = 0;
|
|
|
|
while (offset < length) {
|
|
size_t lineStart = offset;
|
|
while (offset < length && text[offset] != '\n')
|
|
++offset;
|
|
size_t lineEnd = offset;
|
|
if (offset < length)
|
|
++offset;
|
|
|
|
const char* begin = text + lineStart;
|
|
const char* end = text + lineEnd;
|
|
KiBootConfigTrim(&begin, &end);
|
|
if (begin == end || *begin == ';' || *begin == '#')
|
|
continue;
|
|
|
|
if (*begin == '[') {
|
|
if (end[-1] != ']')
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
const char* sectionBegin = begin + 1;
|
|
const char* sectionEnd = end - 1;
|
|
KiBootConfigTrim(§ionBegin, §ionEnd);
|
|
size_t sectionLength = (size_t)(sectionEnd - sectionBegin);
|
|
if (sectionLength >= sizeof(section))
|
|
return NTLSTATUS_BUFFER_TOO_SMALL;
|
|
memcpy(section, sectionBegin, sectionLength);
|
|
section[sectionLength] = '\0';
|
|
continue;
|
|
}
|
|
|
|
const char* equals = NULL;
|
|
for (const char* p = begin; p < end; ++p) {
|
|
if (*p == '=') {
|
|
equals = p;
|
|
break;
|
|
}
|
|
}
|
|
if (!equals)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
|
|
const char* keyBegin = begin;
|
|
const char* keyEnd = equals;
|
|
const char* valueBegin = equals + 1;
|
|
const char* valueEnd = end;
|
|
KiBootConfigTrim(&keyBegin, &keyEnd);
|
|
|
|
if (strcmp(section, "boot") == 0 && KiBootConfigSpanEquals(keyBegin, keyEnd, "system_volume")) {
|
|
if (systemVolumeSeen)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
KSTATUS status = KiBootConfigCopyString(valueBegin, valueEnd,
|
|
config.SystemVolume, sizeof(config.SystemVolume));
|
|
if (!KSUCCESS(status) || config.SystemVolume[0] == '\0')
|
|
return KSUCCESS(status) ? NTLSTATUS_INVALID_PARAMETER : status;
|
|
systemVolumeSeen = true;
|
|
} else if (strcmp(section, "kernel") == 0 && KiBootConfigSpanEquals(keyBegin, keyEnd, "debug")) {
|
|
KSTATUS status = KiBootConfigParseUInt32(valueBegin, valueEnd, &config.Debug);
|
|
if (!KSUCCESS(status))
|
|
return status;
|
|
if (config.Debug & ~KE_DEBUG_VALID_MASK)
|
|
return NTLSTATUS_INVALID_PARAMETER;
|
|
} else if (strcmp(section, "init") == 0 && KiBootConfigSpanEquals(keyBegin, keyEnd, "commandline")) {
|
|
KSTATUS status = KiBootConfigCopyString(valueBegin, valueEnd,
|
|
config.CommandLine, sizeof(config.CommandLine));
|
|
if (!KSUCCESS(status))
|
|
return status;
|
|
}
|
|
}
|
|
|
|
if (!systemVolumeSeen)
|
|
return NTLSTATUS_NOT_FOUND;
|
|
|
|
*configOut = config;
|
|
return NTLSTATUS_SUCCESS;
|
|
}
|