Turn threads into processes by giving them unique page directories

This commit is contained in:
Thomas Lovén 2022-01-14 22:01:28 +01:00
parent 0272605d36
commit 0e1cf97e19
9 changed files with 98 additions and 68 deletions

View File

@ -1,16 +1,19 @@
#include <proc.h>
#include <sched.h>
#include <mittos/graphics.h>
#include <memory.h>
extern gfx_context *term_fb;
extern gfx_context kernel_fb;
int *position = (void *)0x20000;
void thread1()
{
int a = 1;
gfx_context *ctx = framebuffer_make_subcontext(&kernel_fb, 700, 300, 100, 100);
while(1) {
putCharacter(term_fb, 0, 0, RGB(255,255,0), RGB(0,0,0), '0'+(a++%10));
putCharacter(term_fb, *position, *position, RGB(255,255,0), RGB(0,0,0), '0'+(a++%10));
flip(term_fb);
draw_line(ctx, 0, 100, 50, ((a-1)%100), RGB(0,0,0));
draw_line(ctx, 0, 100, 50, (a%100), RGB(255,0,0));
@ -24,7 +27,7 @@ void thread2()
{
int a = 0;
while(1) {
putCharacter(term_fb, 10, 10, RGB(0,255,255), RGB(0,0,0), 'A'+(a++%10));
putCharacter(term_fb, *position, *position, RGB(0,255,255), RGB(0,0,0), 'A'+(a++%10));
flip(term_fb);
sched_yield();
@ -34,9 +37,19 @@ void thread2()
void TEMP_test_scheduler()
{
struct thread *th1 = new_thread(thread1);
struct process *th1 = new_process(thread1);
scheduler_insert(th1);
struct thread *th2 = new_thread(thread2);
struct process *th2 = new_process(thread2);
scheduler_insert(th2);
uint64_t p1 = pmm_alloc();
uint64_t p2 = pmm_alloc();
vmm_set_page(th1->P4, 0x20000, p1, PAGE_PRESENT);
vmm_set_page(th2->P4, 0x20000, p2, PAGE_PRESENT);
// Write different values into the position variable for the two processes
int *a = P2V(p1);
*a = 20;
a = P2V(p2);
*a = 70;
}

View File

@ -3,4 +3,9 @@
.global load_idt
load_idt:
lidt [rdi]
ret
.global write_cr3
write_cr3:
mov cr3, rdi
ret

View File

@ -4,4 +4,5 @@
void cpu_init();
// cpu/registers.S
void load_idt(void *);
void load_idt(void *);
void write_cr3(uint64_t);

View File

@ -32,7 +32,7 @@
extern uint64_t kernel_P4;
// memory/vmm.c
void vmm_init();
uint64_t new_P4();
uint64_t vmm_get_page(uint64_t P4, uint64_t addr);
int vmm_set_page(uint64_t P4, uint64_t addr, uint64_t page, uint16_t flags);
void vmm_clear_page(uint64_t P4, uint64_t addr, int free);

View File

@ -1,25 +1,26 @@
#pragma once
#include <stdint.h>
struct thread
struct process
{
struct thread *q_next;
uint64_t tid;
uint64_t pid;
void *stack_ptr;
uint64_t state;
uint64_t P4;
struct process *q_next;
uint8_t stack[];
};
// proc/thread.c
extern struct thread *current_thread;
// proc/process.c
extern struct process *current_proc;
// proc/swtch.S
void *switch_stack(void *out, void *in);
// proc/thread.c
struct thread *new_thread(void (*function)(void));
struct thread *thread();
// proc/process.c
struct process *new_process(void (*function)(void));
struct process *proc();
// proc/scheduler.c
void scheduler_insert(struct thread *new);
void scheduler_insert(struct process *new);
void start_scheduler();

View File

@ -42,6 +42,13 @@ static int touch_P1(uint64_t P4, uint64_t addr, uint16_t flags)
return 0;
}
uint64_t new_P4()
{
uint64_t p4 = pmm_alloc();
memcpy(P2V(p4), (void *)kernel_P4, PAGE_SIZE);
return p4;
}
uint64_t vmm_get_page(uint64_t P4, uint64_t addr)
{
if(P1_exists(P4, addr))

39
src/kernel/proc/process.c Normal file
View File

@ -0,0 +1,39 @@
#include <stdint.h>
#include <proc.h>
#include <memory.h>
struct swtch_stack
{
uint64_t RBP;
uint64_t RBX;
uint64_t R12;
uint64_t R13;
uint64_t R14;
uint64_t R15;
uint64_t RBP2;
uint64_t ret;
};
static uint64_t next_pid = 1;
struct process *current_proc;
struct process *new_process(void (*function)(void))
{
struct process *p = P2V(pmm_calloc());
p->pid = next_pid++;
p->stack_ptr = incptr(p, PAGE_SIZE - sizeof(struct swtch_stack));
p->q_next = 0;
p->P4 = new_P4();
struct swtch_stack *stck = p->stack_ptr;
stck->RBP = (uint64_t)&stck->RBP2;
stck->ret = (uint64_t)function;
return p;
}
struct process *proc()
{
return current_proc;
}

View File

@ -1,21 +1,22 @@
#include <proc.h>
#include <cpu.h>
static struct {
struct thread *first;
struct thread *last;
struct process *first;
struct process *last;
} run_q = {0,0};
static struct thread *scheduler_thread;
static struct process *scheduler_proc;
static struct thread *scheduler_next()
static struct process *scheduler_next()
{
struct thread *ret = run_q.first;
struct process *ret = run_q.first;
if(run_q.first && !(run_q.first = run_q.first->q_next))
run_q.last = 0;
return ret;
}
void scheduler_insert(struct thread *new)
void scheduler_insert(struct process *new)
{
if(run_q.last) {
run_q.last->q_next = new;
@ -30,28 +31,29 @@ void scheduler()
{
while(1)
{
struct thread *new = 0;
struct process *new = 0;
while(!(new = scheduler_next()));
current_thread = new;
switch_stack(&scheduler_thread->stack_ptr, &new->stack_ptr);
current_proc = new;
write_cr3(new->P4);
switch_stack(&scheduler_proc->stack_ptr, &new->stack_ptr);
scheduler_insert(current_thread);
current_thread = 0;
scheduler_insert(current_proc);
current_proc = 0;
}
}
long k_sched_yield(long, long, long, long, long, long)
{
switch_stack(&current_thread->stack_ptr, &scheduler_thread->stack_ptr);
switch_stack(&current_proc->stack_ptr, &scheduler_proc->stack_ptr);
return 0;
}
void start_scheduler()
{
scheduler_thread = new_thread(scheduler);
scheduler_thread->tid = (uint64_t)-1;
scheduler_proc = new_process(scheduler);
scheduler_proc->pid = (uint64_t)-1;
uint64_t stack;
switch_stack(&stack, &scheduler_thread->stack_ptr);
switch_stack(&stack, &scheduler_proc->stack_ptr);
}

View File

@ -1,38 +0,0 @@
#include <stdint.h>
#include <proc.h>
#include <memory.h>
struct swtch_stack
{
uint64_t RBP;
uint64_t RBX;
uint64_t R12;
uint64_t R13;
uint64_t R14;
uint64_t R15;
uint64_t RBP2;
uint64_t ret;
};
static uint64_t next_tid = 1;
struct thread *current_thread;
struct thread *new_thread(void (*function)(void))
{
struct thread *th = P2V(pmm_calloc());
th->tid = next_tid++;
th->stack_ptr = incptr(th, PAGE_SIZE - sizeof(struct swtch_stack));
th->q_next = 0;
struct swtch_stack *stck = th->stack_ptr;
stck->RBP = (uint64_t)&stck->RBP2;
stck->ret = (uint64_t)function;
return th;
}
struct thread *thread()
{
return current_thread;
}