diff --git a/src/drivers/nulldrv/main.s b/src/drivers/nulldrv/main.s index 0e27af5..da89422 100644 --- a/src/drivers/nulldrv/main.s +++ b/src/drivers/nulldrv/main.s @@ -1,11 +1,22 @@ global _start _start: xor rbp, rbp ; Sentinel rbp + mov r11, 0 ; counter .loop: - ;mov rax, 1 ; DEBUG syscall - mov rax, 0 ; NOOP syscall - syscall + mov rax, 1 ; DEBUG syscall + ;mov rax, 0 ; NOOP syscall + ;syscall + int 0xee + inc r11 + cmp r11, 5 + + jle .loop + + mov rax, 3 ; PAUSE syscall + ; syscall + int 0xee + + mov r11, 0 jmp .loop - diff --git a/src/kernel/cpu.cpp b/src/kernel/cpu.cpp index 60d0f90..6889e1a 100644 --- a/src/kernel/cpu.cpp +++ b/src/kernel/cpu.cpp @@ -52,6 +52,7 @@ cpu_id::cpu_id() } + cpu_id::regs cpu_id::get(uint32_t leaf, uint32_t sub) const { diff --git a/src/kernel/debug.cpp b/src/kernel/debug.cpp new file mode 100644 index 0000000..e5c4d6b --- /dev/null +++ b/src/kernel/debug.cpp @@ -0,0 +1,68 @@ +#include "console.h" +#include "cpu.h" +#include "debug.h" +#include "gdt.h" + +#define print_reg(name, value) cons->printf(" %s: %016lx\n", name, (value)); + +void +print_regs(const cpu_state ®s) +{ + console *cons = console::get(); + + 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(" ds", regs.ds); + print_reg(" cs", regs.cs); + print_reg(" ss", regs.ss); + + cons->puts("\n"); + print_reg("rip", regs.rip); +} + +void +print_stacktrace(int skip) +{ + console *cons = console::get(); + int frame = 0; + uint64_t bp = get_frame(skip); + while (bp) { + cons->printf(" frame %2d: %lx\n", frame, bp); + bp = get_frame(++frame + skip); + } +} + +void +print_stack(const cpu_state ®s) +{ + console *cons = console::get(); + + cons->puts("\nStack:\n"); + uint64_t sp = regs.user_rsp; + while (sp <= regs.rbp) { + cons->printf("%016x: %016x\n", sp, *reinterpret_cast(sp)); + sp += sizeof(uint64_t); + } +} + diff --git a/src/kernel/debug.h b/src/kernel/debug.h new file mode 100644 index 0000000..12c7289 --- /dev/null +++ b/src/kernel/debug.h @@ -0,0 +1,19 @@ +#pragma once +/// \file debug.h +/// Debugging utilities + +#include "kutil/memory.h" + +extern "C" { + addr_t get_rsp(); + addr_t get_rip(); + addr_t get_frame(int frame); + +} + +void print_regs(const cpu_state ®s); +void print_stack(const cpu_state ®s); +void print_stacktrace(int skip = 0); + +#define print_reg(name, value) cons->printf(" %s: %016lx\n", name, (value)); + diff --git a/src/kernel/interrupt_isrs.inc b/src/kernel/interrupt_isrs.inc index de04469..4917a4e 100644 --- a/src/kernel/interrupt_isrs.inc +++ b/src/kernel/interrupt_isrs.inc @@ -237,12 +237,13 @@ IRQ (0xde, 0xbe, irqBE) IRQ (0xdf, 0xbf, irqBF) -ISR (0xe7, isrAssert) +ISR (0xe0, isrTimer) +ISR (0xe1, isrLINT0) +ISR (0xe2, isrLINT1) +ISR (0xe3, isrSpurious) +ISR (0xe4, isrAssert) -ISR (0xec, isrTimer) -ISR (0xed, isrLINT0) -ISR (0xee, isrLINT1) -ISR (0xef, isrSpurious) +UISR(0xee, isrSyscall) ISR (0xf0, isrIgnore0) ISR (0xf1, isrIgnore1) diff --git a/src/kernel/interrupts.cpp b/src/kernel/interrupts.cpp index 49722c8..eecd509 100644 --- a/src/kernel/interrupts.cpp +++ b/src/kernel/interrupts.cpp @@ -1,7 +1,9 @@ #include +#include "kutil/memory.h" #include "console.h" #include "cpu.h" +#include "debug.h" #include "device_manager.h" #include "gdt.h" #include "interrupts.h" @@ -19,9 +21,11 @@ extern "C" { #define ISR(i, name) extern void name (); #define EISR(i, name) extern void name (); +#define UISR(i, name) extern void name (); #define IRQ(i, q, name) extern void name (); #include "interrupt_isrs.inc" #undef IRQ +#undef UISR #undef EISR #undef ISR } @@ -39,9 +43,11 @@ get_irq(unsigned vector) switch (vector) { #define ISR(i, name) #define EISR(i, name) +#define UISR(i, name) #define IRQ(i, q, name) case i : return q; #include "interrupt_isrs.inc" #undef IRQ +#undef UISR #undef EISR #undef ISR @@ -52,7 +58,6 @@ get_irq(unsigned vector) static void disable_legacy_pic() { - static const uint16_t PIC1 = 0x20; static const uint16_t PIC2 = 0xa0; @@ -85,9 +90,11 @@ interrupts_init() { #define ISR(i, name) idt_set_entry(i, reinterpret_cast(& name), 0x08, 0x8e); #define EISR(i, name) idt_set_entry(i, reinterpret_cast(& name), 0x08, 0x8e); +#define UISR(i, name) idt_set_entry(i, reinterpret_cast(& name), 0x08, 0xee); #define IRQ(i, q, name) idt_set_entry(i, reinterpret_cast(& name), 0x08, 0x8e); #include "interrupt_isrs.inc" #undef IRQ +#undef UISR #undef EISR #undef ISR @@ -97,71 +104,6 @@ interrupts_init() log::info(logs::boot, "Interrupts enabled."); } -#define print_reg(name, value) cons->printf(" %s: %016lx\n", name, (value)); - -extern "C" uint64_t get_frame(int frame); - -void -print_stacktrace(int skip = 0) -{ - console *cons = console::get(); - int frame = 0; - uint64_t bp = get_frame(skip); - while (bp) { - cons->printf(" frame %2d: %lx\n", frame, bp); - bp = get_frame(++frame + skip); - } -} - -void -print_regs(const cpu_state ®s) -{ - console *cons = console::get(); - - 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(" ds", regs.ds); - print_reg(" cs", regs.cs); - print_reg(" ss", regs.ss); - - cons->puts("\n"); - print_reg("rip", regs.rip); -} - -void -print_stack(const cpu_state ®s) -{ - console *cons = console::get(); - - cons->puts("\nStack:\n"); - uint64_t sp = regs.user_rsp; - while (sp <= regs.rbp) { - cons->printf("%016x: %016x\n", sp, *reinterpret_cast(sp)); - sp += sizeof(uint64_t); - } -} - addr_t isr_handler(addr_t return_rsp, cpu_state regs) { @@ -197,33 +139,35 @@ isr_handler(addr_t return_rsp, cpu_state regs) cons->puts("\nGeneral Protection Fault:\n"); cons->set_color(); - cons->puts(" flags:"); + cons->printf(" errorcode: %lx", regs.errorcode); if (regs.errorcode & 0x01) cons->puts(" external"); - int index = (regs.errorcode & 0xf8) >> 3; + int index = (regs.errorcode & 0xffff) >> 4; if (index) { - switch (regs.errorcode & 0x06) { + switch ((regs.errorcode & 0x07) >> 1) { case 0: - cons->printf(" GDT[%d]\n", index); + cons->printf(" GDT[%x]\n", index); gdt_dump(); break; case 1: case 3: - cons->printf(" IDT[%d]\n", index); + cons->printf(" IDT[%x]\n", index); idt_dump(); break; default: - cons->printf(" LDT[%d]??\n", index); + cons->printf(" LDT[%x]??\n", index); break; } } else { cons->putc('\n'); } print_regs(regs); + /* print_stacktrace(2); print_stack(regs); + */ } _halt(); @@ -263,17 +207,22 @@ isr_handler(addr_t return_rsp, cpu_state regs) _halt(); break; + case isr::isrSyscall: { + return_rsp = syscall_dispatch(return_rsp, regs); + } + break; + default: cons->set_color(9); - cons->puts("\nReceived ISR interrupt:\n"); - cons->set_color(); + cons->printf("\nReceived %02x interrupt:\n", + (static_cast(regs.interrupt))); - cons->printf(" ISR: %02lx\n", regs.interrupt); - cons->printf(" ERR: %lx\n", regs.errorcode); - cons->puts("\n"); + cons->set_color(); + cons->printf(" ISR: %02lx ERR: %lx\n\n", + regs.interrupt, regs.errorcode); print_regs(regs); - print_stacktrace(2); + //print_stacktrace(2); _halt(); } *reinterpret_cast(0xffffff80fee000b0) = 0; @@ -302,34 +251,5 @@ irq_handler(addr_t return_rsp, cpu_state regs) addr_t syscall_handler(addr_t return_rsp, cpu_state regs) { - console *cons = console::get(); - syscall call = static_cast(regs.rax); - - switch (call) { - case syscall::noop: - break; - - case syscall::debug: - cons->set_color(11); - cons->printf("\nReceived DEBUG syscall\n"); - cons->set_color(); - print_regs(regs); - break; - - case syscall::message: - cons->set_color(11); - cons->printf("\nReceived MESSAGE syscall\n"); - cons->set_color(); - break; - - default: - cons->set_color(9); - cons->printf("\nReceived unknown syscall: %02x\n", call); - cons->set_color(); - print_regs(regs); - _halt(); - break; - } - - return return_rsp; + return syscall_dispatch(return_rsp, regs); } diff --git a/src/kernel/interrupts.h b/src/kernel/interrupts.h index 4966937..839c2ee 100644 --- a/src/kernel/interrupts.h +++ b/src/kernel/interrupts.h @@ -9,9 +9,11 @@ enum class isr : uint8_t { #define ISR(i, name) name = i, #define EISR(i, name) name = i, +#define UISR(i, name) name = i, #define IRQ(i, q, name) name = i, #include "interrupt_isrs.inc" #undef IRQ +#undef UISR #undef EISR #undef ISR diff --git a/src/kernel/interrupts.s b/src/kernel/interrupts.s index d40ed90..f7fb0dc 100644 --- a/src/kernel/interrupts.s +++ b/src/kernel/interrupts.s @@ -57,6 +57,7 @@ irq_handler_prelude: %endmacro %define EISR(i, name) EMIT_EISR name, i +%define UISR(i, name) EMIT_ISR name, i %define ISR(i, name) EMIT_ISR name, i %define IRQ(i, q, name) EMIT_IRQ name, i diff --git a/src/kernel/page_manager.cpp b/src/kernel/page_manager.cpp index e81401a..a5dbc7c 100644 --- a/src/kernel/page_manager.cpp +++ b/src/kernel/page_manager.cpp @@ -266,7 +266,7 @@ page_manager::get_table_page() } reinterpret_cast(virt)->next = nullptr; - log::info(logs::memory, "Mappd %d new page table pages at %lx", n, phys); + log::debug(logs::memory, "Mappd %d new page table pages at %lx", n, phys); } free_page_header *page = m_page_cache; diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index 4c4fc2c..7671241 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -3,6 +3,7 @@ #include "cpu.h" #include "gdt.h" #include "interrupts.h" +#include "io.h" #include "log.h" #include "page_manager.h" #include "scheduler.h" @@ -11,8 +12,8 @@ #include "kutil/assert.h" scheduler scheduler::s_instance(nullptr); -//static const uint32_t quantum = 2000000; -static const uint32_t quantum = 20000000; +static const uint32_t quantum = 2000000; +//static const uint32_t quantum = 20000000; const int stack_size = 0x1000; const uint64_t rflags_noint = 0x002; @@ -69,7 +70,7 @@ load_process(const void *image_start, size_t bytes, process *proc, cpu_state sta 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", + log::debug(logs::task, " Loadable segment %02u: vaddr %016lx size %016lx", i, header->vaddr, header->mem_size); log::debug(logs::task, " - aligned to: vaddr %016lx pages %d", @@ -89,7 +90,7 @@ load_process(const void *image_start, size_t bytes, process *proc, cpu_state sta !bitfield_has(header->flags, elf::section_flags::alloc)) continue; - log::debug(logs::task, " Loadable section %u: vaddr %016lx size %016lx", + log::debug(logs::task, " Loadable section %02u: vaddr %016lx size %016lx", i, header->addr, header->size); void *dest = reinterpret_cast(header->addr); @@ -100,12 +101,7 @@ load_process(const void *image_start, size_t bytes, process *proc, cpu_state sta state.rip = image.entrypoint(); proc->flags &= ~process_flags::loading; - 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); + log::debug(logs::task, " Loaded! New process rip: %016lx", state.rip); } void @@ -166,13 +162,9 @@ scheduler::create_process(const char *name, const void *data, size_t size) loader_state->rcx = reinterpret_cast(proc); - log::debug(logs::task, "Creating process %s:", name); - log::debug(logs::task, " PID %d", pid); - log::debug(logs::task, " Pri %d", pid); + log::debug(logs::task, "Creating process %s: pid %d pri %d", name, proc->pid, proc->priority); 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); } void @@ -187,7 +179,11 @@ scheduler::schedule(addr_t rsp0) { m_current->rsp = rsp0; m_runlists[m_current->priority].remove(m_current); - m_runlists[m_current->priority].push_back(m_current); + + if (m_current->flags && process_flags::ready) + m_runlists[m_current->priority].push_back(m_current); + else + m_blocked.push_back(m_current); uint8_t pri = 0; while (m_runlists[pri].empty()) { @@ -198,14 +194,18 @@ scheduler::schedule(addr_t rsp0) m_current = m_runlists[pri].pop_front(); rsp0 = m_current->rsp; + static const uint64_t ia32_gs_base = 0xc0000101; + static const uint64_t ia32_kernel_gs_base = 0xc0000102; + // Set rsp0 to after the end of the about-to-be-popped cpu state tss_set_stack(0, rsp0 + sizeof(cpu_state)); + wrmsr(ia32_gs_base, rsp0); // Swap page tables page_table *pml4 = m_current->pml4; page_manager::set_pml4(pml4); - bool loading = bitfield_has(m_current->flags, process_flags::loading); + bool loading = m_current->flags && process_flags::loading; log::debug(logs::task, "Scheduler switched to process %d, priority %d%s.", m_current->pid, m_current->priority, loading ? " (loading)" : ""); diff --git a/src/kernel/scheduler.h b/src/kernel/scheduler.h index 6c89288..99b08c5 100644 --- a/src/kernel/scheduler.h +++ b/src/kernel/scheduler.h @@ -25,6 +25,7 @@ enum class process_flags : uint32_t }; IS_BITFIELD(process_flags); +/// A process struct process { uint32_t pid; @@ -39,6 +40,10 @@ struct process addr_t rsp; page_table *pml4; + + /// Helper to check if this process is ready + /// \returns true if the process has the ready flag + inline bool ready() { return bitfield_has(flags, process_flags::ready); } }; using process_list = kutil::linked_list; @@ -79,7 +84,6 @@ public: /// \returns A reference to the global system scheduler static scheduler & get() { return s_instance; } -private: friend addr_t isr_handler(addr_t, cpu_state); /// Handle a timer tick @@ -87,6 +91,7 @@ private: /// \returns The stack pointer to switch to addr_t tick(addr_t rsp0); +private: lapic *m_apic; uint32_t m_next_pid; @@ -94,6 +99,7 @@ private: process_node *m_current; process_slab m_process_allocator; process_list m_runlists[num_priorities]; + process_list m_blocked; static scheduler s_instance; }; diff --git a/src/kernel/syscall.cpp b/src/kernel/syscall.cpp new file mode 100644 index 0000000..6f34b2d --- /dev/null +++ b/src/kernel/syscall.cpp @@ -0,0 +1,60 @@ +#include "console.h" +#include "cpu.h" +#include "debug.h" +#include "scheduler.h" +#include "syscall.h" + +extern "C" { + void _halt(); +} + +addr_t +syscall_dispatch(addr_t return_rsp, const cpu_state ®s) +{ + console *cons = console::get(); + syscall call = static_cast(regs.rax); + + switch (call) { + case syscall::noop: + break; + + case syscall::debug: + cons->set_color(11); + cons->printf("\nReceived DEBUG syscall\n"); + cons->set_color(); + print_regs(regs); + break; + + case syscall::message: + cons->set_color(11); + cons->printf("\nReceived MESSAGE syscall\n"); + cons->set_color(); + break; + + case syscall::pause: + { + cons->set_color(11); + + auto &s = scheduler::get(); + auto *p = s.current(); + p->flags -= process_flags::ready; + //log::debug(logs::task, "Pausing process %d, flags: %08x", p->pid, p->flags); + cons->printf("\nReceived PAUSE syscall\n"); + return_rsp = s.tick(return_rsp); + //log::debug(logs::task, "Switching to stack %016lx", return_rsp); + cons->printf("\nDONE WITH PAUSE syscall\n"); + cons->set_color(); + } + break; + + default: + cons->set_color(9); + cons->printf("\nReceived unknown syscall: %02x\n", call); + cons->set_color(); + _halt(); + break; + } + + return return_rsp; +} + diff --git a/src/kernel/syscall.h b/src/kernel/syscall.h index e36273c..cb9e22c 100644 --- a/src/kernel/syscall.h +++ b/src/kernel/syscall.h @@ -1,10 +1,18 @@ #pragma once +#include +#include "kutil/memory.h" + enum class syscall : uint64_t { noop, debug, message, + pause, last_syscall }; + +struct cpu_state; +addr_t syscall_dispatch(addr_t, const cpu_state &); +