diff --git a/sys/CMakeLists.txt b/sys/CMakeLists.txt index 8c9f81b..f4e5c5e 100644 --- a/sys/CMakeLists.txt +++ b/sys/CMakeLists.txt @@ -1 +1,2 @@ add_subdirectory(ld) +add_subdirectory(bootstrap) diff --git a/sys/bootstrap/CMakeLists.txt b/sys/bootstrap/CMakeLists.txt new file mode 100644 index 0000000..0903b22 --- /dev/null +++ b/sys/bootstrap/CMakeLists.txt @@ -0,0 +1,14 @@ +file(GLOB c_sources *.c *.h) +file(GLOB arch_sources arch/${CMAKE_SYSTEM_PROCESSOR}/*.S) + +set_property(SOURCE ${arch_sources} PROPERTY LANGUAGE C) + +add_executable(bootstrap ${c_sources} ${arch_sources}) + +target_link_libraries(bootstrap libmango ulibc liblaunch) + +target_compile_options(bootstrap PRIVATE + -fPIC -pie -fno-stack-protector -nostdlib -ffreestanding) +target_link_options(bootstrap PRIVATE + -fPIC -static -pie -nostdlib -ffreestanding + -T ${CMAKE_CURRENT_SOURCE_DIR}/arch/${TARGET_ARCH}/layout.ld) diff --git a/sys/bootstrap/arch/x86_64/layout.ld b/sys/bootstrap/arch/x86_64/layout.ld new file mode 100644 index 0000000..c6d7ecc --- /dev/null +++ b/sys/bootstrap/arch/x86_64/layout.ld @@ -0,0 +1,18 @@ +ENTRY(_start) + +SECTIONS { + .text ALIGN(4K) : { + *(.text) + *(.rodata) + } + + .data ALIGN(4K) : { + *(.data) + *(.bss) + } + + /DISCARD/ : { + *(.interp) + *(.dynamic) + } +} diff --git a/sys/bootstrap/arch/x86_64/start.S b/sys/bootstrap/arch/x86_64/start.S new file mode 100644 index 0000000..45ef52b --- /dev/null +++ b/sys/bootstrap/arch/x86_64/start.S @@ -0,0 +1,15 @@ +.code64 + +.global _start +.type _start, @function + +.extern main +.type main, @function + +.extern exit +.type exit, @function + +_start: + call main +1: pause + jmp 1b diff --git a/sys/bootstrap/main.c b/sys/bootstrap/main.c new file mode 100644 index 0000000..71c5911 --- /dev/null +++ b/sys/bootstrap/main.c @@ -0,0 +1,99 @@ +#include "tar.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#define INIT_PATH "/usr/bin/test" + +static enum launch_status resolve_dependency( + struct launch_ctx *ctx, + const char *name, + kern_handle_t *out, + void *arg) +{ + char s[128]; + while (*name == '/') { + name++; + } + + snprintf(s, sizeof s, "searching for library %s", name); + kern_log(s); + + struct tar *fs = arg; + struct tar_file file = {0}; + if (tar_open(fs, name, &file) != 0) { + snprintf(s, sizeof s, "cannot find library %s", name); + kern_log(s); + return LAUNCH_ERR_CANNOT_RESOLVE_DEPENDENCY; + } + + kern_handle_t image = KERN_HANDLE_INVALID; + int err = tar_file_create_vm_object(&file, &image); + if (err != 0) { + snprintf(s, sizeof s, "cannot load library %s", name); + kern_log(s); + return -1; + } + + *out = image; + return LAUNCH_OK; +} + +int main( + int argc, + const char **argv, + kern_handle_t task, + kern_handle_t address_space, + uintptr_t bsp_base) +{ + struct tar bsp = {0}; + if (tar_init(&bsp, bsp_base) != 0) { + kern_log("cannot access bsp"); + return -1; + } + + struct tar_file init = {0}; + if (tar_open(&bsp, INIT_PATH, &init) != 0) { + kern_log("cannot find init program " INIT_PATH); + return -1; + } + + kern_trace("loading " INIT_PATH); + + kern_handle_t image = KERN_HANDLE_INVALID; + int err = tar_file_create_vm_object(&init, &image); + if (err != 0) { + kern_log("cannot load executable " INIT_PATH); + return -1; + } + + kern_trace("loaded executable vm-object " INIT_PATH); + + kern_tracef("task=%x, region=%x", task, address_space); + + struct launch_ctx launch; + struct launch_result result; + struct launch_parameters params = { + .p_executable = image, + .p_parent_task = task, + .p_task_name = "init", + .p_local_address_space = address_space, + .p_resolver_arg = &bsp, + }; + + launch_ctx_init(&launch); + launch.ctx_resolve_library = resolve_dependency; + + enum launch_status status + = launch_ctx_execute(&launch, ¶ms, LAUNCH_F_NONE, &result); + + kern_tracef("launch result: %d", status); + + return 102; +} diff --git a/sys/bootstrap/tar.c b/sys/bootstrap/tar.c new file mode 100644 index 0000000..74af056 --- /dev/null +++ b/sys/bootstrap/tar.c @@ -0,0 +1,96 @@ +#include "tar.h" + +#include +#include +#include + +size_t getsize(const char *in) +{ + size_t size = 0; + size_t j; + size_t count = 1; + + for (j = 11; j > 0; j--, count *= 8) { + size += ((in[j - 1] - '0') * count); + } + + return size; +} + +int tar_init(struct tar *tar, uintptr_t base) +{ + memset(tar, 0x0, sizeof *tar); + tar->tar_entries = (struct tar_bin_header *)base; + return 0; +} + +int tar_open(struct tar *tar, const char *path, struct tar_file *out) +{ + while (*path == '/') { + path++; + } + + if (*path == '\0') { + return -1; + } + + struct tar_bin_header *bin_header = tar->tar_entries; + struct tar_header header; + for (size_t i = 0;; i++) { + tar_header_decode(bin_header, &header); + if (bin_header->filename[0] == 0) { + break; + } + + char *s = (char *)bin_header; + s += sizeof *bin_header; + + if (!strcmp(bin_header->filename, path)) { + out->f_header = header; + out->f_data = s; + return 0; + } + + s += header.size; + s += ((sizeof *bin_header) + - ((uintptr_t)s % (sizeof *bin_header))); + + bin_header = (struct tar_bin_header *)s; + } + + return -1; +} + +int tar_file_create_vm_object(const struct tar_file *file, kern_handle_t *out) +{ + const void *data = file->f_data; + size_t len = file->f_header.size; + kern_handle_t vmo = KERN_HANDLE_INVALID; + + kern_status_t status = vm_object_create( + NULL, + 0, + file->f_header.size, + VM_PROT_READ | VM_PROT_EXEC | VM_PROT_USER, + &vmo); + if (status != KERN_OK) { + return -1; + } + + size_t nr_written = 0; + status = vm_object_write(vmo, data, 0, len, &nr_written); + if (status != KERN_OK || nr_written != len) { + kern_handle_close(vmo); + return -1; + } + + *out = vmo; + return 0; +} + +int tar_header_decode(const struct tar_bin_header *in, struct tar_header *out) +{ + memcpy(out->filename, in->filename, sizeof out->filename); + out->size = getsize(in->size); + return 0; +} diff --git a/sys/bootstrap/tar.h b/sys/bootstrap/tar.h new file mode 100644 index 0000000..a7f7b71 --- /dev/null +++ b/sys/bootstrap/tar.h @@ -0,0 +1,45 @@ +#ifndef TAR_H_ +#define TAR_H_ + +#include +#include +#include + +struct tar { + struct tar_bin_header *tar_entries; +}; + +struct tar_bin_header { + char filename[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char mtime[12]; + char chksum[8]; + char typeflag[1]; +} __attribute__((aligned(512))); + +struct tar_header { + char filename[100]; + size_t size; +}; + +struct tar_file { + struct tar_header f_header; + const void *f_data; +}; + +extern int tar_init(struct tar *tar, uintptr_t base); + +extern int tar_open(struct tar *tar, const char *path, struct tar_file *out); + +extern int tar_file_create_vm_object( + const struct tar_file *file, + kern_handle_t *out); + +extern int tar_header_decode( + const struct tar_bin_header *in, + struct tar_header *out); + +#endif