diff --git a/sys/SConscript b/sys/SConscript index 59e6d30..38514c9 100644 --- a/sys/SConscript +++ b/sys/SConscript @@ -14,14 +14,16 @@ src_amd64 = [ "amd64/critical.c", "amd64/debug.c", "amd64/disasm.c", - "amd64/trap.c", - "amd64/trapentry.S", + "amd64/ioapic.c", + "amd64/irq.c", + "amd64/lapic.c", "amd64/machine.c", "amd64/pci.c", "amd64/pmap.c", - "amd64/lapic.c", - "amd64/ioapic.c", - "amd64/irq.c", + "amd64/switch.S", + "amd64/thread.c", + "amd64/trap.c", + "amd64/trapentry.S", "amd64/xmem.c", # Devices "dev/x86/debugcons.c", @@ -36,6 +38,7 @@ src_common = [ "kern/palloc.c", "kern/printf.c", "kern/spinlock.c", + "kern/thread.c", "dev/ahci.c", "dev/console.c", "dev/pci.c", diff --git a/sys/amd64/include/pmap.h b/sys/amd64/include/pmap.h index c335583..9dc645f 100644 --- a/sys/amd64/include/pmap.h +++ b/sys/amd64/include/pmap.h @@ -2,6 +2,8 @@ #ifndef __PMAP_H__ #define __PMAP_H__ +#include + /* * +----------------------+ * | Zero Page (Unmapped) | @@ -44,8 +46,9 @@ typedef struct AS AS; void PMap_Init(); -AS* Map_NewAS(); +AS* PMap_NewAS(); void PMap_DestroyAS(AS *space); +void PMap_LoadAS(AS *space); void PMap_SystemLookup(uint64_t va, PageEntry **entry, int size); bool PMap_SystemLMap(uint64_t phys, uint64_t virt, uint64_t lpages, uint64_t flags); bool PMap_SystemMap(uint64_t phys, uint64_t virt, uint64_t pages); diff --git a/sys/amd64/include/thread.h b/sys/amd64/include/thread.h new file mode 100644 index 0000000..3cdd7e1 --- /dev/null +++ b/sys/amd64/include/thread.h @@ -0,0 +1,26 @@ + +#ifndef __MACHINE_THREAD_H__ +#define __MACHINE_THREAD_H__ + +#include +#include + +typedef struct ThreadArchStackFrame { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t rbx; + uint64_t rdi; // First argument + uint64_t rbp; + uint64_t rip; +} ThreadArchStackFrame; + +typedef struct ThreadArch { + XSAVEArea xsa; + bool useFP; + uint64_t rsp; +} ThreadArch; + +#endif /* __MACHINE_THREAD_H__ */ + diff --git a/sys/amd64/include/trap.h b/sys/amd64/include/trap.h index bec321c..ae2583d 100644 --- a/sys/amd64/include/trap.h +++ b/sys/amd64/include/trap.h @@ -81,6 +81,7 @@ typedef struct TrapFrame void Trap_Init(); void Trap_Dump(TrapFrame *tf); +void Trap_Pop(TrapFrame *tf); #endif /* __TRAP_H__ */ diff --git a/sys/amd64/kernel.lds b/sys/amd64/kernel.lds index 905ae50..89c1d32 100644 --- a/sys/amd64/kernel.lds +++ b/sys/amd64/kernel.lds @@ -144,12 +144,12 @@ SECTIONS } .data1 : { *(.data1) } /* Kernel Debugger */ - __kdbgcmd_start = .; - .kdbgcmd : + .kdbgcmd ALIGN(CONSTANT(MAXPAGESIZE)) : { + __kdbgcmd_start = .; *(.kdbgcmd) + __kdbgcmd_end = .; } - __kdbgcmd_end = .; _edata = .; PROVIDE (edata = .); . = .; __bss_start = .; diff --git a/sys/amd64/machine.c b/sys/amd64/machine.c index 5d1ff07..fdfd4f4 100644 --- a/sys/amd64/machine.c +++ b/sys/amd64/machine.c @@ -14,6 +14,8 @@ #include #include +#include + #include "../dev/console.h" extern void PCI_Init(); @@ -109,6 +111,11 @@ void Machine_EarlyInit() PAlloc_Init(); } +void Machine_IdleThread(void *test) +{ + while (1) { enable_interrupts(); hlt(); } +} + void Machine_Init() { Machine_GDTInit(); @@ -124,11 +131,19 @@ void Machine_Init() IRQ_Init(); LAPIC_Init(); IOAPIC_Init(); + Thread_Init(); PCI_Init(); IDE_Init(); Critical_Exit(); + + Thread *thr = Thread_KThreadCreate(&Machine_IdleThread, NULL); + if (thr == NULL) { + kprintf("Couldn't create idle thread!\n"); + } + Thread_SetRunnable(thr); + breakpoint(); } diff --git a/sys/amd64/pmap.c b/sys/amd64/pmap.c index 5479284..157376e 100644 --- a/sys/amd64/pmap.c +++ b/sys/amd64/pmap.c @@ -88,10 +88,13 @@ PMap_NewAS() return 0; } - for (i = 0; i < PAGETABLE_ENTRIES; i++) + for (i = 0; i < PAGETABLE_ENTRIES / 2; i++) { as->root->entries[i] = 0; } + for (i = PAGETABLE_ENTRIES / 2; i < PAGETABLE_ENTRIES; i++) { + as->root->entries[i] = systemAS.root->entries[i]; + } return as; } @@ -99,12 +102,21 @@ PMap_NewAS() void PMap_DestroyAS(AS *space) { + int i; + + for (i = 0; i < PAGETABLE_ENTRIES / 2; i++) + { + if (space->root->entries[i] != 0) { + // Remove subpages + PAlloc_FreePage((void *)DMPA2VA(space->root->entries[i])); + } + } } void PMap_LoadAS(AS *space) { - write_cr3((uint64_t)space->root); + write_cr3(DMVA2PA((uint64_t)space->root)); currentAS[THISCPU()] = space; } diff --git a/sys/amd64/switch.S b/sys/amd64/switch.S new file mode 100644 index 0000000..9b2b375 --- /dev/null +++ b/sys/amd64/switch.S @@ -0,0 +1,34 @@ +/* + * Trap Handlers + */ + +#include + +.text + +# switch(uint64_t *oldsp, uint64_t newsp) +# %rdi: oldsp +# %rsi: newsp +FUNC_BEGIN(switchstack) + pushq %rbp + pushq %rdi + pushq %rbx + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 + + # Switch stack + movq %rsp, (%rdi) + movq %rsi, %rsp + + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %rbx + popq %rdi + popq %rbp + ret +FUNC_END(switchstack) + diff --git a/sys/amd64/thread.c b/sys/amd64/thread.c new file mode 100644 index 0000000..426e54f --- /dev/null +++ b/sys/amd64/thread.c @@ -0,0 +1,65 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include + +extern void ThreadKThreadEntry(TrapFrame *tf); +extern void switchstack(uint64_t *oldrsp, uint64_t rsp); + +void +Thread_InitArch(Thread *thr) +{ + thr->arch.useFP = false; +} + +void +Thread_SetupKThread(Thread *thr, void (*f)(void *), void *arg) +{ + // Initialize stack + uint64_t stacktop = thr->kstack + PGSIZE; + ThreadArchStackFrame *sf; + TrapFrame *tf; + + tf = (TrapFrame *)(stacktop - sizeof(*tf)); + sf = (ThreadArchStackFrame *)(stacktop - sizeof(*tf) - sizeof(*sf)); + thr->arch.rsp = (uint64_t)sf; + + memset(tf, 0, sizeof(*tf)); + memset(sf, 0, sizeof(*sf)); + + // Setup thread exit function on stack + + sf->rip = (uint64_t)&ThreadKThreadEntry; + sf->rdi = (uint64_t)tf; + + tf->ss = SEL_KDS; + tf->rsp = stacktop; + tf->cs = SEL_KCS; + tf->rip = (uint64_t)f; + tf->rdi = (uint64_t)arg; + tf->rflags = RFLAGS_IF; +} + +void +Thread_SwitchArch(Thread *oldthr, Thread *newthr) +{ + if (oldthr->arch.useFP) + { + fxsave(&oldthr->arch.xsa); + } + + if (newthr->arch.useFP) + { + fxrstor(&newthr->arch.xsa); + } + + // Jump to trapframe + switchstack(&oldthr->arch.rsp, newthr->arch.rsp); +} + diff --git a/sys/amd64/trap.c b/sys/amd64/trap.c index d4898f1..3d5683c 100644 --- a/sys/amd64/trap.c +++ b/sys/amd64/trap.c @@ -147,6 +147,9 @@ trap_entry(TrapFrame *tf) //kprintf("IRQ: %d\n", tf->vector); IRQ_Handler(tf->vector - T_IRQ_BASE); LAPIC_SendEOI(); + if (tf->vector == T_IRQ_TIMER) { + Thread_Scheduler(); + } return; } diff --git a/sys/amd64/trapentry.S b/sys/amd64/trapentry.S index 55a5dce..8ed602b 100644 --- a/sys/amd64/trapentry.S +++ b/sys/amd64/trapentry.S @@ -170,6 +170,7 @@ trap_common: pushq %r15 movq %rsp, %rdi call trap_entry +.globl trap_return trap_return: popq %r15 popq %r14 @@ -189,8 +190,8 @@ trap_return: addq $16, %rsp // Skip error code and vector number iretq -.globl trap_pop -trap_pop: +.globl Trap_Pop +Trap_Pop: movq %rdi, %rsp jmp trap_return diff --git a/sys/include/thread.h b/sys/include/thread.h new file mode 100644 index 0000000..fcc71ed --- /dev/null +++ b/sys/include/thread.h @@ -0,0 +1,47 @@ + +#ifndef __THREAD_H__ +#define __THREAD_H__ + +#include + +struct Thread; +typedef struct Thread Thread; + +#include +#include + +#define SCHED_STATE_NULL 0 +#define SCHED_STATE_RUNNABLE 1 +#define SCHED_STATE_RUNNING 2 +#define SCHED_STATE_WAITING 3 +#define SCHED_STATE_ZOMBIE 4 + +typedef struct Thread { + ThreadArch arch; + AS *space; + uintptr_t kstack; + // Scheduler + int schedState; + TAILQ_ENTRY(Thread) schedQueue; + // Statistics + uint64_t ctxSwitches; + uint64_t userTime; + uint64_t kernTime; + uint64_t waitTime; +} Thread; + +void Thread_Init(); +Thread *Thread_Create(); +Thread *Thread_KThreadCreate(void (*f)(void*), void *arg); +void Thread_SetRunnable(Thread *thr); +void Thread_Destroy(Thread *thr); +void Thread_Switch(Thread *oldthr, Thread *newthr); +void Thread_Scheduler(); + +// Platform functions +void Thread_InitArch(Thread *thr); +void Thread_SetupKThread(Thread *thr, void (*f)(void *), void *arg); +void Thread_SwitchArch(Thread *oldthr, Thread *newthr); + +#endif /* __THREAD_H__ */ + diff --git a/sys/kern/thread.c b/sys/kern/thread.c new file mode 100644 index 0000000..6a7a6f8 --- /dev/null +++ b/sys/kern/thread.c @@ -0,0 +1,155 @@ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +Spinlock threadLock; +Thread *curProc; +TAILQ_HEAD(ThreadQueueHead, Thread) threadQueue; + +void +Thread_Init() +{ + // Create an thread object for current context + curProc = Thread_Create(); + curProc->schedState = SCHED_STATE_RUNNING; + + Spinlock_Init(&threadLock, "Thread Lock"); + + TAILQ_INIT(&threadQueue); +} + +Thread * +Thread_Create() +{ + Thread *thr = PAlloc_AllocPage(); + + if (!thr) + return NULL; + + memset(thr, 0, sizeof(*thr)); + + thr->kstack = (uintptr_t)PAlloc_AllocPage(); + if (thr->kstack == 0) { + PAlloc_FreePage(thr); + return NULL; + } + + thr->space = PMap_NewAS(); + if (thr->space == NULL) { + PAlloc_FreePage((void *)thr->kstack); + PAlloc_FreePage(thr); + return NULL; + } + + thr->schedState = SCHED_STATE_NULL; + + Thread_InitArch(thr); + // Initialize queue + + return thr; +} + +Thread * +Thread_KThreadCreate(void (*f)(void *), void *arg) +{ + Thread *thr = Thread_Create(); + if (!thr) + return NULL; + + Thread_SetupKThread(thr, f, arg); + + return thr; +} + +void +Thread_SetRunnable(Thread *thr) +{ + Spinlock_Lock(&threadLock); + + thr->schedState = SCHED_STATE_RUNNABLE; + TAILQ_INSERT_TAIL(&threadQueue, thr, schedQueue); + + Spinlock_Unlock(&threadLock); +} + +void +Thread_Destroy(Thread *thr) +{ + // Remove from queue + + // Free AS + PAlloc_FreePage((void *)thr->kstack); + PAlloc_FreePage(thr); +} + +void +Thread_Switch(Thread *oldthr, Thread *newthr) +{ + // Load AS + PMap_LoadAS(newthr->space); + + Thread_SwitchArch(oldthr, newthr); +} + +void +Thread_Scheduler() +{ + Thread *prev; + Thread *next; + + Spinlock_Lock(&threadLock); + + // Select next thread + next = TAILQ_FIRST(&threadQueue); + TAILQ_REMOVE(&threadQueue, next, schedQueue); + + prev = curProc; + curProc = next; + prev->schedState = SCHED_STATE_RUNNABLE; + next->schedState = SCHED_STATE_RUNNING; + next->ctxSwitches++; + + TAILQ_INSERT_TAIL(&threadQueue, prev, schedQueue); + + Thread_Switch(prev, next); + + Spinlock_Unlock(&threadLock); +} + +void +ThreadKThreadEntry(TrapFrame *tf) +{ + Spinlock_Unlock(&threadLock); + + Trap_Pop(tf); +} + +void +Debug_Threads(int argc, const char *argv[]) +{ + Thread *thr; + + Spinlock_Lock(&threadLock); + + kprintf("Current: %016llx %d\n", curProc, curProc->ctxSwitches); + TAILQ_FOREACH(thr, &threadQueue, schedQueue) + { + kprintf("Thread: %016llx %d\n", thr, thr->ctxSwitches); + } + + Spinlock_Unlock(&threadLock); +} + +REGISTER_DBGCMD(threads, "Display list of threads", Debug_Threads); +