Simple ELF program loader

Now any initrd file is treated like a program image and passed to the
loader to load as a process. Very rudimentary elf loading just allocates
pages, copies sections, and sets the ELF's entrypoint as the RIP to
iretq to.
This commit is contained in:
Justin C. Miller
2018-09-06 01:31:47 -07:00
parent 3d0b262435
commit 585abe9a18
13 changed files with 321 additions and 51 deletions

View File

@@ -7,6 +7,9 @@
#include "page_manager.h"
#include "scheduler.h"
#include "elf/elf.h"
#include "kutil/assert.h"
scheduler scheduler::s_instance(nullptr);
//static const uint32_t quantum = 2000000;
static const uint32_t quantum = 20000000;
@@ -16,43 +19,83 @@ const uint64_t rflags_noint = 0x002;
const uint64_t rflags_int = 0x202;
extern "C" {
void taskA();
void taskAend();
void ramdisk_process_loader();
void load_process(void *copy_start, size_t butes, cpu_state state);
void load_process(const void *image_start, size_t butes, cpu_state state);
};
scheduler::scheduler(lapic *apic) :
m_apic(apic),
m_current(0)
m_current(0),
m_next_pid(0)
{
m_processes.ensure_capacity(50);
m_processes.append({m_next_pid++, 0, page_manager::get_pml4()}); // The kernel idle task, also the thread we're in now
}
void
load_process(void *copy_start, size_t bytes, cpu_state state)
load_process(const void *image_start, size_t bytes, cpu_state state)
{
log::debug(logs::task, "Loading task! Start: %016lx [%d]", copy_start, bytes);
log::debug(logs::task, "New process state:");
// We're now in the process space for this process, allocate memory for the
// process code and load it
page_manager *pager = page_manager::get();
log::debug(logs::task, "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");
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;
addr_t aligned = header->vaddr & ~(page_manager::page_size - 1);
size_t size = (header->vaddr + header->mem_size) - aligned;
size_t pages = page_manager::page_count(size);
log::debug(logs::task, " Loadable segment %02d: vaddr %016lx size %016lx",
i, header->vaddr, header->mem_size);
log::debug(logs::task, " - aligned to: vaddr %016lx pages %d",
aligned, pages);
void *mapped = pager->map_pages(aligned, pages, true);
kassert(mapped, "Tried to map userspace pages and failed!");
kutil::memset(mapped, 0, pages * page_manager::page_size);
}
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::task, " Loadable section %u: 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);
}
state.rip = image.entrypoint();
log::debug(logs::task, "Loaded! New process state:");
log::debug(logs::task, " CS: %d [%d]", state.cs >> 3, state.cs & 0x07);
log::debug(logs::task, " SS: %d [%d]", state.ss >> 3, state.ss & 0x07);
log::debug(logs::task, " RFLAGS: %08x", state.rflags);
log::debug(logs::task, " RIP: %016lx", state.rip);
log::debug(logs::task, " uRSP: %016lx", state.user_rsp);
// We're now in the process space for this process, allocate memory for the
// process code and load it
page_manager *pager = page_manager::get();
size_t count = ((bytes - 1) / page_manager::page_size) + 1;
void *loading = pager->map_pages(0x200000, count, true);
kutil::memcpy(loading, copy_start, bytes);
state.rip = reinterpret_cast<uint64_t>(loading);
}
static process
create_process(uint16_t pid)
void
scheduler::create_process(const char *name, const void *data, size_t size)
{
uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0
uint16_t cs = (5 << 3) | 3; // User CS is GDT entry 5, ring 3
@@ -90,29 +133,25 @@ create_process(uint16_t pid)
loader_state->rip = reinterpret_cast<uint64_t>(ramdisk_process_loader);
loader_state->user_rsp = reinterpret_cast<uint64_t>(state);
// TODO: replace with an actual ELF location in memory
loader_state->rax = reinterpret_cast<uint64_t>(taskA);
loader_state->rbx = reinterpret_cast<uint64_t>(taskAend) - reinterpret_cast<uint64_t>(taskA);
loader_state->rax = reinterpret_cast<uint64_t>(data);
loader_state->rbx = size;
log::debug(logs::task, "Creating PID %d:", pid);
uint16_t pid = m_next_pid++;
log::debug(logs::task, "Creating process %s:", name);
log::debug(logs::task, " PID %d", pid);
log::debug(logs::task, " RSP0 %016lx", state);
log::debug(logs::task, " RSP3 %016lx", state->user_rsp);
log::debug(logs::task, " PML4 %016lx", pml4);
log::debug(logs::task, " Loading %016lx [%d]", loader_state->rax, loader_state->rbx);
return {pid, reinterpret_cast<addr_t>(loader_state), pml4};
m_processes.append({pid, reinterpret_cast<addr_t>(loader_state), pml4});
}
void
scheduler::start()
{
log::info(logs::task, "Starting scheduler.");
m_apic->enable_timer(isr::isrTimer, 128, quantum, false);
m_processes.append({0, 0, page_manager::get_pml4()}); // The kernel idle task, also the thread we're in now
m_processes.append(create_process(1));
//m_processes.append(create_process(2, &taskB));
}
addr_t