[boot][kernel] Split programs into sections

To enable setting sections as NX or read-only, the boot program loader
now loads programs as lists of sections, and the kernel args are updated
accordingly. The kernel's loader now just takes a program pointer to
iterate the sections. Also enable NX in IA32_EFER in the bootloader.
This commit is contained in:
Justin C. Miller
2021-01-20 01:25:47 -08:00
parent 14aad62e02
commit cb612c36ea
13 changed files with 140 additions and 61 deletions

View File

@@ -8,11 +8,7 @@ preloaded_process_init:
; create_process already pushed the arguments for load_process_image and
; the following iretq onto the stack for us
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
pop rdi ; a pointer to the program descriptor
call load_process_image
; user rsp is now in rax, put it in the right place for iret

View File

@@ -192,8 +192,8 @@ kernel_main(args::header *header)
// Skip program 0, which is the kernel itself
for (size_t i = 1; i < header->num_programs; ++i) {
args::program &prog = header->programs[i];
thread *th = sched->load_process(prog.phys_addr, prog.virt_addr, prog.size, prog.entrypoint);
args::program *prog = memory::to_virtual(&header->programs[i]);
thread *th = sched->load_process(*prog);
if (i == 2) {
//th->set_state(thread::state::constant);
}

View File

@@ -34,7 +34,7 @@ const uint64_t rflags_int = 0x202;
extern "C" {
void preloaded_process_init();
uintptr_t load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb);
uintptr_t load_process_image(const kernel::args::program*);
};
extern uint64_t idle_stack_end;
@@ -76,20 +76,28 @@ inline T * push(uintptr_t &rsp, size_t size = sizeof(T)) {
}
uintptr_t
load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
load_process_image(const kernel::args::program *program)
{
using memory::page_align_down;
using memory::page_align_up;
using kernel::args::section_flags;
// We're now in the process space for this process, allocate memory for the
// process code and load it
process &proc = process::current();
thread &th = thread::current();
TCB *tcb = th.tcb();
vm_space &space = proc.space();
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));
for (const auto &sect : program->sections) {
vm_flags flags =
(bitfield_has(sect.type, section_flags::execute) ? vm_flags::exec : vm_flags::none) |
(bitfield_has(sect.type, section_flags::write) ? vm_flags::write : vm_flags::none);
vm_area *vma = new vm_area_open(sect.size, space, flags);
space.add(sect.virt_addr, vma);
vma->commit(sect.phys_addr, 0, memory::page_count(sect.size));
}
// double zero stack sentinel
*push<uint64_t>(tcb->rsp3) = 0;
@@ -141,7 +149,8 @@ load_process_image(uintptr_t phys, uintptr_t virt, size_t bytes, TCB *tcb)
// Crazypants framebuffer part
if (fb) {
vma = new vm_area_open(fb->size, space, vm_flags::write|vm_flags::mmio|vm_flags::write_combine);
vm_area *vma = new vm_area_open(fb->size, space,
vm_flags::write|vm_flags::mmio|vm_flags::write_combine);
space.add(0x100000000, vma);
vma->commit(fb->phys_addr, 0, memory::page_count(fb->size));
}
@@ -167,7 +176,7 @@ scheduler::create_process(bool user)
}
thread *
scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry)
scheduler::load_process(kernel::args::program &program)
{
uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0
@@ -180,23 +189,20 @@ scheduler::load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t e
auto *tcb = th->tcb();
// Create an initial kernel stack space
uintptr_t *stack = reinterpret_cast<uintptr_t *>(tcb->rsp0) - 9;
uintptr_t *stack = reinterpret_cast<uintptr_t *>(tcb->rsp0) - 6;
// 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);
stack[0] = reinterpret_cast<uintptr_t>(&program);
tcb->rsp = reinterpret_cast<uintptr_t>(stack);
th->add_thunk_kernel(reinterpret_cast<uintptr_t>(preloaded_process_init));
// Arguments for iret - rip will be pushed on before these
stack[4] = reinterpret_cast<uintptr_t>(entry);
stack[5] = cs;
stack[6] = rflags_int | (3 << 12);
stack[7] = process::stacks_top;
stack[8] = ss;
stack[1] = reinterpret_cast<uintptr_t>(program.entrypoint);
stack[2] = cs;
stack[3] = rflags_int | (3 << 12);
stack[4] = process::stacks_top;
stack[5] = ss;
tcb->rsp3 = process::stacks_top;

View File

@@ -5,6 +5,11 @@
#include <stdint.h>
#include "objects/thread.h"
namespace kernel {
namespace args {
struct program;
}}
class lapic;
class process;
struct page_table;
@@ -41,12 +46,9 @@ public:
scheduler(lapic *apic);
/// Create a new process from a program image in memory.
/// \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
/// \arg entry Virtual address of the program entrypoint
/// \returns The main thread of the loaded process
thread * load_process(uintptr_t phys, uintptr_t virt, size_t size, uintptr_t entry);
/// \arg program The descriptor of the pogram in memory
/// \returns The main thread of the loaded process
thread * load_process(kernel::args::program &program);
/// Create a new kernel task
/// \arg proc Function to run as a kernel task