diff options
Diffstat (limited to 'device/initrd.c')
-rw-r--r-- | device/initrd.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/device/initrd.c b/device/initrd.c new file mode 100644 index 0000000..36eefc6 --- /dev/null +++ b/device/initrd.c @@ -0,0 +1,116 @@ +#if defined(ENABLE_INITRD) + +#include <stddef.h> + +#include "device/initrd.h" +#include "device/processor.h" +#include "object.h" +#include "jove.h" +#include "bootargs.h" +#include "print.h" +#include "string.h" +#include "panic.h" + +struct jove_ObjectDirectory s_initrd_dir = { + .entries = { + [0] = (objdir_entry_t){ + .type = KO_OBJECT_DIRECTORY, + .data = 1 + } + } +}; + +static uintptr_t s_initrd_getaddr(char *path); + +#if defined(__limine__) + +#include "boot/limine/limine.h" +static struct limine_module_request s_module_request = { + .id = LIMINE_MODULE_REQUEST +}; + +static uintptr_t +s_initrd_getaddr(char *path) +{ + struct limine_module_response *response = s_module_request.response; + for(size_t i = 0; i < response->module_count; i++) { + struct limine_file *module = response->modules[i]; + if(strcmp(path, module->path) == 0) + return (uintptr_t)module->address; + } + kpanic("Failed to load module at path %s\n", path); +} + + +#endif + +static size_t +s_tar_oct_dec(const char *oct) +{ + size_t r = 0; + for(; *oct; oct++) r = (r * 8) + (*oct - '0'); + return r; +} + +void +tar_parse(tar_block_t *block) +{ + while(true) { + tar_header_t *header = &block->header; + if(*header->name == 0) return; + if(s_initrd_dir.self.data == OBJECT_DIRECTORY_MAX_ENTRIES) { + klogf("More than %i files in initrd! Skipping the rest.\n", OBJECT_DIRECTORY_MAX_ENTRIES - 1); + } + + size_t file_size = s_tar_oct_dec(header->size); + s_initrd_dir.entries[s_initrd_dir.self.data++] = (objdir_entry_t) { + .type = KO_INITRD_FILE, + .data = (uintptr_t)block + }; + + klogf("Load file '%s' at %p size %x\n", block->header.name, block + 1, file_size); + + block = &block[(file_size / 512) + 1]; + if(file_size % 512) block++; + } +} + +void +initrd_setup(void) +{ + char *initrd_path = bootargs_getarg("initrd"); + if(initrd_path == 0) { + kpanic("Missing kernel commandline argument for initrd."); + } + + uintptr_t initrd_addr = s_initrd_getaddr(initrd_path); + klogf("Initrd found at %p\n", initrd_addr); + tar_parse((tar_block_t*)initrd_addr); + + size_t initrd_diri = _initDirectory.self.data++; + _initDirectory.entries[initrd_diri] = (objdir_entry_t) { + .type = KO_OBJECT_DIRECTORY, + .data = (uintptr_t)&s_initrd_dir + }; + //Add initrd dir to init object + ((init_data_t*)_initDirectory.entries[1].data)->initrd_dir = initrd_diri; +} + +int +initrd_file_size(tar_header_t *file) +{ + return s_tar_oct_dec(file->size); +} + +tar_header_t* +initrd_find_file(const char *filename) +{ + for(size_t i = 0; i < s_initrd_dir.self.data - 1; i++) { + objdir_entry_t *entry = &s_initrd_dir.entries[i+1]; + tar_header_t *file = (tar_header_t*)entry->data; + if(strcmp(file->name + 1, filename) == 0) return file; + } + return NULL; +} + +#endif |