mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
[srv.init] Load initial programs in srv.init
Add a simple ELF loader to srv.init to load and start any module_program parameters passed from the bootloader. Also creates stacks for newly created threads. Also update thread creation in testapp to create stacks.
This commit is contained in:
@@ -1,10 +1,13 @@
|
||||
# vim: ft=python
|
||||
|
||||
module("srv.init",
|
||||
init = module("srv.init",
|
||||
targets = [ "user" ],
|
||||
deps = [ "libc" ],
|
||||
deps = [ "libc", "elf" ],
|
||||
sources = [
|
||||
"loader.cpp",
|
||||
"main.cpp",
|
||||
"modules.cpp",
|
||||
"start.s",
|
||||
])
|
||||
|
||||
init.variables['ldflags'] = ["${ldflags}", "-section-start=.rodata=0x800000"]
|
||||
|
||||
132
src/user/srv.init/loader.cpp
Normal file
132
src/user/srv.init/loader.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "enum_bitfields.h"
|
||||
#include "elf/file.h"
|
||||
#include "elf/headers.h"
|
||||
#include "j6/errors.h"
|
||||
#include "j6/flags.h"
|
||||
#include "j6/syscalls.h"
|
||||
#include "init_args.h"
|
||||
|
||||
using kernel::init::module_flags;
|
||||
using kernel::init::module_program;
|
||||
|
||||
extern j6_handle_t handle_self;
|
||||
extern j6_handle_t handle_system;
|
||||
|
||||
constexpr uintptr_t load_addr_base = 0xf8000000;
|
||||
constexpr size_t stack_size = 0x10000;
|
||||
constexpr uintptr_t stack_top = 0x80000000000;
|
||||
|
||||
bool
|
||||
load_program(const module_program &prog, char *err_msg)
|
||||
{
|
||||
if (bitfields::has(prog.mod_flags, module_flags::no_load)) {
|
||||
sprintf(err_msg, " skipping pre-loaded program module '%s' at %lx", prog.filename, prog.base_address);
|
||||
return true;
|
||||
}
|
||||
|
||||
j6_handle_t elf_vma = j6_handle_invalid;
|
||||
j6_status_t res = j6_system_map_phys(handle_system, &elf_vma, prog.base_address, prog.size, 0);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': creating physical vma: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
res = j6_vma_map(elf_vma, handle_self, prog.base_address);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': mapping vma: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
const void *addr = reinterpret_cast<const void *>(prog.base_address);
|
||||
elf::file progelf {addr, prog.size};
|
||||
|
||||
if (!progelf.valid()) {
|
||||
sprintf(err_msg, " ** error loading program '%s': ELF is invalid", prog.filename);
|
||||
return false;
|
||||
}
|
||||
|
||||
j6_handle_t proc = j6_handle_invalid;
|
||||
res = j6_process_create(&proc);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': creating process: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
uintptr_t load_addr = load_addr_base;
|
||||
|
||||
for (auto &seg : progelf.programs()) {
|
||||
if (seg.type != elf::segment_type::load)
|
||||
continue;
|
||||
|
||||
// TODO: way to remap VMA as read-only if there's no write flag on
|
||||
// the segment
|
||||
unsigned long flags = j6_vm_flag_write;
|
||||
if (bitfields::has(seg.flags, elf::segment_flags::exec))
|
||||
flags |= j6_vm_flag_exec;
|
||||
|
||||
j6_handle_t sub_vma = j6_handle_invalid;
|
||||
res = j6_vma_create_map(&sub_vma, seg.mem_size, load_addr, flags);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': creating sub vma: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
void *src = reinterpret_cast<void *>(prog.base_address + seg.offset);
|
||||
void *dest = reinterpret_cast<void *>(load_addr);
|
||||
memcpy(dest, src, seg.file_size);
|
||||
|
||||
res = j6_vma_map(sub_vma, proc, seg.vaddr);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': mapping sub vma to child: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
res = j6_vma_unmap(sub_vma, handle_self);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': unmapping sub vma: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
load_addr += 0x1000 * ((seg.mem_size + 0xfff) >> 12);
|
||||
}
|
||||
|
||||
j6_handle_t stack_vma = j6_handle_invalid;
|
||||
res = j6_vma_create_map(&stack_vma, stack_size, load_addr, j6_vm_flag_write);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': creating stack vma: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t *stack = reinterpret_cast<uint64_t*>(load_addr + stack_size);
|
||||
memset(stack - 512, 0, 512 * sizeof(uint64_t)); // Zero top page
|
||||
|
||||
res = j6_vma_map(stack_vma, proc, stack_top-stack_size);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': mapping stack vma: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
res = j6_vma_unmap(stack_vma, handle_self);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': unmapping stack vma: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
j6_handle_t thread = j6_handle_invalid;
|
||||
res = j6_thread_create(&thread, proc, stack_top - 6*sizeof(uint64_t), progelf.entrypoint());
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': creating thread: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
res = j6_vma_unmap(elf_vma, handle_self);
|
||||
if (res != j6_status_ok) {
|
||||
sprintf(err_msg, " ** error loading program '%s': unmapping elf vma: %lx", prog.filename, res);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
10
src/user/srv.init/loader.h
Normal file
10
src/user/srv.init/loader.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
/// \file loader.h
|
||||
/// Routines for loading and starting other programs
|
||||
|
||||
namespace kernel {
|
||||
namespace init {
|
||||
struct module_program;
|
||||
}}
|
||||
|
||||
bool load_program(const kernel::init::module_program &prog, char *err_msg);
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <stdio.h>
|
||||
#include "j6/syscalls.h"
|
||||
#include "init_args.h"
|
||||
#include "j6/syscalls.h"
|
||||
|
||||
#include "loader.h"
|
||||
#include "modules.h"
|
||||
|
||||
using kernel::init::module;
|
||||
@@ -24,11 +25,17 @@ main(int argc, const char **argv)
|
||||
|
||||
modules mods = modules::load_modules(_arg_modules_phys, handle_system, handle_self);
|
||||
|
||||
char message[100];
|
||||
for (auto &mod : mods.of_type(module_type::program)) {
|
||||
auto &prog = static_cast<const module_program&>(mod);
|
||||
sprintf(message, " program module '%s' at %lx", prog.filename, prog.base_address);
|
||||
|
||||
char message[100];
|
||||
sprintf(message, " loading program module '%s' at %lx", prog.filename, prog.base_address);
|
||||
j6_log(message);
|
||||
|
||||
if (!load_program(prog, message)) {
|
||||
j6_log(message);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "j6/types.h"
|
||||
#include "j6/errors.h"
|
||||
#include "j6/flags.h"
|
||||
#include "j6/signals.h"
|
||||
#include "j6/syscalls.h"
|
||||
|
||||
@@ -17,6 +18,11 @@ extern "C" {
|
||||
int main(int, const char **);
|
||||
}
|
||||
|
||||
constexpr j6_handle_t handle_self = 1; // Self program handle is always 1
|
||||
|
||||
constexpr size_t stack_size = 0x10000;
|
||||
constexpr uintptr_t stack_top = 0xf80000000;
|
||||
|
||||
void
|
||||
thread_proc()
|
||||
{
|
||||
@@ -52,7 +58,6 @@ thread_proc()
|
||||
int
|
||||
main(int argc, const char **argv)
|
||||
{
|
||||
j6_handle_t children[2] = {j6_handle_invalid, j6_handle_invalid};
|
||||
j6_signal_t out = 0;
|
||||
|
||||
j6_log("main thread starting");
|
||||
@@ -76,7 +81,13 @@ main(int argc, const char **argv)
|
||||
|
||||
j6_log("main thread created endpoint");
|
||||
|
||||
result = j6_thread_create(&children[1], reinterpret_cast<uintptr_t>(&thread_proc));
|
||||
j6_handle_t child_stack_vma = j6_handle_invalid;
|
||||
result = j6_vma_create_map(&child_stack_vma, stack_size, stack_top-stack_size, j6_vm_flag_write);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
j6_handle_t child = j6_handle_invalid;
|
||||
result = j6_thread_create(&child, handle_self, stack_top, reinterpret_cast<uintptr_t>(&thread_proc));
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
@@ -98,29 +109,20 @@ main(int argc, const char **argv)
|
||||
|
||||
j6_log(message);
|
||||
|
||||
j6_log("main thread creating a new process");
|
||||
result = j6_process_create(&children[0]);
|
||||
j6_log("main thread waiting on sub thread");
|
||||
|
||||
result = j6_kobject_wait(child, -1ull, &out);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
j6_log("main thread waiting on children");
|
||||
j6_log("main setting IOPL");
|
||||
|
||||
j6_handle_t outhandle;
|
||||
result = j6_kobject_wait_many(children, 2, -1ull, &outhandle, &out);
|
||||
result = j6_system_request_iopl(__handle_sys, 3);
|
||||
if (result != j6_status_ok)
|
||||
return result;
|
||||
|
||||
if (outhandle == children[1]) {
|
||||
j6_log(" ok from child thread");
|
||||
} else if (outhandle == children[0]) {
|
||||
j6_log(" ok from child process");
|
||||
} else {
|
||||
j6_log(" ... got unknown handle");
|
||||
}
|
||||
|
||||
j6_log("main testing irqs");
|
||||
|
||||
|
||||
serial_port com2(COM2);
|
||||
|
||||
const char *fgseq = "\x1b[2J";
|
||||
|
||||
Reference in New Issue
Block a user