mirror of
https://github.com/justinian/jsix.git
synced 2025-12-10 00:14:32 -08:00
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.
212 lines
6.4 KiB
C++
212 lines
6.4 KiB
C++
#include <utility>
|
|
|
|
#include "kernel_args.h"
|
|
#include "j6/init.h"
|
|
|
|
#include "kutil/assert.h"
|
|
#include "kutil/enum_bitfields.h"
|
|
#include "kutil/heap_allocator.h"
|
|
#include "kutil/no_construct.h"
|
|
|
|
#include "device_manager.h"
|
|
#include "frame_allocator.h"
|
|
#include "gdt.h"
|
|
#include "io.h"
|
|
#include "log.h"
|
|
#include "msr.h"
|
|
#include "objects/process.h"
|
|
#include "objects/thread.h"
|
|
#include "objects/system.h"
|
|
#include "objects/vm_area.h"
|
|
#include "vm_space.h"
|
|
|
|
using memory::heap_start;
|
|
using memory::kernel_max_heap;
|
|
|
|
namespace kernel {
|
|
namespace init {
|
|
is_bitfield(section_flags);
|
|
}}
|
|
|
|
using kernel::init::allocation_register;
|
|
using kernel::init::section_flags;
|
|
|
|
using namespace kernel;
|
|
|
|
extern "C" void initialize_main_thread();
|
|
extern "C" uintptr_t initialize_main_user_stack();
|
|
|
|
// These objects are initialized _before_ global constructors are called,
|
|
// so we don't want them to have global constructors at all, lest they
|
|
// overwrite the previous initialization.
|
|
static kutil::no_construct<kutil::heap_allocator> __g_kernel_heap_storage;
|
|
kutil::heap_allocator &g_kernel_heap = __g_kernel_heap_storage.value;
|
|
|
|
static kutil::no_construct<frame_allocator> __g_frame_allocator_storage;
|
|
frame_allocator &g_frame_allocator = __g_frame_allocator_storage.value;
|
|
|
|
static kutil::no_construct<vm_area_untracked> __g_kernel_heap_area_storage;
|
|
vm_area_untracked &g_kernel_heap_area = __g_kernel_heap_area_storage.value;
|
|
|
|
static kutil::no_construct<vm_area_guarded> __g_kernel_stacks_storage;
|
|
vm_area_guarded &g_kernel_stacks = __g_kernel_stacks_storage.value;
|
|
|
|
vm_area_guarded g_kernel_buffers {
|
|
memory::buffers_start,
|
|
memory::kernel_buffer_pages,
|
|
memory::kernel_max_buffers,
|
|
vm_flags::write};
|
|
|
|
void * operator new(size_t size) { return g_kernel_heap.allocate(size); }
|
|
void * operator new [] (size_t size) { return g_kernel_heap.allocate(size); }
|
|
void operator delete (void *p) noexcept { return g_kernel_heap.free(p); }
|
|
void operator delete [] (void *p) noexcept { return g_kernel_heap.free(p); }
|
|
|
|
namespace kutil {
|
|
void * kalloc(size_t size) { return g_kernel_heap.allocate(size); }
|
|
void kfree(void *p) { return g_kernel_heap.free(p); }
|
|
}
|
|
|
|
template <typename T>
|
|
uintptr_t
|
|
get_physical_page(T *p) {
|
|
return memory::page_align_down(reinterpret_cast<uintptr_t>(p));
|
|
}
|
|
|
|
void
|
|
memory_initialize_pre_ctors(init::args &kargs)
|
|
{
|
|
using kernel::init::frame_block;
|
|
|
|
page_table *kpml4 = static_cast<page_table*>(kargs.pml4);
|
|
|
|
new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap};
|
|
|
|
frame_block *blocks = reinterpret_cast<frame_block*>(memory::bitmap_start);
|
|
new (&g_frame_allocator) frame_allocator {blocks, kargs.frame_blocks.count};
|
|
|
|
// Mark all the things the bootloader allocated for us as used
|
|
allocation_register *reg = kargs.allocations;
|
|
while (reg) {
|
|
for (auto &alloc : reg->entries)
|
|
if (alloc.type != init::allocation_type::none)
|
|
g_frame_allocator.used(alloc.address, alloc.count);
|
|
reg = reg->next;
|
|
}
|
|
|
|
process *kp = process::create_kernel_process(kpml4);
|
|
vm_space &vm = kp->space();
|
|
|
|
vm_area *heap = new (&g_kernel_heap_area)
|
|
vm_area_untracked(kernel_max_heap, vm_flags::write);
|
|
|
|
vm.add(heap_start, heap);
|
|
|
|
vm_area *stacks = new (&g_kernel_stacks) vm_area_guarded {
|
|
memory::stacks_start,
|
|
memory::kernel_stack_pages,
|
|
memory::kernel_max_stacks,
|
|
vm_flags::write};
|
|
vm.add(memory::stacks_start, &g_kernel_stacks);
|
|
|
|
// Clean out any remaning bootloader page table entries
|
|
for (unsigned i = 0; i < memory::pml4e_kernel; ++i)
|
|
kpml4->entries[i] = 0;
|
|
}
|
|
|
|
void
|
|
memory_initialize_post_ctors(init::args &kargs)
|
|
{
|
|
vm_space &vm = vm_space::kernel_space();
|
|
vm.add(memory::buffers_start, &g_kernel_buffers);
|
|
|
|
g_frame_allocator.free(
|
|
get_physical_page(kargs.page_tables.pointer),
|
|
kargs.page_tables.count);
|
|
}
|
|
|
|
static void
|
|
log_mtrrs()
|
|
{
|
|
uint64_t mtrrcap = rdmsr(msr::ia32_mtrrcap);
|
|
uint64_t mtrrdeftype = rdmsr(msr::ia32_mtrrdeftype);
|
|
unsigned vcap = mtrrcap & 0xff;
|
|
log::debug(logs::boot, "MTRRs: vcap=%d %s %s def=%02x %s %s",
|
|
vcap,
|
|
(mtrrcap & (1<< 8)) ? "fix" : "",
|
|
(mtrrcap & (1<<10)) ? "wc" : "",
|
|
mtrrdeftype & 0xff,
|
|
(mtrrdeftype & (1<<10)) ? "fe" : "",
|
|
(mtrrdeftype & (1<<11)) ? "enabled" : ""
|
|
);
|
|
|
|
for (unsigned i = 0; i < vcap; ++i) {
|
|
uint64_t base = rdmsr(find_mtrr(msr::ia32_mtrrphysbase, i));
|
|
uint64_t mask = rdmsr(find_mtrr(msr::ia32_mtrrphysmask, i));
|
|
log::debug(logs::boot, " vcap[%2d] base:%016llx mask:%016llx type:%02x %s", i,
|
|
(base & ~0xfffull),
|
|
(mask & ~0xfffull),
|
|
(base & 0xff),
|
|
(mask & (1<<11)) ? "valid" : "");
|
|
}
|
|
|
|
msr mtrr_fixed[] = {
|
|
msr::ia32_mtrrfix64k_00000,
|
|
msr::ia32_mtrrfix16k_80000,
|
|
msr::ia32_mtrrfix16k_a0000,
|
|
msr::ia32_mtrrfix4k_c0000,
|
|
msr::ia32_mtrrfix4k_c8000,
|
|
msr::ia32_mtrrfix4k_d0000,
|
|
msr::ia32_mtrrfix4k_d8000,
|
|
msr::ia32_mtrrfix4k_e0000,
|
|
msr::ia32_mtrrfix4k_e8000,
|
|
msr::ia32_mtrrfix4k_f0000,
|
|
msr::ia32_mtrrfix4k_f8000,
|
|
};
|
|
|
|
for (int i = 0; i < 11; ++i) {
|
|
uint64_t v = rdmsr(mtrr_fixed[i]);
|
|
log::debug(logs::boot, " fixed[%2d] %02x %02x %02x %02x %02x %02x %02x %02x", i,
|
|
((v << 0) & 0xff), ((v << 8) & 0xff), ((v << 16) & 0xff), ((v << 24) & 0xff),
|
|
((v << 32) & 0xff), ((v << 40) & 0xff), ((v << 48) & 0xff), ((v << 56) & 0xff));
|
|
}
|
|
|
|
uint64_t pat = rdmsr(msr::ia32_pat);
|
|
static const char *pat_names[] = {"UC ","WC ","XX ","XX ","WT ","WP ","WB ","UC-"};
|
|
log::debug(logs::boot, " PAT: 0:%s 1:%s 2:%s 3:%s 4:%s 5:%s 6:%s 7:%s",
|
|
pat_names[(pat >> (0*8)) & 7], pat_names[(pat >> (1*8)) & 7],
|
|
pat_names[(pat >> (2*8)) & 7], pat_names[(pat >> (3*8)) & 7],
|
|
pat_names[(pat >> (4*8)) & 7], pat_names[(pat >> (5*8)) & 7],
|
|
pat_names[(pat >> (6*8)) & 7], pat_names[(pat >> (7*8)) & 7]);
|
|
}
|
|
|
|
|
|
void
|
|
load_init_server(init::program &program, uintptr_t modules_address)
|
|
{
|
|
process *p = new process;
|
|
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) |
|
|
((sect.type && section_flags::write) ? vm_flags::write : vm_flags::none);
|
|
|
|
vm_area *vma = new vm_area_fixed(sect.phys_addr, sect.size, flags);
|
|
space.add(sect.virt_addr, vma);
|
|
}
|
|
|
|
uint64_t iopl = (3ull << 12);
|
|
|
|
thread *main = p->create_thread();
|
|
main->add_thunk_user(program.entrypoint, 0, iopl);
|
|
main->set_state(thread::state::ready);
|
|
|
|
// 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;
|
|
}
|