diff options
author | dzwdz | 2023-08-14 18:51:07 +0200 |
---|---|---|
committer | dzwdz | 2023-08-14 18:51:07 +0200 |
commit | 642b5fb0007b64c77d186fcb018d571152ee1d47 (patch) | |
tree | 1c466461f3602d306be309a053edae558ef2568e /src/bootstrap | |
parent | 8050069c57b729c18c19b1a03ab6e4bf63b4735e (diff) |
reorganization: first steps
Diffstat (limited to 'src/bootstrap')
-rw-r--r-- | src/bootstrap/entry.S | 27 | ||||
-rw-r--r-- | src/bootstrap/linker.ld | 31 | ||||
-rw-r--r-- | src/bootstrap/main.c | 43 | ||||
-rw-r--r-- | src/bootstrap/tar.c | 155 | ||||
-rw-r--r-- | src/bootstrap/tar.h | 6 |
5 files changed, 262 insertions, 0 deletions
diff --git a/src/bootstrap/entry.S b/src/bootstrap/entry.S new file mode 100644 index 0000000..bd1b417 --- /dev/null +++ b/src/bootstrap/entry.S @@ -0,0 +1,27 @@ +#define ASM_FILE 1 +#include <camellia/syscalls.h> +#include <camellia/flags.h> + +.set STACK_TOP, 0xFFFFFFFFFFFFFFFF +.set STACK_PAGES, 4 + +.section .text.startup +.global _start +.type _start, @function +_start: + mov $_SYS_MEMFLAG, %rdi + mov $(STACK_TOP & ~0xFFF - (STACK_PAGES - 1) * 0x1000), %rsi + mov $(STACK_PAGES * 0x1000), %rdx + mov $MEMFLAG_PRESENT, %r10 + syscall + + mov $_SYS_MEMFLAG, %rdi + mov $_bss_start, %rsi + mov $_bss_end, %rdx + sub $_bss_start, %rdx + mov $MEMFLAG_PRESENT, %r10 + mov %rsp, %r8 + syscall + + mov $(STACK_TOP & ~0xF), %rsp + call main // and don't you dare return diff --git a/src/bootstrap/linker.ld b/src/bootstrap/linker.ld new file mode 100644 index 0000000..10e3f98 --- /dev/null +++ b/src/bootstrap/linker.ld @@ -0,0 +1,31 @@ +ENTRY(_start) + +SECTIONS +{ + . = 0x20000; + _bss_start = .; + .bss BLOCK(4K) : ALIGN(4K) + { + *(COMMON) + *(.bss) + } + _bss_end = .; + + . = 2M; + .text BLOCK(4K) : ALIGN(4K) + { + /* the assert needs to be inside of a section or it'll be a syntax error */ + ASSERT(_bss_end <= 2M, "bss too big, needs to be moved down"); + *(.text.startup) + *(.text) + } + .rodata BLOCK(4K) : ALIGN(4K) + { + *(.rodata) + } + .data BLOCK(4K) : ALIGN(4K) + { + *(.data*) + } + _initrd = .; /* is just appended onto the end of the binary */ +} diff --git a/src/bootstrap/main.c b/src/bootstrap/main.c new file mode 100644 index 0000000..d27da39 --- /dev/null +++ b/src/bootstrap/main.c @@ -0,0 +1,43 @@ +#include <_proc.h> +#include <camellia/flags.h> +#include <camellia/syscalls.h> +#include <stdio.h> +#include <string.h> +#include <elfload.h> +#include <camellia/fs/misc.h> + +#include "tar.h" + +extern char _bss_start; +extern char _bss_end; +extern char _initrd; + +__attribute__((section(".text"))) +int main(void) { + _sys_memflag(_psdata_loc, 1, MEMFLAG_PRESENT); + setprogname("bootstrap"); + + _sys_mount(HANDLE_PROCFS, "/proc/", strlen("/proc/")); + MOUNT_AT("/") { + fs_dirinject2((const char*[]) { + "/proc/", + "/init/", + NULL + }); + } + MOUNT_AT("/init/") { + tar_driver(&_initrd); + } + + const char *initpath = "bin/amd64/init"; + char *initargv[] = {"init", NULL}; + void *init = tar_find(initpath, strlen(initpath), &_initrd, ~0) + 512; + if (init) { + _klogf("execing init"); + elf_exec(init, initargv, NULL); + _klogf("elf_exec failed"); + } else { + _klogf("couldn't find init.elf"); + } + _sys_exit(1); +} diff --git a/src/bootstrap/tar.c b/src/bootstrap/tar.c new file mode 100644 index 0000000..2020fe0 --- /dev/null +++ b/src/bootstrap/tar.c @@ -0,0 +1,155 @@ +#include "tar.h" +#include <camellia/flags.h> +#include <camellia/fsutil.h> +#include <camellia/syscalls.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <camellia/compat.h> +#include <camellia/fs/dir.h> + +#define BUF_SIZE 64 + +static void *tar_open(const char *path, int len, void *base, size_t base_len); +static char tar_type(void *meta); +static void tar_dirbuild(struct dirbuild *db, const char *meta, void *base, size_t base_len); +static void tar_read(struct ufs_request *res, void *base, size_t base_len); +static int tar_size(void *sector); +static int oct_parse(char *str, size_t len); + + +static const char *root_fakemeta = ""; /* see comment in tar_open */ + + +void tar_driver(void *base) { + static char buf[BUF_SIZE]; + struct ufs_request res; + void *ptr; + while (!c0_fs_wait(buf, BUF_SIZE, &res)) { + switch (res.op) { + case VFSOP_OPEN: + ptr = tar_open(buf, res.len, base, ~0); + c0_fs_respond(ptr, ptr ? 0 : -1, 0); + break; + + case VFSOP_READ: + tar_read(&res, base, ~0); + break; + + case VFSOP_GETSIZE: + if (tar_type(res.id) != '5') { + c0_fs_respond(NULL, tar_size(res.id), 0); + } else { + struct dirbuild db; + dir_start(&db, res.offset, NULL, 0); + tar_dirbuild(&db, res.id, base, ~0); + c0_fs_respond(NULL, dir_finish(&db), 0); + } + break; + + default: + c0_fs_respond(NULL, -1, 0); // unsupported + break; + } + } + exit(0); +} + +static char tar_type(void *meta) { + if (meta == root_fakemeta) return '5'; + return *(char*)(meta + 156); +} + +static void *tar_open(const char *path, int len, void *base, size_t base_len) { + if (len <= 0) return NULL; + path += 1; // skip the leading slash + len -= 1; + + /* TAR archives don't (seem to) contain an entry for the root dir, so i'm + * returning a fake one. this isn't a full entry because i'm currently too + * lazy to create a full one - thus, it has to be special cased in tar_read */ + if (len == 0) + return (void*)root_fakemeta; + + return tar_find(path, len, base, base_len); +} + +static void tar_dirbuild(struct dirbuild *db, const char *meta, void *base, size_t base_len) { + size_t meta_len = strlen(meta); + for (size_t off = 0; off < base_len;) { + if (0 != memcmp(base + off + 257, "ustar", 5)) + break; // not a metadata sector + + /* check if prefix matches */ + if (0 == memcmp(base + off, meta, meta_len) + && *(char*)(base + off + meta_len) != '\0') { + char *suffix = base + off + meta_len; + + /* check if the path contains any non-trailing slashes */ + char *slash = strchr(suffix, '/'); + if (!slash || slash[1] == '\0') { + if (dir_append(db, suffix)) break; + } + } + + int size = tar_size(base + off); + off += 512; // skip this metadata sector + off += (size + 511) & ~511; // skip the data sectors + } +} + +static void tar_read(struct ufs_request *res, void *base, size_t base_len) { + void *meta = (void*)res->id; + static char buf[BUF_SIZE]; + // TODO reuse a single buffer for both tar_driver and tar_read + + switch (tar_type(meta)) { + case '\0': + case '0': /* normal files */ + fs_normslice(&res->offset, &res->len, tar_size(meta), false); + c0_fs_respond(meta + 512 + res->offset, res->len, 0); + break; + + case '5': /* directory */ + struct dirbuild db; + dir_start(&db, res->offset, buf, sizeof buf); + tar_dirbuild(&db, meta, base, base_len); + c0_fs_respond(buf, dir_finish(&db), 0); + break; + + default: + c0_fs_respond(NULL, -1, 0); + break; + } +} + +static int tar_size(void *sector) { + return oct_parse(sector + 124, 11); +} + +void *tar_find(const char *path, size_t path_len, void *base, size_t base_len) { + int size; + if (path_len > 100) return NULL; // illegal path + + for (size_t off = 0; off < base_len;) { + if (0 != memcmp(base + off + 257, "ustar", 5)) + break; // not a metadata sector + if (0 == memcmp(base + off, path, path_len) && + *(char*)(base + off + path_len) == '\0') + return base + off; // file found, quit + + size = tar_size(base + off); + off += 512; // skip this metadata sector + off += (size + 511) & ~511; // skip the data sectors + } + return NULL; +} + +static int oct_parse(char *str, size_t len) { + int res = 0; + for (size_t i = 0; i < len; i++) { + res *= 8; + res += str[i] - '0'; // no format checking + } + return res; +} diff --git a/src/bootstrap/tar.h b/src/bootstrap/tar.h new file mode 100644 index 0000000..e7ab130 --- /dev/null +++ b/src/bootstrap/tar.h @@ -0,0 +1,6 @@ +#pragma once +#include <camellia/types.h> +#include <stddef.h> + +_Noreturn void tar_driver(void *base); +void *tar_find(const char *path, size_t path_len, void *base, size_t base_len); |