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...
This commit is contained in:
apio 2022-09-25 20:35:05 +02:00
parent d1413541f3
commit f1a7138568
10 changed files with 80 additions and 15 deletions

View File

@ -3,7 +3,7 @@
struct Context 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 r15, r14, r13, r12, r11, r10, r9, r8, rsi, rdi, rbp, rdx, rcx, rbx, rax;
uint64_t number; uint64_t number;
union { union {

View File

@ -17,6 +17,7 @@ namespace Scheduler
void task_yield(Context* context); void task_yield(Context* context);
void task_tick(Context* context); void task_tick(Context* context);
void task_sleep(Context* context);
void reap_task(Task* task); void reap_task(Task* task);
void reap_tasks(); void reap_tasks();

View File

@ -56,7 +56,7 @@ __attribute__((aligned(0x1000))) static InternalGDT internal_gdt = {{0x0000, 0x0
{0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00}, {0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00},
{0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00}, {0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00},
{0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00}, {0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00},
{0x0000, 0x0000, 0x00, 0x89, 0x0f, 0x00}, {0x0000, 0x0000, 0x00, 0xe9, 0x0f, 0x00},
{0x00000000, 0x00000000}}; {0x00000000, 0x00000000}};
static TSS main_tss; static TSS main_tss;
@ -85,11 +85,12 @@ void GDT::load()
gdtr.size = sizeof(InternalGDT); gdtr.size = sizeof(InternalGDT);
memset(&main_tss, 0, sizeof(TSS)); 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.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); set_base(&internal_gdt.tss, (uint64_t)&main_tss & 0xffffffff);
internal_gdt.tss2.base_high = (uint64_t)&main_tss >> 32; internal_gdt.tss2.base_high = (uint64_t)&main_tss >> 32;
set_limit(&internal_gdt.tss, sizeof(TSS) - 1); set_limit(&internal_gdt.tss, sizeof(TSS) - 1);
kdbgln("Loading GDT at offset %lx, size %d", gdtr.offset, gdtr.size); kdbgln("Loading GDT at offset %lx, size %d", gdtr.offset, gdtr.size);
load_gdt(&gdtr); load_gdt(&gdtr);
kdbgln("Loading TR (GDT entry 0x28)"); kdbgln("Loading TR (GDT entry 0x2b)");
load_tr(0x28 | 3); load_tr(0x2b);
} }

View File

@ -4,6 +4,7 @@
#include "interrupts/Context.h" #include "interrupts/Context.h"
#include "interrupts/IRQ.h" #include "interrupts/IRQ.h"
#include "interrupts/Interrupts.h" #include "interrupts/Interrupts.h"
#include "io/Serial.h"
#include "log/Log.h" #include "log/Log.h"
#include "misc/hang.h" #include "misc/hang.h"
#include "panic/Panic.h" #include "panic/Panic.h"
@ -67,6 +68,12 @@ extern "C" void common_handler(Context* context)
Interrupts::ensure_handler(); Interrupts::ensure_handler();
Scheduler::task_exit(context); 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"); } if (context->number == 256) { kwarnln("Unused interrupt"); }
return; return;
} }

View File

@ -47,6 +47,8 @@ extern "C"
void isr47(); void isr47();
void isr48(); void isr48();
void isr49(); void isr49();
void isr50();
void isr51();
} }
#define INSTALL_TRAP(x) IDT::add_handler(x, (void*)&isr##x, IDT_TA_TrapGate) #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(45);
INSTALL_ISR(46); INSTALL_ISR(46);
INSTALL_ISR(47); 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(48);
INSTALL_USER_ISR(49); INSTALL_USER_ISR(49);
INSTALL_USER_ISR(50);
INSTALL_USER_ISR(51);
kdbgln("Installing unused handler stubs for the rest of the IDT"); 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); }
} }

View File

