diff --git a/src/kernel/cpu.cpp b/src/kernel/cpu.cpp index 6889e1a..a7862df 100644 --- a/src/kernel/cpu.cpp +++ b/src/kernel/cpu.cpp @@ -3,6 +3,8 @@ #include "cpu.h" #include "log.h" +cpu_data bsp_cpu_data; + inline static void __cpuid( uint32_t leaf, diff --git a/src/kernel/cpu.h b/src/kernel/cpu.h index 9510e04..9c1d4a0 100644 --- a/src/kernel/cpu.h +++ b/src/kernel/cpu.h @@ -10,6 +10,14 @@ struct cpu_state uint64_t rip, cs, rflags, user_rsp, ss; }; +struct cpu_data +{ + uintptr_t rsp0; + uintptr_t rsp3; +}; + +extern cpu_data bsp_cpu_data; + class cpu_id { public: diff --git a/src/kernel/debug.cpp b/src/kernel/debug.cpp index 620b511..29fd217 100644 --- a/src/kernel/debug.cpp +++ b/src/kernel/debug.cpp @@ -4,10 +4,6 @@ #include "gdt.h" #include "page_manager.h" -#define print_regL(name, value) cons->printf(" %s: %016lx", name, (value)); -#define print_regM(name, value) cons->printf(" %s: %016lx", name, (value)); -#define print_regR(name, value) cons->printf(" %s: %016lx\n", name, (value)); - size_t __counter_syscall_enter = 0; size_t __counter_syscall_sysret = 0; @@ -36,7 +32,7 @@ print_regs(const cpu_state ®s) cons->puts("\n\n"); print_regL("rbp", regs.rbp); print_regM("rsp", regs.user_rsp); - print_regR("sp0", tss_get_stack(0)); + print_regR("sp0", bsp_cpu_data.rsp0); print_regL("rip", regs.rip); print_regM("cr3", page_manager::get()->get_pml4()); diff --git a/src/kernel/debug.h b/src/kernel/debug.h index 6779c41..9484b82 100644 --- a/src/kernel/debug.h +++ b/src/kernel/debug.h @@ -18,5 +18,7 @@ void print_regs(const cpu_state ®s); void print_stack(const cpu_state ®s); void print_stacktrace(int skip); -#define print_reg(name, value) cons->printf(" %s: %016lx\n", name, (value)); +#define print_regL(name, value) cons->printf(" %s: %016lx", name, (value)); +#define print_regM(name, value) cons->printf(" %s: %016lx", name, (value)); +#define print_regR(name, value) cons->printf(" %s: %016lx\n", name, (value)); diff --git a/src/kernel/interrupts.cpp b/src/kernel/interrupts.cpp index 3f20d23..2ffafcc 100644 --- a/src/kernel/interrupts.cpp +++ b/src/kernel/interrupts.cpp @@ -111,6 +111,38 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs) switch (static_cast(regs->interrupt & 0xff)) { + case isr::isrDebug: { + cons->set_color(11); + cons->puts("\nDebug Exception:\n"); + cons->set_color(); + + uint64_t dr = 0; + + __asm__ __volatile__ ("mov %%dr0, %0" : "=r"(dr)); + print_regL("dr0", dr); + + __asm__ __volatile__ ("mov %%dr1, %0" : "=r"(dr)); + print_regM("dr1", dr); + + __asm__ __volatile__ ("mov %%dr2, %0" : "=r"(dr)); + print_regM("dr2", dr); + + __asm__ __volatile__ ("mov %%dr3, %0" : "=r"(dr)); + print_regR("dr3", dr); + + __asm__ __volatile__ ("mov %%dr6, %0" : "=r"(dr)); + print_regL("dr6", dr); + + __asm__ __volatile__ ("mov %%dr7, %0" : "=r"(dr)); + print_regR("dr7", dr); + + print_regL("rip", regs->rip); + print_regM("rsp", regs->user_rsp); + print_regM("fla", regs->rflags); + _halt(); + } + break; + case isr::isrGPFault: { cons->set_color(9); cons->puts("\nGeneral Protection Fault:\n"); @@ -145,7 +177,6 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs) print_stacktrace(2); print_stack(*regs); */ - } _halt(); break; @@ -165,12 +196,9 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs) uint64_t cr2 = 0; __asm__ __volatile__ ("mov %%cr2, %0" : "=r"(cr2)); - print_reg("cr2", cr2); - - print_reg("rsp", regs->user_rsp); - print_reg("rip", regs->rip); - - cons->puts("\n"); + print_regL("cr2", cr2); + print_regM("rsp", regs->user_rsp); + print_regR("rip", regs->rip); //print_stacktrace(2); } _halt(); @@ -242,7 +270,7 @@ isr_handler(uintptr_t return_rsp, cpu_state *regs) regs->interrupt, regs->errorcode); print_regs(*regs); - //print_stacktrace(2); + print_stacktrace(2); _halt(); } *reinterpret_cast(0xffffff80fee000b0) = 0; diff --git a/src/kernel/log.cpp b/src/kernel/log.cpp index 0c1e65c..666d30c 100644 --- a/src/kernel/log.cpp +++ b/src/kernel/log.cpp @@ -28,6 +28,31 @@ output_log(log::area_t area, log::level severity, const char *message) cons->set_color(); } +void +logger_task() +{ + uint8_t buffer[257]; + auto *ent = reinterpret_cast(buffer); + auto *cons = console::get(); + + g_logger.set_immediate(nullptr); + log::info(logs::task, "Starting kernel logger task"); + + while (true) { + __asm__ ("cli"); + if(g_logger.get_entry(buffer, sizeof(buffer))) { + buffer[ent->bytes] = 0; + cons->set_color(level_colors[static_cast(ent->severity)]); + cons->printf("%9s %8s: %s\n", + g_logger.area_name(ent->area), + g_logger.level_name(ent->severity), + ent->message); + cons->set_color(); + } + __asm__ ("sti"); + } +} + void init() { new (&g_logger) log::logger(log_buffer, sizeof(log_buffer)); diff --git a/src/kernel/log.h b/src/kernel/log.h index be48901..8e6c2e3 100644 --- a/src/kernel/log.h +++ b/src/kernel/log.h @@ -11,6 +11,7 @@ namespace logs { #undef LOG void init(); +void logger_task(); } // namespace logs diff --git a/src/kernel/main.cpp b/src/kernel/main.cpp index f768b50..d2bddd0 100644 --- a/src/kernel/main.cpp +++ b/src/kernel/main.cpp @@ -132,6 +132,8 @@ kernel_main(kernel_args *header) syscall_enable(); scheduler *sched = new (&scheduler::get()) scheduler(devices->get_lapic()); + sched->create_kernel_task(-1, logs::logger_task); + for (auto &f : ird.files()) { if (f.executable()) sched->load_process(f.name(), f.data(), f.size()); diff --git a/src/kernel/page_manager.h b/src/kernel/page_manager.h index 548bcf2..d14d398 100644 --- a/src/kernel/page_manager.h +++ b/src/kernel/page_manager.h @@ -108,6 +108,9 @@ public: /// \returns A pointer to the system page manager static page_manager * get(); + /// Get a pointer to the kernel's PML4 + inline page_table * get_kernel_pml4() { return m_kernel_pml4; } + private: /// Copy a physical page /// \arg orig Physical address of the page to copy diff --git a/src/kernel/process.h b/src/kernel/process.h index 8bda077..6911da2 100644 --- a/src/kernel/process.h +++ b/src/kernel/process.h @@ -7,7 +7,7 @@ #include "kutil/linked_list.h" #include "page_manager.h" -typedef uint32_t pid_t; +typedef int32_t pid_t; enum class process_flags : uint32_t diff --git a/src/kernel/push_all.inc b/src/kernel/push_all.inc index 47ed935..b7c41c5 100644 --- a/src/kernel/push_all.inc +++ b/src/kernel/push_all.inc @@ -1,6 +1,14 @@ %macro push_all 0 sub rsp, 0x78 + ; ss3 rsp + 0xa8 + ; rsp3 rsp + 0xa0 + ; flags3 rsp + 0x98 + ; cs3 rsp + 0x90 + ; rip3 rsp + 0x88 + ; error rsp + 0x80 + ; vector rsp + 0x78 + mov [rsp + 0x70], rax mov [rsp + 0x68], rcx mov [rsp + 0x60], rdx diff --git a/src/kernel/scheduler.cpp b/src/kernel/scheduler.cpp index c164548..0a312b0 100644 --- a/src/kernel/scheduler.cpp +++ b/src/kernel/scheduler.cpp @@ -27,14 +27,6 @@ extern "C" { void load_process(const void *image_start, size_t bytes, process *proc, cpu_state *state); }; -struct cpu_data -{ - uintptr_t rsp0; - uintptr_t rsp3; -}; - -static cpu_data bsp_cpu_data; - scheduler::scheduler(lapic *apic) : m_apic(apic), m_next_pid(1) @@ -118,10 +110,12 @@ load_process(const void *image_start, size_t bytes, process *proc, cpu_state *st } process_node * -scheduler::create_process() +scheduler::create_process(pid_t pid) { + kassert(pid <= 0, "Cannot specify a positive pid in create_process"); + auto *proc = m_process_allocator.pop(); - proc->pid = m_next_pid++; + proc->pid = pid ? pid : m_next_pid++; proc->priority = default_priority; return proc; } @@ -189,6 +183,44 @@ scheduler::load_process(const char *name, const void *data, size_t size) log::debug(logs::task, " PML4 %016lx", pml4); } +void +scheduler::create_kernel_task(pid_t pid, void (*task)()) +{ + auto *proc = create_process(pid); + + uint16_t kcs = (1 << 3) | 0; // Kernel CS is GDT entry 1, ring 0 + uint16_t kss = (2 << 3) | 0; // Kernel SS is GDT entry 2, ring 0 + + // Create a one-page kernel stack space + void *stack0 = proc->setup_kernel_stack(stack_size, 0); + + // Stack grows down, point to the end, resere space for initial null frame + static const size_t null_frame = sizeof(uint64_t); + void *sp0 = kutil::offset_pointer(stack0, stack_size - null_frame); + + cpu_state *state = reinterpret_cast(sp0) - 1; + + // Highest state in the stack is the process' kernel stack for the loader + // to iret to: + state->ss = kss; + state->cs = kcs; + state->rflags = rflags_int; + state->rip = reinterpret_cast(task); + state->user_rsp = reinterpret_cast(state); + + proc->rsp = reinterpret_cast(state); + proc->pml4 = page_manager::get()->get_kernel_pml4(); + proc->quanta = process_quanta; + proc->flags = + process_flags::running | + process_flags::ready; + + m_runlists[default_priority].push_back(proc); + + log::debug(logs::task, "Creating kernel task: pid %d pri %d", proc->pid, proc->priority); + log::debug(logs::task, " RSP0 %016lx", state); +} + void scheduler::start() { @@ -276,7 +308,6 @@ scheduler::schedule(uintptr_t rsp0) tss_set_stack(0, rsp0 + sizeof(cpu_state)); bsp_cpu_data.rsp0 = rsp0; - // Swap page tables page_table *pml4 = m_current->pml4; page_manager::set_pml4(pml4); diff --git a/src/kernel/scheduler.h b/src/kernel/scheduler.h index 00e3493..55d2b09 100644 --- a/src/kernel/scheduler.h +++ b/src/kernel/scheduler.h @@ -21,10 +21,10 @@ public: static const uint8_t default_priority = num_priorities / 2; /// How long the timer quantum is - static const uint64_t quantum_micros = 100000; + static const uint64_t quantum_micros = 1000; /// How many quantums a process gets before being rescheduled - static const uint16_t process_quanta = 10; + static const uint16_t process_quanta = 100; /// Constructor. /// \arg apic Pointer to the local APIC object @@ -36,6 +36,11 @@ public: /// \arg size Size of the program image, in bytes void load_process(const char *name, const void *data, size_t size); + /// Create a new kernel task + /// \arg pid Pid to use for this task, must be negative + /// \arg proc Function to run as a kernel task + void create_kernel_task(pid_t pid, void (*task)()); + /// Start the scheduler working. This may involve starting /// timer interrupts or other preemption methods. void start(); @@ -65,8 +70,9 @@ private: /// Create a new process object. This process will have its pid /// set but nothing else. + /// \arg pid The pid to give the process (0 for automatic) /// \returns The new process object - process_node * create_process(); + process_node * create_process(pid_t pid = 0); /// Handle a timer tick /// \arg rsp0 The stack pointer of the current interrupt handler diff --git a/src/libraries/kutil/logger.cpp b/src/libraries/kutil/logger.cpp index cadf15c..aac3173 100644 --- a/src/libraries/kutil/logger.cpp +++ b/src/libraries/kutil/logger.cpp @@ -101,7 +101,7 @@ logger::get_entry(void *buffer, size_t size) void *out; size_t out_size = m_buffer.get_block(&out); entry *ent = reinterpret_cast(out); - if (out_size == 0) + if (out_size == 0 || out == 0) return 0; kassert(out_size >= sizeof(entry), "Couldn't read a full entry");