summaryrefslogtreecommitdiff
path: root/src/bootstrap
diff options
context:
space:
mode:
authordzwdz2023-08-14 18:51:07 +0200
committerdzwdz2023-08-14 18:51:07 +0200
commit642b5fb0007b64c77d186fcb018d571152ee1d47 (patch)
tree1c466461f3602d306be309a053edae558ef2568e /src/bootstrap
parent8050069c57b729c18c19b1a03ab6e4bf63b4735e (diff)
reorganization: first steps
Diffstat (limited to 'src/bootstrap')
-rw-r--r--src/bootstrap/entry.S27
-rw-r--r--src/bootstrap/linker.ld31
-rw-r--r--src/bootstrap/main.c43
-rw-r--r--src/bootstrap/tar.c155
-rw-r--r--src/bootstrap/tar.h6
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);