mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-10-27 12:48:22 +00:00
kernel threads
kernel threads and preemptive multitasking
This commit is contained in:
@@ -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)/$@
|
||||
|
||||
@@ -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
|
||||
@@ -22,6 +22,7 @@ typedef struct{
|
||||
thread_t* thread;
|
||||
size_t timerticksperus;
|
||||
timer_req* timerfirstreq;
|
||||
timer_req schedreq;
|
||||
} cls_t;
|
||||
|
||||
void bsp_setcls();
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#ifndef _KSTACK_H_INCLUDE
|
||||
#define _KSTACK_H_INCLUDE
|
||||
|
||||
void arch_setkernelstack(void*);
|
||||
|
||||
#endif
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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(¤tqueue->lock);
|
||||
|
||||
queue_add(currentqueue, current);
|
||||
|
||||
spinlock_release(¤tqueue->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
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user