[srv.init] Create init server and read init args

Create a new usermode program, srv.init, and have it read the initial
module_page args sent to it by the bootloader. Doesn't yet do anything
useful but sets up the way for loading the rest of the programs from
srv.init.

Other (mostly) related changes:

- bootloader: The allocator now has a function for allocating init
  modules out of a modules_page slab. Also changed how the allocator is
  initialized and passes the allocation register and modules_page list
  to efi_main().
- bootloader: Expose the simple wstrlen() to the rest of the program
- bootloader: Move check_cpu_supported() to hardware.cpp
- bootloader: Moved program_desc to loader.h and made the loader
  functions take it as an argument instead of paths.
- kernel: Rename the system_map_mmio syscall to system_map_phys, and
  stop having it default those VMAs to having the vm_flags::mmio flag.
  Added a new flag mask, vm_flags::driver_mask, so that drivers can be
  allowed to ask for the MMIO flag.
- kernel: Rename load_simple_process() to load_init_server() and got rid
  of all the stack setup routines in memory_bootstrap.cpp and task.s
- Fixed formatting in config/debug.toml, undefined __linux and other
  linux-specific defines, and got rid of _LIBCPP_HAS_THREAD_API_EXTERNAL
  because that's just not true.
This commit is contained in:
Justin C. Miller
2021-07-31 10:00:08 -07:00
parent 1802c5ea2e
commit 5524ca5b25
28 changed files with 464 additions and 270 deletions

View File

@@ -53,7 +53,7 @@ static bool scheduler_ready = false;
/// Bootstrap the memory managers.
void memory_initialize_pre_ctors(init::args &kargs);
void memory_initialize_post_ctors(init::args &kargs);
process * load_simple_process(init::program &program);
void load_init_server(init::program &program, uintptr_t modules_address);
unsigned start_aps(lapic &apic, const kutil::vector<uint8_t> &ids, void *kpml4);
@@ -128,17 +128,8 @@ kernel_main(init::args *args)
cpu->tss->create_ist_stacks(cpu->idt->used_ist_entries());
for (size_t i = 0; i < args->modules.count; ++i) {
init::module &mod = args->modules[i];
switch (mod.type) {
case init::mod_type::symbol_table:
new symbol_table {mod.location, mod.size};
break;
default:
break;
}
if (args->symbol_table.count) {
new symbol_table {args->symbol_table.pointer, args->symbol_table.count};
}
syscall_initialize();
@@ -193,10 +184,8 @@ kernel_main(init::args *args)
scheduler *sched = new scheduler {num_cpus};
scheduler_ready = true;
// Skip program 0, which is the kernel itself
for (unsigned i = 1; i < args->programs.count; ++i)
load_simple_process(args->programs[i]);
// Load the init server
load_init_server(*args->init, args->modules);
sched->create_kernel_task(logger_task, scheduler::max_priority/2, true);
sched->start();

View File

@@ -181,12 +181,13 @@ log_mtrrs()
}
process *
load_simple_process(init::program &program)
void
load_init_server(init::program &program, uintptr_t modules_address)
{
process *p = new process;
vm_space &space = p->space();
p->add_handle(&system::get());
vm_space &space = p->space();
for (const auto &sect : program.sections) {
vm_flags flags =
((sect.type && section_flags::execute) ? vm_flags::exec : vm_flags::none) |
@@ -197,64 +198,14 @@ load_simple_process(init::program &program)
}
uint64_t iopl = (3ull << 12);
uintptr_t trampoline = reinterpret_cast<uintptr_t>(initialize_main_thread);
thread *main = p->create_thread();
main->add_thunk_user(program.entrypoint, trampoline, iopl);
main->add_thunk_user(program.entrypoint, 0, iopl);
main->set_state(thread::state::ready);
return p;
}
template <typename T>
inline T * push(uintptr_t &rsp, size_t size = sizeof(T)) {
rsp -= size;
T *p = reinterpret_cast<T*>(rsp);
rsp &= ~(sizeof(uint64_t)-1); // Align the stack
return p;
}
uintptr_t
initialize_main_user_stack()
{
process &proc = process::current();
thread &th = thread::current();
TCB *tcb = th.tcb();
const char message[] = "Hello from the kernel!";
char *message_arg = push<char>(tcb->rsp3, sizeof(message));
kutil::memcpy(message_arg, message, sizeof(message));
j6_init_value *initv = nullptr;
unsigned n = 0;
initv = push<j6_init_value>(tcb->rsp3);
initv->type = j6_init_handle_other;
initv->handle.type = j6_object_type_system;
initv->handle.handle = proc.add_handle(&system::get());
++n;
initv = push<j6_init_value>(tcb->rsp3);
initv->type = j6_init_handle_self;
initv->handle.type = j6_object_type_process;
initv->handle.handle = proc.self_handle();
++n;
initv = push<j6_init_value>(tcb->rsp3);
initv->type = j6_init_handle_self;
initv->handle.type = j6_object_type_thread;
initv->handle.handle = th.self_handle();
++n;
uint64_t *initc = push<uint64_t>(tcb->rsp3);
*initc = n;
char **argv0 = push<char*>(tcb->rsp3);
*argv0 = message_arg;
uint64_t *argc = push<uint64_t>(tcb->rsp3);
*argc = 1;
th.clear_state(thread::state::loading);
return tcb->rsp3;
// Hacky: No process exists to have created a stack for init; it needs to create
// its own stack. We take advantage of that to use rsp to pass it the init modules
// address.
auto *tcb = main->tcb();
tcb->rsp3 = modules_address;
}

