mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 23:18:21 +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
|
subdirs=boot
|
||||||
OBJPATH=$(OBJDIR)/arch/${TARGET}/
|
OBJPATH=$(OBJDIR)/arch/${TARGET}/
|
||||||
export
|
export
|
||||||
@@ -15,3 +15,7 @@ israsm.o: isr.asm
|
|||||||
nasm -f elf64 -o $@ $<
|
nasm -f elf64 -o $@ $<
|
||||||
mkdir -p $(OBJPATH)
|
mkdir -p $(OBJPATH)
|
||||||
cp $@ $(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;
|
thread_t* thread;
|
||||||
size_t timerticksperus;
|
size_t timerticksperus;
|
||||||
timer_req* timerfirstreq;
|
timer_req* timerfirstreq;
|
||||||
|
timer_req schedreq;
|
||||||
} cls_t;
|
} cls_t;
|
||||||
|
|
||||||
void bsp_setcls();
|
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
|
#define _REGS_H_INCLUDE
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
typedef struct{
|
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;
|
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;
|
} arch_regs;
|
||||||
|
|
||||||
|
void arch_regs_setupkernel(arch_regs* regs, void* ip, void* stack, bool interrupts);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ section .text
|
|||||||
pop rdi
|
pop rdi
|
||||||
pop rsi
|
pop rsi
|
||||||
pop rbp
|
pop rbp
|
||||||
|
add rsp,8 ; remove error code
|
||||||
|
|
||||||
%endmacro
|
%endmacro
|
||||||
|
|
||||||
@@ -96,8 +96,6 @@ section .text
|
|||||||
|
|
||||||
popregs
|
popregs
|
||||||
|
|
||||||
add rsp,8 ; remove error code
|
|
||||||
|
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
|
|
||||||
@@ -121,8 +119,6 @@ section .text
|
|||||||
|
|
||||||
popregs
|
popregs
|
||||||
|
|
||||||
add rsp,8 ; remove error code
|
|
||||||
|
|
||||||
iretq
|
iretq
|
||||||
%endmacro
|
%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;
|
int ttylock = 0;
|
||||||
|
|
||||||
void liminewrite(char* str, size_t c){
|
void liminewrite(char* str, size_t c){
|
||||||
|
|
||||||
liminetty->write(liminetty->terminals[0], str, c);
|
liminetty->write(liminetty->terminals[0], str, c);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void kmain(){
|
void kmain(){
|
||||||
@@ -80,6 +78,8 @@ void kmain(){
|
|||||||
|
|
||||||
pci_enumerate();
|
pci_enumerate();
|
||||||
|
|
||||||
|
sched_init();
|
||||||
|
|
||||||
smp_init();
|
smp_init();
|
||||||
|
|
||||||
_panic("End of kmain()", 0);
|
_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 <arch/regs.h>
|
||||||
#include <kernel/vfs.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_WAITING 0
|
||||||
#define THREAD_STATE_RUNNING 1
|
#define THREAD_STATE_RUNNING 1
|
||||||
#define THREAD_STATE_BLOCKED 2
|
#define THREAD_STATE_BLOCKED 2
|
||||||
|
|
||||||
|
typedef unsigned long state_t;
|
||||||
|
|
||||||
struct _proc_t;
|
struct _proc_t;
|
||||||
|
|
||||||
typedef struct _thread_t{
|
typedef struct _thread_t{
|
||||||
struct _thread_t* next;
|
struct _thread_t* next;
|
||||||
|
struct _thread_t* prev;
|
||||||
struct _proc_t* proc;
|
struct _proc_t* proc;
|
||||||
arch_regs* regs;
|
arch_regs* regs;
|
||||||
size_t state;
|
state_t state;
|
||||||
void* kernelstack;
|
void* kernelstack;
|
||||||
|
void* kernelstackbase;
|
||||||
|
size_t stacksize;
|
||||||
|
pid_t tid;
|
||||||
|
int priority;
|
||||||
} thread_t;
|
} thread_t;
|
||||||
|
|
||||||
typedef struct _proc_t{
|
typedef struct _proc_t{
|
||||||
@@ -26,8 +37,19 @@ typedef struct _proc_t{
|
|||||||
pid_t pid;
|
pid_t pid;
|
||||||
gid_t gid;
|
gid_t gid;
|
||||||
uid_t uid;
|
uid_t uid;
|
||||||
|
thread_t** threads;
|
||||||
|
size_t threadcount;
|
||||||
dirnode_t* root;
|
dirnode_t* root;
|
||||||
dirnode_t* cwd;
|
dirnode_t* cwd;
|
||||||
} proc_t;
|
} proc_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct{
|
||||||
|
thread_t* start;
|
||||||
|
thread_t* end;
|
||||||
|
int lock;
|
||||||
|
} sched_queue;
|
||||||
|
|
||||||
|
void sched_init();
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef _TIMER_H_INCLUDE
|
#ifndef _TIMER_H_INCLUDE
|
||||||
#define _TIMER_H_INCLUDE
|
#define _TIMER_H_INCLUDE
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <arch/regs.h>
|
#include <arch/regs.h>
|
||||||
|
|
||||||
@@ -14,7 +15,7 @@ typedef struct _timer_req{
|
|||||||
} timer_req;
|
} timer_req;
|
||||||
|
|
||||||
void timer_init();
|
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_resume();
|
||||||
void timer_stop();
|
void timer_stop();
|
||||||
void timer_irq(arch_regs* ctx);
|
void timer_irq(arch_regs* ctx);
|
||||||
|
|||||||
@@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
typedef int wint_t;
|
typedef int wint_t;
|
||||||
|
|
||||||
bool ignoresign = false;
|
|
||||||
|
|
||||||
char* __int_str(uintmax_t i, char b[], int base, bool plusSignIfNeeded, bool spaceSignIfNeeded,
|
char* __int_str(uintmax_t i, char b[], int base, bool plusSignIfNeeded, bool spaceSignIfNeeded,
|
||||||
int paddingNo, bool justify, bool zeroPad) {
|
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);
|
size_t integer = va_arg(list, size_t);
|
||||||
ignoresign = true;
|
|
||||||
__int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad);
|
__int_str(integer, intStrBuffer, base, plusSign, spaceNoSign, lengthSpec, leftJustify, zeroPad);
|
||||||
displayString(intStrBuffer, &chars);
|
displayString(intStrBuffer, &chars);
|
||||||
ignoresign = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 't':
|
case 't':
|
||||||
|
|||||||
+164
-16
@@ -1,20 +1,111 @@
|
|||||||
#include <kernel/sched.h>
|
#include <kernel/sched.h>
|
||||||
#include <arch/cls.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;
|
#define THREAD_QUANTUM 10000
|
||||||
thread_t* blocked;
|
|
||||||
|
|
||||||
static thread_t* next_thread(){
|
// queue 0: interrupt threads
|
||||||
|
// queue 1: kernel threads
|
||||||
|
// queue 2: user threads
|
||||||
|
|
||||||
thread_t* thread = queue;
|
#define QUEUE_COUNT 3
|
||||||
|
|
||||||
while(1){
|
sched_queue queues[QUEUE_COUNT];
|
||||||
|
sched_queue running;
|
||||||
|
sched_queue blocked;
|
||||||
|
|
||||||
while(thread != NULL && thread->state != THREAD_STATE_WAITING)
|
static thread_t* allocthread(proc_t* proc, state_t state, pid_t tid, size_t kstacksize){
|
||||||
thread = thread->next;
|
|
||||||
|
|
||||||
if(!thread)
|
thread_t* thread = alloc(sizeof(thread_t));
|
||||||
asm("hlt"); // wait until something happens that would allow a thread to be scheduled
|
if(!thread)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,28 +113,85 @@ static thread_t* next_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;
|
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){
|
if(current->proc != thread->proc){
|
||||||
|
|
||||||
// change address spaces and all
|
// TODO change proc specific stuff
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
arch_setkernelstack(thread->kernelstack);
|
||||||
|
|
||||||
arch_switchcontext(thread->regs);
|
arch_switchcontext(thread->regs);
|
||||||
|
|
||||||
__builtin_unreachable();
|
__builtin_unreachable();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
__attribute__((noreturn)) void sched_timerhook(arch_regs* c){
|
thread_t* sched_newkthread(void* ip, size_t stacksize, bool run, int prio){
|
||||||
|
thread_t* thread = allocthread(NULL, THREAD_STATE_WAITING, 0, stacksize);
|
||||||
|
|
||||||
thread_t* current = arch_getcls()->thread;
|
if(!thread) return NULL;
|
||||||
|
|
||||||
memcpy(current->regs, c, sizeof(arch_regs));
|
thread->priority = prio;
|
||||||
|
|
||||||
;
|
arch_regs_setupkernel(thread->regs, ip, thread->kernelstack, true);
|
||||||
|
|
||||||
__builtin_unreachable();
|
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();
|
size_t remainingticks = arch_cputimer_stop();
|
||||||
|
|
||||||
@@ -55,8 +55,8 @@ void timer_add(timer_req* req, size_t us){
|
|||||||
if(!iter){
|
if(!iter){
|
||||||
arch_getcls()->timerfirstreq = req;
|
arch_getcls()->timerfirstreq = req;
|
||||||
req->next = NULL;
|
req->next = NULL;
|
||||||
arch_cputimer_fire(req->ticks);
|
if(start);
|
||||||
printf("ticks3: %lu", req->ticks);
|
arch_cputimer_fire(req->ticks);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,8 +72,8 @@ void timer_add(timer_req* req, size_t us){
|
|||||||
if(iter->ticks > req->ticks){
|
if(iter->ticks > req->ticks){
|
||||||
req->next = arch_getcls()->timerfirstreq;
|
req->next = arch_getcls()->timerfirstreq;
|
||||||
arch_getcls()->timerfirstreq = req;
|
arch_getcls()->timerfirstreq = req;
|
||||||
arch_cputimer_fire(req->ticks);
|
if(start)
|
||||||
printf("ticks2: %lu", req->ticks);
|
arch_cputimer_fire(req->ticks);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,7 +83,7 @@ void timer_add(timer_req* req, size_t us){
|
|||||||
req->next = iter->next;
|
req->next = iter->next;
|
||||||
iter->next = req;
|
iter->next = req;
|
||||||
|
|
||||||
printf("ticks: %lu", arch_getcls()->timerfirstreq->ticks);
|
if(start)
|
||||||
arch_cputimer_fire(arch_getcls()->timerfirstreq->ticks);
|
arch_cputimer_fire(arch_getcls()->timerfirstreq->ticks);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user