From 24ccf65aba908391128fc84b1e91ba70ccdcb161 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Sun, 20 May 2018 01:03:04 -0700 Subject: [PATCH] WIP ring3 --- src/kernel/interrupts.cpp | 34 ++++++++++++++ src/kernel/interrupts.s | 97 +++++++++++++++++++++++++++++++++++++++ src/kernel/main.cpp | 3 +- src/kernel/scheduler.cpp | 50 ++++++++++---------- 4 files changed, 158 insertions(+), 26 deletions(-) diff --git a/src/kernel/interrupts.cpp b/src/kernel/interrupts.cpp index a8696e4..7ea9a0d 100644 --- a/src/kernel/interrupts.cpp +++ b/src/kernel/interrupts.cpp @@ -12,6 +12,7 @@ extern "C" { addr_t isr_handler(addr_t, cpu_state); void irq_handler(cpu_state); + void syscall_handler(cpu_state); #define ISR(i, name) extern void name (); #define EISR(i, name) extern void name (); @@ -322,3 +323,36 @@ irq_handler(cpu_state regs) *reinterpret_cast(0xffffff80fee000b0) = 0; } +void +syscall_handler(cpu_state regs) +{ + console *cons = console::get(); + cons->printf("SYSCALL\n"); + + cons->puts("\n"); + print_reg("rax", regs.rax); + print_reg("rbx", regs.rbx); + print_reg("rcx", regs.rcx); + print_reg("rdx", regs.rdx); + print_reg("rdi", regs.rdi); + print_reg("rsi", regs.rsi); + + cons->puts("\n"); + print_reg(" r8", regs.r8); + print_reg(" r9", regs.r9); + print_reg("r10", regs.r10); + print_reg("r11", regs.r11); + print_reg("r12", regs.r12); + print_reg("r13", regs.r13); + print_reg("r14", regs.r14); + print_reg("r15", regs.r15); + + cons->puts("\n"); + print_reg("rbp", regs.rbp); + print_reg("rsp", regs.user_rsp); + print_reg("sp0", tss_get_stack(0)); + + cons->puts("\n"); + print_reg("rip", regs.rip); + +} diff --git a/src/kernel/interrupts.s b/src/kernel/interrupts.s index 129ebc0..2796de1 100644 --- a/src/kernel/interrupts.s +++ b/src/kernel/interrupts.s @@ -150,3 +150,100 @@ irq_handler_prelude: section .isrs %include "interrupt_isrs.inc" + +extern syscall_handler +syscall_handler_prelude: + push 0 ; ss, doesn't matter here + push rsp + pushf + push 0 ; cs, doesn't matter here + push rcx ; user rip + push 0 ; bogus interrupt + push 0 ; bogus errorcode + push_all_and_segments + + call syscall_handler + + pop_all_and_segments + add rsp, 16 ; ignore bogus interrupt / error + pop rcx ; user rip + add rsp, 32 ; ignore cs, flags, rsp, ss + + o64 sysret + +global syscall_enable +syscall_enable: + ; IA32_EFER - set bit 0, syscall enable + mov rcx, 0xc0000080 + rdmsr + or rax, 0x1 + wrmsr + + ; IA32_STAR - cs for syscall + mov rcx, 0xc0000081 + mov rax, 0 ; not used + mov rdx, 0x00180008 ; GDT:3 (user code), GDT:1 (kernel code) + wrmsr + + ; IA32_LSTAR - RIP for syscall + mov rcx, 0xc0000082 + lea rax, [rel syscall_handler_prelude] + mov rdx, rax + shr rdx, 32 + wrmsr + + ; IA32_FMASK - FLAGS mask inside syscall + mov rcx, 0xc0000084 + mov rax, 0x200 + mov rdx, 0 + wrmsr + + + ret + +global taskA +taskA: + push rbp + mov rbp, rsp + push 0x123456789abcdef0 + push 0x0fedcba987654321 + +.loop: + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + syscall + nop + nop + nop + nop + nop + nop + jmp .loop diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index 23961e3..50c26b4 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -20,8 +20,8 @@ #include "serial.h" extern "C" { - void do_the_set_registers(popcorn_data *header); void kernel_main(popcorn_data *header); + void syscall_enable(); void *__bss_start, *__bss_end; } @@ -135,6 +135,7 @@ kernel_main(popcorn_data *header) // pager->dump_pml4(); + syscall_enable(); scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic()); sched->start(); diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index a8409d5..f2ea537 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -10,25 +10,18 @@ scheduler scheduler::s_instance(nullptr); static const uint32_t quantum = 5000000; const int stack_size = 0x1000; -char taskAstack[stack_size]; -char taskBstack[stack_size]; +char taskAstack0[stack_size]; +char taskAstack3[stack_size]; +char taskBstack0[stack_size]; +char taskBstack3[stack_size]; uint64_t taskAcount = 0; -void taskA() -{ - console *cons = console::get(); - while(1) { - cons->putc('.'); - } -} +extern "C" void taskA(); void taskB() { - console *cons = console::get(); - while(1) { - cons->putc('+'); - } + while (1); } @@ -40,7 +33,7 @@ scheduler::scheduler(lapic *apic) : } static process -create_process(uint16_t pid, void *stack, void (*rip)()) +create_process(uint16_t pid, void *stack0, void *stack3, void (*rip)()) { uint64_t flags; __asm__ __volatile__ ( "pushf; pop %0" : "=r" (flags) ); @@ -48,21 +41,26 @@ create_process(uint16_t pid, void *stack, void (*rip)()) // This is a hack for now, until we get a lot more set up. // I just want to see task switching working inside ring0 first uint16_t kcs = (1 << 3) | 0; - uint16_t cs = (3 << 3) | 3; + uint16_t cs = (5 << 3) | 3; uint16_t kss = (2 << 3) | 0; uint16_t ss = (4 << 3) | 3; - void *sp = kutil::offset_pointer(stack, stack_size); - cpu_state *state = reinterpret_cast(sp) - 1; + void *sp0 = kutil::offset_pointer(stack0, stack_size); + cpu_state *state = reinterpret_cast(sp0) - 1; kutil::memset(state, 0, sizeof(cpu_state)); - state->ds = state->ss = kss; - state->cs = kcs; - state->rflags = 0x202; - state->user_rsp = reinterpret_cast(sp); + + state->ds = state->ss = ss; + state->cs = cs; + state->rflags = 0x202; // testing. TODO: 0x202 state->rip = reinterpret_cast(rip); - log::debug(logs::task, "Creating a user RSP of %016lx", state->user_rsp); + void *sp3 = kutil::offset_pointer(stack3, stack_size); + state->user_rsp = reinterpret_cast(sp3); + + log::debug(logs::task, "Creating PID %d:", pid); + log::debug(logs::task, " RSP0 %016lx", state); + log::debug(logs::task, " RSP3 %016lx", sp3); return {pid, reinterpret_cast(state)}; } @@ -73,8 +71,8 @@ scheduler::start() m_apic->enable_timer(isr::isrTimer, 128, quantum, false); m_processes.append({0, 0}); // The kernel idle task - m_processes.append(create_process(1, &taskAstack[0], &taskA)); - m_processes.append(create_process(2, &taskBstack[0], &taskB)); + m_processes.append(create_process(1, &taskAstack0[0], &taskAstack3[0], &taskA)); + m_processes.append(create_process(2, &taskBstack0[0], &taskBstack3[0], &taskB)); } addr_t @@ -85,7 +83,9 @@ scheduler::tick(addr_t rsp0) m_processes[m_current].rsp = rsp0; m_current = (m_current + 1) % m_processes.count(); rsp0 = m_processes[m_current].rsp; - tss_set_stack(0, rsp0); + + // Set rsp0 to after the end of the about-to-be-popped cpu state + tss_set_stack(0, rsp0 + sizeof(cpu_state)); m_apic->reset_timer(quantum); return rsp0;