diff --git a/include/sys/sched.h b/include/sys/sched.h new file mode 100644 index 0000000..72394ee --- /dev/null +++ b/include/sys/sched.h @@ -0,0 +1,5 @@ +#pragma once +#include "sys/thread.h" + +void sched_add(struct thread *t); +void sched_init(void); diff --git a/include/sys/thread.h b/include/sys/thread.h index 68379b8..ebc3e5b 100644 --- a/include/sys/thread.h +++ b/include/sys/thread.h @@ -3,6 +3,7 @@ #include "sys/fs/vfs.h" #define THREAD_KERNEL (1 << 31) +#define THREAD_STOPPED (1 << 2) #if defined(ARCH_AMD64) typedef uint64_t *mm_space_t; @@ -22,6 +23,8 @@ struct thread { mm_space_t space; // TODO: maybe __sched_thread + int cpu; + struct thread *prev; struct thread *next; }; diff --git a/sys/amd64/kernel.c b/sys/amd64/kernel.c index bc497db..df2f783 100644 --- a/sys/amd64/kernel.c +++ b/sys/amd64/kernel.c @@ -17,6 +17,7 @@ #include "sys/fs/vfs.h" #include "sys/blk/ram.h" #include "sys/fs/tar.h" +#include "sys/sched.h" #include "sys/tty.h" static multiboot_info_t *multiboot_info; @@ -37,7 +38,6 @@ void kernel_main(struct amd64_loader_data *data) { amd64_mm_init(data); amd64_acpi_init(); - extern void sched_init(void); sched_init(); amd64_apic_init(); rtc_init(); diff --git a/sys/amd64/sys/sched.c b/sys/amd64/sys/sched.c index b541dd1..76e32ab 100644 --- a/sys/amd64/sys/sched.c +++ b/sys/amd64/sys/sched.c @@ -126,6 +126,12 @@ void init_func(void *arg) { } } +static uint32_t sched_alloc_pid(void) { + // The first pid allocation will be 1 (init process) + static uint32_t last_pid = 1; + return last_pid++; +} + void sched_add_to(int cpu, struct thread *t) { t->next = NULL; @@ -135,6 +141,14 @@ void sched_add_to(int cpu, struct thread *t) { } else { sched_queue_heads[cpu] = t; } + t->prev = sched_queue_tails[cpu]; + t->cpu = cpu; + + if (!(t->flags & THREAD_KERNEL)) { + t->pid = sched_alloc_pid(); + } else { + t->pid = 0; + } sched_queue_tails[cpu] = t; ++sched_queue_sizes[cpu]; spin_release(&sched_lock); @@ -187,12 +201,52 @@ void sched_init(void) { int sched(void) { struct thread *from = get_cpu()->thread; struct thread *to; + int cpu = get_cpu()->processor_id; spin_lock(&sched_lock); + // 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 { - to = sched_queue_heads[get_cpu()->processor_id]; + to = sched_queue_heads[cpu]; } spin_release(&sched_lock); diff --git a/sys/amd64/syscall.c b/sys/amd64/syscall.c index 6ada799..4f1b338 100644 --- a/sys/amd64/syscall.c +++ b/sys/amd64/syscall.c @@ -7,6 +7,7 @@ static ssize_t sys_read(int fd, void *buf, size_t lim); static ssize_t sys_write(int fd, const void *buf, size_t lim); +static void sys_exit(int status); uint8_t irq1_key = 0; @@ -16,7 +17,16 @@ intptr_t amd64_syscall(uintptr_t rdi, uintptr_t rsi, uintptr_t rdx, uintptr_t rc return sys_read((int) rdi, (void *) rsi, (size_t) rdx); case 1: return sys_write((int) rdi, (const void *) rsi, (size_t) rdx); + case 60: + 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; default: + kdebug("unknown syscall: %u\n", rax); return -1; } return 0; @@ -38,6 +48,13 @@ static ssize_t sys_read(int fd, void *buf, size_t lim) { return vfs_read(&thr->ioctx, of, buf, lim); } +static void sys_exit(int status) { + struct thread *thr = get_cpu()->thread; + _assert(thr); + kdebug("%u exited with code %d\n", thr->pid, status); + thr->flags |= THREAD_STOPPED; +} + static ssize_t sys_write(int fd, const void *buf, size_t lim) { if (fd >= 4 || fd < 0) { return -EBADF; diff --git a/usr/Makefile b/usr/Makefile index 464b76f..22da67b 100644 --- a/usr/Makefile +++ b/usr/Makefile @@ -12,6 +12,7 @@ usr_CFLAGS=-ffreestanding \ -mno-sse \ -mno-sse2 \ -Ilibc/include \ + -O0 \ -I$(S)/include usr_LDFLAGS=-nostdlib \ -lgcc \ diff --git a/usr/init.c b/usr/init.c index 250cbf5..47759c5 100644 --- a/usr/init.c +++ b/usr/init.c @@ -8,10 +8,17 @@ int main(int argc, char **argv) { ssize_t sz = read(STDIN_FILENO, &c, 1); if (sz >= 0) { + if (c == '\n') { + break; + } + write(STDOUT_FILENO, "Char: ", 6); write(STDOUT_FILENO, &c, 1); c = '\n'; write(STDOUT_FILENO, &c, 1); } } + + write(STDOUT_FILENO, "Enter\n", 6); + return 0; } diff --git a/usr/libc/crt0.S b/usr/libc/crt0.S index 7c0d376..b998d51 100644 --- a/usr/libc/crt0.S +++ b/usr/libc/crt0.S @@ -16,9 +16,8 @@ _start: // Ignore %rdi/%rsi for now xorq %rdi, %rdi + // exit(main(argc, argv)) call main - - // I haven't implemented exit() yet - xorq %rdi, %rdi - jmp *%rdi + movq %rax, %rdi + call exit .size _start, . - _start diff --git a/usr/libc/include/bits/syscall.h b/usr/libc/include/bits/syscall.h index 1284043..71341d8 100644 --- a/usr/libc/include/bits/syscall.h +++ b/usr/libc/include/bits/syscall.h @@ -3,3 +3,4 @@ ssize_t read(int fd, void *buf, size_t count); ssize_t write(int fd, const void *buf, size_t count); +__attribute__((noreturn)) void exit(int code); diff --git a/usr/libc/syscall.c b/usr/libc/syscall.c index baa0b61..e05c21b 100644 --- a/usr/libc/syscall.c +++ b/usr/libc/syscall.c @@ -3,12 +3,27 @@ #define ASM_REGISTER(name) \ register uint64_t name asm (#name) -#define ASM_SYSCALL3(r0, r1, r2, r3) ({ \ +#define ASM_SYSCALL1(r0, r1) ({ \ + ASM_REGISTER(rdi) = (uint64_t) (r1); \ + /* + * Should be the last one because memory accesses for arguments + * fuck up %rax + */ \ ASM_REGISTER(rax) = (uint64_t) (r0); \ + asm volatile ("syscall":::"memory"); \ + rax; \ + }) + +#define ASM_SYSCALL3(r0, r1, r2, r3) ({ \ ASM_REGISTER(rdi) = (uint64_t) (r1); \ ASM_REGISTER(rsi) = (uint64_t) (r2); \ ASM_REGISTER(rdx) = (uint64_t) (r3); \ - asm volatile ("syscall":::"memory"); \ + /* + * Should be the last one because memory accesses for arguments + * fuck up %rax + */ \ + ASM_REGISTER(rax) = (uint64_t) (r0); \ + asm volatile ("syscall":::"memory", "rax", "rdi", "rsi", "rdx"); \ rax; \ }) @@ -19,3 +34,8 @@ ssize_t write(int fd, const void *buf, size_t count) { ssize_t read(int fd, void *buf, size_t count) { return (ssize_t) ASM_SYSCALL3(0, fd, buf, count); } + +__attribute__((noreturn)) void exit(int code) { + (void) ASM_SYSCALL1(60, code); + while (1); +}