[boot] Load programs in boot, not kernel
Remove ELF and initrd loading from the kernel. The bootloader now loads the initial programs, as it does with the kernel. Other files that were in the initrd are now on the ESP, and non-program files are just passed as modules.
This commit is contained in:
@@ -2,21 +2,20 @@
|
||||
|
||||
extern load_process_image
|
||||
|
||||
global ramdisk_process_loader
|
||||
ramdisk_process_loader:
|
||||
global preloaded_process_init
|
||||
preloaded_process_init:
|
||||
|
||||
; create_process already pushed a cpu_state onto the stack for us, this
|
||||
; acts both as the cpu_state parameter to load_process_image, and the
|
||||
; saved state for the following iretq
|
||||
; create_process already pushed the arguments for load_process_image and
|
||||
; the following iretq onto the stack for us
|
||||
|
||||
pop rdi ; the address of the program image
|
||||
pop rsi ; the size of the program image
|
||||
pop rdx ; the address of this thread's TCB
|
||||
pop rdi ; the physical address of the program image
|
||||
pop rsi ; the virtual address of the program image
|
||||
pop rdx ; the size in bytes of the program image
|
||||
pop rcx ; the address of this thread's TCB
|
||||
|
||||
call load_process_image
|
||||
|
||||
push rax ; load_process_image returns the process entrypoint
|
||||
|
||||
; the entrypoint should already be on the stack
|
||||
swapgs
|
||||
iretq
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "j6/signals.h"
|
||||
|
||||
#include "initrd/initrd.h"
|
||||
#include "kutil/assert.h"
|
||||
#include "apic.h"
|
||||
#include "block_device.h"
|
||||
@@ -117,56 +116,31 @@ kernel_main(args::header *header)
|
||||
cpu_id cpu;
|
||||
cpu.validate();
|
||||
|
||||
/*
|
||||
if (header->frame_buffer && header->frame_buffer_length) {
|
||||
page_manager::get()->map_offset_pointer(
|
||||
&header->frame_buffer,
|
||||
header->frame_buffer_length);
|
||||
for (size_t i = 0; i < header->num_modules; ++i) {
|
||||
args::module &mod = header->modules[i];
|
||||
switch (mod.type) {
|
||||
case args::mod_type::symbol_table:
|
||||
new symbol_table {mod.location, mod.size};
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
log::debug(logs::boot, " jsix header is at: %016lx", header);
|
||||
log::debug(logs::boot, " Memory map is at: %016lx", header->mem_map);
|
||||
log::debug(logs::boot, "ACPI root table is at: %016lx", header->acpi_table);
|
||||
log::debug(logs::boot, "Runtime service is at: %016lx", header->runtime_services);
|
||||
|
||||
// Load the module tagged as initrd
|
||||
kutil::vector<initrd::disk> initrds;
|
||||
for (unsigned i = 0; i < header->num_modules; ++i) {
|
||||
args::module &mod = header->modules[i];
|
||||
if (mod.type != args::mod_type::initrd)
|
||||
continue;
|
||||
|
||||
initrd::disk &ird = initrds.emplace(mod.location);
|
||||
log::info(logs::boot, "initrd loaded with %d files.", ird.files().count());
|
||||
for (auto &f : ird.files()) {
|
||||
char type = f.executable() ? '*' :
|
||||
f.symbols() ? '+' : ' ';
|
||||
log::info(logs::boot, " %c%s (%d bytes).", type, f.name(), f.size());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
page_manager::get()->dump_pml4(nullptr, 0);
|
||||
page_manager::get()->dump_blocks(true);
|
||||
*/
|
||||
|
||||
device_manager &devices = device_manager::get();
|
||||
devices.parse_acpi(header->acpi_table);
|
||||
|
||||
interrupts_enable();
|
||||
|
||||
/*
|
||||
auto r = cpu.get(0x15);
|
||||
log::info(logs::boot, "CPU Crystal: %dHz", r.ecx);
|
||||
|
||||
uintptr_t cr4 = 0;
|
||||
__asm__ __volatile__ ( "mov %%cr4, %0" : "=r" (cr4) );
|
||||
log::info(logs::boot, "cr4: %016x", cr4);
|
||||
*/
|
||||
|
||||
devices.init_drivers();
|
||||
|
||||
devices.get_lapic()->calibrate_timer();
|
||||
|
||||
/*
|
||||
block_device *disk = devices->get_block_device(0);
|
||||
if (disk) {
|
||||
@@ -191,22 +165,15 @@ kernel_main(args::header *header)
|
||||
}
|
||||
*/
|
||||
|
||||
devices.get_lapic()->calibrate_timer();
|
||||
devices.init_drivers();
|
||||
|
||||
syscall_enable();
|
||||
scheduler *sched = new scheduler(devices.get_lapic());
|
||||
|
||||
std_out = new channel;
|
||||
|
||||
for (auto &ird : initrds) {
|
||||
for (auto &f : ird.files()) {
|
||||
if (f.executable()) {
|
||||
sched->load_process(f.name(), f.data(), f.size());
|
||||
} else if (f.symbols()) {
|
||||
new symbol_table {f.data(), f.size()};
|
||||
}
|
||||
}
|
||||
// Skip program 0, which is the kernel itself
|
||||
for (size_t i = 1; i < header->num_programs; ++i) {
|
||||
args::program &prog = header->programs[i];
|
||||
sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint);
|
||||
}
|
||||
|
||||
sched->create_kernel_task(logger_task, scheduler::max_priority-1, true);
|
||||
|
||||
@@ -103,20 +103,19 @@ void walk_page_table(
|
||||
void
|
||||
memory_initialize_pre_ctors(args::header *kargs)
|
||||
{
|
||||
args::mem_entry *entries = kargs->mem_map;
|
||||
size_t entry_count = kargs->num_map_entries;
|
||||
page_table *kpml4 = reinterpret_cast<page_table*>(kargs->pml4);
|
||||
|
||||
new (&g_kernel_heap) kutil::heap_allocator {heap_start, kernel_max_heap};
|
||||
|
||||
new (&g_frame_allocator) frame_allocator;
|
||||
for (unsigned i = 0; i < entry_count; ++i) {
|
||||
|
||||
args::mem_entry *entries = kargs->mem_map;
|
||||
const size_t count = kargs->map_count;
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
// TODO: use entry attributes
|
||||
args::mem_entry &e = entries[i];
|
||||
if (e.type == args::mem_type::free)
|
||||
g_frame_allocator.free(e.start, e.pages);
|
||||
}
|
||||
|
||||
page_table *kpml4 = reinterpret_cast<page_table*>(kargs->pml4);
|
||||
process *kp = process::create_kernel_process(kpml4);
|
||||
vm_space &vm = kp->space();
|
||||
|
||||
@@ -153,7 +152,7 @@ memory_initialize_post_ctors(args::header *kargs)
|
||||
vm.add(memory::buffers_start, &g_kernel_buffers);
|
||||
|
||||
g_frame_allocator.free(
|
||||
reinterpret_cast<uintptr_t>(kargs->page_table_cache),
|
||||
kargs->num_free_tables);
|
||||
reinterpret_cast<uintptr_t>(kargs->page_tables),
|
||||
kargs->table_count);
|
||||
|
||||
}
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "objects/vm_area.h"
|
||||
#include "scheduler.h"
|
||||
|
||||
#include "elf/elf.h"
|
||||
#include "kutil/assert.h"
|
||||
|
||||
|
||||
@@ -26,8 +25,8 @@ const uint64_t rflags_noint = 0x002;
|
||||
const uint64_t rflags_int = 0x202;
|
||||
|
||||
extern "C" {
|
||||
void ramdisk_process_loader();
|
||||
uintptr_t load_process_image(const void *image_start, size_t bytes, TCB *tcb);
|
||||
void preloaded_process_init();
|
||||
void load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb);
|
||||
};
|
||||
|
||||
extern uint64_t idle_stack_end;
|
||||
@@ -60,8 +59,8 @@ scheduler::scheduler(lapic *apic) :
|
||||
bsp_cpu_data.t = idle;
|
||||
}
|
||||
|
||||
uintptr_t
|
||||
load_process_image(const void *image_start, size_t bytes, TCB *tcb)
|
||||
void
|
||||
load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
|
||||
{
|
||||
using memory::page_align_down;
|
||||
using memory::page_align_up;
|
||||
@@ -71,53 +70,9 @@ load_process_image(const void *image_start, size_t bytes, TCB *tcb)
|
||||
process &proc = process::current();
|
||||
vm_space &space = proc.space();
|
||||
|
||||
log::debug(logs::loader, "Loading task! ELF: %016lx [%d]", image_start, bytes);
|
||||
|
||||
// TODO: Handle bad images gracefully
|
||||
elf::elf image(image_start, bytes);
|
||||
kassert(image.valid(), "Invalid ELF passed to load_process_image");
|
||||
|
||||
uintptr_t vma_base = -1;
|
||||
uintptr_t vma_end = 0;
|
||||
|
||||
const unsigned program_count = image.program_count();
|
||||
for (unsigned i = 0; i < program_count; ++i) {
|
||||
const elf::program_header *header = image.program(i);
|
||||
|
||||
if (header->type != elf::segment_type::load)
|
||||
continue;
|
||||
|
||||
uintptr_t base = page_align_down(header->vaddr);
|
||||
uintptr_t end = page_align_up(header->vaddr + header->mem_size);
|
||||
if (base < vma_base) vma_base = base;
|
||||
if (end > vma_end) vma_end = end;
|
||||
|
||||
log::debug(logs::loader, " Loadable segment %02u: vaddr %016lx size %016lx",
|
||||
i, header->vaddr, header->mem_size);
|
||||
|
||||
log::debug(logs::loader, " - aligned to: vaddr %016lx pages %d",
|
||||
base, memory::page_count(end-base));
|
||||
}
|
||||
|
||||
vm_area *vma = new vm_area_open(vma_end - vma_base, space,
|
||||
vm_flags::zero|vm_flags::write);
|
||||
space.add(vma_base, vma);
|
||||
|
||||
const unsigned section_count = image.section_count();
|
||||
for (unsigned i = 0; i < section_count; ++i) {
|
||||
const elf::section_header *header = image.section(i);
|
||||
|
||||
if (header->type != elf::section_type::progbits ||
|
||||
!bitfield_has(header->flags, elf::section_flags::alloc))
|
||||
continue;
|
||||
|
||||
log::debug(logs::loader, " Loadable section %02u: vaddr %016lx size %016lx",
|
||||
i, header->addr, header->size);
|
||||
|
||||
void *dest = reinterpret_cast<void *>(header->addr);
|
||||
const void *src = kutil::offset_pointer(image_start, header->offset);
|
||||
kutil::memcpy(dest, src, header->size);
|
||||
}
|
||||
vm_area *vma = new vm_area_open(bytes, space, vm_flags::zero|vm_flags::write);
|
||||
space.add(virt, vma);
|
||||
vma->commit(phys, 0, memory::page_count(bytes));
|
||||
|
||||
tcb->rsp3 -= 2 * sizeof(uint64_t);
|
||||
uint64_t *sentinel = reinterpret_cast<uint64_t*>(tcb->rsp3);
|
||||
@@ -130,10 +85,6 @@ load_process_image(const void *image_start, size_t bytes, TCB *tcb)
|
||||
init->output = proc.add_handle(std_out);
|
||||
|
||||
thread::current().clear_state(thread::state::loading);
|
||||
|
||||
uintptr_t entrypoint = image.entrypoint();
|
||||
log::debug(logs::loader, " Loaded! New thread rip: %016lx", entrypoint);
|
||||
return entrypoint;
|
||||
}
|
||||
|
||||
thread *
|
||||
@@ -153,7 +104,7 @@ scheduler::create_process(bool user)
|
||||
}
|
||||
|
||||
void
|
||||
scheduler::load_process(const char *name, const void *data, size_t size)
|
||||
scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry)
|
||||
{
|
||||
|
||||
uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0
|
||||
@@ -166,25 +117,27 @@ scheduler::load_process(const char *name, const void *data, size_t size)
|
||||
auto *tcb = th->tcb();
|
||||
|
||||
// Create an initial kernel stack space
|
||||
uintptr_t *stack = reinterpret_cast<uintptr_t *>(tcb->rsp0) - 7;
|
||||
uintptr_t *stack = reinterpret_cast<uintptr_t *>(tcb->rsp0) - 9;
|
||||
|
||||
// Pass args to ramdisk_process_loader on the stack
|
||||
stack[0] = reinterpret_cast<uintptr_t>(data);
|
||||
stack[1] = reinterpret_cast<uintptr_t>(size);
|
||||
stack[2] = reinterpret_cast<uintptr_t>(tcb);
|
||||
// Pass args to preloaded_process_init on the stack
|
||||
stack[0] = reinterpret_cast<uintptr_t>(phys);
|
||||
stack[1] = reinterpret_cast<uintptr_t>(virt);
|
||||
stack[2] = reinterpret_cast<uintptr_t>(size);
|
||||
stack[3] = reinterpret_cast<uintptr_t>(tcb);
|
||||
|
||||
tcb->rsp = reinterpret_cast<uintptr_t>(stack);
|
||||
th->add_thunk_kernel(reinterpret_cast<uintptr_t>(ramdisk_process_loader));
|
||||
th->add_thunk_kernel(reinterpret_cast<uintptr_t>(preloaded_process_init));
|
||||
|
||||
// Arguments for iret - rip will be pushed on before these
|
||||
stack[3] = cs;
|
||||
stack[4] = rflags_int;
|
||||
stack[5] = process::stacks_top;
|
||||
stack[6] = ss;
|
||||
stack[4] = reinterpret_cast<uintptr_t>(entry);
|
||||
stack[5] = cs;
|
||||
stack[6] = rflags_int;
|
||||
stack[7] = process::stacks_top;
|
||||
stack[8] = ss;
|
||||
|
||||
tcb->rsp3 = process::stacks_top;
|
||||
|
||||
log::debug(logs::task, "Loading thread %s: koid %llx pri %d", name, th->koid(), tcb->priority);
|
||||
log::debug(logs::task, "Loading thread %llx pri %d", th->koid(), tcb->priority);
|
||||
log::debug(logs::task, " RSP %016lx", tcb->rsp);
|
||||
log::debug(logs::task, " RSP0 %016lx", tcb->rsp0);
|
||||
log::debug(logs::task, " PML4 %016lx", tcb->pml4);
|
||||
|
||||
@@ -41,10 +41,11 @@ public:
|
||||
scheduler(lapic *apic);
|
||||
|
||||
/// Create a new process from a program image in memory.
|
||||
/// \arg name Name of the program image
|
||||
/// \arg data Pointer to the image data
|
||||
/// \arg phys Physical address of the loaded program image
|
||||
/// \arg virt Virtual address of the loaded program image
|
||||
/// \arg size Size of the program image, in bytes
|
||||
void load_process(const char *name, const void *data, size_t size);
|
||||
/// \arg entry Virtual address of the program entrypoint
|
||||
void load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry);
|
||||
|
||||
/// Create a new kernel task
|
||||
/// \arg proc Function to run as a kernel task
|
||||
|
||||
Reference in New Issue
Block a user