View File

@@ -20,7 +20,8 @@ enum class vm_flags : uint32_t
#define VM_FLAG(name, v) name = v,
#include "j6/tables/vm_flags.inc"
#undef VM_FLAG
user_mask = 0x0000ffff ///< flags allowed via syscall
driver_mask = 0x000fffff, ///< flags allowed via syscall for drivers
user_mask = 0x0000ffff, ///< flags allowed via syscall for non-drivers
};

View File

@@ -2,6 +2,7 @@
#include "j6/types.h"
#include "device_manager.h"
#include "frame_allocator.h"
#include "log.h"
#include "objects/endpoint.h"
#include "objects/thread.h"
@@ -60,12 +61,17 @@ system_bind_irq(j6_handle_t sys, j6_handle_t endp, unsigned irq)
}
j6_status_t
system_map_mmio(j6_handle_t sys, j6_handle_t *vma_handle, uintptr_t phys_addr, size_t size, uint32_t flags)
system_map_phys(j6_handle_t sys, j6_handle_t *vma_handle, uintptr_t phys_addr, size_t size, uint32_t flags)
{
// TODO: check capabilities on sys handle
if (!vma_handle) return j6_err_invalid_arg;
vm_flags vmf = vm_flags::mmio | (static_cast<vm_flags>(flags) & vm_flags::user_mask);
// TODO: check to see if frames are already used? How would that collide with
// the bootloader's allocated pages already being marked used?
if (!(flags & vm_flags::mmio))
frame_allocator::get().used(phys_addr, memory::page_count(size));
vm_flags vmf = (static_cast<vm_flags>(flags) & vm_flags::driver_mask);
construct_handle<vm_area_fixed>(vma_handle, phys_addr, size, vmf);
return j6_status_ok;

View File

@@ -53,20 +53,6 @@ task_switch:
pop rbp
ret
extern initialize_main_user_stack
extern kernel_to_user_trampoline
global initialize_main_thread
initialize_main_thread:
call initialize_main_user_stack
; user rsp is now in rax, put it in the right place for sysret
mov [rsp + 0x30], rax
mov [gs:CPU_DATA.rsp3], rax
; the entrypoint should already be on the stack
jmp kernel_to_user_trampoline
global _current_gsbase
_current_gsbase:
mov rax, [gs:CPU_DATA.self]