diff --git a/src/arch/x86_64/Makefile b/src/arch/x86_64/Makefile index 87b716a2..ab5fcb69 100644 --- a/src/arch/x86_64/Makefile +++ b/src/arch/x86_64/Makefile @@ -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)/$@ diff --git a/src/arch/x86_64/context.asm b/src/arch/x86_64/context.asm new file mode 100644 index 00000000..bdca70f0 --- /dev/null +++ b/src/arch/x86_64/context.asm @@ -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 diff --git a/src/arch/x86_64/include/arch/cls.h b/src/arch/x86_64/include/arch/cls.h index 59b1f63d..baae9391 100644 --- a/src/arch/x86_64/include/arch/cls.h +++ b/src/arch/x86_64/include/arch/cls.h @@ -22,6 +22,7 @@ typedef struct{ thread_t* thread; size_t timerticksperus; timer_req* timerfirstreq; + timer_req schedreq; } cls_t; void bsp_setcls(); diff --git a/src/arch/x86_64/include/arch/kstack.h b/src/arch/x86_64/include/arch/kstack.h new file mode 100644 index 00000000..2edf1c44 --- /dev/null +++ b/src/arch/x86_64/include/arch/kstack.h @@ -0,0 +1,6 @@ +#ifndef _KSTACK_H_INCLUDE +#define _KSTACK_H_INCLUDE + +void arch_setkernelstack(void*); + +#endif diff --git a/src/arch/x86_64/include/arch/regs.h b/src/arch/x86_64/include/arch/regs.h index 6ca67b76..97438035 100644 --- a/src/arch/x86_64/include/arch/regs.h +++ b/src/arch/x86_64/include/arch/regs.h @@ -2,10 +2,12 @@ #define _REGS_H_INCLUDE #include +#include 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 diff --git a/src/arch/x86_64/isr.asm b/src/arch/x86_64/isr.asm index 78d92e7d..e2d47100 100644 --- a/src/arch/x86_64/isr.asm +++ b/src/arch/x86_64/isr.asm @@ -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 diff --git a/src/arch/x86_64/kstack.c b/src/arch/x86_64/kstack.c new file mode 100644 index 00000000..2be88f69 --- /dev/null +++ b/src/arch/x86_64/kstack.c @@ -0,0 +1,8 @@ +#include +#include +#include + +void arch_setkernelstack(void* stack){ + + arch_getcls()->ist.rsp0 = (uint64_t)stack; +} diff --git a/src/arch/x86_64/main.c b/src/arch/x86_64/main.c index 9739695c..e26a6448 100644 --- a/src/arch/x86_64/main.c +++ b/src/arch/x86_64/main.c @@ -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); diff --git a/src/arch/x86_64/regs.c b/src/arch/x86_64/regs.c new file mode 100644 index 00000000..0a4d66a3 --- /dev/null +++ b/src/arch/x86_64/regs.c @@ -0,0 +1,13 @@ +#include + +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; +} diff --git a/src/include/kernel/sched.h b/src/include/kernel/sched.h index 39b16401..da9a9a03 100644 --- a/src/include/kernel/sched.h +++ b/src/include/kernel/sched.h @@ -5,18 +5,29 @@ #include #include +#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 diff --git a/src/include/kernel/timer.h b/src/include/kernel/timer.h index 0eb2f4c1..9ae34aa0 100644 --- a/src/include/kernel/timer.h +++ b/src/include/kernel/timer.h @@ -1,6 +1,7 @@ #ifndef _TIMER_H_INCLUDE #define _TIMER_H_INCLUDE +#include #include #include @@ -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); diff --git a/src/include/stdio/vprintf.c b/src/include/stdio/vprintf.c index bae3206c..a9451ebe 100644 --- a/src/include/stdio/vprintf.c +++ b/src/include/stdio/vprintf.c @@ -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': diff --git a/src/sys/sched/scheduler.c b/src/sys/sched/scheduler.c index 24ab179a..05d01b73 100644 --- a/src/sys/sched/scheduler.c +++ b/src/sys/sched/scheduler.c @@ -1,49 +1,197 @@ #include #include +#include +#include +#include +#include +#include +#include -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; + +} + diff --git a/src/sys/timer.c b/src/sys/timer.c index 67198c90..67db21b9 100644 --- a/src/sys/timer.c +++ b/src/sys/timer.c @@ -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); }