Loading processes from within their memory space

The scheduler's create_process now sets up the stack to iretq into a
load_process function, which will load the process image into memory
from within the process' own virtual memory space. Currently this
loading is just copying the old 'taskA' function from kernel space.
This commit is contained in:
Justin C. Miller
2018-09-05 10:09:00 -07:00
parent f1b84ab370
commit 5d861d243a
2 changed files with 86 additions and 28 deletions

View File

@@ -192,9 +192,24 @@ syscall_enable:
mov rdx, 0 mov rdx, 0
wrmsr wrmsr
ret ret
extern load_process
global ramdisk_process_loader
ramdisk_process_loader:
; create_process already pushed a cpu_state onto the stack for us, this
; acts both as the cpu_state parameter to load_process, and the saved
; state for the following iretq
mov rdi, rax
mov rsi, rbx
call load_process
pop_all_and_segments
add rsp, 16 ; because the ISRs add err/num
iretq
global taskA global taskA
taskA: taskA:
push rbp push rbp
@@ -205,12 +220,5 @@ taskA:
syscall syscall
jmp .loop jmp .loop
global taskB global taskAend
taskB: taskAend:
push rbp
mov rbp, rsp
mov rax, 0xbbbbbbbbbbbbbbbb
.loop:
syscall
jmp .loop

View File

@@ -12,10 +12,16 @@ scheduler scheduler::s_instance(nullptr);
static const uint32_t quantum = 20000000; static const uint32_t quantum = 20000000;
const int stack_size = 0x1000; const int stack_size = 0x1000;
const uint64_t rflags_noint = 0x002;
const uint64_t rflags_int = 0x202;
extern "C" void taskA(); extern "C" {
extern "C" void taskB(); void taskA();
void taskAend();
void ramdisk_process_loader();
void load_process(void *copy_start, size_t butes, cpu_state state);
};
scheduler::scheduler(lapic *apic) : scheduler::scheduler(lapic *apic) :
m_apic(apic), m_apic(apic),
@@ -24,8 +30,30 @@ scheduler::scheduler(lapic *apic) :
m_processes.ensure_capacity(50); m_processes.ensure_capacity(50);
} }
void
load_process(void *copy_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:");
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 static process
create_process(uint16_t pid, void (*rip)()) create_process(uint16_t pid)
{ {
uint64_t flags; uint64_t flags;
__asm__ __volatile__ ( "pushf; pop %0" : "=r" (flags) ); __asm__ __volatile__ ( "pushf; pop %0" : "=r" (flags) );
@@ -36,25 +64,47 @@ create_process(uint16_t pid, void (*rip)())
uint16_t kss = (2 << 3) | 0; // Kernel SS is GDT entry 2, ring 0 uint16_t kss = (2 << 3) | 0; // Kernel SS is GDT entry 2, ring 0
uint16_t ss = (4 << 3) | 3; // User SS is GDT entry 4, ring 3 uint16_t ss = (4 << 3) | 3; // User SS is GDT entry 4, ring 3
void *stack0 = kutil::malloc(stack_size); // Set up the page tables - this also allocates an initial user stack
void *sp0 = kutil::offset_pointer(stack0, stack_size); page_table *pml4 = page_manager::get()->create_process_map();
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
kutil::memset(state, 0, sizeof(cpu_state));
// Create a one-page kernel stack space
void *stack0 = kutil::malloc(stack_size);
kutil::memset(stack0, 0, stack_size);
// Stack grows down, point to the end
void *sp0 = kutil::offset_pointer(stack0, stack_size);
cpu_state *state = reinterpret_cast<cpu_state *>(sp0) - 1;
// Highest state in the stack is the process' kernel stack for the loader
// to iret to:
state->ds = state->ss = ss; state->ds = state->ss = ss;
state->cs = cs; state->cs = cs;
state->rflags = 0x202; state->rflags = rflags_int;
state->rip = reinterpret_cast<uint64_t>(rip); state->rip = 0; // to be filled by the loader
page_table *pml4 = page_manager::get()->create_process_map();
state->user_rsp = page_manager::initial_stack; state->user_rsp = page_manager::initial_stack;
log::debug(logs::task, "Creating PID %d:", pid); // Next state in the stack is the loader's kernel stack. The scheduler will
log::debug(logs::task, " RSP0 %016lx", state); // iret to this which will kick off the loading:
log::debug(logs::task, " RSP3 %016lx", state->user_rsp); cpu_state *loader_state = reinterpret_cast<cpu_state *>(sp0) - 2;
log::debug(logs::task, " PML4 %016lx", pml4);
return {pid, reinterpret_cast<addr_t>(state), pml4}; loader_state->ds = loader_state->ss = kss;
loader_state->cs = kcs;
loader_state->rflags = rflags_noint;
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);
log::debug(logs::task, "Creating 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};
} }
void void
@@ -65,8 +115,8 @@ scheduler::start()
m_apic->enable_timer(isr::isrTimer, 128, quantum, false); 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({0, 0, page_manager::get_pml4()}); // The kernel idle task, also the thread we're in now
m_processes.append(create_process(1, &taskA)); m_processes.append(create_process(1));
m_processes.append(create_process(2, &taskB)); //m_processes.append(create_process(2, &taskB));
} }
addr_t addr_t