@ -62,6 +62,9 @@ asm_common:
push r14 push r14
push r15 push r15
mov ax, ds
push rax
mov r8, cr2 mov r8, cr2
push r8 push r8
@ -73,8 +76,13 @@ asm_common:
global _asm_interrupt_exit global _asm_interrupt_exit
_asm_interrupt_exit: _asm_interrupt_exit:
add rsp, 8 add rsp, 8
pop rax
mov ds, ax
mov es, ax
mov BYTE [__is_in_interrupt_handler], 0 mov BYTE [__is_in_interrupt_handler], 0
pop r15 pop r15
@ -135,4 +143,6 @@ IRQ 45, 13
IRQ 46, 14 IRQ 46, 14
IRQ 47, 15 IRQ 47, 15
SOFT 48 SOFT 48
SOFT 49 SOFT 49
SOFT 50
SOFT 51

View File

@ -3,4 +3,16 @@ extern _start
_main: _main:
xor rbp, rbp xor rbp, rbp
call _start 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

View File

@ -31,6 +31,8 @@
#include "thread/PIT.h" #include "thread/PIT.h"
#include "thread/Scheduler.h" #include "thread/Scheduler.h"
extern "C" void _userspace();
extern "C" void _start() extern "C" void _start()
{ {
Init::check_magic(); 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"); kinfoln("Prepared scheduler tasks");
ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT(); ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT();

View File

@ -172,6 +172,11 @@ namespace Paging
PML4->entries[PDP_i] = PDE; PML4->entries[PDP_i] = PDE;
} }
else { PDP = (PageTable*)((uint64_t)PDE.Address << 12); } 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]; PDE = PDP->entries[PD_i];
PageTable* PD; PageTable* PD;
@ -187,6 +192,11 @@ namespace Paging
PDP->entries[PD_i] = PDE; PDP->entries[PD_i] = PDE;
} }
else { PD = (PageTable*)((uint64_t)PDE.Address << 12); } 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]; PDE = PD->entries[PT_i];
PageTable* PT; PageTable* PT;
@ -202,6 +212,11 @@ namespace Paging
PD->entries[PT_i] = PDE; PD->entries[PT_i] = PDE;
} }
else { PT = (PageTable*)((uint64_t)PDE.Address << 12); } 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 = PT->entries[P_i];
PDE.Present = true; PDE.Present = true;

View File

@ -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.rsp = new_task->allocated_stack + (4096 * 4) - sizeof(uintptr_t);
new_task->regs.cs = 0x08; new_task->regs.cs = 0x08;
new_task->regs.ss = 0x10; 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"); 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->regs.rflags |= 0x200; // enable interrupts
new_task->task_sleep = 0; new_task->task_sleep = 0;
new_task->task_time = 0; new_task->task_time = 0;
new_task->cpu_time = 0;
end_task->next_task = new_task; end_task->next_task = new_task;
new_task->prev_task = end_task; new_task->prev_task = end_task;
base_task->prev_task = new_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.rsp = new_task->allocated_stack + (4096 * 4) - sizeof(uintptr_t);
new_task->regs.cs = 0x18 | 0x03; new_task->regs.cs = 0x18 | 0x03;
new_task->regs.ss = 0x20 | 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->regs.rflags = (1 << 21) | (1 << 9); // enable interrupts
new_task->task_sleep = 0; new_task->task_sleep = 0;
new_task->task_time = 0; new_task->task_time = 0;
new_task->cpu_time = 0;
end_task->next_task = new_task; end_task->next_task = new_task;
new_task->prev_task = end_task; new_task->prev_task = end_task;
base_task->prev_task = new_task; base_task->prev_task = new_task;
@ -249,6 +253,16 @@ void Scheduler::task_yield(Context* context)
return; 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() void Scheduler::yield()
{ {
asm volatile("int $48"); asm volatile("int $48");
@ -261,13 +275,7 @@ void Scheduler::exit()
void Scheduler::sleep(unsigned long ms) void Scheduler::sleep(unsigned long ms)
{ {
ASSERT(!Interrupts::is_in_handler()); asm volatile("int $51" : : "D"(ms));
Interrupts::disable();
Task* task = current_task();
task->task_sleep = ms;
task->state = task->Sleeping;
Interrupts::enable();
yield();
} }
Task* Scheduler::current_task() Task* Scheduler::current_task()