From 642b5fb0007b64c77d186fcb018d571152ee1d47 Mon Sep 17 00:00:00 2001
From: dzwdz
Date: Mon, 14 Aug 2023 18:51:07 +0200
Subject: reorganization: first steps

---
 src/bootstrap/entry.S   |  27 +++++++++
 src/bootstrap/linker.ld |  31 ++++++++++
 src/bootstrap/main.c    |  43 ++++++++++++++
 src/bootstrap/tar.c     | 155 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/bootstrap/tar.h     |   6 ++
 5 files changed, 262 insertions(+)
 create mode 100644 src/bootstrap/entry.S
 create mode 100644 src/bootstrap/linker.ld
 create mode 100644 src/bootstrap/main.c
 create mode 100644 src/bootstrap/tar.c
 create mode 100644 src/bootstrap/tar.h

(limited to 'src/bootstrap')

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);
-- 
cgit v1.2.3