kernel threads

kernel threads and preemptive multitasking
This commit is contained in:
Matheus
2022-08-13 14:00:26 -03:00
parent ac5339453b
commit e7f4245c6d
14 changed files with 274 additions and 44 deletions
+5 -1
View File
@@ -1,4 +1,4 @@
objects := $(patsubst %.c,%.o,$(wildcard *.c)) israsm.o
objects := $(patsubst %.c,%.o,$(wildcard *.c)) israsm.o context.o
subdirs=boot
OBJPATH=$(OBJDIR)/arch/${TARGET}/
export
@@ -15,3 +15,7 @@ israsm.o: isr.asm
nasm -f elf64 -o $@ $<
mkdir -p $(OBJPATH)
cp $@ $(OBJPATH)/$@
context.o: context.asm
nasm -f elf64 -o $@ $<
mkdir -p $(OBJPATH)
cp $@ $(OBJPATH)/$@
+32
View File
@@ -0,0 +1,32 @@
global arch_switchcontext
arch_switchcontext:
mov rsp,rdi
add rsp, 8 ; cr2
pop rax
mov gs,rax
pop rax
mov fs,rax
pop rax
mov es,rax
pop rax
mov ds,rax
pop rax
pop rbx
pop rcx
pop rdx
pop r8
pop r9
pop r10
pop r11
pop r12
pop r13
pop r14
pop r15
pop rdi
pop rsi
pop rbp
add rsp,8 ; remove error code
swapgs
iretq
+1
View File
@@ -22,6 +22,7 @@ typedef struct{
thread_t* thread;
size_t timerticksperus;
timer_req* timerfirstreq;
timer_req schedreq;
} cls_t;
void bsp_setcls();
+6
View File
@@ -0,0 +1,6 @@
#ifndef _KSTACK_H_INCLUDE
#define _KSTACK_H_INCLUDE
void arch_setkernelstack(void*);
#endif
+2
View File
@@ -2,10 +2,12 @@
#define _REGS_H_INCLUDE
#include <stdint.h>
#include <stdbool.h>
typedef struct{
uint64_t cr2,gs,fs,es,ds,rax,rbx,rcx,rdx,r8,r9,r10,r11,r12,r13,r14,r15,rdi,rsi,rbp,error,rip,cs,rflags,rsp,ss;
} arch_regs;
void arch_regs_setupkernel(arch_regs* regs, void* ip, void* stack, bool interrupts);
#endif
+2 -6
View File
@@ -75,7 +75,7 @@ section .text
pop rdi
pop rsi
pop rbp
add rsp,8 ; remove error code
%endmacro
@@ -95,8 +95,6 @@ section .text
call %2
popregs
add rsp,8 ; remove error code
iretq
@@ -120,9 +118,7 @@ section .text
call %2
popregs
add rsp,8 ; remove error code
iretq
%endmacro
+8
View File
@@ -0,0 +1,8 @@
#include <arch/kstack.h>
#include <arch/ist.h>
#include <arch/cls.h>
void arch_setkernelstack(void* stack){
arch_getcls()->ist.rsp0 = (uint64_t)stack;
}
+2 -2
View File
@@ -28,9 +28,7 @@ struct limine_terminal_response* liminetty;
int ttylock = 0;
void liminewrite(char* str, size_t c){
liminetty->write(liminetty->terminals[0], str, c);
}
void kmain(){
@@ -80,6 +78,8 @@ void kmain(){
pci_enumerate();
sched_init();
smp_init();
_panic("End of kmain()", 0);
+13
View File
@@ -0,0 +1,13 @@
#include <arch/regs.h>
void arch_regs_setupkernel(arch_regs* regs, void* ip, void* stack, bool interrupts){
regs->rip = ip;
regs->rsp = stack;
regs->cs = 0x28;
regs->ds = 0x30;
regs->es = 0x30;
regs->fs = 0x30;
regs->gs = 0x30;
regs->ss = 0x30;
regs->rflags = interrupts ? 0x200 : 0;
}
+23 -1
View File
@@ -5,18 +5,29 @@
#include <arch/regs.h>
#include <kernel/vfs.h>
#define THREAD_PRIORITY_INTERRUPT 0
#define THREAD_PRIORITY_KERNEL 1
#define THREAD_PRIORITY_USER 2
#define THREAD_STATE_WAITING 0
#define THREAD_STATE_RUNNING 1
#define THREAD_STATE_BLOCKED 2
typedef unsigned long state_t;
struct _proc_t;
typedef struct _thread_t{
struct _thread_t* next;
struct _thread_t* prev;
struct _proc_t* proc;
arch_regs* regs;
size_t state;
state_t state;
void* kernelstack;
void* kernelstackbase;
size_t stacksize;
pid_t tid;
int priority;
} thread_t;
typedef struct _proc_t{
@@ -26,8 +37,19 @@ typedef struct _proc_t{
pid_t pid;
gid_t gid;
uid_t uid;
thread_t** threads;
size_t threadcount;
dirnode_t* root;
dirnode_t* cwd;
} proc_t;
typedef struct{
thread_t* start;
thread_t* end;
int lock;
} sched_queue;
void sched_init();
#endif
+2 -1
View File
@@ -1,6 +1,7 @@
#ifndef _TIMER_H_INCLUDE
#define _TIMER_H_INCLUDE
#include <stdbool.h>
#include <stddef.h>
#include <arch/regs.h>
@@ -14,7 +15,7 @@ typedef struct _timer_req{
} timer_req;
void timer_init();
void timer_add(timer_req* req, size_t us);
void timer_add(timer_req* req, size_t us, bool start);
void timer_resume();
void timer_stop();
void timer_irq(arch_regs* ctx);
-3
View File
@@ -11,7 +11,6 @@
typedef int wint_t;
bool ignoresign = false;
char* __int_str(uintmax_t i, char b[], int base, bool plusSignIfNeeded, bool spaceSignIfNeeded,
int paddingNo, bool justify, bool zeroPad) {
@@ -262,10 +261,8 @@ int vprintf (const char* format, va_list list)
{
size_t integer = va_arg(list, size_t);
ignoresign = true;
__int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad);
displayString(intStrBuffer, &chars);
ignoresign = false;
break;
}
case 't':
+171 -23
View File
@@ -1,49 +1,197 @@
#include <kernel/sched.h>
#include <arch/cls.h>
#include <kernel/sched.h>
#include <arch/spinlock.h>
#include <kernel/alloc.h>
#include <arch/mmu.h>
#include <kernel/pmm.h>
#include <kernel/timer.h>
thread_t* queue;
thread_t* blocked;
#define THREAD_QUANTUM 10000
static thread_t* next_thread(){
// queue 0: interrupt threads
// queue 1: kernel threads
// queue 2: user threads
#define QUEUE_COUNT 3
sched_queue queues[QUEUE_COUNT];
sched_queue running;
sched_queue blocked;
static thread_t* allocthread(proc_t* proc, state_t state, pid_t tid, size_t kstacksize){
thread_t* thread = queue;
thread_t* thread = alloc(sizeof(thread_t));
if(!thread)
return NULL;
while(1){
while(thread != NULL && thread->state != THREAD_STATE_WAITING)
thread = thread->next;
if(!thread)
asm("hlt"); // wait until something happens that would allow a thread to be scheduled
thread->regs = alloc(sizeof(arch_regs));
if(!thread->regs){
free(thread);
return NULL;
}
// XXX use alloc() when it's better
size_t pagec = kstacksize / PAGE_SIZE + 1;
thread->kernelstackbase = pmm_hhdmalloc(pagec);
if(!thread->kernelstackbase){
free(thread->regs);
free(thread);
return NULL;
}
thread->proc = proc;
thread->state = state;
thread->tid = tid;
thread->kernelstack = thread->kernelstackbase + kstacksize;
thread->stacksize = kstacksize;
return thread;
}
static void queue_add(sched_queue* queue, thread_t* thread){
thread->next = NULL;
thread->prev = queue->end;
if(queue->end)
queue->end->next = thread;
queue->end = thread;
if(!queue->start)
queue->start = thread;
}
static void queue_remove(sched_queue* queue, thread_t* thread){
if(thread->next)
thread->next->prev = thread->prev;
else
queue->end = thread->prev;
if(thread->prev)
thread->prev->next = thread->next;
else
queue->start = thread->next;
}
static thread_t* getnext(){
thread_t* thread = NULL;
for(int i = 0; i < QUEUE_COUNT && thread == NULL; ++i){
spinlock_acquire(&queues[i].lock);
if(queues[i].start){
thread = queues[i].start;
queue_remove(&queues[i], thread);
}
spinlock_release(&queues[i].lock);
}
if(thread){
spinlock_acquire(&running.lock);
queue_add(&running, thread);
spinlock_release(&running.lock);
}
return thread;
}
__attribute__((noreturn)) static void sched_switch(thread_t* thread){
int a = 0;
void sched_timerhook(arch_regs* regs){
thread_t* current = arch_getcls()->thread;
sched_queue* currentqueue = &queues[current->priority];
spinlock_acquire(&running.lock);
queue_remove(&running, current);
spinlock_release(&running.lock);
memcpy(current->regs, regs, sizeof(arch_regs));
spinlock_acquire(&currentqueue->lock);
queue_add(currentqueue, current);
spinlock_release(&currentqueue->lock);
thread_t* next = getnext();
if(next)
memcpy(regs, next->regs, sizeof(arch_regs));
timer_add(&arch_getcls()->schedreq, THREAD_QUANTUM, false);
arch_getcls()->thread = next;
}
static void switch_thread(thread_t* thread){
thread_t* current = arch_getcls()->thread;
// if we don't have to change processes don't waste time
if(current->proc != thread->proc){
// change address spaces and all
// TODO change proc specific stuff
}
arch_setkernelstack(thread->kernelstack);
arch_switchcontext(thread->regs);
__builtin_unreachable();
}
__attribute__((noreturn)) void sched_timerhook(arch_regs* c){
thread_t* current = arch_getcls()->thread;
thread_t* sched_newkthread(void* ip, size_t stacksize, bool run, int prio){
thread_t* thread = allocthread(NULL, THREAD_STATE_WAITING, 0, stacksize);
memcpy(current->regs, c, sizeof(arch_regs));
if(!thread) return NULL;
;
thread->priority = prio;
__builtin_unreachable();
arch_regs_setupkernel(thread->regs, ip, thread->kernelstack, true);
if(run)
queue_add(&queues[prio], thread);
return thread;
}
void sched_init(){
arch_getcls()->thread = allocthread(NULL, THREAD_STATE_RUNNING, 0, 0);
arch_getcls()->thread->priority = THREAD_PRIORITY_KERNEL;
timer_req* req = &arch_getcls()->schedreq;
req->func = sched_timerhook;
}
+7 -7
View File
@@ -43,7 +43,7 @@ void timer_stop(){
}
}
void timer_add(timer_req* req, size_t us){
void timer_add(timer_req* req, size_t us, bool start){
size_t remainingticks = arch_cputimer_stop();
@@ -55,8 +55,8 @@ void timer_add(timer_req* req, size_t us){
if(!iter){
arch_getcls()->timerfirstreq = req;
req->next = NULL;
arch_cputimer_fire(req->ticks);
printf("ticks3: %lu", req->ticks);
if(start);
arch_cputimer_fire(req->ticks);
return;
}
@@ -72,8 +72,8 @@ void timer_add(timer_req* req, size_t us){
if(iter->ticks > req->ticks){
req->next = arch_getcls()->timerfirstreq;
arch_getcls()->timerfirstreq = req;
arch_cputimer_fire(req->ticks);
printf("ticks2: %lu", req->ticks);
if(start)
arch_cputimer_fire(req->ticks);
return;
}
@@ -83,7 +83,7 @@ void timer_add(timer_req* req, size_t us){
req->next = iter->next;
iter->next = req;
printf("ticks: %lu", arch_getcls()->timerfirstreq->ticks);
arch_cputimer_fire(arch_getcls()->timerfirstreq->ticks);
if(start)
arch_cputimer_fire(arch_getcls()->timerfirstreq->ticks);
}