diff --git a/kernel-src/arch/x86-64/hpet.c b/kernel-src/arch/x86-64/hpet.c index 75e57498..58914567 100644 --- a/kernel-src/arch/x86-64/hpet.c +++ b/kernel-src/arch/x86-64/hpet.c @@ -4,7 +4,7 @@ #include #include #include -#include +#include #include #include @@ -61,8 +61,10 @@ static void counterirq(isr_t *isr, context_t *context) { write64(HPET_REG_CONFIG, 1 + ((hpet_private.type == TYPE_LEGACY) ? 2 : 0)); } +DEFINE_KERNEL_ARGUMENT(nohpet, bool); + static bool hpet_probe(void) { - if (cmdline_get("nohpet")) + if (GET_KERNEL_ARGUMENT(nohpet, bool)) return false; bool usable = false; diff --git a/kernel-src/arch/x86-64/kernel.ld b/kernel-src/arch/x86-64/kernel.ld index b119c07e..6f3f0c48 100644 --- a/kernel-src/arch/x86-64/kernel.ld +++ b/kernel-src/arch/x86-64/kernel.ld @@ -48,6 +48,13 @@ SECTIONS *(.data .data.*); } :data + . = ALIGN(8); + .kernel_arguments : { + kernel_arguments = .; + *(.kernel_arguments); + kernel_arguments_end = .; + } :data + . = ALIGN(8); .bss : { *(COMMON) diff --git a/kernel-src/arch/x86-64/kvmclock.c b/kernel-src/arch/x86-64/kvmclock.c index 7b7a70b5..d3f4ac47 100644 --- a/kernel-src/arch/x86-64/kvmclock.c +++ b/kernel-src/arch/x86-64/kvmclock.c @@ -6,7 +6,7 @@ #include #include #include -#include +#include #define KVM_TIMER_SYSTEM_TIME_ALIGNMENT 4 #define KVM_TIMER_SYSTEM_TIME_ENABLE 1 @@ -23,8 +23,10 @@ typedef struct { uint8_t padding1[2]; } __attribute__((packed)) kvm_timer_info_t; +DEFINE_KERNEL_ARGUMENT(nokvmclock, bool); + static bool kvm_timer_probe(void) { - if (cmdline_get("nokvmclock")) + if (GET_KERNEL_ARGUMENT(nokvmclock, bool)) return false; // figure out if we are running in kvm diff --git a/kernel-src/arch/x86-64/smp.c b/kernel-src/arch/x86-64/smp.c index 1a034d58..82fd65a1 100644 --- a/kernel-src/arch/x86-64/smp.c +++ b/kernel-src/arch/x86-64/smp.c @@ -4,11 +4,13 @@ #include #include #include -#include +#include #include #include #include +DEFINE_KERNEL_ARGUMENT(nosmp, bool); + static volatile struct limine_smp_request smprequest = { .id = LIMINE_SMP_REQUEST }; @@ -58,8 +60,8 @@ void arch_smp_haltallothers(void) { } size_t arch_smp_get_cpu_count(void) { - //if (cmdline_get("nosmp")) - // return 1; + if (GET_KERNEL_ARGUMENT(nosmp, bool)) + return 1; struct limine_smp_response *response = smprequest.response; if (response == NULL) @@ -95,7 +97,7 @@ void arch_smp_wakeup(void) { smp_cpus = alloc(response->cpu_count * sizeof(cpu_t *)); __assert(smp_cpus); - void (*wakeupfn)(struct limine_smp_info *) = cpuwakeup;//cmdline_get("nosmp") ? cpuwakeuphalt : cpuwakeup; + void (*wakeupfn)(struct limine_smp_info *) = GET_KERNEL_ARGUMENT(nosmp, bool) ? cpuwakeuphalt : cpuwakeup; // make the other processors jump to cpuwakeup() for (int i = 0; i < response->cpu_count; ++i) { diff --git a/kernel-src/arch/x86-64/tsc.c b/kernel-src/arch/x86-64/tsc.c index e39e9b82..96f8d0a7 100644 --- a/kernel-src/arch/x86-64/tsc.c +++ b/kernel-src/arch/x86-64/tsc.c @@ -4,10 +4,12 @@ #include #include #include -#include +#include + +DEFINE_KERNEL_ARGUMENT(notsc, bool); static bool tsc_probe(void) { - if (cmdline_get("notsc")) + if (GET_KERNEL_ARGUMENT(notsc, bool)) return false; cpuid_results_t cpuid_results; diff --git a/kernel-src/include/kernel/cmdline.h b/kernel-src/include/kernel/cmdline.h deleted file mode 100644 index 9ae6ccb9..00000000 --- a/kernel-src/include/kernel/cmdline.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef _CMDLINE_H -#define _CMDLINE_H - -char *cmdline_get(char *); -void cmdline_parse(); - -#endif diff --git a/kernel-src/include/kernel/kernel_args.h b/kernel-src/include/kernel/kernel_args.h new file mode 100644 index 00000000..5b624154 --- /dev/null +++ b/kernel-src/include/kernel/kernel_args.h @@ -0,0 +1,57 @@ +#ifndef _KERNEL_ARGS_H +#define _KERNEL_ARGS_H + +#include +#include + +void kernel_arguments_parse(void); + +#define KERNEL_ARGUMENT_TYPE_BOOL 0 +#define KERNEL_ARGUMENT_TYPE_STR 1 +#define KERNEL_ARGUMENT_TYPE_INT 2 + +typedef struct { + const char *key; + int type; + bool found; + union { + char *value_str; + uint64_t value_int; + }; +} kernel_argument_t; + +#define DEFINE_KERNEL_ARGUMENT(name, t) \ + static kernel_argument_t kernel_argument_##name = { \ + .key = #name , \ + .type = _Generic((t)0, \ + uint8_t: KERNEL_ARGUMENT_TYPE_INT, \ + uint16_t: KERNEL_ARGUMENT_TYPE_INT, \ + uint32_t: KERNEL_ARGUMENT_TYPE_INT, \ + uint64_t: KERNEL_ARGUMENT_TYPE_INT, \ + int8_t: KERNEL_ARGUMENT_TYPE_INT, \ + int16_t: KERNEL_ARGUMENT_TYPE_INT, \ + int32_t: KERNEL_ARGUMENT_TYPE_INT, \ + int64_t: KERNEL_ARGUMENT_TYPE_INT, \ + bool: KERNEL_ARGUMENT_TYPE_BOOL, \ + char *: KERNEL_ARGUMENT_TYPE_STR, \ + default: (kernel_argument_t *)NULL \ + ), \ + .found = false \ + }; \ + __attribute__((section(".kernel_arguments"), used)) static kernel_argument_t *kernel_argument_ptr_##name = &kernel_argument_##name; + +#define GET_KERNEL_ARGUMENT(name, t) _Generic((t)0, \ + uint8_t: kernel_argument_##name.value_int, \ + uint16_t: kernel_argument_##name.value_int, \ + uint32_t: kernel_argument_##name.value_int, \ + uint64_t: kernel_argument_##name.value_int, \ + int8_t: kernel_argument_##name.value_int, \ + int16_t: kernel_argument_##name.value_int, \ + int32_t: kernel_argument_##name.value_int, \ + int64_t: kernel_argument_##name.value_int, \ + bool: kernel_argument_##name.found, \ + char *: kernel_argument_##name.value_str, \ + default: (kernel_argument_t *)NULL \ + ) + +#endif diff --git a/kernel-src/include/string.h b/kernel-src/include/string.h index f06057f1..60ccfd22 100644 --- a/kernel-src/include/string.h +++ b/kernel-src/include/string.h @@ -13,5 +13,6 @@ int strncmp(const char *a, const char *b, size_t c); int memcmp(const void *a, const void *b, size_t s); void *memmove(void *_d, const void *_s, size_t c); char *strerror(int errno); +long long atoll(const char *c); #endif diff --git a/kernel-src/lib/string.c b/kernel-src/lib/string.c index 7b1e4fb5..79aee8b5 100644 --- a/kernel-src/lib/string.c +++ b/kernel-src/lib/string.c @@ -99,6 +99,19 @@ void *memmove(void *_d, const void *_s, size_t c) { return _d; } +long long atoll(const char *c) { + char first = *c; + if (first == '-') + ++c; + + int v = 0; + + while (*c) + v = v * 10 + (*c++) - '0'; + + return first == '-' ? -v : v; +} + #define DO_NAME(e) \ case e: \ return #e; diff --git a/kernel-src/main.c b/kernel-src/main.c index f1a6a659..fba17a5f 100644 --- a/kernel-src/main.c +++ b/kernel-src/main.c @@ -1,7 +1,7 @@ #include #include #include -#include +#include #include #include #include @@ -9,27 +9,31 @@ static cpu_t bsp_cpu; -INIT_ROUTINE_DEFINE(bsp_early, - INIT_ROUTINE_FLAGS_PHONY, +INIT_ROUTINE_DEFINE(bsp_early, + INIT_ROUTINE_FLAGS_PHONY, NULL, alloc, term, cpu ); +DEFINE_KERNEL_ARGUMENT(root, char *); +DEFINE_KERNEL_ARGUMENT(rootfs, char *); +DEFINE_KERNEL_ARGUMENT(initrd, bool); + void kernel_entry() { cpu_set(&bsp_cpu); logging_sethook(arch_early_log); - init_run_routine(INIT_GET_ROUTINE(bsp_early)); + kernel_arguments_parse(); - cmdline_parse(); + init_run_routine(INIT_GET_ROUTINE(bsp_early)); init_run_all_routines(); // kernel is fully up and running by now // mount root filesystem - char *root = cmdline_get("root"); - char *rootfs = cmdline_get("rootfs"); + char *root = GET_KERNEL_ARGUMENT(root, char *); + char *rootfs = GET_KERNEL_ARGUMENT(rootfs, char *); printf("entry: mounting %s (%s) on /\n", root == NULL ? "none" : root, rootfs); @@ -46,7 +50,7 @@ void kernel_entry() { VOP_RELEASE(backing); } - if (cmdline_get("initrd")) + if (GET_KERNEL_ARGUMENT(initrd, bool)) initrd_unpack(); // spawn init diff --git a/kernel-src/sys/cmdline.c b/kernel-src/sys/cmdline.c deleted file mode 100644 index 9fbf4276..00000000 --- a/kernel-src/sys/cmdline.c +++ /dev/null @@ -1,77 +0,0 @@ -#include -#include -#include -#include -#include - -static volatile struct limine_kernel_file_request kernel_file_request = { - .id = LIMINE_KERNEL_FILE_REQUEST, - .revision = 0 -}; - -static hashtable_t pair_table; - -char *cmdline_get(char *key) { - void *v; - return hashtable_get(&pair_table, &v, key, strlen(key)) == 0 ? v : NULL; -} - -void cmdline_parse() { - __assert(hashtable_init(&pair_table, 16) == 0); - __assert(kernel_file_request.response); - struct limine_file *kernel_file = kernel_file_request.response->kernel_file; - __assert(kernel_file); - char *cmdline = kernel_file->cmdline; - __assert(cmdline); - - size_t buffer_len = strlen(cmdline) + 1; - char buffer[buffer_len]; - memset(buffer, 0, buffer_len); - char *cmdline_ptr = cmdline; - char *buffer_ptr = buffer; - - bool do_convert = true; - - while (*cmdline_ptr) { - char cmd_char = *cmdline_ptr++; - if (cmd_char == ' ' && do_convert) - *buffer_ptr++ = '\0'; - else if (cmd_char == '"') { - do_convert = !do_convert; - --buffer_len; - } else - *buffer_ptr++ = cmd_char; - } - buffer[buffer_len - 1] = '\0'; - - int i = 0; - while (i < buffer_len) { - char *iterator = &buffer[i]; - bool pair = false; - while (*iterator) { - if (*iterator == '=') { - pair = true; - *iterator = '\0'; - } - ++iterator; - } - - size_t key_len = strlen(&buffer[i]); - if (pair) { - char *value_ptr = &buffer[i + key_len + 1]; - size_t value_len = strlen(value_ptr); - - char *value = alloc(value_len) + 1; - __assert(value); - strcpy(value, value_ptr); - __assert(hashtable_set(&pair_table, value, &buffer[i], key_len, true) == 0); - i += value_len + 1; - } else { - char *value = alloc(key_len + 1); - __assert(value); - strcpy(value, &buffer[i]); - __assert(hashtable_set(&pair_table, value, &buffer[i], key_len, true) == 0); - } - i += key_len + 1; - } -} diff --git a/kernel-src/sys/kernel_args.c b/kernel-src/sys/kernel_args.c new file mode 100644 index 00000000..eb793b89 --- /dev/null +++ b/kernel-src/sys/kernel_args.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include + +#define TOTAL_ARGUMENTS_CHARACTER_LIMIT 4096 + +static volatile struct limine_kernel_file_request kernel_file_request = { + .id = LIMINE_KERNEL_FILE_REQUEST, + .revision = 0 +}; + +static size_t allocated = 0; +static char argument_buffer[TOTAL_ARGUMENTS_CHARACTER_LIMIT]; + +extern kernel_argument_t *kernel_arguments[]; +extern kernel_argument_t *kernel_arguments_end[]; + +static void insert_argument(const char *key, const char *value) { + size_t argument_count = ((uintptr_t)kernel_arguments_end - (uintptr_t)kernel_arguments) / sizeof(kernel_argument_t *); + char *buffer = &argument_buffer[allocated]; + if (value) { + strcpy(buffer, value); + allocated += strlen(value) + 1; + } + + for (int i = 0; i < argument_count; ++i) { + if (strcmp(kernel_arguments[i]->key, key)) + continue; + + kernel_arguments[i]->found = true; + + switch (kernel_arguments[i]->type) { + case KERNEL_ARGUMENT_TYPE_STR: + kernel_arguments[i]->value_str = value ? buffer : NULL; + break; + case KERNEL_ARGUMENT_TYPE_INT: + kernel_arguments[i]->value_int = value ? atoll(buffer) : 0; + break; + } + } +} + +void kernel_arguments_parse(void) { + __assert(kernel_file_request.response); + const char *cmdline = kernel_file_request.response->kernel_file->cmdline; + __assert(cmdline); + size_t length = min(strlen(cmdline), TOTAL_ARGUMENTS_CHARACTER_LIMIT); + char temp_buffer[length]; + memcpy(temp_buffer, cmdline, length); + + bool escaping = false; + const char *key = temp_buffer[0] == ' ' ? NULL : temp_buffer; + const char *value = NULL; + for (int i = 0; i < length; ++i) { + if (temp_buffer[i] == '"') { + escaping = !escaping; + temp_buffer[i] = '\0'; + continue; + } + + if (temp_buffer[i] == '=') { + value = &temp_buffer[i + 1]; + temp_buffer[i] = '\0'; + continue; + } + + if (temp_buffer[i] == ' ' && !escaping) { + temp_buffer[i] = '\0'; + + if (key) + insert_argument(key, value); + + key = &temp_buffer[i + 1]; + value = NULL; + } + } + + if (key != temp_buffer + length) + insert_argument(key, value); +} diff --git a/kernel-src/sys/proc.c b/kernel-src/sys/proc.c index f56ebb81..e28959c1 100644 --- a/kernel-src/sys/proc.c +++ b/kernel-src/sys/proc.c @@ -8,7 +8,7 @@ #include #include #include -#include +#include static hashtable_t pid_table; static scache_t *processcache; @@ -292,6 +292,8 @@ void proc_exit(void) { } } +DEFINE_KERNEL_ARGUMENT(initarg, char *); + void proc_run_init() { printf("proc: loading /init\n"); @@ -358,7 +360,7 @@ void proc_run_init() { proc->root = vfsroot; VOP_HOLD(vfsroot); - char *argv[] = {"/init", cmdline_get("initarg"), NULL}; + char *argv[] = {"/init", GET_KERNEL_ARGUMENT(initarg, char *), NULL}; char *envp[] = {NULL}; void *stack = elf_preparestack(STACK_TOP, &auxv64, argv, envp, "/init"); diff --git a/kernel-src/sys/scheduler/scheduler.c b/kernel-src/sys/scheduler/scheduler.c index 9371d0e7..ff8d88bd 100644 --- a/kernel-src/sys/scheduler/scheduler.c +++ b/kernel-src/sys/scheduler/scheduler.c @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/kernel-src/sys/syscalls/newthread.c b/kernel-src/sys/syscalls/newthread.c index a7f9b305..3c6cd952 100644 --- a/kernel-src/sys/syscalls/newthread.c +++ b/kernel-src/sys/syscalls/newthread.c @@ -1,9 +1,11 @@ #include #include -#include +#include #include #include +DEFINE_KERNEL_ARGUMENT(nomultithread, bool); + syscallret_t syscall_newthread(context_t *, void *entry, void *stack) { syscallret_t ret = { .ret = -1 @@ -11,7 +13,7 @@ syscallret_t syscall_newthread(context_t *, void *entry, void *stack) { // TODO perhaps clean up threads here as well // if the kernel was specified to have no user threading in the cmdline - if (cmdline_get("nomultithread")) { + if (GET_KERNEL_ARGUMENT(nomultithread, bool)) { ret.errno = ENOSYS; return ret; }