diff --git a/src/kernel/interrupts.s b/src/kernel/interrupts.s index 2eb7fed..ee71b4f 100644 --- a/src/kernel/interrupts.s +++ b/src/kernel/interrupts.s @@ -192,9 +192,24 @@ syscall_enable: mov rdx, 0 wrmsr - 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 taskA: push rbp @@ -205,12 +220,5 @@ taskA: syscall jmp .loop -global taskB -taskB: - push rbp - mov rbp, rsp - mov rax, 0xbbbbbbbbbbbbbbbb - -.loop: - syscall - jmp .loop +global taskAend +taskAend: diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index 1734bea..25a681c 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -12,10 +12,16 @@ scheduler scheduler::s_instance(nullptr); static const uint32_t quantum = 20000000; const int stack_size = 0x1000; +const uint64_t rflags_noint = 0x002; +const uint64_t rflags_int = 0x202; -extern "C" void taskA(); -extern "C" void taskB(); +extern "C" { + void taskA(); + void taskAend(); + void ramdisk_process_loader(); + void load_process(void *copy_start, size_t butes, cpu_state state); +}; scheduler::scheduler(lapic *apic) : m_apic(apic), @@ -24,8 +30,30 @@ scheduler::scheduler(lapic *apic) : 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(loading); +} + static process -create_process(uint16_t pid, void (*rip)()) +create_process(uint16_t pid) { uint64_t 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 ss = (4 << 3) | 3; // User SS is GDT entry 4, ring 3 - void *stack0 = kutil::malloc(stack_size); - void *sp0 = kutil::offset_pointer(stack0, stack_size); - cpu_state *state = reinterpret_cast(sp0) - 1; - kutil::memset(state, 0, sizeof(cpu_state)); + // Set up the page tables - this also allocates an initial user stack + page_table *pml4 = page_manager::get()->create_process_map(); + // 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(sp0) - 1; + + // Highest state in the stack is the process' kernel stack for the loader + // to iret to: state->ds = state->ss = ss; state->cs = cs; - state->rflags = 0x202; - state->rip = reinterpret_cast(rip); - - page_table *pml4 = page_manager::get()->create_process_map(); + state->rflags = rflags_int; + state->rip = 0; // to be filled by the loader state->user_rsp = page_manager::initial_stack; - 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); + // Next state in the stack is the loader's kernel stack. The scheduler will + // iret to this which will kick off the loading: + cpu_state *loader_state = reinterpret_cast(sp0) - 2; - return {pid, reinterpret_cast(state), pml4}; + loader_state->ds = loader_state->ss = kss; + loader_state->cs = kcs; + loader_state->rflags = rflags_noint; + loader_state->rip = reinterpret_cast(ramdisk_process_loader); + loader_state->user_rsp = reinterpret_cast(state); + + // TODO: replace with an actual ELF location in memory + loader_state->rax = reinterpret_cast(taskA); + loader_state->rbx = reinterpret_cast(taskAend) - reinterpret_cast(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(loader_state), pml4}; } void @@ -65,8 +115,8 @@ scheduler::start() 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, &taskA)); - m_processes.append(create_process(2, &taskB)); + m_processes.append(create_process(1)); + //m_processes.append(create_process(2, &taskB)); } addr_t