sys: add userspace bootstrap program
This commit is contained in:
14
sys/bootstrap/CMakeLists.txt
Normal file
14
sys/bootstrap/CMakeLists.txt
Normal file
@@ -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)
|
||||
18
sys/bootstrap/arch/x86_64/layout.ld
Normal file
18
sys/bootstrap/arch/x86_64/layout.ld
Normal file
@@ -0,0 +1,18 @@
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS {
|
||||
.text ALIGN(4K) : {
|
||||
*(.text)
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
.data ALIGN(4K) : {
|
||||
*(.data)
|
||||
*(.bss)
|
||||
}
|
||||
|
||||
/DISCARD/ : {
|
||||
*(.interp)
|
||||
*(.dynamic)
|
||||
}
|
||||
}
|
||||
15
sys/bootstrap/arch/x86_64/start.S
Normal file
15
sys/bootstrap/arch/x86_64/start.S
Normal file
@@ -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
|
||||
99
sys/bootstrap/main.c
Normal file
99
sys/bootstrap/main.c
Normal file
@@ -0,0 +1,99 @@
|
||||
#include "tar.h"
|
||||
|
||||
#include <launch.h>
|
||||
#include <mango/log.h>
|
||||
#include <mango/msg.h>
|
||||
#include <mango/task.h>
|
||||
#include <mango/types.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
96
sys/bootstrap/tar.c
Normal file
96
sys/bootstrap/tar.c
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "tar.h"
|
||||
|
||||
#include <mango/handle.h>
|
||||
#include <mango/vm.h>
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
}
|
||||
45
sys/bootstrap/tar.h
Normal file
45
sys/bootstrap/tar.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#ifndef TAR_H_
|
||||
#define TAR_H_
|
||||
|
||||
#include <mango/types.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user