Well, seems to work
This commit is contained in:
@@ -9,9 +9,8 @@ struct cpu {
|
||||
// TODO: somehow export offsets to asm
|
||||
struct cpu *self; // 0x00
|
||||
|
||||
uint64_t ticks;
|
||||
amd64_tss_t *tss;
|
||||
uint64_t syscall_rsp;
|
||||
uint64_t ticks; // 0x08
|
||||
amd64_tss_t *tss; // 0x10
|
||||
|
||||
uint64_t processor_id;
|
||||
|
||||
|
||||
@@ -6,8 +6,14 @@ struct thread {
|
||||
uintptr_t rsp0; // 0x00
|
||||
uintptr_t syscall_rsp; // 0x08
|
||||
|
||||
uintptr_t rsp0_top; // 0x10
|
||||
uintptr_t cr3; // 0x18
|
||||
|
||||
uintptr_t rsp0_base;
|
||||
size_t rsp0_size;
|
||||
|
||||
uintptr_t rsp3_base;
|
||||
size_t rsp3_size;
|
||||
} data;
|
||||
|
||||
int pid;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#include "sys/amd64/asm/asm_cpu.h"
|
||||
.section .text
|
||||
.global context_enter
|
||||
context_enter:
|
||||
@@ -40,5 +41,22 @@ context_switch_first:
|
||||
popq %r14
|
||||
popq %r15
|
||||
|
||||
// Load TSS.RSP0 for user -> kernel transition
|
||||
// %rax = top of task's stack
|
||||
movq 0x10(%rdi), %rax
|
||||
// %rcx = &tss
|
||||
movq get_cpu(0x10), %rcx
|
||||
// &tss->rsp0 = %rax
|
||||
movq %rax, 4(%rcx)
|
||||
|
||||
// Load new %cr3 if changed
|
||||
movq 0x18(%rdi), %rax
|
||||
movq %cr3, %rcx
|
||||
test %rcx, %rax
|
||||
jz 1f
|
||||
// Only load if cr3 != thr->cr3
|
||||
movq %rax, %cr3
|
||||
1:
|
||||
|
||||
ret
|
||||
.size context_switch_to, . - context_switch_to
|
||||
|
||||
@@ -61,6 +61,11 @@ void debug_backtrace(uintptr_t rbp, int depth, int limit) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((rbp & 0xFFFFFF0000000000) != 0xFFFFFF0000000000) {
|
||||
kfatal("-- %rbp is not from kernel space\n");
|
||||
return;
|
||||
}
|
||||
|
||||
uintptr_t rip = ((uintptr_t *) rbp)[1];
|
||||
uintptr_t rbp_next = ((uintptr_t *) rbp)[0];
|
||||
|
||||
|
||||
+126
-3
@@ -1,6 +1,8 @@
|
||||
#include "sys/amd64/mm/phys.h"
|
||||
#include "sys/amd64/mm/pool.h"
|
||||
#include "sys/amd64/hw/irq.h"
|
||||
#include "sys/amd64/hw/idt.h"
|
||||
#include "sys/amd64/cpu.h"
|
||||
#include "sys/assert.h"
|
||||
#include "sys/thread.h"
|
||||
#include "sys/debug.h"
|
||||
@@ -73,6 +75,8 @@ static void init_thread(struct thread *thr, void *(*entry)(void *), void *arg) {
|
||||
thr->data.rsp0_base = MM_VIRTUALIZE(stack_pages);
|
||||
thr->data.rsp0_size = MM_PAGE_SIZE;
|
||||
|
||||
thr->data.cr3 = MM_PHYS(mm_kernel);
|
||||
|
||||
uint64_t *stack = (uint64_t *) (thr->data.rsp0_base + thr->data.rsp0_size);
|
||||
|
||||
// Initial thread context
|
||||
@@ -143,6 +147,99 @@ static void init_thread(struct thread *thr, void *(*entry)(void *), void *arg) {
|
||||
thr->data.rsp0 = (uintptr_t) stack;
|
||||
}
|
||||
|
||||
static void init_user(struct thread *thr, void *(*entry)(void *), void *arg) {
|
||||
uintptr_t stack_pages = amd64_phys_alloc_page();
|
||||
_assert(stack_pages != MM_NADDR);
|
||||
uintptr_t stack3_pages = amd64_phys_alloc_page();
|
||||
_assert(stack3_pages != MM_NADDR);
|
||||
|
||||
thr->data.rsp0_base = MM_VIRTUALIZE(stack_pages);
|
||||
thr->data.rsp0_size = MM_PAGE_SIZE;
|
||||
thr->data.rsp0_top = thr->data.rsp0_base + thr->data.rsp0_size;
|
||||
|
||||
thr->data.rsp3_base = MM_VIRTUALIZE(stack3_pages);
|
||||
thr->data.rsp3_size = MM_PAGE_SIZE;
|
||||
|
||||
mm_space_t space = amd64_mm_pool_alloc();
|
||||
mm_space_clone(space, mm_kernel, MM_CLONE_FLG_KERNEL);
|
||||
thr->data.cr3 = MM_PHYS(space);
|
||||
|
||||
// Allow this thread to access upper pages for testing
|
||||
space[AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 39] |= MM_PAGE_USER;
|
||||
uint64_t *pdpt = (uint64_t *) MM_VIRTUALIZE(space[AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 39] & ~0xFFF);
|
||||
for (uint64_t i = 0; i < 4; ++i) {
|
||||
pdpt[((AMD64_MM_STRIPSX(KERNEL_VIRT_BASE) >> 30) + i) & 0x1FF] |= MM_PAGE_USER;
|
||||
}
|
||||
|
||||
uint64_t *stack = (uint64_t *) (thr->data.rsp0_base + thr->data.rsp0_size);
|
||||
|
||||
// Initial thread context
|
||||
|
||||
// Entry context
|
||||
// ss
|
||||
*--stack = 0x1B;
|
||||
// rsp
|
||||
*--stack = thr->data.rsp3_base + thr->data.rsp3_size;
|
||||
// rflags
|
||||
*--stack = 0x200;
|
||||
// cs
|
||||
*--stack = 0x23;
|
||||
// rip
|
||||
*--stack = (uintptr_t) entry;
|
||||
|
||||
// Caller-saved
|
||||
// r11
|
||||
*--stack = 0;
|
||||
// r10
|
||||
*--stack = 0;
|
||||
// r9
|
||||
*--stack = 0;
|
||||
// r8
|
||||
*--stack = 0;
|
||||
// rcx
|
||||
*--stack = 0;
|
||||
// rdx
|
||||
*--stack = 0;
|
||||
// rsi
|
||||
*--stack = 0;
|
||||
// rdi
|
||||
*--stack = (uintptr_t) arg;
|
||||
// rax
|
||||
*--stack = 0;
|
||||
|
||||
// Small stub so that context switch enters the thread properly
|
||||
*--stack = (uintptr_t) context_enter;
|
||||
// Callee-saved
|
||||
// r15
|
||||
*--stack = 0;
|
||||
// r14
|
||||
*--stack = 0;
|
||||
// r13
|
||||
*--stack = 0;
|
||||
// r12
|
||||
*--stack = 0;
|
||||
// rbp
|
||||
*--stack = 0;
|
||||
// rbx
|
||||
*--stack = 0;
|
||||
|
||||
// Thread lifecycle:
|
||||
// * context_switch_to():
|
||||
// - pops callee-saved registers (initializing them to 0)
|
||||
// - enters context_enter()
|
||||
// * context_enter():
|
||||
// - pops caller-saved registers (initializing them to 0 and setting up rdi)
|
||||
// - enters proper execution context via iret
|
||||
// ... Thread is running here until it yields
|
||||
// * yield leads to context_switch_to():
|
||||
// - call to yield() automatically (per ABI) stores caller-saved registers
|
||||
// - context_switch_to() pushes callee-saved registers onto current stack
|
||||
// - selects a new thread
|
||||
// - step one
|
||||
|
||||
thr->data.rsp0 = (uintptr_t) stack;
|
||||
}
|
||||
|
||||
static void *idle(void *arg) {
|
||||
while (1) {
|
||||
asm volatile ("hlt");
|
||||
@@ -151,14 +248,17 @@ static void *idle(void *arg) {
|
||||
}
|
||||
|
||||
static void *t0(void *arg) {
|
||||
uint16_t *ptr = (uint16_t *) MM_VIRTUALIZE(0xB8000 + (uint64_t) arg * 2);
|
||||
size_t cntr = 0;
|
||||
|
||||
*ptr = 0;
|
||||
while (1) {
|
||||
for (size_t i = 0; i < 10000000; ++i);
|
||||
|
||||
*((uint16_t *) MM_VIRTUALIZE(0xB8000 + (uint64_t) arg * 2)) ^= 'A';
|
||||
*ptr ^= 'A' | 0x700;
|
||||
++cntr;
|
||||
|
||||
if (cntr == 50 * (((uint64_t) arg) +1)) {
|
||||
if (cntr == 20 * (((uint64_t) arg) +1)) {
|
||||
kdebug("[%d] Død\n", arg);
|
||||
sched_unqueue(thread_current);
|
||||
}
|
||||
@@ -166,6 +266,17 @@ static void *t0(void *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *u0(void *arg) {
|
||||
uint16_t *ptr = (uint16_t *) MM_VIRTUALIZE(0xB8000 + (uint64_t) arg * 2);
|
||||
*ptr = 0;
|
||||
while (1) {
|
||||
for (size_t i = 0; i < 10000000; ++i);
|
||||
|
||||
*ptr ^= 'A' | 0x1200;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void yield(void) {
|
||||
struct thread *from = thread_current;
|
||||
struct thread *to;
|
||||
@@ -183,12 +294,16 @@ void yield(void) {
|
||||
}
|
||||
|
||||
static struct thread t_n[3] = {0};
|
||||
static struct thread t_u[3] = {0};
|
||||
|
||||
void sched_init(void) {
|
||||
init_thread(&t_n[0], t0, (void *) 0);
|
||||
init_thread(&t_n[1], t0, (void *) 1);
|
||||
init_thread(&t_n[2], t0, (void *) 2);
|
||||
init_thread(&thread_idle, idle, NULL);
|
||||
init_user(&t_u[0], u0, (void *) 5);
|
||||
init_user(&t_u[1], u0, (void *) 6);
|
||||
init_user(&t_u[2], u0, (void *) 7);
|
||||
init_thread(&thread_idle, idle, 0);
|
||||
|
||||
thread_idle.pid = -1;
|
||||
|
||||
@@ -196,9 +311,17 @@ void sched_init(void) {
|
||||
t_n[1].pid = 2;
|
||||
t_n[2].pid = 3;
|
||||
|
||||
t_u[0].pid = 10;
|
||||
t_u[1].pid = 11;
|
||||
t_u[2].pid = 12;
|
||||
|
||||
sched_queue(&t_n[0]);
|
||||
sched_queue(&t_n[1]);
|
||||
sched_queue(&t_n[2]);
|
||||
|
||||
sched_queue(&t_u[0]);
|
||||
sched_queue(&t_u[1]);
|
||||
sched_queue(&t_u[2]);
|
||||
}
|
||||
|
||||
void sched_enter(void) {
|
||||
|
||||
Reference in New Issue
Block a user