[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:
@@ -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();
|
||||
|
||||
@@ -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 § : 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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user