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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user