From f1a71385682e9c4979c660200555835831f2a3ea Mon Sep 17 00:00:00 2001 From: apio Date: Sun, 25 Sep 2022 20:35:05 +0200 Subject: [PATCH] User mode (with a few syscalls) IT ACTUALLY WORKS NOW. Why wasn't it working? Oh, because I was not setting already present page tables's permissions to user mode. Just a little bug. THAT I SPENT DAYS TRYING TO FIND Anyways, it works now. Such a relief... --- kernel/include/interrupts/Context.h | 2 +- kernel/include/thread/Scheduler.h | 1 + kernel/src/gdt/GDT.cpp | 7 ++++--- kernel/src/interrupts/Entry.cpp | 7 +++++++ kernel/src/interrupts/Install.cpp | 8 ++++++-- kernel/src/interrupts/InterruptEntry.asm | 12 +++++++++++- kernel/src/main.asm | 14 +++++++++++++- kernel/src/main.cpp | 7 +++++++ kernel/src/memory/VMM.cpp | 15 +++++++++++++++ kernel/src/thread/Scheduler.cpp | 22 +++++++++++++++------- 10 files changed, 80 insertions(+), 15 deletions(-) diff --git a/kernel/include/interrupts/Context.h b/kernel/include/interrupts/Context.h index ac0beb83..41f60847 100644 --- a/kernel/include/interrupts/Context.h +++ b/kernel/include/interrupts/Context.h @@ -3,7 +3,7 @@ struct Context { - uint64_t cr2; + uint64_t cr2, ds; uint64_t r15, r14, r13, r12, r11, r10, r9, r8, rsi, rdi, rbp, rdx, rcx, rbx, rax; uint64_t number; union { diff --git a/kernel/include/thread/Scheduler.h b/kernel/include/thread/Scheduler.h index 6359dabe..7ce7d263 100644 --- a/kernel/include/thread/Scheduler.h +++ b/kernel/include/thread/Scheduler.h @@ -17,6 +17,7 @@ namespace Scheduler void task_yield(Context* context); void task_tick(Context* context); + void task_sleep(Context* context); void reap_task(Task* task); void reap_tasks(); diff --git a/kernel/src/gdt/GDT.cpp b/kernel/src/gdt/GDT.cpp index fa6acbfa..d5e5c164 100644 --- a/kernel/src/gdt/GDT.cpp +++ b/kernel/src/gdt/GDT.cpp @@ -56,7 +56,7 @@ __attribute__((aligned(0x1000))) static InternalGDT internal_gdt = {{0x0000, 0x0 {0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00}, {0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00}, {0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00}, - {0x0000, 0x0000, 0x00, 0x89, 0x0f, 0x00}, + {0x0000, 0x0000, 0x00, 0xe9, 0x0f, 0x00}, {0x00000000, 0x00000000}}; static TSS main_tss; @@ -85,11 +85,12 @@ void GDT::load() gdtr.size = sizeof(InternalGDT); memset(&main_tss, 0, sizeof(TSS)); main_tss.rsp[0] = (uint64_t)MemoryManager::get_pages(4) + (4096 * 4) - 8; // allocate 16KB for the syscall stack + main_tss.iomap_base = sizeof(TSS); set_base(&internal_gdt.tss, (uint64_t)&main_tss & 0xffffffff); internal_gdt.tss2.base_high = (uint64_t)&main_tss >> 32; set_limit(&internal_gdt.tss, sizeof(TSS) - 1); kdbgln("Loading GDT at offset %lx, size %d", gdtr.offset, gdtr.size); load_gdt(&gdtr); - kdbgln("Loading TR (GDT entry 0x28)"); - load_tr(0x28 | 3); + kdbgln("Loading TR (GDT entry 0x2b)"); + load_tr(0x2b); } \ No newline at end of file diff --git a/kernel/src/interrupts/Entry.cpp b/kernel/src/interrupts/Entry.cpp index 30d5a6e8..3c82f386 100644 --- a/kernel/src/interrupts/Entry.cpp +++ b/kernel/src/interrupts/Entry.cpp @@ -4,6 +4,7 @@ #include "interrupts/Context.h" #include "interrupts/IRQ.h" #include "interrupts/Interrupts.h" +#include "io/Serial.h" #include "log/Log.h" #include "misc/hang.h" #include "panic/Panic.h" @@ -67,6 +68,12 @@ extern "C" void common_handler(Context* context) Interrupts::ensure_handler(); Scheduler::task_exit(context); } + if (context->number == 50) { Serial::print((const char*)context->rdi); } + if (context->number == 51) + { + Interrupts::ensure_handler(); + Scheduler::task_sleep(context); + } if (context->number == 256) { kwarnln("Unused interrupt"); } return; } \ No newline at end of file diff --git a/kernel/src/interrupts/Install.cpp b/kernel/src/interrupts/Install.cpp index 4a9d1238..ee266353 100644 --- a/kernel/src/interrupts/Install.cpp +++ b/kernel/src/interrupts/Install.cpp @@ -47,6 +47,8 @@ extern "C" void isr47(); void isr48(); void isr49(); + void isr50(); + void isr51(); } #define INSTALL_TRAP(x) IDT::add_handler(x, (void*)&isr##x, IDT_TA_TrapGate) @@ -106,9 +108,11 @@ void Interrupts::install() INSTALL_ISR(45); INSTALL_ISR(46); INSTALL_ISR(47); - kdbgln("Installing handler stub for software interrupt 48, 49"); + kdbgln("Installing handler stubs for user-accessible syscalls 48, 49, 50, 51 (30h, 31h, 32h, 33h)"); INSTALL_USER_ISR(48); INSTALL_USER_ISR(49); + INSTALL_USER_ISR(50); + INSTALL_USER_ISR(51); kdbgln("Installing unused handler stubs for the rest of the IDT"); - for (int i = 50; i < 256; i++) { INSTALL_UNUSED(i); } + for (int i = 52; i < 256; i++) { INSTALL_UNUSED(i); } } \ No newline at end of file diff --git a/kernel/src/interrupts/InterruptEntry.asm b/kernel/src/interrupts/InterruptEntry.asm index 73bd425c..bae8999e 100644 --- a/kernel/src/interrupts/InterruptEntry.asm +++ b/kernel/src/interrupts/InterruptEntry.asm @@ -62,6 +62,9 @@ asm_common: push r14 push r15 + mov ax, ds + push rax + mov r8, cr2 push r8 @@ -73,8 +76,13 @@ asm_common: global _asm_interrupt_exit _asm_interrupt_exit: + add rsp, 8 + pop rax + mov ds, ax + mov es, ax + mov BYTE [__is_in_interrupt_handler], 0 pop r15 @@ -135,4 +143,6 @@ IRQ 45, 13 IRQ 46, 14 IRQ 47, 15 SOFT 48 -SOFT 49 \ No newline at end of file +SOFT 49 +SOFT 50 +SOFT 51 \ No newline at end of file diff --git a/kernel/src/main.asm b/kernel/src/main.asm index 92eee7f3..9b9e3890 100644 --- a/kernel/src/main.asm +++ b/kernel/src/main.asm @@ -3,4 +3,16 @@ extern _start _main: xor rbp, rbp - call _start \ No newline at end of file + call _start + +global _userspace +_userspace: + mov rdi, 4000 ; 4000 ms / 4 seconds + int 33h ; Sleep + mov rdi, .message + int 32h ; Print string + mov rdi, 2000 ; 2000 ms / 2 seconds + int 33h ; Sleep + int 31h ; Exit current task +.message: + db "hello from userspace!", 0xA, 0 \ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp index 7222d079..823d9e94 100644 --- a/kernel/src/main.cpp +++ b/kernel/src/main.cpp @@ -31,6 +31,8 @@ #include "thread/PIT.h" #include "thread/Scheduler.h" +extern "C" void _userspace(); + extern "C" void _start() { Init::check_magic(); @@ -123,6 +125,11 @@ extern "C" void _start() } }); + uint64_t userspace_phys = kernelVMM.getPhysical((uint64_t)_userspace); + if (userspace_phys == UINT64_MAX) panic("_userspace is not mapped"); + kernelVMM.map(0x7000, userspace_phys, MAP_USER); + Scheduler::add_user_task((void*)(0x7000 + ((uint64_t)_userspace % 4096))); + kinfoln("Prepared scheduler tasks"); ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT(); diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp index 21d4b972..1f8155fc 100644 --- a/kernel/src/memory/VMM.cpp +++ b/kernel/src/memory/VMM.cpp @@ -172,6 +172,11 @@ namespace Paging PML4->entries[PDP_i] = PDE; } else { PDP = (PageTable*)((uint64_t)PDE.Address << 12); } + if ((flags & User) && !PDE.UserSuper) + { + PDE.UserSuper = true; + PML4->entries[PDP_i] = PDE; + } PDE = PDP->entries[PD_i]; PageTable* PD; @@ -187,6 +192,11 @@ namespace Paging PDP->entries[PD_i] = PDE; } else { PD = (PageTable*)((uint64_t)PDE.Address << 12); } + if ((flags & User) && !PDE.UserSuper) + { + PDE.UserSuper = true; + PDP->entries[PD_i] = PDE; + } PDE = PD->entries[PT_i]; PageTable* PT; @@ -202,6 +212,11 @@ namespace Paging PD->entries[PT_i] = PDE; } else { PT = (PageTable*)((uint64_t)PDE.Address << 12); } + if ((flags & User) && !PDE.UserSuper) + { + PDE.UserSuper = true; + PD->entries[PT_i] = PDE; + } PDE = PT->entries[P_i]; PDE.Present = true; diff --git a/kernel/src/thread/Scheduler.cpp b/kernel/src/thread/Scheduler.cpp index 6ebb7bb7..ebb05340 100644 --- a/kernel/src/thread/Scheduler.cpp +++ b/kernel/src/thread/Scheduler.cpp @@ -70,10 +70,12 @@ void Scheduler::add_kernel_task(void (*task)(void)) new_task->regs.rsp = new_task->allocated_stack + (4096 * 4) - sizeof(uintptr_t); new_task->regs.cs = 0x08; new_task->regs.ss = 0x10; + new_task->regs.ds = 0x10; asm volatile("pushfq; movq (%%rsp), %%rax; movq %%rax, %0; popfq;" : "=m"(new_task->regs.rflags)::"%rax"); new_task->regs.rflags |= 0x200; // enable interrupts new_task->task_sleep = 0; new_task->task_time = 0; + new_task->cpu_time = 0; end_task->next_task = new_task; new_task->prev_task = end_task; base_task->prev_task = new_task; @@ -96,9 +98,11 @@ void Scheduler::add_user_task(void* task) new_task->regs.rsp = new_task->allocated_stack + (4096 * 4) - sizeof(uintptr_t); new_task->regs.cs = 0x18 | 0x03; new_task->regs.ss = 0x20 | 0x03; + new_task->regs.ds = 0x20 | 0x03; new_task->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts new_task->task_sleep = 0; new_task->task_time = 0; + new_task->cpu_time = 0; end_task->next_task = new_task; new_task->prev_task = end_task; base_task->prev_task = new_task; @@ -249,6 +253,16 @@ void Scheduler::task_yield(Context* context) return; } +void Scheduler::task_sleep(Context* context) +{ + ASSERT(Interrupts::is_in_handler()); + Interrupts::disable(); + Task* task = current_task(); + task->task_sleep = context->rdi; + task->state = task->Sleeping; + task_yield(context); +} + void Scheduler::yield() { asm volatile("int $48"); @@ -261,13 +275,7 @@ void Scheduler::exit() void Scheduler::sleep(unsigned long ms) { - ASSERT(!Interrupts::is_in_handler()); - Interrupts::disable(); - Task* task = current_task(); - task->task_sleep = ms; - task->state = task->Sleeping; - Interrupts::enable(); - yield(); + asm volatile("int $51" : : "D"(ms)); } Task* Scheduler::current_task()