From a6a8129c151dc0e3a070c74161e117ec1365c099 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 24 Apr 2025 11:30:07 -0400 Subject: add tss --- kernel/cpu/cpu.c | 3 +++ kernel/cpu/tss.S | 6 +++++ kernel/cpu/tss.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ kernel/cpu/tss.h | 31 ++++++++++++++++++++++ 4 files changed, 120 insertions(+) create mode 100644 kernel/cpu/tss.S create mode 100644 kernel/cpu/tss.c create mode 100644 kernel/cpu/tss.h (limited to 'kernel/cpu') diff --git a/kernel/cpu/cpu.c b/kernel/cpu/cpu.c index 136a1d8..6ef5ef5 100644 --- a/kernel/cpu/cpu.c +++ b/kernel/cpu/cpu.c @@ -3,6 +3,7 @@ #include "pic.h" #include "idt.h" +#include "tss.h" static inline void fpu_init(void) { @@ -73,6 +74,8 @@ void cpu_init(void) if (feats.avx) avx_init(); } + + tss_init(); } void cpu_report(void) diff --git a/kernel/cpu/tss.S b/kernel/cpu/tss.S new file mode 100644 index 0000000..27f2955 --- /dev/null +++ b/kernel/cpu/tss.S @@ -0,0 +1,6 @@ + .globl tss_flush + +tss_flush: + movw $0x28, %ax + ltr %ax + ret diff --git a/kernel/cpu/tss.c b/kernel/cpu/tss.c new file mode 100644 index 0000000..bda713b --- /dev/null +++ b/kernel/cpu/tss.c @@ -0,0 +1,80 @@ +#include "lib/kstring.h" +#include + +#include "tss.h" + +struct sys_seg_descriptor { + uint64_t limit0_15 : 16; + uint64_t base0_15 : 16; + uint64_t base16_23 : 8; + uint64_t type : 4; + uint64_t : 1; + uint64_t DPL : 2; + uint64_t present : 1; + uint64_t limit16_19: 4; + uint64_t available : 1; + uint64_t : 1; + uint64_t : 1; + uint64_t gran : 1; + uint64_t base24_31 : 8; + uint64_t base32_63 : 32; + uint64_t : 32; +} __attribute__((packed)); + +struct tss { + uint64_t : 32; + uint64_t rsp0 : 64; + uint64_t rsp1 : 64; + uint64_t rsp2 : 64; + uint64_t : 64; + uint64_t ist1 : 64; + uint64_t ist2 : 64; + uint64_t ist3 : 64; + uint64_t ist4 : 64; + uint64_t ist5 : 64; + uint64_t ist6 : 64; + uint64_t ist7 : 64; + uint64_t : 64; + uint64_t : 16; + uint64_t iopb : 16; +} __attribute__((packed)); + +// tss entry +static volatile struct tss tss; + +// gdt entries +extern volatile uint8_t GDT[]; +static volatile struct sys_seg_descriptor *GDT_TSS; + +// kernel stack pointer +extern char kern_stack_end[]; + +void tss_init(void) { + uint64_t base = (uint64_t) &tss; + uint64_t limit = sizeof tss - 1; + + // setup tss entry + memsetv(&tss, 0, sizeof(struct tss)); + tss.rsp0 = (uint64_t) kern_stack_end; + + // map tss into gdt + GDT_TSS = (volatile struct sys_seg_descriptor *) (GDT + 0x28); + memsetv(GDT_TSS, 0, sizeof(struct sys_seg_descriptor)); + GDT_TSS->limit0_15 = limit & 0xFFFF; + GDT_TSS->base0_15 = base & 0xFFFF; + GDT_TSS->base16_23 = (base >> 16) & 0xFF; + GDT_TSS->type = 0x9; + GDT_TSS->DPL = 0; + GDT_TSS->present = 1; + GDT_TSS->limit16_19 = (limit >> 16) & 0xF; + GDT_TSS->available = 0; + GDT_TSS->gran = 0; + GDT_TSS->base24_31 = (base >> 24) & 0xFF; + GDT_TSS->base32_63 = (base >> 32) & 0xFFFFFFFF; + + tss_flush(); +} + +void tss_set_stack(uint64_t stack) { + tss.rsp0 = stack; +} diff --git a/kernel/cpu/tss.h b/kernel/cpu/tss.h new file mode 100644 index 0000000..f17b619 --- /dev/null +++ b/kernel/cpu/tss.h @@ -0,0 +1,31 @@ +/** + * @file tss.h + * + * @author Freya Murphy + * + * TSS functions + */ + +#ifndef TSS_H_ +#define TSS_H_ + +#define TSS_REMAP_OFFSET 0x20 + +#include + +/** + * Load the TSS selector + */ +void tss_init(void); + +/** + * Flush the tss + */ +void tss_flush(void); + +/** + * Set the kernel stack pointer in the tss + */ +void tss_set_stack(uint64_t stack); + +#endif /* tss.h */ -- cgit v1.2.3-freya From 65f10ab06b9918ee971ec14a3d18db9f27da99c9 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 24 Apr 2025 11:32:03 -0400 Subject: make 0x80 ring3, add kernel mem ctx switch in idt handler --- kernel/cpu/idt.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'kernel/cpu') diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c index bf4b499..8bddc21 100644 --- a/kernel/cpu/idt.c +++ b/kernel/cpu/idt.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "idt.h" #include "pic.h" @@ -66,6 +67,9 @@ void idt_init(void) entry->isr_mid = (isr >> 16) & 0xffff; entry->isr_high = (isr >> 32) & 0xffffffff; entry->reserved = 0; + + if (vector == 0x80) + entry->flags |= RING3; } __asm__ volatile("lidt %0" : : "m"(idtr)); @@ -116,6 +120,9 @@ void idt_exception_handler(uint64_t exception, uint64_t code, { uint64_t cr2; + // make sure were in the kernel memory context + mem_ctx_switch(kernel_mem_ctx); + switch (exception) { case EX_PAGE_FAULT: // page faults store the offending address in cr2 -- cgit v1.2.3-freya From fb31d11331585a99a537f438f79b472074209c13 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 24 Apr 2025 12:38:51 -0400 Subject: kernel syscall handler --- kernel/cpu/idt.S | 28 ++++++++++- kernel/include/comus/syscalls.h | 2 +- kernel/syscall.c | 107 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 134 insertions(+), 3 deletions(-) create mode 100644 kernel/syscall.c (limited to 'kernel/cpu') diff --git a/kernel/cpu/idt.S b/kernel/cpu/idt.S index 0ba35f8..177d3b1 100644 --- a/kernel/cpu/idt.S +++ b/kernel/cpu/idt.S @@ -1,10 +1,13 @@ .global isr_stub_table + .global isr_restore + .global awd .extern idt_exception_handler .extern idt_pic_timer .extern idt_pic_keyboard .extern idt_pic_mouse .extern idt_pic_eoi + .extern syscall_handler .macro PUSHALL pushq %rax @@ -78,6 +81,16 @@ isr_stub_\num: iretq .endm +.macro SYSCALL num + .align 8 +isr_stub_\num: + PUSHALL + cld + movq %rsp, %rdi # top of stack + callq syscall_handler + jmp isr_restore +.endm + .macro PICGeneric num .align 8 isr_stub_\num: @@ -402,10 +415,21 @@ isr_stub_table: .quad isr_stub_254 .quad isr_stub_255 -# isr stubs .section .text .code64 +# isr restore +isr_restore: + movw $(0x20 | 3), %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + + POPALL + iretq + +# isr stubs ISRException 0 ISRException 1 ISRException 2 @@ -536,7 +560,7 @@ ISRIgnore 124 ISRIgnore 125 ISRIgnore 126 ISRIgnore 127 -ISRIgnore 128 +SYSCALL 128 ISRIgnore 129 ISRIgnore 130 ISRIgnore 131 diff --git a/kernel/include/comus/syscalls.h b/kernel/include/comus/syscalls.h index 3dc128d..3b9ea70 100644 --- a/kernel/include/comus/syscalls.h +++ b/kernel/include/comus/syscalls.h @@ -29,7 +29,7 @@ #define SYS_sbrk 16 // UPDATE THIS DEFINITION IF MORE SYSCALLS ARE ADDED! -#define N_SYSCALLS 13 +#define N_SYSCALLS 17 // interrupt vector entry for system calls #define VEC_SYSCALL 0x80 diff --git a/kernel/syscall.c b/kernel/syscall.c new file mode 100644 index 0000000..7887e83 --- /dev/null +++ b/kernel/syscall.c @@ -0,0 +1,107 @@ +#include +#include +#include +#include +#include + +#define ARG1(type, name) type name = (type)(current_pcb->regs->rdi) +#define ARG2(type, name) type name = (type)(current_pcb->regs->rsi) +#define ARG3(type, name) type name = (type)(current_pcb->regs->rdx) +#define ARG4(type, name) type name = (type)(current_pcb->regs->rcx) + +static int sys_exit(void) +{ + ARG1(int, status); + (void) status; + + // FIXME: schedule somthing else + while (1) + ; + + return 1; +} + +static int sys_write(void) +{ + ARG1(int, fd); + ARG2(const void *, buffer); + ARG3(size_t, nbytes); + + const char *map_buf = kmapuseraddr(current_pcb->memctx, buffer, nbytes); + if (map_buf == NULL) + return 0; + + // cannot write to stdin + if (fd == 0) + nbytes = 0; + + // write to stdout + else if (fd == 1) { + for (size_t i = 0; i < nbytes; i++) + kputc(map_buf[i]); + } + + // files + else { + // TODO: write to files + nbytes = 0; + } + + kunmapaddr(map_buf); + + return nbytes; +} + +static int (*syscall_tbl[N_SYSCALLS])(void) = { + [SYS_exit] = sys_exit, + [SYS_waitpid] = NULL, + [SYS_fork] = NULL, + [SYS_exec] = NULL, + [SYS_open] = NULL, + [SYS_close] = NULL, + [SYS_read] = NULL, + [SYS_write] = sys_write, + [SYS_getpid] = NULL, + [SYS_getppid] = NULL, + [SYS_gettime] = NULL, + [SYS_getprio] = NULL, + [SYS_setprio] = NULL, + [SYS_kill] = NULL, + [SYS_sleep] = NULL, + [SYS_brk] = NULL, + [SYS_sbrk] = NULL, +}; + +void syscall_handler(struct cpu_regs *regs) +{ + uint64_t num; + int (*handler)(void); + int ret = 1; + + // make sure were in the kernel memory context + mem_ctx_switch(kernel_mem_ctx); + + // update data + current_pcb->regs = regs; + num = current_pcb->regs->rax; + + // syscall number + + // check for invalid syscall + if (num >= N_SYSCALLS) { + // invalid syscall + // FIXME: kill user process + while(1); + } + + // run syscall handler (if exists) + handler = syscall_tbl[num]; + if (handler != NULL) + handler(); + + // save return value + current_pcb->regs->rax = ret; + + // switch back to process ctx + mem_ctx_switch(current_pcb->memctx); +} -- cgit v1.2.3-freya From f5c474cf77965376614e8c42a48f1f295228bcd6 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 24 Apr 2025 13:41:38 -0400 Subject: fmt --- kernel/cpu/tss.c | 14 ++++++++------ kernel/lib/backtrace.c | 4 +++- kernel/memory/paging.c | 6 +++--- kernel/syscall.c | 28 +++++++++------------------- 4 files changed, 23 insertions(+), 29 deletions(-) (limited to 'kernel/cpu') diff --git a/kernel/cpu/tss.c b/kernel/cpu/tss.c index bda713b..100525b 100644 --- a/kernel/cpu/tss.c +++ b/kernel/cpu/tss.c @@ -11,7 +11,7 @@ struct sys_seg_descriptor { uint64_t : 1; uint64_t DPL : 2; uint64_t present : 1; - uint64_t limit16_19: 4; + uint64_t limit16_19 : 4; uint64_t available : 1; uint64_t : 1; uint64_t : 1; @@ -49,16 +49,17 @@ static volatile struct sys_seg_descriptor *GDT_TSS; // kernel stack pointer extern char kern_stack_end[]; -void tss_init(void) { - uint64_t base = (uint64_t) &tss; +void tss_init(void) +{ + uint64_t base = (uint64_t)&tss; uint64_t limit = sizeof tss - 1; // setup tss entry memsetv(&tss, 0, sizeof(struct tss)); - tss.rsp0 = (uint64_t) kern_stack_end; + tss.rsp0 = (uint64_t)kern_stack_end; // map tss into gdt - GDT_TSS = (volatile struct sys_seg_descriptor *) (GDT + 0x28); + GDT_TSS = (volatile struct sys_seg_descriptor *)(GDT + 0x28); memsetv(GDT_TSS, 0, sizeof(struct sys_seg_descriptor)); GDT_TSS->limit0_15 = limit & 0xFFFF; GDT_TSS->base0_15 = base & 0xFFFF; @@ -75,6 +76,7 @@ void tss_init(void) { tss_flush(); } -void tss_set_stack(uint64_t stack) { +void tss_set_stack(uint64_t stack) +{ tss.rsp0 = stack; } diff --git a/kernel/lib/backtrace.c b/kernel/lib/backtrace.c index 102e775..2507be4 100644 --- a/kernel/lib/backtrace.c +++ b/kernel/lib/backtrace.c @@ -9,7 +9,9 @@ struct stackframe { extern char kern_stack_start[]; extern char kern_stack_end[]; -#define VALID(frame) (frame && (char*)(frame) >= kern_stack_start && ((char*)(frame) <= kern_stack_end)) +#define VALID(frame) \ + (frame && (char *)(frame) >= kern_stack_start && \ + ((char *)(frame) <= kern_stack_end)) size_t backtrace(void **dst, size_t len) { diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index f286027..80ab833 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -236,7 +236,8 @@ static volatile struct pdpt *pdpt_locate(volatile struct pml4 *pPML4, // locate a pd for a vitural address // @returns PHYSICAL ADDRESS -static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT, const void *vADDR) +static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT, + const void *vADDR) { volatile struct pdpt *vPDPT; volatile struct pdpte *vPDPTE; @@ -667,8 +668,7 @@ volatile void *paging_alloc(void) if (pPML4 == NULL) return NULL; - if (map_pages(pPML4, kernel_start, kernel_start, - F_PRESENT | F_WRITEABLE, + if (map_pages(pPML4, kernel_start, kernel_start, F_PRESENT | F_WRITEABLE, (kernel_end - kernel_start) / PAGE_SIZE)) { pml4_free(pPML4, false); return NULL; diff --git a/kernel/syscall.c b/kernel/syscall.c index 7887e83..7944f46 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -12,7 +12,7 @@ static int sys_exit(void) { ARG1(int, status); - (void) status; + (void)status; // FIXME: schedule somthing else while (1) @@ -53,23 +53,12 @@ static int sys_write(void) } static int (*syscall_tbl[N_SYSCALLS])(void) = { - [SYS_exit] = sys_exit, - [SYS_waitpid] = NULL, - [SYS_fork] = NULL, - [SYS_exec] = NULL, - [SYS_open] = NULL, - [SYS_close] = NULL, - [SYS_read] = NULL, - [SYS_write] = sys_write, - [SYS_getpid] = NULL, - [SYS_getppid] = NULL, - [SYS_gettime] = NULL, - [SYS_getprio] = NULL, - [SYS_setprio] = NULL, - [SYS_kill] = NULL, - [SYS_sleep] = NULL, - [SYS_brk] = NULL, - [SYS_sbrk] = NULL, + [SYS_exit] = sys_exit, [SYS_waitpid] = NULL, [SYS_fork] = NULL, + [SYS_exec] = NULL, [SYS_open] = NULL, [SYS_close] = NULL, + [SYS_read] = NULL, [SYS_write] = sys_write, [SYS_getpid] = NULL, + [SYS_getppid] = NULL, [SYS_gettime] = NULL, [SYS_getprio] = NULL, + [SYS_setprio] = NULL, [SYS_kill] = NULL, [SYS_sleep] = NULL, + [SYS_brk] = NULL, [SYS_sbrk] = NULL, }; void syscall_handler(struct cpu_regs *regs) @@ -91,7 +80,8 @@ void syscall_handler(struct cpu_regs *regs) if (num >= N_SYSCALLS) { // invalid syscall // FIXME: kill user process - while(1); + while (1) + ; } // run syscall handler (if exists) -- cgit v1.2.3-freya From 228366dcf517266097a77b846efe2c2364a10fa3 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 11:20:08 -0400 Subject: syscall_return fn --- kernel/cpu/idt.S | 23 +++++++++++++++-------- kernel/include/comus/cpu.h | 6 ++++++ kernel/procs.c | 2 ++ 3 files changed, 23 insertions(+), 8 deletions(-) (limited to 'kernel/cpu') diff --git a/kernel/cpu/idt.S b/kernel/cpu/idt.S index 177d3b1..06c70a0 100644 --- a/kernel/cpu/idt.S +++ b/kernel/cpu/idt.S @@ -1,5 +1,5 @@ .global isr_stub_table - .global isr_restore + .global syscall_return .global awd .extern idt_exception_handler @@ -8,6 +8,7 @@ .extern idt_pic_mouse .extern idt_pic_eoi .extern syscall_handler + .extern current_pcb .macro PUSHALL pushq %rax @@ -88,7 +89,7 @@ isr_stub_\num: cld movq %rsp, %rdi # top of stack callq syscall_handler - jmp isr_restore + jmp syscall_return .endm .macro PICGeneric num @@ -419,12 +420,18 @@ isr_stub_table: .code64 # isr restore -isr_restore: - movw $(0x20 | 3), %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs +syscall_return: + movq current_pcb, %rbx // return user stack + movq 0(%rbx), %rsp // esp + movq 8(%rbx), %rcx // pml4 + movq (%rcx), %rcx + movq %rcx, %cr3 + + movw $(0x20 | 3), %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs POPALL iretq diff --git a/kernel/include/comus/cpu.h b/kernel/include/comus/cpu.h index ffc1782..8f485be 100644 --- a/kernel/include/comus/cpu.h +++ b/kernel/include/comus/cpu.h @@ -89,4 +89,10 @@ void cpu_feats(struct cpu_feat *feats); */ void cpu_print_regs(struct cpu_regs *regs); +/** + * Return from a syscall handler back into userspace + */ +__attribute__((noreturn)) +void syscall_return(void); + #endif /* cpu.h */ diff --git a/kernel/procs.c b/kernel/procs.c index 9cde22f..8cd44a4 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -472,4 +472,6 @@ void dispatch(void) // set the process up for success current_pcb->state = PROC_STATE_RUNNING; current_pcb->ticks = 3; // ticks per process + + syscall_return(); } -- cgit v1.2.3-freya From 4d6dfd75aeeb5138bdf0b67336dd5eba937ac910 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 23:19:07 -0400 Subject: seperate interrupt stack --- kernel/cpu/tss.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'kernel/cpu') diff --git a/kernel/cpu/tss.c b/kernel/cpu/tss.c index 100525b..184b884 100644 --- a/kernel/cpu/tss.c +++ b/kernel/cpu/tss.c @@ -1,3 +1,4 @@ +#include "comus/memory.h" #include "lib/kstring.h" #include @@ -47,7 +48,7 @@ extern volatile uint8_t GDT[]; static volatile struct sys_seg_descriptor *GDT_TSS; // kernel stack pointer -extern char kern_stack_end[]; +static char interrupt_stack[PAGE_SIZE*2]; void tss_init(void) { @@ -56,7 +57,7 @@ void tss_init(void) // setup tss entry memsetv(&tss, 0, sizeof(struct tss)); - tss.rsp0 = (uint64_t)kern_stack_end; + tss.rsp0 = (uint64_t)interrupt_stack + sizeof(interrupt_stack); // map tss into gdt GDT_TSS = (volatile struct sys_seg_descriptor *)(GDT + 0x28); -- cgit v1.2.3-freya From 103e9e001036dce5cd34209b62a416fd1f34abbf Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 11:09:43 -0400 Subject: move context save area to pcb not in stack --- kernel/cpu/cpu.c | 62 ++++++++++++++---------- kernel/cpu/idt.S | 107 +++++++++++++++++++++++++----------------- kernel/cpu/idt.c | 40 ++++++++++++---- kernel/cpu/tss.c | 7 ++- kernel/include/comus/cpu.h | 7 +++ kernel/include/comus/memory.h | 5 ++ kernel/include/comus/procs.h | 11 +++-- kernel/memory/memory.c | 21 ++++++++- kernel/memory/physalloc.c | 1 - kernel/procs.c | 85 ++++++++++++++++++++++++--------- kernel/syscall.c | 22 ++++----- kernel/user.c | 40 +++++++++++----- 12 files changed, 273 insertions(+), 135 deletions(-) (limited to 'kernel/cpu') diff --git a/kernel/cpu/cpu.c b/kernel/cpu/cpu.c index 6ef5ef5..f607b36 100644 --- a/kernel/cpu/cpu.c +++ b/kernel/cpu/cpu.c @@ -1,5 +1,6 @@ #include #include +#include #include "pic.h" #include "idt.h" @@ -61,8 +62,10 @@ void cpu_init(void) struct cpu_feat feats; cpu_feats(&feats); - pic_remap(); + cli(); idt_init(); + tss_init(); + pic_remap(); if (feats.fpu) fpu_init(); if (feats.sse) { @@ -74,8 +77,6 @@ void cpu_init(void) if (feats.avx) avx_init(); } - - tss_init(); } void cpu_report(void) @@ -181,25 +182,26 @@ void cpu_feats(struct cpu_feat *feats) void cpu_print_regs(struct cpu_regs *regs) { - kprintf("rax: %#016lx (%lu)\n", regs->rax, regs->rax); - kprintf("rbx: %#016lx (%lu)\n", regs->rbx, regs->rbx); - kprintf("rcx: %#016lx (%lu)\n", regs->rcx, regs->rcx); - kprintf("rdx: %#016lx (%lu)\n", regs->rdx, regs->rdx); - kprintf("rsi: %#016lx (%lu)\n", regs->rsi, regs->rsi); - kprintf("rdi: %#016lx (%lu)\n", regs->rdi, regs->rdi); - kprintf("rsp: %#016lx (%lu)\n", regs->rsp, regs->rsp); - kprintf("rbp: %#016lx (%lu)\n", regs->rbp, regs->rbp); - kprintf("r8 : %#016lx (%lu)\n", regs->r8, regs->r8); - kprintf("r9 : %#016lx (%lu)\n", regs->r9, regs->r9); - kprintf("r10: %#016lx (%lu)\n", regs->r10, regs->r10); - kprintf("r11: %#016lx (%lu)\n", regs->r11, regs->r11); - kprintf("r12: %#016lx (%lu)\n", regs->r12, regs->r12); - kprintf("r13: %#016lx (%lu)\n", regs->r13, regs->r13); - kprintf("r14: %#016lx (%lu)\n", regs->r14, regs->r14); - kprintf("r15: %#016lx (%lu)\n", regs->r15, regs->r15); - kprintf("rip: %#016lx (%lu)\n", regs->rip, regs->rip); - kprintf("rflags: %#016lx (%lu)\n", regs->rflags, regs->rflags); - kputs("rflags: "); + kprintf("rax:\t%#016lx (%lu)\n", regs->rax, regs->rax); + kprintf("rbx:\t%#016lx (%lu)\n", regs->rbx, regs->rbx); + kprintf("rcx:\t%#016lx (%lu)\n", regs->rcx, regs->rcx); + kprintf("rdx:\t%#016lx (%lu)\n", regs->rdx, regs->rdx); + kprintf("rsi:\t%#016lx (%lu)\n", regs->rsi, regs->rsi); + kprintf("rdi:\t%#016lx (%lu)\n", regs->rdi, regs->rdi); + kprintf("rsp:\t%#016lx (%lu)\n", regs->rsp, regs->rsp); + kprintf("rbp:\t%#016lx (%lu)\n", regs->rbp, regs->rbp); + kprintf("r8:\t%#016lx (%lu)\n", regs->r8, regs->r8); + kprintf("r9:\t%#016lx (%lu)\n", regs->r9, regs->r9); + kprintf("r10:\t%#016lx (%lu)\n", regs->r10, regs->r10); + kprintf("r11:\t%#016lx (%lu)\n", regs->r11, regs->r11); + kprintf("r12:\t%#016lx (%lu)\n", regs->r12, regs->r12); + kprintf("r13:\t%#016lx (%lu)\n", regs->r13, regs->r13); + kprintf("r14:\t%#016lx (%lu)\n", regs->r14, regs->r14); + kprintf("r15:\t%#016lx (%lu)\n", regs->r15, regs->r15); + kprintf("rip:\t%#016lx (%lu)\n", regs->rip, regs->rip); + kprintf("rflags: %#016lx (%lu) [ ", regs->rflags, regs->rflags); + if (regs->rflags & (3 << 12)) + kprintf("IOPL=%lu ", (regs->rflags >> 12) & 0x3); if (regs->rflags & (1 << 0)) kputs("CF "); if (regs->rflags & (1 << 2)) @@ -218,8 +220,6 @@ void cpu_print_regs(struct cpu_regs *regs) kputs("DF "); if (regs->rflags & (1 << 11)) kputs("OF "); - if (regs->rflags & (3 << 12)) - kputs("IOPL "); if (regs->rflags & (1 << 14)) kputs("NT "); if (regs->rflags & (1 << 15)) @@ -236,5 +236,19 @@ void cpu_print_regs(struct cpu_regs *regs) kputs("VIP "); if (regs->rflags & (1 << 21)) kputs("ID "); + kputs("]\n"); + kprintf("cs:\t%#04lx (%lu) [ DPL=%lu ]\n", regs->cs, regs->cs, + regs->cs & 0x3); + kprintf("ss:\t%#04lx (%lu) [ DPL=%lu ]\n", regs->ss, regs->ss, + regs->ss & 0x3); + kprintf("ds:\t%#04hx (%hu) [ DPL=%hu ]\n", regs->ds, regs->ds, + regs->ds & 0x3); + kprintf("es:\t%#04hx (%hu) [ DPL=%hu ]\n", regs->es, regs->es, + regs->es & 0x3); + kprintf("fs:\t%#04hx (%hu) [ DPL=%hu ]\n", regs->fs, regs->fs, + regs->fs & 0x3); + kprintf("gs:\t%#04hx (%hu) [ DPL=%hu ]\n", regs->gs, regs->gs, + regs->gs & 0x3); + kprintf("cr3:\t%#016lx (%lu)\n", regs->cr3, regs->cr3); kputs("\n"); } diff --git a/kernel/cpu/idt.S b/kernel/cpu/idt.S index 06c70a0..05c34f5 100644 --- a/kernel/cpu/idt.S +++ b/kernel/cpu/idt.S @@ -1,6 +1,5 @@ .global isr_stub_table .global syscall_return - .global awd .extern idt_exception_handler .extern idt_pic_timer @@ -9,8 +8,10 @@ .extern idt_pic_eoi .extern syscall_handler .extern current_pcb + .extern isr_save .macro PUSHALL + # regs pushq %rax pushq %rbx pushq %rcx @@ -26,9 +27,38 @@ pushq %r13 pushq %r14 pushq %r15 + + # segments + movw %ds, %ax + pushw %ax + movw %es, %ax + pushw %ax + movw %fs, %ax + pushw %ax + movw %gs, %ax + pushw %ax + + # pgdir + movq %cr3, %rax + pushq %rax .endm .macro POPALL + # pgdir + popq %rax + movq %rax, %cr3 + + # segments + popw %ax + movw %ax, %gs + movw %ax, %fs + popw %ax + movw %ax, %es + popw %ax + movw %ax, %ds + popw %ax + + # regs popq %r15 popq %r14 popq %r13 @@ -46,19 +76,28 @@ popq %rax .endm +.macro ISRSave + PUSHALL + cld + movq %rsp, %rdi + callq isr_save +.endm + +.macro ISRRestore + POPALL + iretq +.endm + # call the exception handler with the interrupt number # args: interrupt number .macro ISRException num .align 8 isr_stub_\num: - PUSHALL - cld - movq $\num, %rdi # exception number + ISRSave + movq $\num, %rdi # exception number movq $0, %rsi # placeholder error code - movq %rsp, %rdx # top of stack callq idt_exception_handler - POPALL - iretq + ISRRestore .endm # call the exception handler with the interrupt number @@ -68,26 +107,21 @@ isr_stub_\num: .align 8 isr_stub_\num: # retrieve the error code without corrupting registers - mov %eax, isr_tmp + movq %rax, isr_tmp popq %rax - mov %eax, isr_err_code + movq %rax, isr_err_code movq isr_tmp, %rax - PUSHALL - cld + ISRSave movq $\num, %rdi # exception number movq isr_err_code, %rsi # error code - movq %rsp, %rdx # top of stack callq idt_exception_handler - POPALL - iretq + ISRRestore .endm .macro SYSCALL num .align 8 isr_stub_\num: - PUSHALL - cld - movq %rsp, %rdi # top of stack + ISRSave callq syscall_handler jmp syscall_return .endm @@ -95,48 +129,40 @@ isr_stub_\num: .macro PICGeneric num .align 8 isr_stub_\num: - PUSHALL - cld + ISRSave movq $\num, %rdi callq idt_pic_eoi - POPALL - iretq + ISRRestore .endm .macro PICTimer num .align 8 isr_stub_\num: - PUSHALL - cld + ISRSave callq idt_pic_timer movq $\num, %rdi callq idt_pic_eoi - POPALL - iretq + ISRRestore .endm .macro PICKeyboard num .align 8 isr_stub_\num: - PUSHALL - cld + ISRSave callq idt_pic_keyboard movq $\num, %rdi callq idt_pic_eoi - POPALL - iretq + ISRRestore .endm .macro PICMouse num .align 8 isr_stub_\num: - PUSHALL - cld + ISRSave callq idt_pic_mouse movq $\num, %rdi callq idt_pic_eoi - POPALL - iretq + ISRRestore .endm # do nothing @@ -421,18 +447,13 @@ isr_stub_table: # isr restore syscall_return: - movq current_pcb, %rbx // return user stack - movq 0(%rbx), %rsp // esp - movq 8(%rbx), %rcx // pml4 - movq (%rcx), %rcx - movq %rcx, %cr3 + // get current pcb address + movq current_pcb, %rbx - movw $(0x20 | 3), %ax - movw %ax, %ds - movw %ax, %es - movw %ax, %fs - movw %ax, %gs + // load user stack + leaq 8(%rbx), %rsp + // return POPALL iretq diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c index 8bddc21..d071d29 100644 --- a/kernel/cpu/idt.c +++ b/kernel/cpu/idt.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "idt.h" @@ -42,8 +43,12 @@ struct idtr { __attribute__((aligned(0x10))) static struct idt_entry idt[256]; static struct idtr idtr; -// from idt.S extern void *isr_stub_table[]; +extern char kern_stack_start[]; +extern char kern_stack_end[]; + +// current register state on interrupt +static struct cpu_regs *state; // initialize and load the IDT void idt_init(void) @@ -58,11 +63,10 @@ void idt_init(void) uint64_t isr = (uint64_t)isr_stub_table[vector]; // interrupts before 0x20 are for cpu exceptions - uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT; entry->kernel_cs = 0x08; // offset of 1 into GDT entry->ist = 0; - entry->flags = PRESENT | RING0 | gate_type; + entry->flags = PRESENT | RING0 | GATE_64BIT_INT; entry->isr_low = isr & 0xffff; entry->isr_mid = (isr >> 16) & 0xffff; entry->isr_high = (isr >> 32) & 0xffffffff; @@ -115,14 +119,11 @@ char *EXCEPTIONS[] = { "Reserved", }; -void idt_exception_handler(uint64_t exception, uint64_t code, - struct cpu_regs *state) +__attribute__((noreturn)) void idt_exception_handler(uint64_t exception, + uint64_t code) { uint64_t cr2; - // make sure were in the kernel memory context - mem_ctx_switch(kernel_mem_ctx); - switch (exception) { case EX_PAGE_FAULT: // page faults store the offending address in cr2 @@ -151,16 +152,35 @@ void idt_exception_handler(uint64_t exception, uint64_t code, } } +void isr_save(struct cpu_regs *regs) +{ + // make sure were in the kernel memory context + mem_ctx_switch(kernel_mem_ctx); + + // save pointer to registers + state = regs; + + // if we have a kernel stack pointer + // we should return to not save kernel context + // data to userspace + if (regs->rsp >= (size_t)kern_stack_start && + regs->rsp <= (size_t)kern_stack_end) + return; + + // save registers in current_pcb + if (current_pcb != NULL) + current_pcb->regs = *regs; +} + void idt_pic_eoi(uint8_t exception) { pic_eoi(exception - PIC_REMAP_OFFSET); } -int counter = 0; - void idt_pic_timer(void) { ticks++; + pcb_on_tick(); } void idt_pic_keyboard(void) diff --git a/kernel/cpu/tss.c b/kernel/cpu/tss.c index 184b884..bca979d 100644 --- a/kernel/cpu/tss.c +++ b/kernel/cpu/tss.c @@ -1,6 +1,5 @@ -#include "comus/memory.h" -#include "lib/kstring.h" -#include +#include +#include #include "tss.h" @@ -48,7 +47,7 @@ extern volatile uint8_t GDT[]; static volatile struct sys_seg_descriptor *GDT_TSS; // kernel stack pointer -static char interrupt_stack[PAGE_SIZE*2]; +static char interrupt_stack[PAGE_SIZE * 2]; void tss_init(void) { diff --git a/kernel/include/comus/cpu.h b/kernel/include/comus/cpu.h index 3669000..df8f44e 100644 --- a/kernel/include/comus/cpu.h +++ b/kernel/include/comus/cpu.h @@ -31,6 +31,13 @@ struct cpu_feat { }; struct cpu_regs { + // pgdir + uint64_t cr3; + // segments + uint16_t gs; + uint16_t fs; + uint16_t es; + uint16_t ds; // registers uint64_t r15; uint64_t r14; diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h index 408521b..47ea103 100644 --- a/kernel/include/comus/memory.h +++ b/kernel/include/comus/memory.h @@ -103,6 +103,11 @@ void mem_ctx_free(mem_ctx_t ctx); */ void mem_ctx_switch(mem_ctx_t ctx); +/** + * @returns the pgdir pointer in the memory ctx + */ +volatile void *mem_ctx_pgdir(mem_ctx_t ctx); + /** * Allocates at least len bytes of memory starting at * physical address addr. Returned address can be diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h index 0150975..eb6c54f 100644 --- a/kernel/include/comus/procs.h +++ b/kernel/include/comus/procs.h @@ -15,8 +15,8 @@ #include #include -#define PCB_REG(pcb, x) ((pcb)->regs->x) -#define PCB_RET(pcb) ((pcb)->regs->rax) +#define PCB_REG(pcb, x) ((pcb)->regs.x) +#define PCB_RET(pcb) ((pcb)->regs.rax) #define PCB_ARG1(pcb) PCB_REG((pcb), rdi) #define PCB_ARG2(pcb) PCB_REG((pcb), rsi) #define PCB_ARG3(pcb) PCB_REG((pcb), rdx) @@ -47,8 +47,8 @@ enum proc_state { /// process control block struct pcb { // context - struct cpu_regs *regs; mem_ctx_t memctx; + struct cpu_regs regs; // metadata pid_t pid; @@ -224,4 +224,9 @@ void schedule(struct pcb *pcb); */ __attribute__((noreturn)) void dispatch(void); +/** + * Scheduler function called on every system tick + */ +void pcb_on_tick(void); + #endif /* procs.h */ diff --git a/kernel/memory/memory.c b/kernel/memory/memory.c index bd3e06b..ecfd639 100644 --- a/kernel/memory/memory.c +++ b/kernel/memory/memory.c @@ -71,7 +71,12 @@ mem_ctx_t mem_ctx_alloc(void) mem_ctx_t mem_ctx_clone(const mem_ctx_t old, bool cow) { - mem_ctx_t new = user_mem_ctx_next; + mem_ctx_t new; + + assert(old != NULL, "memory context is null"); + assert(old->pml4 != NULL, "pgdir is null"); + + new = user_mem_ctx_next; if (new == NULL) return NULL; @@ -93,6 +98,9 @@ mem_ctx_t mem_ctx_clone(const mem_ctx_t old, bool cow) void mem_ctx_free(mem_ctx_t ctx) { + assert(ctx != NULL, "memory context is null"); + assert(ctx->pml4 != NULL, "pgdir is null"); + pgdir_free(ctx->pml4); virtaddr_cleanup(&ctx->virtctx); @@ -107,9 +115,20 @@ void mem_ctx_free(mem_ctx_t ctx) void mem_ctx_switch(mem_ctx_t ctx) { + assert(ctx != NULL, "memory context is null"); + assert(ctx->pml4 != NULL, "pgdir is null"); + __asm__ volatile("mov %0, %%cr3" ::"r"(ctx->pml4) : "memory"); } +volatile void *mem_ctx_pgdir(mem_ctx_t ctx) +{ + assert(ctx != NULL, "memory context is null"); + assert(ctx->pml4 != NULL, "pgdir is null"); + + return ctx->pml4; +} + void memory_init(void) { struct memory_map mmap; diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index 55ece02..c5a74b7 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -1,4 +1,3 @@ -#include "lib/kio.h" #include #include #include diff --git a/kernel/procs.c b/kernel/procs.c index c1bcc4f..f3d855c 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -179,45 +180,47 @@ void pcb_zombify(struct pcb *victim) // schedule init if zombie child found if (zchild != NULL && init_pcb->state == PROC_STATE_WAITING) { + pid_t pid; + int *status; + assert(pcb_queue_remove(zombie, zchild) == SUCCESS, "pcb_zombify: cannot remove zombie process from queue"); assert(pcb_queue_remove(waiting, init_pcb) == SUCCESS, "pcb_zombify: cannot remove waiting process from queue"); - // send exited pid to init - PCB_RET(init_pcb) = zchild->pid; - // set &status in init's waitpid call - int *ptr = (int *)PCB_ARG2(init_pcb); - if (ptr != NULL) { - mem_ctx_switch(init_pcb->memctx); - *ptr = zchild->exit_status; - mem_ctx_switch(kernel_mem_ctx); + pid = (pid_t)PCB_ARG1(init_pcb); + status = (int *)PCB_ARG2(init_pcb); + + // set exited pid and exist status in init's waitpid call + if (pid == 0 || pid == zchild->pid) { + PCB_RET(init_pcb) = zchild->pid; + if (status != NULL) { + mem_ctx_switch(init_pcb->memctx); + *status = zchild->exit_status; + mem_ctx_switch(kernel_mem_ctx); + } + schedule(init_pcb); } - // schedule init and cleanup child - schedule(init_pcb); pcb_cleanup(zchild); } // if the parent is waiting, wake it up and clean the victim, // otherwise the victim will become a zombie if (parent->state == PROC_STATE_WAITING) { - // verify that the parent is either waiting for this process - // or is waiting for any of its children - uint64_t target = PCB_ARG1(parent); - - if (target != 0 || target == victim->pid) { - // send exited pid to parent - PCB_RET(parent) = victim->pid; - // send &status to parent - int *ptr = (int *)PCB_ARG2(parent); - if (ptr != NULL) { + pid_t pid; + int *status; + + pid = (pid_t)PCB_ARG1(parent); + status = (int *)PCB_ARG2(parent); + + if (pid == 0 || pid == victim->pid) { + PCB_RET(parent) = zchild->pid; + if (status != NULL) { mem_ctx_switch(parent->memctx); - *ptr = victim->exit_status; + *status = victim->exit_status; mem_ctx_switch(kernel_mem_ctx); } - - // schedule the parent, and clean up the zombie schedule(parent); pcb_cleanup(victim); return; @@ -476,3 +479,39 @@ __attribute__((noreturn)) void dispatch(void) syscall_return(); } + +void pcb_on_tick(void) +{ + // procs not initalized yet + if (init_pcb == NULL) + return; + + // update on sleeping + do { + struct pcb *pcb; + + if (pcb_queue_empty(sleeping)) + break; + + pcb = pcb_queue_peek(sleeping); + assert(pcb != NULL, "sleeping queue should not be empty"); + + if (pcb->wakeup >= ticks) + break; + + if (pcb_queue_remove(sleeping, pcb)) + panic("failed to wake sleeping process: %d", pcb->pid); + + schedule(pcb); + } while (1); + + if (current_pcb) { + current_pcb->ticks--; + if (current_pcb->ticks < 1) { + // schedule another process + schedule(current_pcb); + current_pcb = NULL; + dispatch(); + } + } +} diff --git a/kernel/syscall.c b/kernel/syscall.c index b595b6a..44bfe5f 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -10,11 +10,11 @@ static struct pcb *pcb; -#define RET(type, name) type *name = (type *)(&pcb->regs->rax) -#define ARG1(type, name) type name = (type)(pcb->regs->rdi) -#define ARG2(type, name) type name = (type)(pcb->regs->rsi) -#define ARG3(type, name) type name = (type)(pcb->regs->rdx) -#define ARG4(type, name) type name = (type)(pcb->regs->rcx) +#define RET(type, name) type *name = (type *)(&pcb->regs.rax) +#define ARG1(type, name) type name = (type)(pcb->regs.rdi) +#define ARG2(type, name) type name = (type)(pcb->regs.rsi) +#define ARG3(type, name) type name = (type)(pcb->regs.rdx) +#define ARG4(type, name) type name = (type)(pcb->regs.rcx) __attribute__((noreturn)) static int sys_exit(void) { @@ -255,20 +255,16 @@ static int (*syscall_tbl[N_SYSCALLS])(void) = { [SYS_drm] = sys_drm, [SYS_ticks] = sys_ticks, }; -void syscall_handler(struct cpu_regs *regs) +void syscall_handler(void) { uint64_t num; int (*handler)(void); int ret = 1; - // make sure were in the kernel memory context - mem_ctx_switch(kernel_mem_ctx); - // update data pcb = current_pcb; - pcb->regs = regs; - num = pcb->regs->rax; - pcb->regs->rax = 0; + num = pcb->regs.rax; + pcb->regs.rax = 0; current_pcb = NULL; // check for invalid syscall @@ -287,7 +283,7 @@ void syscall_handler(struct cpu_regs *regs) // on failure, set rax if (ret) - pcb->regs->rax = ret; + pcb->regs.rax = ret; // return to current pcb current_pcb = pcb; diff --git a/kernel/user.c b/kernel/user.c index 9d933e5..ce24b3e 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -16,6 +16,10 @@ #define BLOCK_SIZE (PAGE_SIZE * 1000) static uint8_t *load_buffer = NULL; +#define USER_CODE 0x18 +#define USER_DATA 0x20 +#define RING3 3 + static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) { Elf64_Phdr hdr; @@ -63,7 +67,7 @@ static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) kunmapaddr(mapADDR); return 1; } - memcpyv(mapADDR + total_read, load_buffer, read); + memcpy(mapADDR + total_read, load_buffer, read); total_read += read; } @@ -156,16 +160,28 @@ static int user_setup_stack(struct pcb *pcb) F_WRITEABLE | F_UNPRIVILEGED) == NULL) return 1; - // setup initial context save area - pcb->regs = (struct cpu_regs *)(USER_STACK_TOP - sizeof(struct cpu_regs)); - mem_ctx_switch(pcb->memctx); - memset(pcb->regs, 0, sizeof(struct cpu_regs)); - pcb->regs->rip = pcb->elf_header.e_entry; - pcb->regs->cs = 0x18 | 3; - pcb->regs->rflags = (1 << 9); - pcb->regs->rsp = USER_STACK_TOP; - pcb->regs->ss = 0x20 | 3; - mem_ctx_switch(kernel_mem_ctx); + memset(&pcb->regs, 0, sizeof(struct cpu_regs)); + + // pgdir + pcb->regs.cr3 = (uint64_t)mem_ctx_pgdir(pcb->memctx); + // segments + pcb->regs.gs = USER_DATA | RING3; + pcb->regs.fs = USER_DATA | RING3; + pcb->regs.es = USER_DATA | RING3; + pcb->regs.ds = USER_DATA | RING3; + // registers + pcb->regs.rdi = 0; // argc + pcb->regs.rsi = 0; // argv + // intruction pointer + pcb->regs.rip = pcb->elf_header.e_entry; + // code segment + pcb->regs.cs = 0x18 | 3; + // rflags + pcb->regs.rflags = (1 << 9); + // stack pointer + pcb->regs.rsp = USER_STACK_TOP; + // stack segment + pcb->regs.ss = 0x20 | 3; return 0; } @@ -176,8 +192,6 @@ int user_load(struct pcb *pcb, struct disk *disk) if (pcb == NULL || disk == NULL) return 1; - pcb->regs = NULL; - // allocate memory context pcb->memctx = mem_ctx_alloc(); if (pcb->memctx == NULL) -- cgit v1.2.3-freya From 6f720f67383fee1e143caf04cc537a11a170d7c6 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 11:34:35 -0400 Subject: fix pic eoi in timer --- kernel/cpu/idt.S | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'kernel/cpu') diff --git a/kernel/cpu/idt.S b/kernel/cpu/idt.S index 05c34f5..05f80c7 100644 --- a/kernel/cpu/idt.S +++ b/kernel/cpu/idt.S @@ -135,13 +135,15 @@ isr_stub_\num: ISRRestore .endm +# we have to send eoi first since +# idt_pic_timer may not return .macro PICTimer num .align 8 isr_stub_\num: ISRSave - callq idt_pic_timer - movq $\num, %rdi callq idt_pic_eoi + movq $\num, %rdi + callq idt_pic_timer ISRRestore .endm -- cgit v1.2.3-freya From 3dfffb0b8d89d22bd914daa97339d6a8161c4fdb Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 11:56:18 -0400 Subject: fix segments --- kernel/cpu/idt.S | 3 ++- kernel/user.c | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'kernel/cpu') diff --git a/kernel/cpu/idt.S b/kernel/cpu/idt.S index 05f80c7..b3a8454 100644 --- a/kernel/cpu/idt.S +++ b/kernel/cpu/idt.S @@ -51,12 +51,12 @@ # segments popw %ax movw %ax, %gs + popw %ax movw %ax, %fs popw %ax movw %ax, %es popw %ax movw %ax, %ds - popw %ax # regs popq %r15 @@ -79,6 +79,7 @@ .macro ISRSave PUSHALL cld + movq %rsp, %rdi callq isr_save .endm diff --git a/kernel/user.c b/kernel/user.c index ce24b3e..8f626a7 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -175,13 +175,13 @@ static int user_setup_stack(struct pcb *pcb) // intruction pointer pcb->regs.rip = pcb->elf_header.e_entry; // code segment - pcb->regs.cs = 0x18 | 3; + pcb->regs.cs = USER_CODE | RING3; // rflags pcb->regs.rflags = (1 << 9); // stack pointer pcb->regs.rsp = USER_STACK_TOP; // stack segment - pcb->regs.ss = 0x20 | 3; + pcb->regs.ss = USER_DATA | RING3; return 0; } -- cgit v1.2.3-freya From 5d52bae4a9e42d5d53f397f0088fd4879e2ff02d Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Tue, 29 Apr 2025 10:36:54 -0400 Subject: ps2 --- kernel/cpu/idt.c | 3 + kernel/drivers.c | 2 + kernel/drivers/ps2.c | 296 +++++++++++++++++++++++++++++++++++++ kernel/include/comus/drivers/ps2.h | 49 ++++++ kernel/include/comus/keycodes.h | 143 ++++++++++++++++++ 5 files changed, 493 insertions(+) create mode 100644 kernel/drivers/ps2.c create mode 100644 kernel/include/comus/drivers/ps2.h create mode 100644 kernel/include/comus/keycodes.h (limited to 'kernel/cpu') diff --git a/kernel/cpu/idt.c b/kernel/cpu/idt.c index d071d29..2eab7ec 100644 --- a/kernel/cpu/idt.c +++ b/kernel/cpu/idt.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include #include @@ -185,8 +186,10 @@ void idt_pic_timer(void) void idt_pic_keyboard(void) { + ps2kb_recv(); } void idt_pic_mouse(void) { + ps2mouse_recv(); } diff --git a/kernel/drivers.c b/kernel/drivers.c index 98bf1bd..3d6ec10 100644 --- a/kernel/drivers.c +++ b/kernel/drivers.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,7 @@ void drivers_init(void) { pit_set_divider(1193); // 1ms uart_init(); + ps2_init(); pci_init(); ata_init(); acpi_init(mboot_get_rsdp()); diff --git a/kernel/drivers/ps2.c b/kernel/drivers/ps2.c new file mode 100644 index 0000000..5c18b5b --- /dev/null +++ b/kernel/drivers/ps2.c @@ -0,0 +1,296 @@ +#include +#include +#include +#include + +#define STATUS_OUT_BUF ((uint8_t)0x01) +#define STATUS_IN_BUF ((uint8_t)0x02) + +#define CONFIG_INT_0 ((uint8_t)0x01) +#define CONFIG_INT_1 ((uint8_t)0x02) +#define CONFIG_SYS ((uint8_t)0x04) +#define CONFIG_CLOCK_0 ((uint8_t)0x10) +#define CONFIG_CLOCK_1 ((uint8_t)0x20) +#define CONFIG_TRANS ((uint8_t)0x40) + +static uint8_t scancodes[] = { + KEY_NONE, KEY_F9, KEY_NONE, KEY_F5, KEY_F3, + KEY_F1, KEY_F2, KEY_F12, KEY_NONE, KEY_F10, + KEY_F8, KEY_F6, KEY_F4, KEY_TAB, KEY_BACKTICK, + KEY_NONE, KEY_NONE, KEY_L_ALT, KEY_L_SHIFT, KEY_NONE, + KEY_L_CTRL, KEY_Q, KEY_1, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_Z, KEY_S, KEY_A, KEY_W, + KEY_2, KEY_NONE, KEY_NONE, KEY_C, KEY_X, + KEY_D, KEY_E, KEY_4, KEY_3, KEY_NONE, + KEY_NONE, KEY_SPACE, KEY_V, KEY_F, KEY_T, + KEY_R, KEY_5, KEY_NONE, KEY_NONE, KEY_N, + KEY_B, KEY_H, KEY_G, KEY_Y, KEY_6, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_M, KEY_J, + KEY_U, KEY_7, KEY_8, KEY_NONE, KEY_NONE, + KEY_COMMA, KEY_K, KEY_I, KEY_O, KEY_0, + KEY_9, KEY_NONE, KEY_NONE, KEY_PERIOD, KEY_SLASH, + KEY_L, KEY_SEMICOLON, KEY_P, KEY_MINUS, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_QUOTE, KEY_NONE, KEY_L_BRACE, + KEY_EQUAL, KEY_NONE, KEY_NONE, KEY_CAPS_LOCK, KEY_R_SHIFT, + KEY_ENTER, KEY_R_BRACE, KEY_NONE, KEY_BACKSLASH, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_BACKSPACE, KEY_NONE, KEY_NONE, + KEY_NP_1, KEY_NONE, KEY_NP_4, KEY_NP_7, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NP_0, KEY_NP_PERIOD, KEY_NP_2, + KEY_NP_5, KEY_NP_6, KEY_NP_8, KEY_ESCAPE, KEY_NUM_LOCK, + KEY_F11, KEY_NP_PLUS, KEY_NP_3, KEY_NP_MINUS, KEY_NP_ASTERISK, + KEY_NP_9, KEY_SCROLL_LOCK, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_F7, +}; +static uint8_t scancodes_ext[] = { + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_UNKNOWN, KEY_R_ALT, KEY_PRINT_SCREEN, KEY_NONE, + KEY_R_CTRL, KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_L_META, KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, + KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_R_META, + KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_MENU, KEY_UNKNOWN, KEY_NONE, + KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, + KEY_UNKNOWN, KEY_UNKNOWN, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_UNKNOWN, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NP_SLASH, + KEY_NONE, KEY_NONE, KEY_UNKNOWN, KEY_NONE, KEY_NONE, + KEY_UNKNOWN, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NP_ENTER, KEY_NONE, KEY_NONE, KEY_NONE, KEY_UNKNOWN, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_END, KEY_NONE, KEY_LEFT, KEY_HOME, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_INSERT, KEY_DELETE, KEY_DOWN, + KEY_NONE, KEY_RIGHT, KEY_UP, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_PAGE_DOWN, KEY_NONE, KEY_NONE, + KEY_PAGE_UP, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, KEY_NONE, + KEY_NONE, +}; + +// ctrl +static bool has_kbd = false; +static bool has_mouse = false; + +// kbd +static struct keycode last_keycode = { + .key = KEY_NONE, + .flags = 0, +}; +static bool state_keyup = false; +static bool state_ext = false; + +// mouse +static struct mouse_event last_mouse_ev = { + .updated = false, + .lmb = false, + .mmb = false, + .rmb = false, + .relx = 0, + .rely = 0, +}; +static uint8_t first_b, second_b, third_b; + +static uint8_t ps2ctrl_in_status(void) +{ + return inb(0x64); +} + +static uint8_t ps2ctrl_in(void) +{ + while ((ps2ctrl_in_status() & STATUS_OUT_BUF) == 0) { + io_wait(); + } + return inb(0x60); +} + +static void ps2ctrl_out_cmd(uint8_t cmd) +{ + while ((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) { + io_wait(); + } + outb(0x64, cmd); +} + +static void ps2ctrl_out_data(uint8_t data) +{ + while ((ps2ctrl_in_status() & STATUS_IN_BUF) != 0) { + io_wait(); + } + outb(0x60, data); +} + +static void ps2ctrl_set_port2(void) +{ + outb(0x64, 0xD4); +} + +static int ps2kb_init(void) +{ + uint8_t result; + + ps2ctrl_out_data(0xFF); + if ((result = ps2ctrl_in()) != 0xFA) + return 1; + + if ((result = ps2ctrl_in()) != 0xAA) + return 1; + + ps2ctrl_out_data(0xF4); + if ((result = ps2ctrl_in()) != 0xFA) + return 1; + + has_kbd = true; + return 0; +} + +static int ps2mouse_init(void) +{ + uint8_t result; + + ps2ctrl_set_port2(); + ps2ctrl_out_data(0xFF); + if ((result = ps2ctrl_in()) != 0xFA) + return 1; + + if ((result = ps2ctrl_in()) != 0xAA) + return 1; + + ps2ctrl_set_port2(); + ps2ctrl_out_data(0xF4); + + has_mouse = true; + return 0; +} + +void ps2kb_recv(void) +{ + uint8_t code; + + if (!has_kbd) + return; + + code = ps2ctrl_in(); + if (code == 0x00 || code == 0x0F) { + last_keycode.key = KEY_NONE; + last_keycode.flags = KC_FLAG_ERROR; + } else if (code == 0xF0) { + state_keyup = true; + } else if (code == 0xE0) { + state_ext = true; + } else if (code <= 0x84) { + uint8_t *scancode_table = state_ext ? scancodes_ext : scancodes; + uint8_t keycode = scancode_table[code]; + if (keycode != KEY_NONE) { + last_keycode.key = keycode; + last_keycode.flags = state_keyup ? KC_FLAG_KEY_UP : + KC_FLAG_KEY_DOWN; + } + state_keyup = false; + state_ext = false; + } +} + +struct keycode ps2kb_get(void) +{ + struct keycode code; + + if (!has_kbd) + return last_keycode; + + code = last_keycode; + last_keycode.key = KEY_NONE; + last_keycode.flags = 0; + return code; +} + +void ps2mouse_recv(void) +{ + static uint8_t packet_num = 0; + uint8_t code; + + if (!has_mouse) + return; + + code = ps2ctrl_in(); + switch (packet_num) { + case 0: + first_b = code; + break; + case 1: + second_b = code; + break; + case 2: { + int state, d; + + third_b = code; + state = first_b; + d = second_b; + last_mouse_ev.relx = d - ((state << 4) & 0x100); + d = third_b; + last_mouse_ev.rely = d - ((state << 3) & 0x100); + + last_mouse_ev.lmb = first_b & 0x01; + last_mouse_ev.rmb = first_b & 0x02; + last_mouse_ev.mmb = first_b & 0x04; + last_mouse_ev.updated = true; + break; + } + } + + packet_num += 1; + packet_num %= 3; +} + +struct mouse_event ps2mouse_get(void) +{ + struct mouse_event event = last_mouse_ev; + last_mouse_ev.updated = false; + return event; +} + +int ps2_init(void) +{ + uint8_t result; + + cli(); + + inb(0x60); + + // self-test + ps2ctrl_out_cmd(0xAA); + if ((result = ps2ctrl_in()) != 0x55) { + WARN("PS/2 Controller failed to initalize."); + return 1; + } + + // set config + ps2ctrl_out_cmd(0x20); + uint8_t config = ps2ctrl_in(); + config = (config | CONFIG_INT_0 | CONFIG_INT_1) & ~CONFIG_TRANS; + // config = 0xFF; + ps2ctrl_out_cmd(0x60); + ps2ctrl_out_data(config); + + // enable port 0 + ps2ctrl_out_cmd(0xAE); + + // enable port 2 + ps2ctrl_out_cmd(0xA9); + if ((result != ps2ctrl_in()) != 0x01) { + WARN("PS/2 port 2 not supported"); + return 1; + } + + ps2ctrl_out_cmd(0xA8); + + ps2kb_init(); + ps2mouse_init(); + sti(); + return 0; +} diff --git a/kernel/include/comus/drivers/ps2.h b/kernel/include/comus/drivers/ps2.h new file mode 100644 index 0000000..6e594e9 --- /dev/null +++ b/kernel/include/comus/drivers/ps2.h @@ -0,0 +1,49 @@ +/** + * @file ps2.h + * + * @author Freya Murphy + * + * PS/2 Mouse & Keyboard + */ + +#ifndef PS2_H_ +#define PS2_H_ + +#include +#include + +struct mouse_event { + bool updated; + bool lmb; + bool rmb; + bool mmb; + int relx; + int rely; +}; + +/** + * Initalize the ps2 controller + */ +int ps2_init(void); + +/** + * Recieve input from ps2 keyboard during interrupt + */ +void ps2kb_recv(void); + +/** + * Return last read keycode + */ +struct keycode ps2kb_get(void); + +/** + * Recieve input from ps2 mouse during interrupt + */ +void ps2mouse_recv(void); + +/** + * Return last read mouse event + */ +struct mouse_event ps2mouse_get(void); + +#endif /* ps2.h */ diff --git a/kernel/include/comus/keycodes.h b/kernel/include/comus/keycodes.h new file mode 100644 index 0000000..8930937 --- /dev/null +++ b/kernel/include/comus/keycodes.h @@ -0,0 +1,143 @@ +/** + * @file keycodes.h + * + * @author Tristan Miller + * + * Kernel keycodes + */ + +#ifndef KEYCODES_H_ +#define KEYCODES_H_ + +struct keycode { + char key; + char flags; +}; + +#define KC_FLAG_KEY_DOWN 0x01 +#define KC_FLAG_KEY_UP 0x02 +#define KC_FLAG_ERROR 0x04 + +#define KEY_NONE 0x00 +#define KEY_UNKNOWN 0x01 + +#define KEY_ESCAPE 0x10 +#define KEY_1 0x11 +#define KEY_2 0x12 +#define KEY_3 0x13 +#define KEY_4 0x14 +#define KEY_5 0x15 +#define KEY_6 0x16 +#define KEY_7 0x17 +#define KEY_8 0x18 +#define KEY_9 0x19 +#define KEY_0 0x1A +#define KEY_MINUS 0x1B +#define KEY_EQUAL 0x1C +#define KEY_BACKSPACE 0x1D +#define KEY_L_SHIFT 0x1E +#define KEY_R_SHIFT 0x1F + +#define KEY_TAB 0x20 +#define KEY_Q 0x21 +#define KEY_W 0x22 +#define KEY_E 0x23 +#define KEY_R 0x24 +#define KEY_T 0x25 +#define KEY_Y 0x26 +#define KEY_U 0x27 +#define KEY_I 0x28 +#define KEY_O 0x29 +#define KEY_P 0x2A +#define KEY_L_BRACE 0x2B +#define KEY_R_BRACE 0x2C +#define KEY_BACKSLASH 0x2D +#define KEY_L_CTRL 0x2E +#define KEY_R_CTRL 0x2F + +#define KEY_CAPS_LOCK 0x30 +#define KEY_A 0x31 +#define KEY_S 0x32 +#define KEY_D 0x33 +#define KEY_F 0x34 +#define KEY_G 0x35 +#define KEY_H 0x36 +#define KEY_J 0x37 +#define KEY_K 0x38 +#define KEY_L 0x39 +#define KEY_SEMICOLON 0x3A +#define KEY_QUOTE 0x3B +#define KEY_ENTER 0x3C +#define KEY_MENU 0x3D +#define KEY_L_ALT 0x3E +#define KEY_R_ALT 0x3F + +#define KEY_SPACE 0x40 +#define KEY_Z 0x41 +#define KEY_X 0x42 +#define KEY_C 0x43 +#define KEY_V 0x44 +#define KEY_B 0x45 +#define KEY_N 0x46 +#define KEY_M 0x47 +#define KEY_COMMA 0x48 +#define KEY_PERIOD 0x49 +#define KEY_SLASH 0x4A +#define KEY_BACKTICK 0x4B +#define KEY_NUM_LOCK 0x4C +#define KEY_SCROLL_LOCK 0x4D +#define KEY_L_META 0x4E +#define KEY_R_META 0x4F + +#define KEY_NP_SLASH 0x50 +#define KEY_NP_7 0x51 +#define KEY_NP_8 0x52 +#define KEY_NP_9 0x53 +#define KEY_NP_ASTERISK 0x54 +#define KEY_NP_4 0x55 +#define KEY_NP_5 0x56 +#define KEY_NP_6 0x57 +#define KEY_NP_MINUS 0x58 +#define KEY_NP_1 0x59 +#define KEY_NP_2 0x5A +#define KEY_NP_3 0x5B +#define KEY_NP_PLUS 0x5C +#define KEY_NP_0 0x5D +#define KEY_NP_PERIOD 0x5E +#define KEY_NP_ENTER 0x5F + +#define KEY_PRINT_SCREEN 0x60 +#define KEY_PAUSE 0x61 +#define KEY_INSERT 0x62 +#define KEY_HOME 0x63 +#define KEY_PAGE_UP 0x64 +#define KEY_DELETE 0x65 +#define KEY_END 0x66 +#define KEY_PAGE_DOWN 0x67 +#define KEY_UP 0x68 +#define KEY_DOWN 0x69 +#define KEY_LEFT 0x6A +#define KEY_RIGHT 0x6B +// #define _ 0x6C +// #define _ 0x6D +// #define _ 0x6E +// #define _ 0x6F + +#define KEY_F1 0x70 +#define KEY_F2 0x71 +#define KEY_F3 0x72 +#define KEY_F4 0x73 +#define KEY_F5 0x74 +#define KEY_F6 0x75 +#define KEY_F7 0x76 +#define KEY_F8 0x77 +#define KEY_F9 0x78 +#define KEY_F10 0x79 +#define KEY_F11 0x7A +#define KEY_F12 0x7B +// #define _ 0x7C +// #define _ 0x7D +// #define _ 0x7E +// #define _ 0x7F + +#endif /* keycodes */ -- cgit v1.2.3-freya