summaryrefslogtreecommitdiffstats
path: root/device/initrd.c
blob: 1a043389e096f8d2ce40441bbf87aa147e350ed9 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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 sie %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
    _initData.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