diff --git a/etc/amd64/gdbrc b/etc/amd64/gdbrc new file mode 100644 index 0000000..f12501e --- /dev/null +++ b/etc/amd64/gdbrc @@ -0,0 +1,3 @@ +target remote localhost:1234 +layout regs +symbol-file build/sys/amd64/kernel.elf diff --git a/sys/amd64/sys/sched.c b/sys/amd64/sys/sched.c index 84779dd..11873b8 100644 --- a/sys/amd64/sys/sched.c +++ b/sys/amd64/sys/sched.c @@ -201,51 +201,39 @@ void sched_init(void) { sched_add_to(0, &t_init); } +void sched_remove_from(int cpu, struct thread *thr) { + struct thread *prev = thr->prev; + struct thread *next = thr->next; + kdebug("cpu%d: removing thread %d\n", cpu, thr->pid); + + _assert(prev); + prev->next = next; + + if (next) { + next->prev = prev; + } else { + sched_queue_tails[cpu] = prev; + } + + --sched_queue_sizes[cpu]; + + thr->next = NULL; + thr->prev = NULL; + + // TODO: make other cpus schedule a new thread if they're running a stopped one +} + +void sched_remove(struct thread *thr) { + kdebug("Remove %p\n", thr); + sched_remove_from(thr->cpu, thr); +} + int sched(void) { struct thread *from = get_cpu()->thread; struct thread *to; int cpu = get_cpu()->processor_id; uintptr_t flags; - // Cleanup stopped tasks - // TODO: this won't be needed if I call sched_remove directly - to = sched_queue_heads[cpu]; - while (to) { - if (to->flags & THREAD_STOPPED) { - // So we don't remove [idle] - _assert(to != sched_queue_heads[cpu]); - kdebug("(cpu%d) Removing %u from queue\n", cpu, to->pid); - - if (to->pid == 1) { - panic("init process was killed\n"); - } - - struct thread *prev, *next; - prev = to->prev; - next = to->next; - - _assert(prev); - - prev->next = next; - if (next) { - next->prev = prev; - } else { - sched_queue_tails[cpu] = prev; - } - - // TODO: free the task? - if (to == from) { - // Removing current thread - from = NULL; - } - - if (!next) { - break; - } - } - to = to->next; - } - if (from && from->next) { to = from->next; } else { diff --git a/sys/amd64/syscall.c b/sys/amd64/syscall.c index 413d55a..fa404f9 100644 --- a/sys/amd64/syscall.c +++ b/sys/amd64/syscall.c @@ -14,7 +14,7 @@ static void sys_close(int fd); static int sys_stat(const char *filename, struct stat *st); static void sys_exit(int status); -uint8_t irq1_key = 0; +__attribute__((noreturn)) void amd64_syscall_yield_stopped(void); intptr_t amd64_syscall(uintptr_t rdi, uintptr_t rsi, uintptr_t rdx, uintptr_t rcx, uintptr_t r10, uintptr_t rax) { switch (rax) { @@ -32,12 +32,8 @@ intptr_t amd64_syscall(uintptr_t rdi, uintptr_t rsi, uintptr_t rdx, uintptr_t rc case SYSCALL_NR_EXIT: sys_exit((int) rdi); - // TODO: call sched_remove and reschedule a new task so that - // this one does not return - asm volatile ("sti; hlt"); - panic("This should not happen\n"); - // WTF? - return -1; + amd64_syscall_yield_stopped(); + default: kdebug("unknown syscall: %u\n", rax); return -1; diff --git a/sys/amd64/syscall_s.S b/sys/amd64/syscall_s.S index 342b4c8..e3467a0 100644 --- a/sys/amd64/syscall_s.S +++ b/sys/amd64/syscall_s.S @@ -1,7 +1,9 @@ #include "sys/amd64/asm/asm_cpu.h" +#include "sys/amd64/asm/asm_irq.h" .section .text .global amd64_syscall_init +.global amd64_syscall_yield_stopped #define MSR_STAR 0xC0000081 #define MSR_LSTAR 0xC0000082 @@ -104,5 +106,41 @@ amd64_syscall_entry: swapgs sysretq -_fmt0: - .string "rsp = %p\n" +// Schedule control to a new task instead of stopped one +amd64_syscall_yield_stopped: + cli + // No stack frame - the kernel stack is going to be discarded anyways + movq get_cpu(0x08), %rbx + + call sched + test %rax, %rax + jz 1f + + // sched() failed + leaq _yield_failed(%rip), %rdi + xorq %rax, %rax + call panicf + +1: + // Remove old thread from queues + movq %rbx, %rdi + call sched_remove + + // Load a new context + // rsi = thread structure pointer + movq get_cpu(0x08), %rsi + movq 0(%rsi), %rsp + + // Write TSS entry + movq get_cpu(0x18), %rdi + movq %rsp, %rax + addq $(25 * 8), %rax + movq %rax, 4(%rdi) +1: + // Assume we're now on TASK2's stack + irq_pop_ctx + + iretq + +_yield_failed: + .string "sched() returned -1 on amd64_syscall_yield\n"