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 ++++++++++++++++++++++ kernel/entry.S | 5 +++- 5 files changed, 124 insertions(+), 1 deletion(-) create mode 100644 kernel/cpu/tss.S create mode 100644 kernel/cpu/tss.c create mode 100644 kernel/cpu/tss.h (limited to 'kernel') 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 */ diff --git a/kernel/entry.S b/kernel/entry.S index aa4c38d..4b5415b 100644 --- a/kernel/entry.S +++ b/kernel/entry.S @@ -7,8 +7,10 @@ .globl kernel_pd_0_ents .globl kernel_pd_1 .globl paging_pt + .globl GDT + .globl kern_stack_end + .globl kern_stack_start .extern main - .extern GDT .section .multiboot @@ -155,6 +157,7 @@ GDT: # TSS segment (0x28) .equ GDT.TSS, . - GDT + .quad 0 .quad 0 # to be modified in kernel # GDT Pointer -- 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') 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 f9df808fd5e39a2494a5ab3eb90ea71fdc7b187f Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 24 Apr 2025 11:32:21 -0400 Subject: only backtrace on valid kernel frames --- kernel/lib/backtrace.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/lib/backtrace.c b/kernel/lib/backtrace.c index 485cc0f..102e775 100644 --- a/kernel/lib/backtrace.c +++ b/kernel/lib/backtrace.c @@ -6,6 +6,11 @@ struct stackframe { void *rip; }; +extern char kern_stack_start[]; +extern char 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) { struct stackframe *rbp; @@ -17,11 +22,13 @@ size_t backtrace_ex(void **dst, size_t len, void *ip, void *bp) { struct stackframe *frame = bp; __asm__("mov %%rbp, %0" : "=r"(frame)); + if (!VALID(frame)) + return 0; if (len > 0) { dst[0] = ip; } size_t i; - for (i = 1; frame && i < len; i++) { + for (i = 1; VALID(frame) && i < len; i++) { dst[i] = frame->rip; frame = frame->rbp; } @@ -38,9 +45,11 @@ void log_backtrace(void) void log_backtrace_ex(void *ip, void *bp) { struct stackframe *frame = bp; + if (!VALID(frame)) + return; kputs("Stack trace:\n"); kprintf(" %p\t%s\n", ip, mboot_get_elf_sym((uint64_t)ip)); - while (frame) { + while (VALID(frame)) { kprintf(" %p\t%s\n", frame->rip, mboot_get_elf_sym((uint64_t)frame->rip)); frame = frame->rbp; -- cgit v1.2.3-freya From 8a81340b78def3895c119d5ada63cbe3a8452985 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 24 Apr 2025 12:38:28 -0400 Subject: const pointers on free & kmapuseraddr --- kernel/include/comus/memory.h | 18 ++++++++++++++---- kernel/memory/memory.c | 4 ++-- kernel/memory/paging.c | 32 ++++++++++++++++++++++++-------- kernel/memory/virtalloc.c | 2 +- kernel/memory/virtalloc.h | 2 +- 5 files changed, 42 insertions(+), 16 deletions(-) (limited to 'kernel') diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h index 942e7a8..255eca2 100644 --- a/kernel/include/comus/memory.h +++ b/kernel/include/comus/memory.h @@ -121,7 +121,7 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, * Unmaps mapped address from the kmapaddr function * @param virt - the vitural address returned from kmapaddr */ -void mem_unmapaddr(mem_ctx_t ctx, void *virt); +void mem_unmapaddr(mem_ctx_t ctx, const void *virt); /** * Allocate a single page of memory with the given paging structure @@ -169,7 +169,7 @@ void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, * * @param ptr - the pointer provided by alloc_page or alloc_pages */ -void mem_free_pages(mem_ctx_t ctx, void *ptr); +void mem_free_pages(mem_ctx_t ctx, const void *ptr); /** * Allocates at least len bytes of memory starting at @@ -184,11 +184,21 @@ void mem_free_pages(mem_ctx_t ctx, void *ptr); */ void *kmapaddr(void *phys, void *virt, size_t len, unsigned int flags); +/** + * Map a vitural address in a userspace context to kernel space + * + * @param ctx - the userspace memory context to map from + * @param virt - the vitural address given by userspace + * @param len - the length of the buffer to map + * @returns vitural address mapped in kernel context + */ +void *kmapuseraddr(mem_ctx_t ctx, const void *virt, size_t len); + /** * Unmaps mapped address from the kmapaddr function * @param virt - the vitural address returned from kmapaddr */ -void kunmapaddr(void *virt); +void kunmapaddr(const void *virt); /** * Allocate a single page of memory @@ -210,6 +220,6 @@ void *kalloc_pages(size_t count); * * @param ptr - the pointer provided by alloc_page or alloc_pages */ -void kfree_pages(void *ptr); +void kfree_pages(const void *ptr); #endif /* memory.h */ diff --git a/kernel/memory/memory.c b/kernel/memory/memory.c index 2a9c15e..7ceb491 100644 --- a/kernel/memory/memory.c +++ b/kernel/memory/memory.c @@ -26,7 +26,7 @@ void *kmapaddr(void *phys, void *virt, size_t len, unsigned int flags) return mem_mapaddr(kernel_mem_ctx, phys, virt, len, flags); } -void kunmapaddr(void *virt) +void kunmapaddr(const void *virt) { mem_unmapaddr(kernel_mem_ctx, virt); } @@ -41,7 +41,7 @@ void *kalloc_pages(size_t count) return mem_alloc_pages(kernel_mem_ctx, count, F_PRESENT | F_WRITEABLE); } -void kfree_pages(void *ptr) +void kfree_pages(const void *ptr) { mem_free_pages(kernel_mem_ctx, ptr); } diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index 4f1b788..f286027 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -5,6 +5,7 @@ #include "physalloc.h" #include "paging.h" #include "memory.h" +#include // PAGE MAP LEVEL 4 ENTRY struct pml4e { @@ -214,7 +215,7 @@ static volatile struct pt *pt_map(volatile struct pt *pPT) // locate a pdpt for a vitural address // @returns PHYSICAL ADDRESS static volatile struct pdpt *pdpt_locate(volatile struct pml4 *pPML4, - void *vADDR) + const void *vADDR) { volatile struct pml4 *vPML4; volatile struct pml4e *vPML4E; @@ -235,7 +236,7 @@ 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, void *vADDR) +static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT, const void *vADDR) { volatile struct pdpt *vPDPT; volatile struct pdpte *vPDPTE; @@ -256,7 +257,7 @@ static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT, void *vADDR) // locate a pt for a vitural address // @returns PHYSICAL ADDRESS -static volatile struct pt *pt_locate(volatile struct pd *pPD, void *vADDR) +static volatile struct pt *pt_locate(volatile struct pd *pPD, const void *vADDR) { volatile struct pd *vPD; volatile struct pde *vPDE; @@ -506,7 +507,7 @@ free: // locate a pte for a vitural address // @returns VIRTUAL ADDRESS static volatile struct pte *page_locate(volatile struct pml4 *pPML4, - void *vADDR) + const void *vADDR) { volatile struct pdpt *pPDPT; volatile struct pd *pPD; @@ -573,7 +574,7 @@ static volatile struct pte *page_alloc(volatile struct pml4 *pPML4, void *vADDR, } // free a pte (page) for a vitural address -static void page_free(volatile struct pml4 *pPML4, void *vADDR) +static void page_free(volatile struct pml4 *pPML4, const void *vADDR) { volatile struct pte *vPTE; void *pADDR; @@ -591,7 +592,7 @@ static void page_free(volatile struct pml4 *pPML4, void *vADDR) /* map & unmap pages */ -static void unmap_pages(volatile struct pml4 *pPML4, void *vADDR, +static void unmap_pages(volatile struct pml4 *pPML4, const void *vADDR, long page_count) { for (long i = 0; i < page_count; i++) { @@ -717,7 +718,22 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, return (char *)virt + error; } -void mem_unmapaddr(mem_ctx_t ctx, void *virt) +void *kmapuseraddr(mem_ctx_t ctx, const void *vADDR, size_t len) +{ + char *pADDR; + volatile struct pte *vPTE; + + vPTE = page_locate((volatile struct pml4 *)ctx->pml4, vADDR); + if (vPTE == NULL) + return NULL; + + pADDR = (void *)((uintptr_t)vPTE->address << 12); + pADDR += ((uint64_t)vADDR % PAGE_SIZE); + + return kmapaddr(pADDR, NULL, len, F_PRESENT | F_WRITEABLE); +} + +void mem_unmapaddr(mem_ctx_t ctx, const void *virt) { if (virt == NULL) return; @@ -768,7 +784,7 @@ void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, return virt; } -void mem_free_pages(mem_ctx_t ctx, void *virt) +void mem_free_pages(mem_ctx_t ctx, const void *virt) { if (virt == NULL) return; diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c index 0f4de93..3690eae 100644 --- a/kernel/memory/virtalloc.c +++ b/kernel/memory/virtalloc.c @@ -165,7 +165,7 @@ void *virtaddr_alloc(struct virt_ctx *ctx, int n_pages) return NULL; } -long virtaddr_free(struct virt_ctx *ctx, void *virtaddr) +long virtaddr_free(struct virt_ctx *ctx, const void *virtaddr) { if (virtaddr == NULL) return -1; diff --git a/kernel/memory/virtalloc.h b/kernel/memory/virtalloc.h index 7bf8b91..78adc46 100644 --- a/kernel/memory/virtalloc.h +++ b/kernel/memory/virtalloc.h @@ -64,7 +64,7 @@ void *virtaddr_alloc(struct virt_ctx *ctx, int pages); * @param virtaddr - the addr to free * @returns number of pages used for virtaddr */ -long virtaddr_free(struct virt_ctx *ctx, void *virtaddr); +long virtaddr_free(struct virt_ctx *ctx, const void *virtaddr); /** * Cleans up heap allocations and frees the virtalloc context -- 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') 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') 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 3a0fbbe6c75c06f1a38b5ef7e3bc8c4b47ccd4b0 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 24 Apr 2025 13:42:14 -0400 Subject: user.c for loading userspace elfs into memory --- kernel/include/comus/limits.h | 3 + kernel/include/comus/procs.h | 6 ++ kernel/include/comus/user.h | 25 +++++++++ kernel/user.c | 124 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 158 insertions(+) create mode 100644 kernel/include/comus/user.h (limited to 'kernel') diff --git a/kernel/include/comus/limits.h b/kernel/include/comus/limits.h index 675df47..cadfc93 100644 --- a/kernel/include/comus/limits.h +++ b/kernel/include/comus/limits.h @@ -22,6 +22,9 @@ #define N_FILE_NAME 256 #define N_DISKS 8 +/// elf limits +#define N_ELF_SEGMENTS 16 + /// length of terminal buffer #define TERM_MAX_WIDTH 1920 #define TERM_MAX_HEIGHT 1080 diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h index d92bc5d..d105867 100644 --- a/kernel/include/comus/procs.h +++ b/kernel/include/comus/procs.h @@ -13,6 +13,7 @@ #include #include #include +#include #define PCB_REG(pcb, x) ((pcb)->regs->x) #define PCB_RET(pcb) ((pcb)->regs->rax) @@ -56,6 +57,11 @@ struct pcb { size_t priority; size_t ticks; + // elf metadata + Elf64_Ehdr elf_header; + Elf64_Phdr elf_segments[N_ELF_SEGMENTS]; + Elf64_Half n_elf_segments; + // queue linkage struct pcb *next; // next PDB in queue diff --git a/kernel/include/comus/user.h b/kernel/include/comus/user.h new file mode 100644 index 0000000..29c978c --- /dev/null +++ b/kernel/include/comus/user.h @@ -0,0 +1,25 @@ +/** + * @file user.h + * + * @author Freya Murphy + * + * Userland functions + */ + +#ifndef USER_H_ +#define USER_H_ + +#include +#include + +/** + * Load a user elf program from a file into a pcb + */ +int user_load(struct pcb *pcb, struct disk *disk); + +/** + * Clean up all loaded userland data from a pcb + */ +void user_cleanup(struct pcb *pcb); + +#endif /* user.h */ diff --git a/kernel/user.c b/kernel/user.c index 0a237e9..592b35b 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -1,5 +1,129 @@ +#include "lib/kio.h" +#include #include #include +#include +#include + +/// FIXME: the following code is using direct +/// disk access instead of file access, this is +/// because filesystems are not yet implemented. +/// This MUST be changed once we have files. +/// - Freya + +#define USER_STACK_TOP 0x800000000000 +#define USER_STACK_LEN (4 * PAGE_SIZE) + +static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) +{ + uint8_t buf[PAGE_SIZE]; + Elf64_Phdr hdr; + size_t npages; + int ret = 0; + + hdr = pcb->elf_segments[idx]; + npages = (hdr.p_filesz + PAGE_SIZE - 1) / PAGE_SIZE; + + // allocate memory in user process + if (mem_alloc_pages_at(pcb->memctx, npages, (void *)hdr.p_vaddr, + F_WRITEABLE | F_UNPRIVILEGED) == NULL) + return 1; + + // load data + for (size_t i = 0; i < npages; i++) { + mem_ctx_switch(kernel_mem_ctx); // disk_read is kernel internal + ret = disk_read(disk, hdr.p_offset + i * PAGE_SIZE, PAGE_SIZE, buf); + if (ret < 0) + break; + mem_ctx_switch(pcb->memctx); + memcpy((char *)hdr.p_vaddr + i * PAGE_SIZE, buf, PAGE_SIZE); + } + + mem_ctx_switch(kernel_mem_ctx); + return ret; +} + +static int user_load_segments(struct pcb *pcb, struct disk *disk) +{ + int ret = 0; + + for (int i = 0; i < pcb->n_elf_segments; i++) + if ((ret = user_load_segment(pcb, disk, i))) + return ret; + return 0; +} + +static int user_load_elf(struct pcb *pcb, struct disk *disk) +{ + int ret = 0; + + ret = disk_read(disk, 0, sizeof(Elf64_Ehdr), &pcb->elf_header); + if (ret < 0) + return 1; + + if (pcb->elf_header.e_phnum > N_ELF_SEGMENTS) + return 1; + + pcb->n_elf_segments = pcb->elf_header.e_phnum; + ret = disk_read(disk, pcb->elf_header.e_phoff, + sizeof(Elf64_Phdr) * pcb->elf_header.e_phnum, + &pcb->elf_segments); + if (ret < 0) + return 1; + + return 0; +} + +static int user_setup_stack(struct pcb *pcb) +{ + // allocate stack + if (mem_alloc_pages_at(pcb->memctx, USER_STACK_LEN / PAGE_SIZE, + (void *)(USER_STACK_TOP - USER_STACK_LEN), + 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); + + return 0; +} + +int user_load(struct pcb *pcb, struct disk *disk) +{ + pcb->regs = NULL; + + // allocate memory context + pcb->memctx = mem_ctx_alloc(); + if (pcb->memctx == NULL) + goto fail; + + // load elf information + if (user_load_elf(pcb, disk)) + goto fail; + + // load segments into memory + if (user_load_segments(pcb, disk)) + goto fail; + + // setup process stack + if (user_setup_stack(pcb)) + goto fail; + + // success + return 0; + +fail: + user_cleanup(pcb); + return 1; +} void user_cleanup(struct pcb *pcb) { -- cgit v1.2.3-freya From d113de791c51f8ea3a066569783783290451ad75 Mon Sep 17 00:00:00 2001 From: Ian McFarlane Date: Thu, 24 Apr 2025 14:37:50 -0400 Subject: size_t for alloc pages cals --- kernel/memory/physalloc.c | 10 +++++----- kernel/memory/physalloc.h | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index b164358..60e7017 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -79,12 +79,12 @@ void *alloc_phys_page(void) return alloc_phys_pages(1); } -void *alloc_phys_pages(int pages) +void *alloc_phys_pages(size_t pages) { if (pages < 1) return NULL; - int n_contiguous = 0; + size_t n_contiguous = 0; int free_region_start = 0; for (uint64_t i = 0; i < page_count; i++) { bool free = !bitmap_get(i); @@ -94,7 +94,7 @@ void *alloc_phys_pages(int pages) free_region_start = i; n_contiguous++; if (n_contiguous == pages) { - for (int j = 0; j < pages; j++) + for (size_t j = 0; j < pages; j++) bitmap_set(free_region_start + j, true); return page_at(free_region_start); } @@ -110,7 +110,7 @@ void free_phys_page(void *ptr) free_phys_pages(ptr, 1); } -void free_phys_pages(void *ptr, int pages) +void free_phys_pages(void *ptr, size_t pages) { if (ptr == NULL) return; @@ -119,7 +119,7 @@ void free_phys_pages(void *ptr, int pages) if (idx == -1) return; - for (int i = 0; i < pages; i++) + for (size_t i = 0; i < pages; i++) bitmap_set(idx + pages, false); } diff --git a/kernel/memory/physalloc.h b/kernel/memory/physalloc.h index 7afe998..d91c57a 100644 --- a/kernel/memory/physalloc.h +++ b/kernel/memory/physalloc.h @@ -26,7 +26,7 @@ void *alloc_phys_page(void); * Allocates count physical pages in memory * @returns the physical address of the first page */ -void *alloc_phys_pages(int count); +void *alloc_phys_pages(size_t count); /** * Frees a single physical page in memory @@ -39,6 +39,6 @@ void free_phys_page(void *ptr); * @param ptr - the physical address of the first page * @param count - the number of pages in the list */ -void free_phys_pages(void *ptr, int count); +void free_phys_pages(void *ptr, size_t count); #endif /* physalloc.h */ -- cgit v1.2.3-freya From 0096743bce5e1e3e03756fd4f7c441036e1589cd Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Thu, 24 Apr 2025 14:37:44 -0400 Subject: fix paging free fns --- kernel/memory/paging.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'kernel') diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index 80ab833..58c5091 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -416,6 +416,13 @@ static void pt_free(volatile struct pt *pPT, bool force) pADDR = (void *)((uintptr_t)vPTE->address << 12); free_phys_page(pADDR); + count--; + } + + if (!force && count) { + vPT->count_low = count; + vPT->count_high = count >> 2; + return; } free: @@ -443,6 +450,12 @@ static void pd_free(volatile struct pd *pPD, bool force) pPT = (volatile struct pt *)((uintptr_t)vPDE->address << 12); pt_free(pPT, force); + count--; + } + + if (!force && count) { + vPD->count = count; + return; } free: @@ -470,6 +483,12 @@ static void pdpt_free(volatile struct pdpt *pPDPT, bool force) pPD = (volatile struct pd *)((uintptr_t)vPDPTE->address << 12); pd_free(pPD, force); + count--; + } + + if (!force && count) { + vPDPT->count = count; + return; } free: @@ -497,6 +516,12 @@ static void pml4_free(volatile struct pml4 *pPML4, bool force) pPDPT = (volatile struct pdpt *)((uintptr_t)vPML4E->address << 12); pdpt_free(pPDPT, force); + count--; + } + + if (!force && count) { + vPML4->count = count; + return; } free: -- cgit v1.2.3-freya From 3c213ce446c6547c79f683f035b191e92b4e914e Mon Sep 17 00:00:00 2001 From: Ian McFarlane Date: Thu, 24 Apr 2025 15:50:50 -0400 Subject: make alloc_pages_at() able to allocate noncontiguous physical pages --- kernel/include/lib.h | 1 + kernel/include/lib/kmath.h | 20 ++++++++++++++++++ kernel/memory/paging.c | 36 +++++++++++++++++++++++++------- kernel/memory/physalloc.c | 52 +++++++++++++++++++++++++++++++++++++++++----- kernel/memory/physalloc.h | 33 ++++++++++++++++++++++++++--- 5 files changed, 126 insertions(+), 16 deletions(-) create mode 100644 kernel/include/lib/kmath.h (limited to 'kernel') diff --git a/kernel/include/lib.h b/kernel/include/lib.h index be4e739..edfbeb4 100644 --- a/kernel/include/lib.h +++ b/kernel/include/lib.h @@ -15,6 +15,7 @@ #include #include #include +#include #include #endif /* lib.h */ diff --git a/kernel/include/lib/kmath.h b/kernel/include/lib/kmath.h new file mode 100644 index 0000000..3be953d --- /dev/null +++ b/kernel/include/lib/kmath.h @@ -0,0 +1,20 @@ +/** + * @file kmath.h + * + * @author Ian McFarlane + * + * Kernel math functions + */ + +#ifndef _KMATH_H +#define _KMATH_H + +#include + +// min and max both prefer a over b +#define MAX(a, b) ((a) >= (b) ? (a) : (b)) +#define MIN(a, b) ((a) <= (b) ? (a) : (b)) + +#define CLAMP(val, min, max) (MAX((min), MIN((val), (max)))) + +#endif diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index 58c5091..24a9ea7 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -796,16 +796,36 @@ void *mem_alloc_pages(mem_ctx_t ctx, size_t count, unsigned int flags) void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, unsigned int flags) { - void *phys = alloc_phys_pages(count); - if (phys == NULL) - return NULL; + size_t pages_needed = count; + uint8_t *virtual_address = virt; + + void *phys_start = NULL; + + while (pages_needed > 0) { + struct phys_page_slice phys_pages = + alloc_phys_page_withextra(pages_needed); + if (phys_pages.pagestart == NULL) { + free_phys_pages(phys_start ? phys_start : phys_pages.pagestart, + count - pages_needed); + return NULL; + } - if (map_pages((volatile struct pml4 *)ctx->pml4, virt, phys, flags, - count)) { - if (phys) - free_phys_pages(phys, count); - return NULL; + if (!phys_start) + phys_start = phys_pages.pagestart; + + assert(pages_needed >= phys_pages.num_pages, "overflow"); + pages_needed -= phys_pages.num_pages; + virtual_address += phys_pages.num_pages * PAGE_SIZE; + + if (map_pages((volatile struct pml4 *)ctx->pml4, + (void *)virtual_address, phys_pages.pagestart, flags, + phys_pages.num_pages)) { + assert(phys_start, "expected something allocated"); + free_phys_pages(phys_start, count - pages_needed); + return NULL; + } } + return virt; } diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index 60e7017..856a627 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -58,7 +58,7 @@ static long page_idx(void *page) return -1; } -static inline bool bitmap_get(int i) +static inline bool bitmap_get(size_t i) { return (bitmap[i / 64] >> i % 64) & 1; } @@ -76,17 +76,17 @@ static inline void bitmap_set(int i, bool v) void *alloc_phys_page(void) { - return alloc_phys_pages(1); + return alloc_phys_pages_exact(1); } -void *alloc_phys_pages(size_t pages) +void *alloc_phys_pages_exact(size_t pages) { if (pages < 1) return NULL; size_t n_contiguous = 0; - int free_region_start = 0; - for (uint64_t i = 0; i < page_count; i++) { + size_t free_region_start = 0; + for (size_t i = 0; i < page_count; i++) { bool free = !bitmap_get(i); if (free) { @@ -105,11 +105,53 @@ void *alloc_phys_pages(size_t pages) return NULL; } +struct phys_page_slice alloc_phys_page_withextra(size_t max_pages) +{ + if (max_pages == 0) + return PHYS_PAGE_SLICE_NULL; + + for (size_t i = 0; i < page_count; i++) { + const bool free = !bitmap_get(i); + if (!free) + continue; + + // now allocated + bitmap_set(i, true); + + // found at least one page, guaranteed to return valid slice at this + // point + struct phys_page_slice out = { + .pagestart = page_at(i), + .num_pages = 1, + }; + + // add some extra pages if possible + for (; out.num_pages < MIN(page_count - i, max_pages); + ++out.num_pages) { + // early return if max_pages isn't available + if (bitmap_get(i + out.num_pages)) { + return out; + } + bitmap_set(i + out.num_pages, true); + } + + return out; + } + + // only reachable if there is not a single free page in the bitmap + return PHYS_PAGE_SLICE_NULL; +} + void free_phys_page(void *ptr) { free_phys_pages(ptr, 1); } +void free_phys_pages_slice(struct phys_page_slice slice) +{ + free_phys_pages(slice.pagestart, slice.num_pages); +} + void free_phys_pages(void *ptr, size_t pages) { if (ptr == NULL) diff --git a/kernel/memory/physalloc.h b/kernel/memory/physalloc.h index d91c57a..e279409 100644 --- a/kernel/memory/physalloc.h +++ b/kernel/memory/physalloc.h @@ -11,11 +11,31 @@ #include +/// Represents some contiguous physical pages +struct phys_page_slice { + void *pagestart; + size_t num_pages; +}; + +#define PHYS_PAGE_SLICE_NULL \ + ((struct phys_page_slice){ .pagestart = NULL, .num_pages = 0 }) + /** * Initalize the physical page allocator */ void physalloc_init(struct memory_map *map); +/* + * Allocates the first page(s) it finds. Returns a pointer to that page + * and, if there are (up to max_pages) extra pages free after it, it allocates + * them as well. + * + * @param max_pages - the maximum number of pages to mark as allocated + * @returns a slice of all of the allocated pages, num_pages will be + * <= max_pages + */ +struct phys_page_slice alloc_phys_page_withextra(size_t max_pages); + /** * Allocates a single physical page in memory * @preturns the physical address of the page @@ -23,10 +43,11 @@ void physalloc_init(struct memory_map *map); void *alloc_phys_page(void); /** - * Allocates count physical pages in memory - * @returns the physical address of the first page + * Allocates count contiguous physical pages in memory + * @returns the physical address of the first page, or NULL if no + * contiguous pages exist. */ -void *alloc_phys_pages(size_t count); +void *alloc_phys_pages_exact(size_t count); /** * Frees a single physical page in memory @@ -41,4 +62,10 @@ void free_phys_page(void *ptr); */ void free_phys_pages(void *ptr, size_t count); +/** + * Frees a slice of physical pages in memory + * @param slice - the pages to free + */ +void free_phys_pages_slice(struct phys_page_slice slice); + #endif /* physalloc.h */ -- cgit v1.2.3-freya From 7876e466c222ed015bc65c7ab4f63d05596ede2c Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 10:02:29 -0400 Subject: virt ctx clone --- kernel/memory/virtalloc.c | 34 ++++++++++++++++++++++++++++++++++ kernel/memory/virtalloc.h | 5 +++++ 2 files changed, 39 insertions(+) (limited to 'kernel') diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c index 3690eae..a077532 100644 --- a/kernel/memory/virtalloc.c +++ b/kernel/memory/virtalloc.c @@ -96,6 +96,40 @@ void virtaddr_init(struct virt_ctx *ctx) ctx->is_allocating = false; } +int virtaddr_clone(struct virt_ctx *old, struct virt_ctx *new) +{ + // copy over data + memcpy(new, old, sizeof(struct virt_ctx)); + + // allocate new space + new->alloc_nodes = kalloc(sizeof(struct virt_addr_node) * new->alloc_node_count); + if (new->alloc_nodes == NULL) + return 1; + + // update prev/next in new allocation space + update_node_ptrs(old->alloc_nodes, new->alloc_nodes, old->alloc_node_count, new->alloc_node_count); + + // update bootstrap nodes + for (size_t i = 0; i < new->used_node_count; i++) { + struct virt_addr_node *prev, *next; + + if (i >= BOOTSTRAP_VIRT_ALLOC_NODES) + break; + + // get prev + prev = i > 0 ? &new->bootstrap_nodes[i-1] : NULL; + next = i < BOOTSTRAP_VIRT_ALLOC_NODES - 1 ? &new->bootstrap_nodes[i+1] : NULL; + + new->bootstrap_nodes[i].prev = prev; + new->bootstrap_nodes[i].next = next; + } + + // get starting node + new->start_node = &new->bootstrap_nodes[0]; // for now + + return 0; +} + static void merge_back(struct virt_ctx *ctx, struct virt_addr_node *node) { while (node->prev) { diff --git a/kernel/memory/virtalloc.h b/kernel/memory/virtalloc.h index 78adc46..9a94208 100644 --- a/kernel/memory/virtalloc.h +++ b/kernel/memory/virtalloc.h @@ -52,6 +52,11 @@ struct virt_ctx { */ void virtaddr_init(struct virt_ctx *ctx); +/** + * Clone the virtual address allocator + */ +int virtaddr_clone(struct virt_ctx *old, struct virt_ctx *new); + /** * Allocate a virtual address of length x pages * @param pages - x pages -- cgit v1.2.3-freya From b39f0b08ca73f9059402a0bc869244b384cebd5c Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 10:03:30 -0400 Subject: pgdir clone stub, constify free fns --- kernel/include/comus/memory.h | 2 +- kernel/memory/memory.c | 26 ++++++++++++++++++++------ kernel/memory/paging.c | 25 ++++++++++++++++--------- kernel/memory/paging.h | 7 +++++-- 4 files changed, 42 insertions(+), 18 deletions(-) (limited to 'kernel') diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h index 255eca2..92525da 100644 --- a/kernel/include/comus/memory.h +++ b/kernel/include/comus/memory.h @@ -87,7 +87,7 @@ mem_ctx_t mem_ctx_alloc(void); * * @returns pointer context or NULL on failure */ -mem_ctx_t mem_ctx_clone(mem_ctx_t ctx, bool cow); +mem_ctx_t mem_ctx_clone(const mem_ctx_t ctx, bool cow); /** * Free a memory context into a new one diff --git a/kernel/memory/memory.c b/kernel/memory/memory.c index 7ceb491..295823e 100644 --- a/kernel/memory/memory.c +++ b/kernel/memory/memory.c @@ -52,7 +52,7 @@ mem_ctx_t mem_ctx_alloc(void) if (ctx == NULL) return NULL; - if ((ctx->pml4 = paging_alloc()) == NULL) + if ((ctx->pml4 = pgdir_alloc()) == NULL) return NULL; virtaddr_init(&ctx->virtctx); @@ -64,17 +64,31 @@ mem_ctx_t mem_ctx_alloc(void) return ctx; } -mem_ctx_t mem_ctx_clone(mem_ctx_t ctx, bool cow) +mem_ctx_t mem_ctx_clone(const mem_ctx_t old, bool cow) { - (void)ctx; - (void)cow; + mem_ctx_t new = user_mem_ctx_next; + if (new == NULL) + return NULL; + + if ((new->pml4 = pgdir_clone(old->pml4, cow)) == NULL) + return NULL; + + if (virtaddr_clone(&old->virtctx, &new->virtctx)) { + pgdir_free(new->pml4); + return NULL; + } + + user_mem_ctx_next = new->prev; + if (new->prev) + new->prev->next = NULL; + new->prev = NULL; - panic("not yet implemented"); + return new; } void mem_ctx_free(mem_ctx_t ctx) { - paging_free(ctx->pml4); + pgdir_free(ctx->pml4); virtaddr_cleanup(&ctx->virtctx); if (user_mem_ctx_next == NULL) { diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index 24a9ea7..c6e6a82 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -5,7 +5,6 @@ #include "physalloc.h" #include "paging.h" #include "memory.h" -#include // PAGE MAP LEVEL 4 ENTRY struct pml4e { @@ -139,7 +138,7 @@ extern char kernel_start[]; extern char kernel_end[]; // invalidate page cache at a vitural address -static inline void invlpg(volatile void *vADDR) +static inline void invlpg(volatile const void *vADDR) { __asm__ volatile("invlpg (%0)" ::"r"(vADDR) : "memory"); } @@ -150,7 +149,7 @@ static inline void invlpg(volatile void *vADDR) // @returns VIRTUAL ADDRESS static volatile struct pml4 *pml4_map(volatile struct pml4 *pPML4) { - static struct pml4 *vPML4 = (void *)(uintptr_t)0x40000000; + static volatile struct pml4 *vPML4 = (void *)(uintptr_t)0x40000000; static volatile struct pte *vPTE = &paging_pt.entries[0]; if ((uint64_t)pPML4 >> 12 == vPTE->address) @@ -166,7 +165,7 @@ static volatile struct pml4 *pml4_map(volatile struct pml4 *pPML4) // @returns VIRTUAL ADDRESS static volatile struct pdpt *pdpt_map(volatile struct pdpt *pPDPT) { - static struct pdpt *vPDPT = (void *)(uintptr_t)0x40001000; + static volatile struct pdpt *vPDPT = (void *)(uintptr_t)0x40001000; static volatile struct pte *vPTE = &paging_pt.entries[1]; if ((uint64_t)pPDPT >> 12 == vPTE->address) @@ -182,7 +181,7 @@ static volatile struct pdpt *pdpt_map(volatile struct pdpt *pPDPT) // @returns VIRTUAL ADDRESS static volatile struct pd *pd_map(volatile struct pd *pPD) { - static struct pd *vPD = (void *)(uintptr_t)0x40002000; + static volatile struct pd *vPD = (void *)(uintptr_t)0x40002000; static volatile struct pte *vPTE = &paging_pt.entries[2]; if ((uint64_t)pPD >> 12 == vPTE->address) @@ -198,7 +197,7 @@ static volatile struct pd *pd_map(volatile struct pd *pPD) // @returns VIRTUAL ADDRESS static volatile struct pt *pt_map(volatile struct pt *pPT) { - static struct pt *vPT = (void *)(uintptr_t)0x40003000; + static volatile struct pt *vPT = (void *)(uintptr_t)0x40003000; static volatile struct pte *vPTE = &paging_pt.entries[3]; if ((uint64_t)pPT >> 12 == vPTE->address) @@ -678,14 +677,14 @@ void paging_init(void) kernel_pd_1.entries[0].flags = F_PRESENT | F_WRITEABLE; kernel_pd_1.entries[0].address = (uint64_t)(paging_pt.entries) >> 12; - memsetv(paging_pt.entries, 0, 4096); + memsetv(paging_pt.entries, 0, PAGE_SIZE); // make sure we are using THESE pagetables // EFI doesnt on boot __asm__ volatile("mov %0, %%cr3" ::"r"(kernel_pml4.entries) : "memory"); } -volatile void *paging_alloc(void) +volatile void *pgdir_alloc(void) { volatile struct pml4 *pPML4; @@ -702,7 +701,15 @@ volatile void *paging_alloc(void) return pPML4; } -void paging_free(volatile void *addr) +volatile void *pgdir_clone(volatile const void *old_pgdir, bool cow) +{ + // TODO: + (void) old_pgdir; + (void) cow; + return NULL; +} + +void pgdir_free(volatile void *addr) { pml4_free(addr, true); } diff --git a/kernel/memory/paging.h b/kernel/memory/paging.h index d80a9bf..94b7260 100644 --- a/kernel/memory/paging.h +++ b/kernel/memory/paging.h @@ -9,9 +9,12 @@ #ifndef PAGING_H_ #define PAGING_H_ +#include + void paging_init(void); -volatile void *paging_alloc(void); -void paging_free(volatile void *addr); +volatile void *pgdir_alloc(void); +volatile void *pgdir_clone(volatile const void *pdir, bool cow); +void pgdir_free(volatile void *addr); #endif /* paging.h */ -- cgit v1.2.3-freya From 1f89036816a1a3d45e62b101a9cff873ac41dfbc Mon Sep 17 00:00:00 2001 From: Ian McFarlane Date: Fri, 25 Apr 2025 10:24:35 -0400 Subject: fix freeing of virtual memory --- kernel/memory/paging.c | 57 +++++++++++++++++++++++++++++++++++--------------- 1 file changed, 40 insertions(+), 17 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index c6e6a82..8de1a24 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -804,36 +804,59 @@ void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, unsigned int flags) { size_t pages_needed = count; - uint8_t *virtual_address = virt; - void *phys_start = NULL; + struct phys_page_slice prev_phys_block = PHYS_PAGE_SLICE_NULL; + struct phys_page_slice phys_pages; while (pages_needed > 0) { - struct phys_page_slice phys_pages = - alloc_phys_page_withextra(pages_needed); + phys_pages = alloc_phys_page_withextra(pages_needed); if (phys_pages.pagestart == NULL) { - free_phys_pages(phys_start ? phys_start : phys_pages.pagestart, - count - pages_needed); - return NULL; + goto mem_alloc_pages_at_fail; } - if (!phys_start) - phys_start = phys_pages.pagestart; + { + // allocate the first page and store in it the physical address of the + // previous chunk of pages + // TODO: skip this if there are already enough pages from first alloc + void *pageone = kmapaddr(phys_pages.pagestart, NULL, 1, + F_PRESENT | F_WRITEABLE); + if (pageone == NULL) { + panic("kernel out of virtual memory"); + } + *((struct phys_page_slice *)pageone) = prev_phys_block; + prev_phys_block = phys_pages; + kunmapaddr(pageone); + } assert(pages_needed >= phys_pages.num_pages, "overflow"); pages_needed -= phys_pages.num_pages; - virtual_address += phys_pages.num_pages * PAGE_SIZE; - - if (map_pages((volatile struct pml4 *)ctx->pml4, - (void *)virtual_address, phys_pages.pagestart, flags, - phys_pages.num_pages)) { - assert(phys_start, "expected something allocated"); - free_phys_pages(phys_start, count - pages_needed); - return NULL; + + // index into virtual page array at index [count - pages_needed] + void *vaddr = ((uint8_t *)virt) + ((count - pages_needed) * PAGE_SIZE); + if (map_pages((volatile struct pml4 *)ctx->pml4, vaddr, + phys_pages.pagestart, flags, phys_pages.num_pages)) { + goto mem_alloc_pages_at_fail; } } return virt; + +mem_alloc_pages_at_fail: + while (prev_phys_block.pagestart) { + void *virtpage = kmapaddr(prev_phys_block.pagestart, NULL, 1, + F_PRESENT | F_WRITEABLE); + if (!virtpage) { + // memory corruption, most likely a bug + // could also ERROR here and exit with leak + panic("unable to free memory from failed mem_alloc_pages_at call"); + } + struct phys_page_slice prev = *(struct phys_page_slice *)virtpage; + prev_phys_block = prev; + free_phys_pages_slice(prev); + kunmapaddr(virtpage); + } + + return NULL; } void mem_free_pages(mem_ctx_t ctx, const void *virt) -- cgit v1.2.3-freya From 46116758f8c74db62d263433eb10c36d94f1b48f Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 10:59:14 -0400 Subject: change start vitaddr --- kernel/memory/virtalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c index a077532..08a0758 100644 --- a/kernel/memory/virtalloc.c +++ b/kernel/memory/virtalloc.c @@ -79,7 +79,7 @@ static void free_node(struct virt_ctx *ctx, struct virt_addr_node *node) void virtaddr_init(struct virt_ctx *ctx) { struct virt_addr_node init = { - .start = 0x40005000, // map after paging pt + .start = 0x50000000, .end = 0x1000000000000, // 48bit memory address max .next = NULL, .prev = NULL, -- cgit v1.2.3-freya From 03ce2cd514ee2c87528cff12591241963fde3ffe Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 10:59:49 -0400 Subject: fix physalloc edge case --- kernel/memory/physalloc.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index 856a627..833c995 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -1,3 +1,4 @@ +#include "lib/kio.h" #include #include #include @@ -11,13 +12,13 @@ extern char kernel_end; // between memory_start and kernel_start will be the bitmap static uintptr_t memory_start = 0; -static uint64_t *bitmap; +static uint64_t *bitmap = NULL; static uint64_t total_memory; static uint64_t free_memory; static uint64_t page_count; static uint64_t segment_count; struct memory_map phys_mmap; -struct memory_segment *page_start; +struct memory_segment *page_start = NULL; static const char *segment_type_str[] = { [SEG_TYPE_FREE] = "Free", [SEG_TYPE_RESERVED] = "Reserved", @@ -84,6 +85,13 @@ void *alloc_phys_pages_exact(size_t pages) if (pages < 1) return NULL; + if (bitmap == NULL || page_start == NULL) { + // temporary bump allocator + void *addr = (void*)memory_start; + memory_start += PAGE_SIZE; + return addr; + } + size_t n_contiguous = 0; size_t free_region_start = 0; for (size_t i = 0; i < page_count; i++) { -- 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') 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 5d4601d864c03448e32a5b9e1748ce5010a28c44 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 11:21:20 -0400 Subject: noreturn on dispatch --- kernel/include/comus/procs.h | 1 + kernel/procs.c | 1 + 2 files changed, 2 insertions(+) (limited to 'kernel') diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h index d105867..de65849 100644 --- a/kernel/include/comus/procs.h +++ b/kernel/include/comus/procs.h @@ -222,6 +222,7 @@ void schedule(struct pcb *pcb); /** * Select the next process to receive the CPU */ +__attribute__((noreturn)) void dispatch(void); #endif /* procs.h */ diff --git a/kernel/procs.c b/kernel/procs.c index 8cd44a4..f114f52 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -461,6 +461,7 @@ void schedule(struct pcb *pcb) panic("schedule insert fail"); } +__attribute__((noreturn)) void dispatch(void) { assert(current_pcb == NULL, "dispatch: current process is not null"); -- cgit v1.2.3-freya From 53c7f83e611d6b249097dcae1f748fc2fcc42173 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 11:22:24 -0400 Subject: fmt --- kernel/include/comus/cpu.h | 3 +-- kernel/include/comus/procs.h | 3 +-- kernel/memory/paging.c | 6 +++--- kernel/memory/physalloc.c | 2 +- kernel/memory/virtalloc.c | 12 ++++++++---- kernel/procs.c | 3 +-- 6 files changed, 15 insertions(+), 14 deletions(-) (limited to 'kernel') diff --git a/kernel/include/comus/cpu.h b/kernel/include/comus/cpu.h index 8f485be..3669000 100644 --- a/kernel/include/comus/cpu.h +++ b/kernel/include/comus/cpu.h @@ -92,7 +92,6 @@ void cpu_print_regs(struct cpu_regs *regs); /** * Return from a syscall handler back into userspace */ -__attribute__((noreturn)) -void syscall_return(void); +__attribute__((noreturn)) void syscall_return(void); #endif /* cpu.h */ diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h index de65849..0150975 100644 --- a/kernel/include/comus/procs.h +++ b/kernel/include/comus/procs.h @@ -222,7 +222,6 @@ void schedule(struct pcb *pcb); /** * Select the next process to receive the CPU */ -__attribute__((noreturn)) -void dispatch(void); +__attribute__((noreturn)) void dispatch(void); #endif /* procs.h */ diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index c6e6a82..3453636 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -704,8 +704,8 @@ volatile void *pgdir_alloc(void) volatile void *pgdir_clone(volatile const void *old_pgdir, bool cow) { // TODO: - (void) old_pgdir; - (void) cow; + (void)old_pgdir; + (void)cow; return NULL; } @@ -827,7 +827,7 @@ void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, if (map_pages((volatile struct pml4 *)ctx->pml4, (void *)virtual_address, phys_pages.pagestart, flags, phys_pages.num_pages)) { - assert(phys_start, "expected something allocated"); + assert(phys_start, "expected something allocated"); free_phys_pages(phys_start, count - pages_needed); return NULL; } diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index 833c995..9fcbe8f 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -87,7 +87,7 @@ void *alloc_phys_pages_exact(size_t pages) if (bitmap == NULL || page_start == NULL) { // temporary bump allocator - void *addr = (void*)memory_start; + void *addr = (void *)memory_start; memory_start += PAGE_SIZE; return addr; } diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c index 08a0758..cbde9b4 100644 --- a/kernel/memory/virtalloc.c +++ b/kernel/memory/virtalloc.c @@ -102,12 +102,14 @@ int virtaddr_clone(struct virt_ctx *old, struct virt_ctx *new) memcpy(new, old, sizeof(struct virt_ctx)); // allocate new space - new->alloc_nodes = kalloc(sizeof(struct virt_addr_node) * new->alloc_node_count); + new->alloc_nodes = + kalloc(sizeof(struct virt_addr_node) * new->alloc_node_count); if (new->alloc_nodes == NULL) return 1; // update prev/next in new allocation space - update_node_ptrs(old->alloc_nodes, new->alloc_nodes, old->alloc_node_count, new->alloc_node_count); + update_node_ptrs(old->alloc_nodes, new->alloc_nodes, old->alloc_node_count, + new->alloc_node_count); // update bootstrap nodes for (size_t i = 0; i < new->used_node_count; i++) { @@ -117,8 +119,10 @@ int virtaddr_clone(struct virt_ctx *old, struct virt_ctx *new) break; // get prev - prev = i > 0 ? &new->bootstrap_nodes[i-1] : NULL; - next = i < BOOTSTRAP_VIRT_ALLOC_NODES - 1 ? &new->bootstrap_nodes[i+1] : NULL; + prev = i > 0 ? &new->bootstrap_nodes[i - 1] : NULL; + next = i < BOOTSTRAP_VIRT_ALLOC_NODES - 1 ? + &new->bootstrap_nodes[i + 1] : + NULL; new->bootstrap_nodes[i].prev = prev; new->bootstrap_nodes[i].next = next; diff --git a/kernel/procs.c b/kernel/procs.c index f114f52..340739d 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -461,8 +461,7 @@ void schedule(struct pcb *pcb) panic("schedule insert fail"); } -__attribute__((noreturn)) -void dispatch(void) +__attribute__((noreturn)) void dispatch(void) { assert(current_pcb == NULL, "dispatch: current process is not null"); -- cgit v1.2.3-freya From 16f5d0443aa072d977517be45dcf9b0d12f584b4 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 11:36:23 -0400 Subject: load init from ata and run it --- Makefile | 2 +- kernel/main.c | 13 ++++++++++--- kernel/procs.c | 3 ++- kernel/syscall.c | 3 --- kernel/user.c | 4 ++++ 5 files changed, 17 insertions(+), 8 deletions(-) (limited to 'kernel') diff --git a/Makefile b/Makefile index 59b32d1..b40443d 100644 --- a/Makefile +++ b/Makefile @@ -40,7 +40,7 @@ UNAME := $(shell uname) QEMU = qemu-system-x86_64 QEMUOPTS = -cdrom $(BIN)/$(ISO) \ -no-reboot \ - -drive format=raw,file=$(BIN)/$(IMAGE)\ + -drive format=raw,file=$(BIN)/user/hello\ -serial mon:stdio \ -m 4G \ -name kern diff --git a/kernel/main.c b/kernel/main.c index 4047a64..c15c38d 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -21,7 +22,7 @@ void kreport(void) gpu_report(); } -void main(long magic, volatile void *mboot) +__attribute__((noreturn)) void main(long magic, volatile void *mboot) { // initalize idt and pic cpu_init(); @@ -47,6 +48,12 @@ void main(long magic, volatile void *mboot) // report system state kreport(); - // halt - kprintf("halting...\n"); + // load init process + pcb_alloc(&init_pcb); + if (user_load(init_pcb, &fs_disks[0])) + panic("failed to load init"); + + // schedule and dispatch init + schedule(init_pcb); + dispatch(); } diff --git a/kernel/procs.c b/kernel/procs.c index 340739d..c1bcc4f 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -35,7 +35,7 @@ struct pcb *init_pcb = NULL; struct pcb ptable[N_PROCS]; /// next avaliable pid -pid_t next_pid = 0; +pid_t next_pid = 1; static struct pcb *find_prev_wakeup(pcb_queue_t queue, struct pcb *pcb) { @@ -119,6 +119,7 @@ int pcb_alloc(struct pcb **pcb) if (pcb_queue_pop(pcb_freelist, &tmp) != SUCCESS) return E_NO_PCBS; + tmp->pid = next_pid++; *pcb = tmp; return SUCCESS; } diff --git a/kernel/syscall.c b/kernel/syscall.c index 7944f46..12db401 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -91,7 +91,4 @@ void syscall_handler(struct cpu_regs *regs) // save return value current_pcb->regs->rax = ret; - - // switch back to process ctx - mem_ctx_switch(current_pcb->memctx); } diff --git a/kernel/user.c b/kernel/user.c index 592b35b..3c686a0 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -98,6 +98,10 @@ static int user_setup_stack(struct pcb *pcb) int user_load(struct pcb *pcb, struct disk *disk) { + // check inputs + if (pcb == NULL || disk == NULL) + return 1; + pcb->regs = NULL; // allocate memory context -- cgit v1.2.3-freya From 87e8de4f0050ec154286189783ddbd269fbcc7ee Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 11:45:15 -0400 Subject: poweroff syscall --- kernel/include/comus/syscalls.h | 3 ++- kernel/syscall.c | 23 ++++++++++++++++------- user/include/unistd.h | 7 +++++++ user/lib/syscall.S | 1 + user/poweroff.c | 6 ++++++ 5 files changed, 32 insertions(+), 8 deletions(-) create mode 100644 user/poweroff.c (limited to 'kernel') diff --git a/kernel/include/comus/syscalls.h b/kernel/include/comus/syscalls.h index 3b9ea70..0105104 100644 --- a/kernel/include/comus/syscalls.h +++ b/kernel/include/comus/syscalls.h @@ -27,9 +27,10 @@ #define SYS_sleep 14 #define SYS_brk 15 #define SYS_sbrk 16 +#define SYS_poweroff 17 // UPDATE THIS DEFINITION IF MORE SYSCALLS ARE ADDED! -#define N_SYSCALLS 17 +#define N_SYSCALLS 18 // interrupt vector entry for system calls #define VEC_SYSCALL 0x80 diff --git a/kernel/syscall.c b/kernel/syscall.c index 12db401..00e6afb 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -1,6 +1,6 @@ #include #include -#include +#include #include #include @@ -52,13 +52,22 @@ static int sys_write(void) return nbytes; } +static int sys_poweroff(void) +{ + acpi_shutdown(); + return 1; +} + 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, [SYS_poweroff] = sys_poweroff, }; void syscall_handler(struct cpu_regs *regs) diff --git a/user/include/unistd.h b/user/include/unistd.h index a815914..bbacdbe 100644 --- a/user/include/unistd.h +++ b/user/include/unistd.h @@ -162,4 +162,11 @@ extern void *brk(const void *addr); */ extern void *sbrk(intptr_t increment); +/** + * Poweroff the system. + * + * @return 1 on failure + */ +extern int poweroff(void); + #endif /* unistd.h */ diff --git a/user/lib/syscall.S b/user/lib/syscall.S index fc1ab93..c5a23b5 100644 --- a/user/lib/syscall.S +++ b/user/lib/syscall.S @@ -24,3 +24,4 @@ SYSCALL kill SYS_kill SYSCALL sleep SYS_sleep SYSCALL brk SYS_brk SYSCALL sbrk SYS_sbrk +SYSCALL poweroff SYS_poweroff diff --git a/user/poweroff.c b/user/poweroff.c new file mode 100644 index 0000000..f51a86f --- /dev/null +++ b/user/poweroff.c @@ -0,0 +1,6 @@ +#include + +int main(void) +{ + return poweroff(); +} -- cgit v1.2.3-freya From f88e7fada2f9998063d1816d4375ee7c8735f57f Mon Sep 17 00:00:00 2001 From: Ian McFarlane Date: Fri, 25 Apr 2025 12:15:41 -0400 Subject: fixed segfault caused by mapping the wrong virtual address in mem_alloc_pages_at --- kernel/memory/paging.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index b23e39b..5a0b285 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -828,11 +828,12 @@ void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, kunmapaddr(pageone); } + // index into virtual page array at index [count - pages_needed] + void *vaddr = ((uint8_t *)virt) + ((count - pages_needed) * PAGE_SIZE); + assert(pages_needed >= phys_pages.num_pages, "overflow"); pages_needed -= phys_pages.num_pages; - // index into virtual page array at index [count - pages_needed] - void *vaddr = ((uint8_t *)virt) + ((count - pages_needed) * PAGE_SIZE); if (map_pages((volatile struct pml4 *)ctx->pml4, vaddr, phys_pages.pagestart, flags, phys_pages.num_pages)) { goto mem_alloc_pages_at_fail; -- cgit v1.2.3-freya From 85450e3bf3e93a5bbd523993f7ad60b331545e3c Mon Sep 17 00:00:00 2001 From: Ian McFarlane Date: Fri, 25 Apr 2025 12:16:00 -0400 Subject: added assert that bump allocator is only being asked for one page at a time --- kernel/memory/physalloc.c | 1 + 1 file changed, 1 insertion(+) (limited to 'kernel') diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index 9fcbe8f..01464ee 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -88,6 +88,7 @@ void *alloc_phys_pages_exact(size_t pages) if (bitmap == NULL || page_start == NULL) { // temporary bump allocator void *addr = (void *)memory_start; + assert(pages == 1, "caller expects more pages, but is only getting one"); memory_start += PAGE_SIZE; return addr; } -- cgit v1.2.3-freya From 7e707c61ab0aaf36875bd6645c0898f15fbef0f9 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 15:02:54 -0400 Subject: fix fs off by 1 sector --- kernel/fs/fs.c | 6 +++--- kernel/include/comus/fs.h | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/fs/fs.c b/kernel/fs/fs.c index c8399a3..98b04df 100644 --- a/kernel/fs/fs.c +++ b/kernel/fs/fs.c @@ -110,8 +110,8 @@ static int disk_read_ata(struct disk *disk, size_t offset, size_t len, static size_t atabuf_len = 0; static uint16_t *atabuf = NULL; - uint32_t numsects = (len + ATA_SECT_SIZE - 1) / ATA_SECT_SIZE; uint32_t err = offset % ATA_SECT_SIZE; + uint32_t numsects = (len + err + ATA_SECT_SIZE - 1) / ATA_SECT_SIZE; int ret = 0; if (atabuf == NULL || atabuf_len < numsects * ATA_SECT_SIZE) { @@ -123,12 +123,12 @@ static int disk_read_ata(struct disk *disk, size_t offset, size_t len, // read sectors if ((ret = ide_device_read_sectors(disk->ide, numsects, offset / ATA_SECT_SIZE, atabuf))) - return 1; + return ret; // copy over to buffer memcpy(buffer, (char *)atabuf + err, len); - return ret; + return 0; } int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer) diff --git a/kernel/include/comus/fs.h b/kernel/include/comus/fs.h index e67b6fe..dab84a5 100644 --- a/kernel/include/comus/fs.h +++ b/kernel/include/comus/fs.h @@ -45,7 +45,7 @@ struct disk { * @param offset - the offset into the disk to read * @param len - the length of the data to read into `buffer` * @param buffer - the buffer to save data into - * @returns bytes read on success, negative fs error code in failure + * @returns 0 on success, error code in failure */ int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer); @@ -56,7 +56,7 @@ int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer); * @param offset - the offset into the disk to write * @param len - the length of the data to write into `buffer` * @param buffer - the buffer to read from - * @returns bytes written on success, negative fs error code in failure + * @returns 0 on success, error code in failure */ int disk_write(struct disk *disk, size_t offset, size_t len, void *buffer); -- cgit v1.2.3-freya From ddc5cbc7a394e30bcbe7914ea900fa6df4bac575 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 15:05:08 -0400 Subject: add elf file checks --- kernel/user.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 62 insertions(+), 11 deletions(-) (limited to 'kernel') diff --git a/kernel/user.c b/kernel/user.c index 3c686a0..543c033 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -1,4 +1,3 @@ -#include "lib/kio.h" #include #include #include @@ -18,11 +17,17 @@ static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) { uint8_t buf[PAGE_SIZE]; Elf64_Phdr hdr; - size_t npages; - int ret = 0; + size_t npages, nbytes; hdr = pcb->elf_segments[idx]; - npages = (hdr.p_filesz + PAGE_SIZE - 1) / PAGE_SIZE; + nbytes = hdr.p_filesz; + npages = (nbytes + PAGE_SIZE - 1) / PAGE_SIZE; + + if (npages < 1) + return 0; + + if (hdr.p_type != PT_LOAD) + return 0; // allocate memory in user process if (mem_alloc_pages_at(pcb->memctx, npages, (void *)hdr.p_vaddr, @@ -30,17 +35,21 @@ static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) return 1; // load data - for (size_t i = 0; i < npages; i++) { + for (size_t i = 0; i < npages && nbytes; i++) { + size_t bytes = PAGE_SIZE; + if (nbytes < bytes) + bytes = nbytes; mem_ctx_switch(kernel_mem_ctx); // disk_read is kernel internal - ret = disk_read(disk, hdr.p_offset + i * PAGE_SIZE, PAGE_SIZE, buf); - if (ret < 0) - break; + memset(buf + bytes, 0, PAGE_SIZE - bytes); + if (disk_read(disk, hdr.p_offset + i * PAGE_SIZE, bytes, buf)) + return 1; mem_ctx_switch(pcb->memctx); - memcpy((char *)hdr.p_vaddr + i * PAGE_SIZE, buf, PAGE_SIZE); + memcpy((char *)hdr.p_vaddr + i * PAGE_SIZE, buf, bytes); + nbytes -= bytes; } mem_ctx_switch(kernel_mem_ctx); - return ret; + return 0; } static int user_load_segments(struct pcb *pcb, struct disk *disk) @@ -53,6 +62,48 @@ static int user_load_segments(struct pcb *pcb, struct disk *disk) return 0; } +static int validate_elf_hdr(struct pcb *pcb) +{ + Elf64_Ehdr *ehdr = &pcb->elf_header; + + if (strncmp((const char *)ehdr->e_ident, ELFMAG, SELFMAG)) { + WARN("Invalid ELF File.\n"); + return 1; + } + + if (ehdr->e_ident[EI_CLASS] != ELFCLASS64) { + WARN("Unsupported ELF Class.\n"); + return 1; + } + + if(ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { + ERROR("Unsupported ELF File byte order.\n"); + return 1; + } + + if (ehdr->e_machine != EM_X86_64) { + WARN("Unsupported ELF File target.\n"); + return 1; + } + + if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) { + WARN("Unsupported ELF File version.\n"); + return 1; + } + + if (ehdr->e_phnum > N_ELF_SEGMENTS) { + WARN("Too many ELF segments.\n"); + return 1; + } + + if(ehdr->e_type != ET_EXEC) { + ERROR("Unsupported ELF File type.\n"); + return 1; + } + + return 0; +} + static int user_load_elf(struct pcb *pcb, struct disk *disk) { int ret = 0; @@ -61,7 +112,7 @@ static int user_load_elf(struct pcb *pcb, struct disk *disk) if (ret < 0) return 1; - if (pcb->elf_header.e_phnum > N_ELF_SEGMENTS) + if (validate_elf_hdr(pcb)) return 1; pcb->n_elf_segments = pcb->elf_header.e_phnum; -- cgit v1.2.3-freya From 79d9e1cad4431b54d723bbce75275776859d3bb6 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 15:06:17 -0400 Subject: add comment --- kernel/syscall.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'kernel') diff --git a/kernel/syscall.c b/kernel/syscall.c index 00e6afb..5e0abff 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -54,6 +54,9 @@ static int sys_write(void) static int sys_poweroff(void) { + // TODO: we should probably + // kill all user processes + // and then sync the fs acpi_shutdown(); return 1; } -- cgit v1.2.3-freya From 2cf6fe3f4d0811f1d62ed3ba73d15c8a187f600f Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 18:42:30 -0400 Subject: mem_get_phys fn --- kernel/include/comus/memory.h | 13 +++++++++++++ kernel/memory/memory.c | 5 +++++ kernel/memory/paging.c | 23 +++++++++++++++++------ kernel/memory/physalloc.c | 3 ++- 4 files changed, 37 insertions(+), 7 deletions(-) (limited to 'kernel') diff --git a/kernel/include/comus/memory.h b/kernel/include/comus/memory.h index 92525da..408521b 100644 --- a/kernel/include/comus/memory.h +++ b/kernel/include/comus/memory.h @@ -123,6 +123,13 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, */ void mem_unmapaddr(mem_ctx_t ctx, const void *virt); +/** + * Gets the physical address for a given vitural address + * @param ctx - the memory context + * @param virt - the vitural address + */ +void *mem_get_phys(mem_ctx_t ctx, const void *virt); + /** * Allocate a single page of memory with the given paging structure * @@ -194,6 +201,12 @@ void *kmapaddr(void *phys, void *virt, size_t len, unsigned int flags); */ void *kmapuseraddr(mem_ctx_t ctx, const void *virt, size_t len); +/** + * Gets the physical address for a given vitural address + * @param virt - the vitural address + */ +void *kget_phys(const void *virt); + /** * Unmaps mapped address from the kmapaddr function * @param virt - the vitural address returned from kmapaddr diff --git a/kernel/memory/memory.c b/kernel/memory/memory.c index 295823e..bd3e06b 100644 --- a/kernel/memory/memory.c +++ b/kernel/memory/memory.c @@ -31,6 +31,11 @@ void kunmapaddr(const void *virt) mem_unmapaddr(kernel_mem_ctx, virt); } +void *kget_phys(const void *virt) +{ + return mem_get_phys(kernel_mem_ctx, virt); +} + void *kalloc_page(void) { return mem_alloc_page(kernel_mem_ctx, F_PRESENT | F_WRITEABLE); diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index 5a0b285..d54a26b 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -5,6 +5,7 @@ #include "physalloc.h" #include "paging.h" #include "memory.h" +#include // PAGE MAP LEVEL 4 ENTRY struct pml4e { @@ -753,15 +754,11 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, void *kmapuseraddr(mem_ctx_t ctx, const void *vADDR, size_t len) { char *pADDR; - volatile struct pte *vPTE; - vPTE = page_locate((volatile struct pml4 *)ctx->pml4, vADDR); - if (vPTE == NULL) + pADDR = mem_get_phys(ctx, vADDR); + if (pADDR == NULL) return NULL; - pADDR = (void *)((uintptr_t)vPTE->address << 12); - pADDR += ((uint64_t)vADDR % PAGE_SIZE); - return kmapaddr(pADDR, NULL, len, F_PRESENT | F_WRITEABLE); } @@ -776,6 +773,20 @@ void mem_unmapaddr(mem_ctx_t ctx, const void *virt) unmap_pages(&kernel_pml4, virt, pages); } +void *mem_get_phys(mem_ctx_t ctx, const void *vADDR) +{ + char *pADDR; + volatile struct pte *vPTE; + + vPTE = page_locate((volatile struct pml4 *)ctx->pml4, vADDR); + if (vPTE == NULL) + return NULL; + + pADDR = (void *)((uintptr_t)vPTE->address << 12); + pADDR += ((uint64_t)vADDR % PAGE_SIZE); + return pADDR; +} + void *mem_alloc_page(mem_ctx_t ctx, unsigned int flags) { return mem_alloc_pages(ctx, 1, flags); diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index 01464ee..48d2e3f 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -88,7 +88,8 @@ void *alloc_phys_pages_exact(size_t pages) if (bitmap == NULL || page_start == NULL) { // temporary bump allocator void *addr = (void *)memory_start; - assert(pages == 1, "caller expects more pages, but is only getting one"); + assert(pages == 1, + "caller expects more pages, but is only getting one"); memory_start += PAGE_SIZE; return addr; } -- cgit v1.2.3-freya From f857cfe3d4d3ab6b1eed603f5b948051853b5f63 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Fri, 25 Apr 2025 18:43:16 -0400 Subject: fmt --- kernel/user.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/user.c b/kernel/user.c index 543c033..b4f10d5 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -17,11 +17,12 @@ static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) { uint8_t buf[PAGE_SIZE]; Elf64_Phdr hdr; - size_t npages, nbytes; + size_t npages, nvpages, nbytes; hdr = pcb->elf_segments[idx]; nbytes = hdr.p_filesz; npages = (nbytes + PAGE_SIZE - 1) / PAGE_SIZE; + nvpages = (hdr.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE; if (npages < 1) return 0; @@ -30,7 +31,7 @@ static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) return 0; // allocate memory in user process - if (mem_alloc_pages_at(pcb->memctx, npages, (void *)hdr.p_vaddr, + if (mem_alloc_pages_at(pcb->memctx, nvpages, (void *)hdr.p_vaddr, F_WRITEABLE | F_UNPRIVILEGED) == NULL) return 1; @@ -76,7 +77,7 @@ static int validate_elf_hdr(struct pcb *pcb) return 1; } - if(ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { + if (ehdr->e_ident[EI_DATA] != ELFDATA2LSB) { ERROR("Unsupported ELF File byte order.\n"); return 1; } @@ -96,7 +97,7 @@ static int validate_elf_hdr(struct pcb *pcb) return 1; } - if(ehdr->e_type != ET_EXEC) { + if (ehdr->e_type != ET_EXEC) { ERROR("Unsupported ELF File type.\n"); return 1; } -- cgit v1.2.3-freya From 7c996a6d51bd929ee508b6352459498ab2268d8a Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 14:03:33 -0400 Subject: remove pit fixme --- kernel/drivers.c | 2 +- kernel/drivers/pit.c | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/kernel/drivers.c b/kernel/drivers.c index d2230e8..98bf1bd 100644 --- a/kernel/drivers.c +++ b/kernel/drivers.c @@ -9,7 +9,7 @@ void drivers_init(void) { - pit_set_divider(100); // 1ms + pit_set_divider(1193); // 1ms uart_init(); pci_init(); ata_init(); diff --git a/kernel/drivers/pit.c b/kernel/drivers/pit.c index d77df08..53a9263 100644 --- a/kernel/drivers/pit.c +++ b/kernel/drivers/pit.c @@ -22,9 +22,8 @@ uint16_t pit_read_divider(void) void pit_set_divider(uint16_t count) { (void)count; - // FIXME: broken on -O0 - // cli(); - // outb(CHAN_0, count & 0xFF); // low byte - // outb(CHAN_0, (count & 0xFF00) >> 8); // high byte - // sti(); + cli(); + outb(CHAN_0, count & 0xFF); // low byte + outb(CHAN_0, (count & 0xFF00) >> 8); // high byte + sti(); } -- cgit v1.2.3-freya From 53a3d70e238e423f8543164c0d4c5d2db2e1adbd Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 14:05:45 -0400 Subject: new syscalls --- kernel/include/comus/syscalls.h | 4 ++- kernel/syscall.c | 61 ++++++++++++++++++++++++++++++++++++++--- user/include/unistd.h | 16 +++++++++++ user/lib/syscall.S | 2 ++ 4 files changed, 78 insertions(+), 5 deletions(-) (limited to 'kernel') diff --git a/kernel/include/comus/syscalls.h b/kernel/include/comus/syscalls.h index 0105104..f714184 100644 --- a/kernel/include/comus/syscalls.h +++ b/kernel/include/comus/syscalls.h @@ -28,9 +28,11 @@ #define SYS_brk 15 #define SYS_sbrk 16 #define SYS_poweroff 17 +#define SYS_drm 18 +#define SYS_ticks 19 // UPDATE THIS DEFINITION IF MORE SYSCALLS ARE ADDED! -#define N_SYSCALLS 18 +#define N_SYSCALLS 20 // interrupt vector entry for system calls #define VEC_SYSCALL 0x80 diff --git a/kernel/syscall.c b/kernel/syscall.c index 5e0abff..f5dc56e 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -1,9 +1,13 @@ #include #include #include +#include +#include #include #include +#include +#define RET(type, name) type *name = (type *)(¤t_pcb->regs->rax) #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) @@ -61,6 +65,52 @@ static int sys_poweroff(void) return 1; } +static int sys_drm(void) +{ + ARG1(void **, res_fb); + ARG2(int *, res_width); + ARG3(int *, res_height); + ARG4(int *, res_bpp); + + void *pADDR, *vADDR; + int width, height, bpp; + size_t len; + + if (gpu_dev == NULL) + return 1; + + len = gpu_dev->width * gpu_dev->height * gpu_dev->bit_depth / 8; + pADDR = + mem_get_phys(kernel_mem_ctx, (void *)(uintptr_t)gpu_dev->framebuffer); + if (pADDR == NULL) + return 1; + + vADDR = mem_mapaddr(current_pcb->memctx, pADDR, (void *)0x1000000000, len, + F_PRESENT | F_WRITEABLE | F_UNPRIVILEGED); + if (vADDR == NULL) + return 1; + + width = gpu_dev->width; + height = gpu_dev->height; + bpp = gpu_dev->bit_depth; + + mem_ctx_switch(current_pcb->memctx); + *res_fb = vADDR; + *res_width = width; + *res_height = height; + *res_bpp = bpp; + mem_ctx_switch(kernel_mem_ctx); + + return 0; +} + +static int sys_ticks(void) +{ + RET(uint64_t, res_ticks); + *res_ticks = ticks; + return 0; +} + static int (*syscall_tbl[N_SYSCALLS])(void) = { [SYS_exit] = sys_exit, [SYS_waitpid] = NULL, [SYS_fork] = NULL, [SYS_exec] = NULL, @@ -71,6 +121,7 @@ static int (*syscall_tbl[N_SYSCALLS])(void) = { [SYS_setprio] = NULL, [SYS_kill] = NULL, [SYS_sleep] = NULL, [SYS_brk] = NULL, [SYS_sbrk] = NULL, [SYS_poweroff] = sys_poweroff, + [SYS_drm] = sys_drm, [SYS_ticks] = sys_ticks, }; void syscall_handler(struct cpu_regs *regs) @@ -85,6 +136,7 @@ void syscall_handler(struct cpu_regs *regs) // update data current_pcb->regs = regs; num = current_pcb->regs->rax; + current_pcb->regs->rax = 0; // syscall number @@ -96,11 +148,12 @@ void syscall_handler(struct cpu_regs *regs) ; } - // run syscall handler (if exists) + // run syscall handler handler = syscall_tbl[num]; if (handler != NULL) - handler(); + ret = handler(); - // save return value - current_pcb->regs->rax = ret; + // on failure, set rax + if (ret) + current_pcb->regs->rax = ret; } diff --git a/user/include/unistd.h b/user/include/unistd.h index bbacdbe..f080917 100644 --- a/user/include/unistd.h +++ b/user/include/unistd.h @@ -169,4 +169,20 @@ extern void *sbrk(intptr_t increment); */ extern int poweroff(void); +/** + * Gets access to the "direct rendering manager" (framebuffer) + * + * @param fb - address of framebuffer + * @param width - returns the width of the framebuffer + * @param height - returns the height of the framebuffer + * @param bpp - returns the bit depth of the framebuffer + * @returns 0 on success, error code on failure + */ +extern int drm(void **fb, int *width, int *height, int *bbp); + +/** + * @returns number of ticks the system has been up for (1ms) + */ +extern uint64_t ticks(void); + #endif /* unistd.h */ diff --git a/user/lib/syscall.S b/user/lib/syscall.S index c5a23b5..2ba4dc0 100644 --- a/user/lib/syscall.S +++ b/user/lib/syscall.S @@ -25,3 +25,5 @@ SYSCALL sleep SYS_sleep SYSCALL brk SYS_brk SYSCALL sbrk SYS_sbrk SYSCALL poweroff SYS_poweroff +SYSCALL drm SYS_drm +SYSCALL ticks SYS_ticks -- cgit v1.2.3-freya From bec577fb669910091f09719b5bb6829b963c50c6 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 14:07:11 -0400 Subject: fix pgdir free, fix mapadder fns --- kernel/memory/paging.c | 82 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 27 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index d54a26b..2cc5b7e 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -600,7 +600,8 @@ static volatile struct pte *page_alloc(volatile struct pml4 *pPML4, void *vADDR, } // free a pte (page) for a vitural address -static void page_free(volatile struct pml4 *pPML4, const void *vADDR) +static void page_free(volatile struct pml4 *pPML4, const void *vADDR, + bool deallocate) { volatile struct pte *vPTE; void *pADDR; @@ -612,17 +613,19 @@ static void page_free(volatile struct pml4 *pPML4, const void *vADDR) vPTE->flags = 0; vPTE->address = 0; - pADDR = (void *)((uintptr_t)vPTE->address << 12); - free_phys_page(pADDR); + if (deallocate) { + pADDR = (void *)((uintptr_t)vPTE->address << 12); + free_phys_page(pADDR); + } } /* map & unmap pages */ static void unmap_pages(volatile struct pml4 *pPML4, const void *vADDR, - long page_count) + long page_count, bool deallocate) { for (long i = 0; i < page_count; i++) { - page_free(pPML4, vADDR); + page_free(pPML4, vADDR, deallocate); vADDR = (char *)vADDR + PAGE_SIZE; } } @@ -644,7 +647,7 @@ static int map_pages(volatile struct pml4 *pPML4, void *vADDR, void *pADDR, return 0; fail: - unmap_pages(pPML4, vADDR, page_count); + unmap_pages(pPML4, vADDR, page_count, true); return 1; } @@ -715,26 +718,17 @@ void pgdir_free(volatile void *addr) pml4_free(addr, true); } -static inline void *page_align(void *addr) -{ - uintptr_t a = (uintptr_t)addr; - a /= PAGE_SIZE; - a *= PAGE_SIZE; - return (void *)a; -} - void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, unsigned int flags) { long pages; - ptrdiff_t error; + size_t error; void *aligned_phys; - // get length and physical page aligned address - aligned_phys = page_align(phys); - error = (char *)phys - (char *)aligned_phys; + error = (size_t)phys % PAGE_SIZE; len += error; - pages = len / PAGE_SIZE + 1; + pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + aligned_phys = (char *)phys - error; // get page aligned (or allocate) vitural address if (virt == NULL) @@ -742,6 +736,9 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, if (virt == NULL) return NULL; + assert((uint64_t)virt % PAGE_SIZE == 0, + "mem_mapaddr: vitural address not page aligned"); + if (map_pages((volatile struct pml4 *)ctx->pml4, virt, aligned_phys, F_PRESENT | flags, pages)) { virtaddr_free(&ctx->virtctx, virt); @@ -751,26 +748,57 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, return (char *)virt + error; } -void *kmapuseraddr(mem_ctx_t ctx, const void *vADDR, size_t len) +void *kmapuseraddr(mem_ctx_t ctx, const void *usrADDR, size_t len) { - char *pADDR; + volatile struct pml4 *pml4; + char *pADDR, *vADDR; + size_t npages, error, i; - pADDR = mem_get_phys(ctx, vADDR); - if (pADDR == NULL) + pml4 = (volatile struct pml4 *)kernel_mem_ctx->pml4; + npages = (len + PAGE_SIZE - 1) / PAGE_SIZE; + error = (size_t)usrADDR % PAGE_SIZE; + vADDR = virtaddr_alloc(&kernel_mem_ctx->virtctx, npages); + if (vADDR == NULL) return NULL; - return kmapaddr(pADDR, NULL, len, F_PRESENT | F_WRITEABLE); + assert((size_t)vADDR % PAGE_SIZE == 0, + "kmapuseraddr: vitural address not page aligned"); + + for (i = 0; i < npages; i++) { + pADDR = mem_get_phys(ctx, (char *)usrADDR + i * PAGE_SIZE); + if (pADDR == NULL) + goto fail; + + // page align + pADDR = (char *)(((size_t)pADDR / PAGE_SIZE) * PAGE_SIZE); + + if (map_pages(pml4, vADDR + i * PAGE_SIZE, pADDR, + F_PRESENT | F_WRITEABLE, 1)) + goto fail; + } + + return vADDR + error; + +fail: + unmap_pages(&kernel_pml4, vADDR, i, false); + virtaddr_free(&kernel_mem_ctx->virtctx, vADDR); + return NULL; } void mem_unmapaddr(mem_ctx_t ctx, const void *virt) { + long pages; + if (virt == NULL) return; - long pages = virtaddr_free(&ctx->virtctx, virt); + // page align + virt = (void *)(((size_t)virt / PAGE_SIZE) * PAGE_SIZE); + + pages = virtaddr_free(&ctx->virtctx, virt); if (pages < 1) return; - unmap_pages(&kernel_pml4, virt, pages); + unmap_pages(&kernel_pml4, virt, pages, false); } void *mem_get_phys(mem_ctx_t ctx, const void *vADDR) @@ -877,5 +905,5 @@ void mem_free_pages(mem_ctx_t ctx, const void *virt) return; long pages = virtaddr_free(&ctx->virtctx, virt); - unmap_pages((volatile struct pml4 *)ctx->pml4, virt, pages); + unmap_pages((volatile struct pml4 *)ctx->pml4, virt, pages, true); } -- cgit v1.2.3-freya From bcfcfc348ebda9f08391348a3e58b3168d678ffc Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 14:09:14 -0400 Subject: zero and set define magic header in kalloc --- kernel/lib/kalloc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/lib/kalloc.c b/kernel/lib/kalloc.c index 9845a62..0141149 100644 --- a/kernel/lib/kalloc.c +++ b/kernel/lib/kalloc.c @@ -54,7 +54,8 @@ static void *alloc_new(size_t size) } struct page_header *header = addr; - header->magic = 0xBEEFCAFE; + memsetv(header, 0, sizeof(struct page_header)); + header->magic = MAGIC; header->used = size; header->free = free; header->prev = end_header; -- cgit v1.2.3-freya From 0258328d1d7bdd70e70693c983c172710df353e1 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 14:09:25 -0400 Subject: fix free phys pages --- kernel/memory/physalloc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index 48d2e3f..55ece02 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -172,7 +172,7 @@ void free_phys_pages(void *ptr, size_t pages) return; for (size_t i = 0; i < pages; i++) - bitmap_set(idx + pages, false); + bitmap_set(idx + i, false); } static bool segment_invalid(const struct memory_segment *segment) -- cgit v1.2.3-freya From 5ee82510b5fefd10fd8de1fa85adb38c9fa87975 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 15:00:29 -0400 Subject: lba48 for more then 256 sectors --- kernel/drivers/ata.c | 19 +++++++++++-------- kernel/include/comus/drivers/ata.h | 4 ++-- 2 files changed, 13 insertions(+), 10 deletions(-) (limited to 'kernel') diff --git a/kernel/drivers/ata.c b/kernel/drivers/ata.c index 63c4559..022ec81 100644 --- a/kernel/drivers/ata.c +++ b/kernel/drivers/ata.c @@ -506,7 +506,7 @@ static uint8_t get_ata_cmd_for_access(enum lba_mode lba_mode, static enum ide_error ide_device_ata_access(struct ide_device *dev, enum access_mode mode, uint32_t lba, - uint8_t numsects, + uint16_t numsects, uint16_t buf[numsects * 256]) { struct ide_channel *chan = channel(dev->channel_idx); @@ -521,7 +521,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev, chan->no_interrupt = (ide_irq_invoked = 0x0) + 0x02); // select one from LBA28, LBA48 or CHS - if (lba >= 0x10000000) { + if (lba >= 0x10000000 || numsects > UINT8_MAX) { // drive should support LBA in this case, or you are giving a bad LBA lba_mode = LBA48; lba_io[0] = (lba & 0x000000FF) >> 0; @@ -565,19 +565,22 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev, if (lba_mode == CHS) { ide_channel_write(chan, ATA_REG_HDDEVSEL, 0xA0 | (dev->drive_idx << 4) | head); - } else { + } else if (lba_mode == LBA28) { ide_channel_write(chan, ATA_REG_HDDEVSEL, 0xE0 | (dev->drive_idx << 4) | head); + } else { + ide_channel_write(chan, ATA_REG_HDDEVSEL, + 0x40 | (dev->drive_idx << 4)); } // write Parameters - if (lba_mode == 2) { - ide_channel_write(chan, ATA_REG_SECCOUNT1, 0); + if (lba_mode == LBA48) { + ide_channel_write(chan, ATA_REG_SECCOUNT1, (numsects >> 8) & 0xff); ide_channel_write(chan, ATA_REG_LBA3, lba_io[3]); ide_channel_write(chan, ATA_REG_LBA4, lba_io[4]); ide_channel_write(chan, ATA_REG_LBA5, lba_io[5]); } - ide_channel_write(chan, ATA_REG_SECCOUNT0, numsects); + ide_channel_write(chan, ATA_REG_SECCOUNT0, numsects & 0xff); ide_channel_write(chan, ATA_REG_LBA0, lba_io[0]); ide_channel_write(chan, ATA_REG_LBA1, lba_io[1]); ide_channel_write(chan, ATA_REG_LBA2, lba_io[2]); @@ -624,7 +627,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev, } enum ide_error ide_device_read_sectors(ide_device_t dev_identifier, - uint8_t numsects, uint32_t lba, + uint16_t numsects, uint32_t lba, uint16_t buf[numsects * 256]) { struct ide_device *dev = device(dev_identifier); @@ -656,7 +659,7 @@ enum ide_error ide_device_read_sectors(ide_device_t dev_identifier, } enum ide_error ide_device_write_sectors(ide_device_t device_identifier, - uint8_t numsects, uint32_t lba, + uint16_t numsects, uint32_t lba, uint16_t buf[numsects * 256]) { struct ide_device *dev = device(device_identifier); diff --git a/kernel/include/comus/drivers/ata.h b/kernel/include/comus/drivers/ata.h index 2f35e03..c404d84 100644 --- a/kernel/include/comus/drivers/ata.h +++ b/kernel/include/comus/drivers/ata.h @@ -44,7 +44,7 @@ enum ide_error ata_init(void); * * @returns IDE_ERROR_OK (0) on success or an error code on failure */ -enum ide_error ide_device_read_sectors(ide_device_t, uint8_t numsects, +enum ide_error ide_device_read_sectors(ide_device_t, uint16_t numsects, uint32_t lba, uint16_t buf[numsects * 256]); @@ -53,7 +53,7 @@ enum ide_error ide_device_read_sectors(ide_device_t, uint8_t numsects, * * @returns 0 on success or an error code on failure */ -enum ide_error ide_device_write_sectors(ide_device_t, uint8_t numsects, +enum ide_error ide_device_write_sectors(ide_device_t, uint16_t numsects, uint32_t lba, uint16_t buf[numsects * 256]); -- cgit v1.2.3-freya From 4fce3b9facd3624fd3b8fdc1d3e7d66324cfa5ce Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 15:01:58 -0400 Subject: fs return bytes read --- kernel/fs/fs.c | 25 +++++++++++++------------ kernel/include/comus/fs.h | 4 ++-- 2 files changed, 15 insertions(+), 14 deletions(-) (limited to 'kernel') diff --git a/kernel/fs/fs.c b/kernel/fs/fs.c index 98b04df..b46450d 100644 --- a/kernel/fs/fs.c +++ b/kernel/fs/fs.c @@ -1,6 +1,7 @@ #include #include #include +#include struct disk fs_disks[N_DISKS]; struct file_system fs_loaded_file_systems[N_DISKS]; @@ -97,7 +98,7 @@ static int disk_read_rd(struct disk *disk, size_t offset, size_t len, { if (offset + len >= disk->rd.len) { WARN("attempted to read past length of ramdisk"); - return 1; + return -E_BAD_PARAM; } memcpy(buffer, disk->rd.start + offset, len); @@ -112,11 +113,11 @@ static int disk_read_ata(struct disk *disk, size_t offset, size_t len, uint32_t err = offset % ATA_SECT_SIZE; uint32_t numsects = (len + err + ATA_SECT_SIZE - 1) / ATA_SECT_SIZE; - int ret = 0; + int ret; if (atabuf == NULL || atabuf_len < numsects * ATA_SECT_SIZE) { if ((atabuf = krealloc(atabuf, numsects * ATA_SECT_SIZE)) == NULL) - return 1; + return -E_NO_MEMORY; atabuf_len = numsects * ATA_SECT_SIZE; } @@ -128,7 +129,7 @@ static int disk_read_ata(struct disk *disk, size_t offset, size_t len, // copy over to buffer memcpy(buffer, (char *)atabuf + err, len); - return 0; + return len; } int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer) @@ -145,7 +146,7 @@ int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer) default: ERROR("attempted to read from disk with invalid type: %d\n", disk->type); - ret = 1; + ret = -E_BAD_PARAM; } return ret; @@ -156,7 +157,7 @@ static int disk_write_rd(struct disk *disk, size_t offset, size_t len, { if (offset + len >= disk->rd.len) { WARN("attempted to write past length of ramdisk"); - return 1; + return -E_BAD_PARAM; } memcpy(disk->rd.start + offset, buffer, len); @@ -171,18 +172,18 @@ static int disk_write_ata(struct disk *disk, size_t offset, size_t len, uint32_t numsects = (len + ATA_SECT_SIZE - 1) / ATA_SECT_SIZE; uint32_t err = offset % ATA_SECT_SIZE; - int ret = 0; + int ret; if (atabuf == NULL || atabuf_len < numsects * ATA_SECT_SIZE) { if ((atabuf = krealloc(atabuf, numsects * ATA_SECT_SIZE)) == NULL) - return 1; + return -E_NO_MEMORY; atabuf_len = numsects * ATA_SECT_SIZE; } // read sectors what will be overwritten if ((ret = ide_device_read_sectors(disk->ide, numsects, offset / ATA_SECT_SIZE, atabuf))) - return 1; + return ret; // copy custom data over memcpy((char *)atabuf + err, buffer, len); @@ -190,9 +191,9 @@ static int disk_write_ata(struct disk *disk, size_t offset, size_t len, // write back sectors if ((ret = ide_device_write_sectors(disk->ide, numsects, offset / ATA_SECT_SIZE, atabuf))) - return 1; + return ret; - return ret; + return len; } int disk_write(struct disk *disk, size_t offset, size_t len, void *buffer) @@ -208,7 +209,7 @@ int disk_write(struct disk *disk, size_t offset, size_t len, void *buffer) break; default: ERROR("attempted to write to disk with invalid type: %d\n", disk->type); - ret = 1; + ret = -E_BAD_PARAM; } return ret; diff --git a/kernel/include/comus/fs.h b/kernel/include/comus/fs.h index dab84a5..872c298 100644 --- a/kernel/include/comus/fs.h +++ b/kernel/include/comus/fs.h @@ -45,7 +45,7 @@ struct disk { * @param offset - the offset into the disk to read * @param len - the length of the data to read into `buffer` * @param buffer - the buffer to save data into - * @returns 0 on success, error code in failure + * @returns number of bytes read on success, negative fs error code in failure */ int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer); @@ -56,7 +56,7 @@ int disk_read(struct disk *disk, size_t offset, size_t len, void *buffer); * @param offset - the offset into the disk to write * @param len - the length of the data to write into `buffer` * @param buffer - the buffer to read from - * @returns 0 on success, error code in failure + * @returns number of bytes written on success, negative fs error code in failure */ int disk_write(struct disk *disk, size_t offset, size_t len, void *buffer); -- cgit v1.2.3-freya From 8dde461b65798cc1552a860dcec148a7c261f461 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 15:39:01 -0400 Subject: better rep insw --- kernel/include/comus/asm.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/include/comus/asm.h b/kernel/include/comus/asm.h index c7597e7..a6a8a45 100644 --- a/kernel/include/comus/asm.h +++ b/kernel/include/comus/asm.h @@ -36,8 +36,7 @@ static inline uint16_t inw(uint16_t port) static inline void rep_inw(uint16_t port, uint16_t *buffer, size_t count) { - while (count--) - *(buffer++) = inw(port); + __asm__ volatile("rep insw" : "+D"(buffer), "+c"(count) : "d"(port) : "memory"); } static inline void outw(uint16_t port, uint16_t val) -- cgit v1.2.3-freya From d6b45c3172b731a8bde81a750afbf70842d667c5 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 15:39:23 -0400 Subject: convert user.c to use a standard block size --- kernel/user.c | 60 ++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 41 insertions(+), 19 deletions(-) (limited to 'kernel') diff --git a/kernel/user.c b/kernel/user.c index b4f10d5..9d933e5 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -13,43 +13,61 @@ #define USER_STACK_TOP 0x800000000000 #define USER_STACK_LEN (4 * PAGE_SIZE) +#define BLOCK_SIZE (PAGE_SIZE * 1000) +static uint8_t *load_buffer = NULL; + static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) { - uint8_t buf[PAGE_SIZE]; Elf64_Phdr hdr; - size_t npages, nvpages, nbytes; + size_t mem_bytes, mem_pages; + size_t file_bytes, file_pages; + uint8_t *mapADDR; hdr = pcb->elf_segments[idx]; - nbytes = hdr.p_filesz; - npages = (nbytes + PAGE_SIZE - 1) / PAGE_SIZE; - nvpages = (hdr.p_memsz + PAGE_SIZE - 1) / PAGE_SIZE; - if (npages < 1) + // return if this is not a lodable segment + if (hdr.p_type != PT_LOAD) return 0; - if (hdr.p_type != PT_LOAD) + mem_bytes = hdr.p_memsz; + file_bytes = hdr.p_filesz; + + // we cannot read more data to less memory + if (file_bytes > mem_bytes) + return 1; + + mem_pages = (mem_bytes + PAGE_SIZE - 1) / PAGE_SIZE; + file_pages = (file_bytes + PAGE_SIZE - 1) / PAGE_SIZE; + + // return if were reading no data + if (file_pages < 1) return 0; // allocate memory in user process - if (mem_alloc_pages_at(pcb->memctx, nvpages, (void *)hdr.p_vaddr, + if (mem_alloc_pages_at(pcb->memctx, mem_pages, (void *)hdr.p_vaddr, F_WRITEABLE | F_UNPRIVILEGED) == NULL) return 1; + mapADDR = kmapuseraddr(pcb->memctx, (void *)hdr.p_vaddr, mem_bytes); + if (mapADDR == NULL) + return 1; + // load data - for (size_t i = 0; i < npages && nbytes; i++) { - size_t bytes = PAGE_SIZE; - if (nbytes < bytes) - bytes = nbytes; - mem_ctx_switch(kernel_mem_ctx); // disk_read is kernel internal - memset(buf + bytes, 0, PAGE_SIZE - bytes); - if (disk_read(disk, hdr.p_offset + i * PAGE_SIZE, bytes, buf)) + size_t total_read = 0; + while (total_read < file_bytes) { + size_t read = BLOCK_SIZE; + if (read > file_bytes - total_read) + read = file_bytes - total_read; + if ((read = disk_read(disk, hdr.p_offset + total_read, read, + load_buffer)) < 1) { + kunmapaddr(mapADDR); return 1; - mem_ctx_switch(pcb->memctx); - memcpy((char *)hdr.p_vaddr + i * PAGE_SIZE, buf, bytes); - nbytes -= bytes; + } + memcpyv(mapADDR + total_read, load_buffer, read); + total_read += read; } - mem_ctx_switch(kernel_mem_ctx); + kunmapaddr(mapADDR); return 0; } @@ -57,6 +75,10 @@ static int user_load_segments(struct pcb *pcb, struct disk *disk) { int ret = 0; + if (load_buffer == NULL) + if ((load_buffer = kalloc(BLOCK_SIZE)) == NULL) + return 1; + for (int i = 0; i < pcb->n_elf_segments; i++) if ((ret = user_load_segment(pcb, disk, i))) return ret; -- cgit v1.2.3-freya From 809d74a00e56048df39fc008606d8f62e731d56c Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 16:06:41 -0400 Subject: fix FIXMEs in syscall.c --- kernel/syscall.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'kernel') diff --git a/kernel/syscall.c b/kernel/syscall.c index f5dc56e..7a57353 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -13,16 +13,17 @@ #define ARG3(type, name) type name = (type)(current_pcb->regs->rdx) #define ARG4(type, name) type name = (type)(current_pcb->regs->rcx) +__attribute__((noreturn)) static int sys_exit(void) { ARG1(int, status); - (void)status; - // FIXME: schedule somthing else - while (1) - ; + current_pcb->exit_status = status; + pcb_zombify(current_pcb); + current_pcb = NULL; - return 1; + // call next process + dispatch(); } static int sys_write(void) @@ -56,13 +57,13 @@ static int sys_write(void) return nbytes; } +__attribute__((noreturn)) static int sys_poweroff(void) { // TODO: we should probably // kill all user processes // and then sync the fs acpi_shutdown(); - return 1; } static int sys_drm(void) @@ -138,14 +139,14 @@ void syscall_handler(struct cpu_regs *regs) num = current_pcb->regs->rax; current_pcb->regs->rax = 0; - // syscall number - // check for invalid syscall if (num >= N_SYSCALLS) { - // invalid syscall - // FIXME: kill user process - while (1) - ; + // kill process + current_pcb->exit_status = 1; + pcb_zombify(current_pcb); + current_pcb = NULL; + // call next process + dispatch(); } // run syscall handler @@ -156,4 +157,6 @@ void syscall_handler(struct cpu_regs *regs) // on failure, set rax if (ret) current_pcb->regs->rax = ret; + + // return to current pcb } -- cgit v1.2.3-freya From 91fb39db553dea9d07bb124f38c83460abc48d21 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 16:11:54 -0400 Subject: fmt --- kernel/drivers/ata.c | 3 +-- kernel/include/comus/asm.h | 5 ++++- kernel/syscall.c | 6 ++---- user/apple.c | 7 +++++-- 4 files changed, 12 insertions(+), 9 deletions(-) (limited to 'kernel') diff --git a/kernel/drivers/ata.c b/kernel/drivers/ata.c index 022ec81..6c8de86 100644 --- a/kernel/drivers/ata.c +++ b/kernel/drivers/ata.c @@ -569,8 +569,7 @@ static enum ide_error ide_device_ata_access(struct ide_device *dev, ide_channel_write(chan, ATA_REG_HDDEVSEL, 0xE0 | (dev->drive_idx << 4) | head); } else { - ide_channel_write(chan, ATA_REG_HDDEVSEL, - 0x40 | (dev->drive_idx << 4)); + ide_channel_write(chan, ATA_REG_HDDEVSEL, 0x40 | (dev->drive_idx << 4)); } // write Parameters diff --git a/kernel/include/comus/asm.h b/kernel/include/comus/asm.h index a6a8a45..4f376b1 100644 --- a/kernel/include/comus/asm.h +++ b/kernel/include/comus/asm.h @@ -36,7 +36,10 @@ static inline uint16_t inw(uint16_t port) static inline void rep_inw(uint16_t port, uint16_t *buffer, size_t count) { - __asm__ volatile("rep insw" : "+D"(buffer), "+c"(count) : "d"(port) : "memory"); + __asm__ volatile("rep insw" + : "+D"(buffer), "+c"(count) + : "d"(port) + : "memory"); } static inline void outw(uint16_t port, uint16_t val) diff --git a/kernel/syscall.c b/kernel/syscall.c index 7a57353..11db5e5 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -13,8 +13,7 @@ #define ARG3(type, name) type name = (type)(current_pcb->regs->rdx) #define ARG4(type, name) type name = (type)(current_pcb->regs->rcx) -__attribute__((noreturn)) -static int sys_exit(void) +__attribute__((noreturn)) static int sys_exit(void) { ARG1(int, status); @@ -57,8 +56,7 @@ static int sys_write(void) return nbytes; } -__attribute__((noreturn)) -static int sys_poweroff(void) +__attribute__((noreturn)) static int sys_poweroff(void) { // TODO: we should probably // kill all user processes diff --git a/user/apple.c b/user/apple.c index d0a5cc4..000718c 100644 --- a/user/apple.c +++ b/user/apple.c @@ -8,7 +8,7 @@ INCBIN(APPLE, "data/apple.bin"); #define APPLE_WIDTH 256 #define APPLE_HEIGHT 144 #define APPLE_FPS 12 -#define APPLE_FRAMES 5259 +#define APPLE_FRAMES 2630 #define MIN(a, b) (((a) < (b)) ? (a) : (b)) @@ -33,7 +33,10 @@ static void draw_frame(void) } } - frame = ((ticks() - ticks_off) / (1000 / APPLE_FPS)) % APPLE_FRAMES; + frame = ((ticks() - ticks_off) / (1000 / APPLE_FPS)); + + if (frame >= APPLE_FRAMES) + exit(0); } int main(void) -- cgit v1.2.3-freya From 21e2ed43f7d60e11f5b231212e6cada61f6e20c9 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 18:22:39 -0400 Subject: add more syscall impls --- kernel/syscall.c | 192 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 163 insertions(+), 29 deletions(-) (limited to 'kernel') diff --git a/kernel/syscall.c b/kernel/syscall.c index 11db5e5..b595b6a 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -5,21 +5,34 @@ #include #include #include -#include +#include +#include -#define RET(type, name) type *name = (type *)(¤t_pcb->regs->rax) -#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 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) __attribute__((noreturn)) static int sys_exit(void) { ARG1(int, status); - current_pcb->exit_status = status; - pcb_zombify(current_pcb); - current_pcb = NULL; + pcb->exit_status = status; + pcb_zombify(pcb); + + // call next process + dispatch(); +} + +static int sys_waitpid(void) +{ + // arguments are read later + // by procs.c + pcb->state = PROC_STATE_WAITING; + pcb_queue_insert(waiting, pcb); // call next process dispatch(); @@ -31,7 +44,7 @@ static int sys_write(void) ARG2(const void *, buffer); ARG3(size_t, nbytes); - const char *map_buf = kmapuseraddr(current_pcb->memctx, buffer, nbytes); + const char *map_buf = kmapuseraddr(pcb->memctx, buffer, nbytes); if (map_buf == NULL) return 0; @@ -56,6 +69,125 @@ static int sys_write(void) return nbytes; } +static int sys_getpid(void) +{ + return pcb->pid; +} + +static int sys_getppid(void) +{ + // init's parent is itself + if (pcb->parent == NULL) + return init_pcb->pid; + return pcb->parent->pid; +} + +static int sys_gettime(void) +{ + RET(unsigned long, time); + *time = unixtime(); + return 0; +} + +static int sys_getprio(void) +{ + RET(unsigned int, prio); + *prio = pcb->priority; + return 0; +} + +static int sys_setprio(void) +{ + RET(unsigned int, old); + ARG1(unsigned int, new); + + *old = pcb->priority; + pcb->priority = new; + return 0; +} + +static int sys_kill(void) +{ + ARG1(pid_t, pid); + struct pcb *victim, *parent; + + victim = pcb_find_pid(pid); + + // pid does not exist + if (victim == NULL) + return 1; + + parent = victim; + while (parent) { + if (parent->pid == pcb->pid) + break; + parent = parent->parent; + } + + // we do not own this pid + if (parent == NULL) + return 1; + + switch (victim->state) { + case PROC_STATE_KILLED: + case PROC_STATE_ZOMBIE: + // you can't kill it if it's already dead + return 0; + + case PROC_STATE_READY: + case PROC_STATE_SLEEPING: + case PROC_STATE_BLOCKED: + // here, the process is on a queue somewhere; mark + // it as "killed", and let the scheduler deal with it + victim->state = PROC_STATE_KILLED; + return 0; + + case PROC_STATE_RUNNING: + // we have met the enemy, and it is us! + pcb->exit_status = 1; + pcb_zombify(pcb); + // we need a new current process + dispatch(); + break; + + case PROC_STATE_WAITING: + // similar to the 'running' state, but we don't need + // to dispatch a new process + victim->exit_status = 1; + pcb_queue_remove(waiting, pcb); + pcb_zombify(victim); + break; + + default: + // cannot kill a previable process + return 1; + } + + return 0; +} + +static int sys_sleep(void) +{ + RET(int, ret); + ARG1(unsigned long, ms); + + if (ms == 0) { + *ret = 0; + schedule(pcb); + dispatch(); + } + + pcb->wakeup = ticks + ms; + if (pcb_queue_insert(sleeping, pcb)) { + WARN("sleep pcb insert failed"); + return 1; + } + + // calling pcb is in sleeping queue, + // we must call a new one + dispatch(); +} + __attribute__((noreturn)) static int sys_poweroff(void) { // TODO: we should probably @@ -84,7 +216,7 @@ static int sys_drm(void) if (pADDR == NULL) return 1; - vADDR = mem_mapaddr(current_pcb->memctx, pADDR, (void *)0x1000000000, len, + vADDR = mem_mapaddr(pcb->memctx, pADDR, (void *)0x1000000000, len, F_PRESENT | F_WRITEABLE | F_UNPRIVILEGED); if (vADDR == NULL) return 1; @@ -93,7 +225,7 @@ static int sys_drm(void) height = gpu_dev->height; bpp = gpu_dev->bit_depth; - mem_ctx_switch(current_pcb->memctx); + mem_ctx_switch(pcb->memctx); *res_fb = vADDR; *res_width = width; *res_height = height; @@ -111,16 +243,16 @@ static int sys_ticks(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_poweroff] = sys_poweroff, - [SYS_drm] = sys_drm, [SYS_ticks] = sys_ticks, + [SYS_exit] = sys_exit, [SYS_waitpid] = sys_waitpid, + [SYS_fork] = NULL, [SYS_exec] = NULL, + [SYS_open] = NULL, [SYS_close] = NULL, + [SYS_read] = NULL, [SYS_write] = sys_write, + [SYS_getpid] = sys_getpid, [SYS_getppid] = sys_getppid, + [SYS_gettime] = sys_gettime, [SYS_getprio] = sys_getprio, + [SYS_setprio] = sys_setprio, [SYS_kill] = sys_kill, + [SYS_sleep] = sys_sleep, [SYS_brk] = NULL, + [SYS_sbrk] = NULL, [SYS_poweroff] = sys_poweroff, + [SYS_drm] = sys_drm, [SYS_ticks] = sys_ticks, }; void syscall_handler(struct cpu_regs *regs) @@ -133,16 +265,17 @@ void syscall_handler(struct cpu_regs *regs) mem_ctx_switch(kernel_mem_ctx); // update data - current_pcb->regs = regs; - num = current_pcb->regs->rax; - current_pcb->regs->rax = 0; + pcb = current_pcb; + pcb->regs = regs; + num = pcb->regs->rax; + pcb->regs->rax = 0; + current_pcb = NULL; // check for invalid syscall if (num >= N_SYSCALLS) { // kill process - current_pcb->exit_status = 1; - pcb_zombify(current_pcb); - current_pcb = NULL; + pcb->exit_status = 1; + pcb_zombify(pcb); // call next process dispatch(); } @@ -154,7 +287,8 @@ void syscall_handler(struct cpu_regs *regs) // on failure, set rax if (ret) - current_pcb->regs->rax = ret; + pcb->regs->rax = ret; // return to current pcb + current_pcb = pcb; } -- cgit v1.2.3-freya From 5c96b3206d568f359eeb99034b571a2885166e2c Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sun, 27 Apr 2025 22:42:09 -0400 Subject: add register to n param --- kernel/lib/memcmp.c | 2 +- kernel/lib/memcpy.c | 2 +- kernel/lib/memmove.c | 2 +- kernel/lib/memmovev.c | 2 +- kernel/lib/memset.c | 2 +- kernel/lib/memsetv.c | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) (limited to 'kernel') diff --git a/kernel/lib/memcmp.c b/kernel/lib/memcmp.c index f938d0a..464fda3 100644 --- a/kernel/lib/memcmp.c +++ b/kernel/lib/memcmp.c @@ -1,6 +1,6 @@ #include -int memcmp(const void *restrict vl, const void *restrict vr, size_t n) +int memcmp(const void *restrict vl, const void *restrict vr, register size_t n) { const unsigned char *l = vl, *r = vr; for (; n && *l == *r; n--, l++, r++) diff --git a/kernel/lib/memcpy.c b/kernel/lib/memcpy.c index e848cef..168c926 100644 --- a/kernel/lib/memcpy.c +++ b/kernel/lib/memcpy.c @@ -1,6 +1,6 @@ #include -void *memcpy(void *restrict dest, const void *restrict src, size_t n) +void *memcpy(void *restrict dest, const void *restrict src, register size_t n) { char *d = dest; const char *s = src; diff --git a/kernel/lib/memmove.c b/kernel/lib/memmove.c index 55be66d..b413c1f 100644 --- a/kernel/lib/memmove.c +++ b/kernel/lib/memmove.c @@ -1,6 +1,6 @@ #include -void *memmove(void *dest, const void *src, size_t n) +void *memmove(void *dest, const void *src, register size_t n) { char *d = dest; const char *s = src; diff --git a/kernel/lib/memmovev.c b/kernel/lib/memmovev.c index 56684a5..65e6278 100644 --- a/kernel/lib/memmovev.c +++ b/kernel/lib/memmovev.c @@ -1,6 +1,6 @@ #include -volatile void *memmovev(volatile void *dest, const volatile void *src, size_t n) +volatile void *memmovev(volatile void *dest, const volatile void *src, register size_t n) { volatile char *d = dest; volatile const char *s = src; diff --git a/kernel/lib/memset.c b/kernel/lib/memset.c index d1c2a5e..7132e02 100644 --- a/kernel/lib/memset.c +++ b/kernel/lib/memset.c @@ -1,6 +1,6 @@ #include -void *memset(void *dest, int c, size_t n) +void *memset(void *dest, int c, register size_t n) { unsigned char *d = dest; for (; n; n--) { diff --git a/kernel/lib/memsetv.c b/kernel/lib/memsetv.c index 647847f..d5267b7 100644 --- a/kernel/lib/memsetv.c +++ b/kernel/lib/memsetv.c @@ -1,6 +1,6 @@ #include -volatile void *memsetv(volatile void *dest, int c, size_t n) +volatile void *memsetv(volatile void *dest, int c, register size_t n) { volatile unsigned char *d = dest; for (; n; n--) { -- 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') 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') 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 10d5e592e490ae89b88209635b1afd0343cae161 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 11:10:00 -0400 Subject: fmt --- kernel/lib/memmovev.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'kernel') diff --git a/kernel/lib/memmovev.c b/kernel/lib/memmovev.c index 65e6278..7884cef 100644 --- a/kernel/lib/memmovev.c +++ b/kernel/lib/memmovev.c @@ -1,6 +1,7 @@ #include -volatile void *memmovev(volatile void *dest, const volatile void *src, register size_t n) +volatile void *memmovev(volatile void *dest, const volatile void *src, + register size_t n) { volatile char *d = dest; volatile const char *s = src; -- cgit v1.2.3-freya From 36ba79324740ec3b6dc305961a9a2609223b032d Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 11:10:59 -0400 Subject: stderr in write syscall --- kernel/syscall.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'kernel') diff --git a/kernel/syscall.c b/kernel/syscall.c index 44bfe5f..94eec36 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -16,6 +16,10 @@ static struct pcb *pcb; #define ARG3(type, name) type name = (type)(pcb->regs.rdx) #define ARG4(type, name) type name = (type)(pcb->regs.rcx) +#define stdin 0 +#define stdout 1 +#define stderr 2 + __attribute__((noreturn)) static int sys_exit(void) { ARG1(int, status); @@ -52,8 +56,8 @@ static int sys_write(void) if (fd == 0) nbytes = 0; - // write to stdout - else if (fd == 1) { + // write to stdout / stderr + else if (fd == stdout || fd == stderr) { for (size_t i = 0; i < nbytes; i++) kputc(map_buf[i]); } -- 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') 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 3bff7f2cc98b335f19e46d1f95675b03ede60921 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 11:34:49 -0400 Subject: make sure sleep sets pcb to state sleeping --- kernel/syscall.c | 1 + 1 file changed, 1 insertion(+) (limited to 'kernel') diff --git a/kernel/syscall.c b/kernel/syscall.c index 94eec36..16eb243 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -186,6 +186,7 @@ static int sys_sleep(void) WARN("sleep pcb insert failed"); return 1; } + pcb->state = PROC_STATE_SLEEPING; // calling pcb is in sleeping queue, // we must call a new one -- 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') 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 f894f09bd84c13fb104d3720ead627728f04d6c6 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 13:05:14 -0400 Subject: allocate vaddrs when given directly --- kernel/memory/paging.c | 9 ++++++ kernel/memory/virtalloc.c | 80 ++++++++++++++++++++++++++++++++++------------- kernel/memory/virtalloc.h | 8 +++++ 3 files changed, 76 insertions(+), 21 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index 2cc5b7e..ec3c5c7 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -736,6 +736,9 @@ void *mem_mapaddr(mem_ctx_t ctx, void *phys, void *virt, size_t len, if (virt == NULL) return NULL; + if (virtaddr_take(&ctx->virtctx, virt, pages)) + return NULL; + assert((uint64_t)virt % PAGE_SIZE == 0, "mem_mapaddr: vitural address not page aligned"); @@ -761,6 +764,9 @@ void *kmapuseraddr(mem_ctx_t ctx, const void *usrADDR, size_t len) if (vADDR == NULL) return NULL; + if (virtaddr_take(&kernel_mem_ctx->virtctx, vADDR, npages)) + return NULL; + assert((size_t)vADDR % PAGE_SIZE == 0, "kmapuseraddr: vitural address not page aligned"); @@ -847,6 +853,9 @@ void *mem_alloc_pages_at(mem_ctx_t ctx, size_t count, void *virt, struct phys_page_slice prev_phys_block = PHYS_PAGE_SLICE_NULL; struct phys_page_slice phys_pages; + if (virtaddr_take(&ctx->virtctx, virt, count)) + return NULL; + while (pages_needed > 0) { phys_pages = alloc_phys_page_withextra(pages_needed); if (phys_pages.pagestart == NULL) { diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c index cbde9b4..863959e 100644 --- a/kernel/memory/virtalloc.c +++ b/kernel/memory/virtalloc.c @@ -1,5 +1,7 @@ +#include "lib/kio.h" #include #include +#include #include "virtalloc.h" @@ -177,32 +179,68 @@ void *virtaddr_alloc(struct virt_ctx *ctx, int n_pages) if (node->is_alloc) continue; - if (length >= n_length) { - struct virt_addr_node *new = get_node(ctx); - if (node->prev != NULL) { - node->prev->next = new; - } else { - ctx->start_node = new; - } - new->next = node; - new->prev = node->prev; - node->prev = new; - new->start = node->start; - new->end = new->start + n_length; - node->start = new->end; - new->is_alloc = true; - new->is_used = true; - new->next = node; - void *mem = (void *)new->start; - merge_back(ctx, new); - merge_forward(ctx, new); - return mem; - } + if (length < n_length) + continue; + + return (void*)node->start; } return NULL; } +int virtaddr_take(struct virt_ctx *ctx, const void *virt, int n_pages) +{ + if (n_pages < 1) + return 0; + + long n_length = n_pages * PAGE_SIZE; + struct virt_addr_node *node = ctx->start_node; + + for (; node != NULL; node = node->next) { + if (node->is_alloc) + continue; + + if (node->start > (uintptr_t)virt || + node->end < (uintptr_t)virt + n_length) + continue; + + // create new node on left + if (node->start < (uintptr_t) virt) { + struct virt_addr_node *left = get_node(ctx); + left->next = node; + left->prev = node->prev; + left->start = node->start; + left->end = (uintptr_t) virt; + left->is_used = true; + left->is_alloc = false; + node->prev->next = left; + node->prev = left; + } + + // create new node on right + if (node->end > (uintptr_t) virt + n_length) { + struct virt_addr_node *right = get_node(ctx); + right->prev = node; + right->next = node->next; + right->start = (uintptr_t) virt + n_length; + right->end = node->end; + right->is_used = true; + right->is_alloc = false; + node->next->prev = right; + node->next = right; + } + + node->start = (uintptr_t) virt; + node->end = node->start + n_length; + node->is_alloc = true; + node->is_used = true; + + return 0; + } + + return 1; +} + long virtaddr_free(struct virt_ctx *ctx, const void *virtaddr) { if (virtaddr == NULL) diff --git a/kernel/memory/virtalloc.h b/kernel/memory/virtalloc.h index 9a94208..5033242 100644 --- a/kernel/memory/virtalloc.h +++ b/kernel/memory/virtalloc.h @@ -64,6 +64,14 @@ int virtaddr_clone(struct virt_ctx *old, struct virt_ctx *new); */ void *virtaddr_alloc(struct virt_ctx *ctx, int pages); +/** + * Take (yoink) a predefined virtual address of length x pages + * @param virt - the start of the vitural address to take + * @param pages - x pages + * @returns 0 on success, 1 on err + */ +int virtaddr_take(struct virt_ctx *ctx, const void *virt, int pages); + /** * Free the virtual address from virtaddr_alloc * @param virtaddr - the addr to free -- cgit v1.2.3-freya From 3ff27507ccbffba7adf09b2322271606717a9164 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 13:21:58 -0400 Subject: heap (brk / sbrk) --- kernel/include/comus/procs.h | 4 +++ kernel/memory/virtalloc.c | 12 ++++---- kernel/syscall.c | 68 ++++++++++++++++++++++++++++++++++++++++++-- kernel/user.c | 13 +++++++++ user/heap.c | 46 ++++++++++++++++++++++++++++++ 5 files changed, 135 insertions(+), 8 deletions(-) create mode 100644 user/heap.c (limited to 'kernel') diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h index eb6c54f..cf3f90d 100644 --- a/kernel/include/comus/procs.h +++ b/kernel/include/comus/procs.h @@ -57,6 +57,10 @@ struct pcb { size_t priority; size_t ticks; + // heap + char *heap_start; + size_t heap_len; + // elf metadata Elf64_Ehdr elf_header; Elf64_Phdr elf_segments[N_ELF_SEGMENTS]; diff --git a/kernel/memory/virtalloc.c b/kernel/memory/virtalloc.c index 863959e..0cbba33 100644 --- a/kernel/memory/virtalloc.c +++ b/kernel/memory/virtalloc.c @@ -182,7 +182,7 @@ void *virtaddr_alloc(struct virt_ctx *ctx, int n_pages) if (length < n_length) continue; - return (void*)node->start; + return (void *)node->start; } return NULL; @@ -205,12 +205,12 @@ int virtaddr_take(struct virt_ctx *ctx, const void *virt, int n_pages) continue; // create new node on left - if (node->start < (uintptr_t) virt) { + if (node->start < (uintptr_t)virt) { struct virt_addr_node *left = get_node(ctx); left->next = node; left->prev = node->prev; left->start = node->start; - left->end = (uintptr_t) virt; + left->end = (uintptr_t)virt; left->is_used = true; left->is_alloc = false; node->prev->next = left; @@ -218,11 +218,11 @@ int virtaddr_take(struct virt_ctx *ctx, const void *virt, int n_pages) } // create new node on right - if (node->end > (uintptr_t) virt + n_length) { + if (node->end > (uintptr_t)virt + n_length) { struct virt_addr_node *right = get_node(ctx); right->prev = node; right->next = node->next; - right->start = (uintptr_t) virt + n_length; + right->start = (uintptr_t)virt + n_length; right->end = node->end; right->is_used = true; right->is_alloc = false; @@ -230,7 +230,7 @@ int virtaddr_take(struct virt_ctx *ctx, const void *virt, int n_pages) node->next = right; } - node->start = (uintptr_t) virt; + node->start = (uintptr_t)virt; node->end = node->start + n_length; node->is_alloc = true; node->is_used = true; diff --git a/kernel/syscall.c b/kernel/syscall.c index 16eb243..dd9bc16 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -1,3 +1,4 @@ +#include "lib/kio.h" #include #include #include @@ -7,6 +8,7 @@ #include #include #include +#include static struct pcb *pcb; @@ -201,6 +203,68 @@ __attribute__((noreturn)) static int sys_poweroff(void) acpi_shutdown(); } +static void *pcb_update_heap(intptr_t increment) +{ + char *curr_brk; + size_t curr_pages, new_pages, new_len; + + new_len = pcb->heap_len + increment; + new_pages = (new_len + PAGE_SIZE - 1) / PAGE_SIZE; + + curr_brk = pcb->heap_start + pcb->heap_len; + curr_pages = (pcb->heap_len + PAGE_SIZE - 1) / PAGE_SIZE; + if (pcb->heap_len == 0) + curr_pages = 0; + + // do nothing i guess + if (increment == 0 || new_pages == curr_pages) + return curr_brk; + + // unmap pages if decreasing + if (new_pages < curr_pages) { + void *new_end = pcb->heap_start + new_pages * PAGE_SIZE; + mem_free_pages(pcb->memctx, new_end); + pcb->heap_len = new_pages * PAGE_SIZE; + } + + // map pages if increasing + else { + void *curr_end = pcb->heap_start + curr_pages * PAGE_SIZE; + if (mem_alloc_pages_at(pcb->memctx, new_pages - curr_pages, curr_end, + F_PRESENT | F_WRITEABLE | F_UNPRIVILEGED) == + NULL) + return NULL; + pcb->heap_len = new_pages * PAGE_SIZE; + } + + return curr_brk; +} + +static int sys_brk(void) +{ + RET(void *, brk); + ARG1(const void *, addr); + + // cannot make heap smaller than start + if ((const char *)addr < pcb->heap_start) { + *brk = NULL; + return 0; + } + + *brk = pcb_update_heap((intptr_t)addr - + ((intptr_t)pcb->heap_start + pcb->heap_len)); + return 0; +} + +static int sys_sbrk(void) +{ + RET(void *, brk); + ARG1(intptr_t, increment); + + *brk = pcb_update_heap(increment); + return 0; +} + static int sys_drm(void) { ARG1(void **, res_fb); @@ -255,8 +319,8 @@ static int (*syscall_tbl[N_SYSCALLS])(void) = { [SYS_getpid] = sys_getpid, [SYS_getppid] = sys_getppid, [SYS_gettime] = sys_gettime, [SYS_getprio] = sys_getprio, [SYS_setprio] = sys_setprio, [SYS_kill] = sys_kill, - [SYS_sleep] = sys_sleep, [SYS_brk] = NULL, - [SYS_sbrk] = NULL, [SYS_poweroff] = sys_poweroff, + [SYS_sleep] = sys_sleep, [SYS_brk] = sys_brk, + [SYS_sbrk] = sys_sbrk, [SYS_poweroff] = sys_poweroff, [SYS_drm] = sys_drm, [SYS_ticks] = sys_ticks, }; diff --git a/kernel/user.c b/kernel/user.c index 8f626a7..fc1167d 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -71,6 +71,10 @@ static int user_load_segment(struct pcb *pcb, struct disk *disk, int idx) total_read += read; } + // update heap end + if (hdr.p_vaddr + mem_pages * PAGE_SIZE > (uint64_t)pcb->heap_start) + pcb->heap_start = (void *)(hdr.p_vaddr + mem_pages * PAGE_SIZE); + kunmapaddr(mapADDR); return 0; } @@ -79,6 +83,9 @@ static int user_load_segments(struct pcb *pcb, struct disk *disk) { int ret = 0; + pcb->heap_start = NULL; + pcb->heap_len = 0; + if (load_buffer == NULL) if ((load_buffer = kalloc(BLOCK_SIZE)) == NULL) return 1; @@ -86,6 +93,12 @@ static int user_load_segments(struct pcb *pcb, struct disk *disk) for (int i = 0; i < pcb->n_elf_segments; i++) if ((ret = user_load_segment(pcb, disk, i))) return ret; + + if (pcb->heap_start == NULL) { + WARN("No loadable ELF segments found."); + return 1; + }; + return 0; } diff --git a/user/heap.c b/user/heap.c new file mode 100644 index 0000000..ffa107b --- /dev/null +++ b/user/heap.c @@ -0,0 +1,46 @@ + +#include +#include +#include + +#define PAGE_SIZE 4096 + +int main(void) +{ + void *start, *brk; + + start = sbrk(0); + printf("heap start: %p\n", start); + + // test extending + if (sbrk(PAGE_SIZE) == NULL) { + fprintf(stderr, "failed to extend break\n"); + return 1; + } + + brk = sbrk(0); + printf("new break: %p\n", brk); + + // test reextending + if (sbrk(PAGE_SIZE) == NULL) { + fprintf(stderr, "failed to extend break\n"); + return 1; + } + + brk = sbrk(0); + printf("new new break: %p\n", brk); + + // test shrinking + if (sbrk(-PAGE_SIZE) == NULL) { + fprintf(stderr, "failed to shrink break\n"); + return 1; + } + + brk = sbrk(0); + printf("new new new break: %p\n", brk); + + // test write + memset(start, 1, PAGE_SIZE); + + return 0; +} -- cgit v1.2.3-freya From 91baa1659fa523da9b95d426137d32f5aeebc0cd Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 16:00:53 -0400 Subject: fix pml4 free and physalloc_free --- kernel/memory/paging.c | 8 ++++---- kernel/memory/physalloc.c | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index ec3c5c7..0571148 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -411,7 +411,7 @@ static void pt_free(volatile struct pt *pPT, bool force) void *pADDR; vPTE = &vPT->entries[i]; - if (!force && !(vPTE->flags & F_PRESENT)) + if (!(vPTE->flags & F_PRESENT)) continue; pADDR = (void *)((uintptr_t)vPTE->address << 12); @@ -445,7 +445,7 @@ static void pd_free(volatile struct pd *pPD, bool force) volatile struct pt *pPT; vPDE = &vPD->entries[i]; - if (!force && !(vPDE->flags & F_PRESENT)) + if (!(vPDE->flags & F_PRESENT)) continue; pPT = (volatile struct pt *)((uintptr_t)vPDE->address << 12); @@ -478,7 +478,7 @@ static void pdpt_free(volatile struct pdpt *pPDPT, bool force) volatile struct pd *pPD; vPDPTE = &vPDPT->entries[i]; - if (!force && !(vPDPTE->flags & F_PRESENT)) + if (!(vPDPTE->flags & F_PRESENT)) continue; pPD = (volatile struct pd *)((uintptr_t)vPDPTE->address << 12); @@ -511,7 +511,7 @@ static void pml4_free(volatile struct pml4 *pPML4, bool force) volatile struct pdpt *pPDPT; vPML4E = &vPML4->entries[i]; - if (!force && !(vPML4E->flags & F_PRESENT)) + if (!(vPML4E->flags & F_PRESENT)) continue; pPDPT = (volatile struct pdpt *)((uintptr_t)vPML4E->address << 12); diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index c5a74b7..f47f875 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -4,9 +4,8 @@ #include "physalloc.h" -extern char kernel_start; -extern char kernel_end; -#define kaddr(addr) ((uintptr_t)(&addr)) +extern char kernel_start[]; +extern char kernel_end[]; // between memory_start and kernel_start will be the bitmap static uintptr_t memory_start = 0; @@ -50,6 +49,9 @@ static long page_idx(void *page) int cur_page = 0; for (uint64_t idx = 0; idx < segment_count; idx++) { const struct memory_segment *m = page_start; + if (addr < m->addr) { + return -1; + } if ((uintptr_t)m + m->len > addr) { return cur_page + ((addr - m->addr) / PAGE_SIZE); } @@ -63,7 +65,7 @@ static inline bool bitmap_get(size_t i) return (bitmap[i / 64] >> i % 64) & 1; } -static inline void bitmap_set(int i, bool v) +static inline void bitmap_set(size_t i, bool v) { if (v) free_memory -= PAGE_SIZE; @@ -180,11 +182,11 @@ static bool segment_invalid(const struct memory_segment *segment) return true; if (segment->type != SEG_TYPE_FREE) return true; - if (segment->addr < kaddr(kernel_start)) + if (segment->addr < (uintptr_t) kernel_start) return true; if (segment->addr + segment->len < memory_start) return true; - if (segment->addr + segment->len < kaddr(kernel_start)) + if (segment->addr + segment->len < (uintptr_t) kernel_start) return true; return false; } @@ -198,7 +200,7 @@ static struct memory_segment clamp_segment(const struct memory_segment *segment) if (memory_start) start = memory_start; else - start = kaddr(kernel_end); + start = (uintptr_t) kernel_end; if (segment->addr < start) { addr = start; @@ -243,7 +245,7 @@ void physalloc_init(struct memory_map *map) long bitmap_pages = (page_count / 64 / PAGE_SIZE) + 1; long bitmap_size = bitmap_pages * PAGE_SIZE; - bitmap = (uint64_t *)page_align(kaddr(kernel_end)); + bitmap = (uint64_t *)page_align((uintptr_t)kernel_end); long page_area_size = segment_count * sizeof(struct memory_segment); char *page_area_addr = (char *)bitmap + bitmap_size; -- cgit v1.2.3-freya From 74517ed402d318fee911f9701396fee648887165 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 17:06:57 -0400 Subject: clone pgdir --- kernel/memory/paging.c | 323 ++++++++++++++++++++++++++++++++++++---------- kernel/memory/physalloc.c | 6 +- kernel/procs.c | 1 + 3 files changed, 257 insertions(+), 73 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index 0571148..b089895 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -146,69 +146,41 @@ static inline void invlpg(volatile const void *vADDR) /* map */ -// map a physical pml4 address to access +// map a physical address to a virtural address // @returns VIRTUAL ADDRESS -static volatile struct pml4 *pml4_map(volatile struct pml4 *pPML4) +static volatile void *map_addr(volatile const void *pADDR, size_t pt_idx) { - static volatile struct pml4 *vPML4 = (void *)(uintptr_t)0x40000000; - static volatile struct pte *vPTE = &paging_pt.entries[0]; + volatile char *vADDR; + volatile struct pte *vPTE; - if ((uint64_t)pPML4 >> 12 == vPTE->address) - return vPML4; + assert(pt_idx < 512, "invalid page table entry index"); - vPTE->address = (uint64_t)pPML4 >> 12; - vPTE->flags = F_PRESENT | F_WRITEABLE; - invlpg(vPML4); - return vPML4; -} + vADDR = (char *)(uintptr_t)(0x40000000 + pt_idx * PAGE_SIZE); + vPTE = &paging_pt.entries[pt_idx]; -// map a physical pdpt address to access -// @returns VIRTUAL ADDRESS -static volatile struct pdpt *pdpt_map(volatile struct pdpt *pPDPT) -{ - static volatile struct pdpt *vPDPT = (void *)(uintptr_t)0x40001000; - static volatile struct pte *vPTE = &paging_pt.entries[1]; - - if ((uint64_t)pPDPT >> 12 == vPTE->address) - return vPDPT; + if ((uint64_t)pADDR >> 12 == vPTE->address) + return vADDR; - vPTE->address = (uint64_t)pPDPT >> 12; + vPTE->address = (uint64_t)pADDR >> 12; vPTE->flags = F_PRESENT | F_WRITEABLE; - invlpg(vPDPT); - return vPDPT; + invlpg(vADDR); + return vADDR; } -// map a physical pd address to access -// @returns VIRTUAL ADDRESS -static volatile struct pd *pd_map(volatile struct pd *pPD) -{ - static volatile struct pd *vPD = (void *)(uintptr_t)0x40002000; - static volatile struct pte *vPTE = &paging_pt.entries[2]; - - if ((uint64_t)pPD >> 12 == vPTE->address) - return vPD; +#define PML4_MAP(pADDR) (volatile struct pml4 *)map_addr(pADDR, 0) +#define PML4_MAPC(pADDR) (volatile const struct pml4 *)map_addr(pADDR, 4) - vPTE->address = (uint64_t)pPD >> 12; - vPTE->flags = F_PRESENT | F_WRITEABLE; - invlpg(vPD); - return vPD; -} +#define PDPT_MAP(pADDR) (volatile struct pdpt *)map_addr(pADDR, 1) +#define PDPT_MAPC(pADDR) (volatile const struct pdpt *)map_addr(pADDR, 5) -// map a physical pt address to access -// @returns VIRTUAL ADDRESS -static volatile struct pt *pt_map(volatile struct pt *pPT) -{ - static volatile struct pt *vPT = (void *)(uintptr_t)0x40003000; - static volatile struct pte *vPTE = &paging_pt.entries[3]; +#define PD_MAP(pADDR) (volatile struct pd *)map_addr(pADDR, 2) +#define PD_MAPC(pADDR) (volatile const struct pd *)map_addr(pADDR, 6) - if ((uint64_t)pPT >> 12 == vPTE->address) - return vPT; +#define PT_MAP(pADDR) (volatile struct pt *)map_addr(pADDR, 3) +#define PT_MAPC(pADDR) (volatile const struct pt *)map_addr(pADDR, 7) - vPTE->address = (uint64_t)pPT >> 12; - vPTE->flags = F_PRESENT | F_WRITEABLE; - invlpg(vPT); - return vPT; -} +#define PAGE_MAP(pADDR) (volatile void *)map_addr(pADDR, 8) +#define PAGE_MAPC(pADDR) (volatile const void *)map_addr(pADDR, 9) /* locate */ @@ -223,7 +195,7 @@ static volatile struct pdpt *pdpt_locate(volatile struct pml4 *pPML4, uint64_t offset; offset = (uint64_t)vADDR >> 39; - vPML4 = pml4_map(pPML4); + vPML4 = PML4_MAP(pPML4); vPML4E = &vPML4->entries[offset]; if (vPML4E->flags & F_PRESENT) { @@ -245,7 +217,7 @@ static volatile struct pd *pd_locate(volatile struct pdpt *pPDPT, uint64_t offset; offset = ((uint64_t)vADDR >> 30) & 0x1ff; - vPDPT = pdpt_map(pPDPT); + vPDPT = PDPT_MAP(pPDPT); vPDPTE = &vPDPT->entries[offset]; if (vPDPTE->flags & F_PRESENT) { @@ -266,7 +238,7 @@ static volatile struct pt *pt_locate(volatile struct pd *pPD, const void *vADDR) uint64_t offset; offset = ((uint64_t)vADDR >> 21) & 0x1ff; - vPD = pd_map(pPD); + vPD = PD_MAP(pPD); vPDE = &vPD->entries[offset]; if (vPDE->flags & F_PRESENT) { @@ -289,7 +261,7 @@ static volatile struct pml4 *pml4_alloc(void) if (pPML4 == NULL) return NULL; - vPML4 = pml4_map(pPML4); + vPML4 = PML4_MAP(pPML4); memsetv(vPML4, 0, sizeof(struct pml4)); return pPML4; } @@ -305,7 +277,7 @@ static volatile struct pdpt *pdpt_alloc(volatile struct pml4 *pPML4, uint64_t offset; offset = (uint64_t)vADDR >> 39; - vPML4 = pml4_map(pPML4); + vPML4 = PML4_MAP(pPML4); vPML4E = &vPML4->entries[offset]; pPDPT = pdpt_locate(pPML4, vADDR); @@ -318,7 +290,7 @@ static volatile struct pdpt *pdpt_alloc(volatile struct pml4 *pPML4, if (pPML4 == NULL) return NULL; - vPDPT = pdpt_map(pPDPT); + vPDPT = PDPT_MAP(pPDPT); memsetv(vPDPT, 0, sizeof(struct pdpt)); vPML4E->address = (uintptr_t)pPDPT >> 12; vPML4E->flags = F_PRESENT | flags; @@ -338,7 +310,7 @@ static volatile struct pd *pd_alloc(volatile struct pdpt *pPDPT, void *vADDR, uint64_t offset; offset = ((uint64_t)vADDR >> 30) & 0x1ff; - vPDPT = pdpt_map(pPDPT); + vPDPT = PDPT_MAP(pPDPT); vPDPTE = &vPDPT->entries[offset]; pPD = pd_locate(pPDPT, vADDR); @@ -351,7 +323,7 @@ static volatile struct pd *pd_alloc(volatile struct pdpt *pPDPT, void *vADDR, if (pPDPT == NULL) return NULL; - vPD = pd_map(pPD); + vPD = PD_MAP(pPD); memsetv(vPD, 0, sizeof(struct pd)); vPDPTE->address = (uintptr_t)pPD >> 12; vPDPTE->flags = F_PRESENT | flags; @@ -371,7 +343,7 @@ static volatile struct pt *pt_alloc(volatile struct pd *pPD, void *vADDR, uint64_t offset; offset = ((uint64_t)vADDR >> 21) & 0x1ff; - vPD = pd_map(pPD); + vPD = PD_MAP(pPD); vPDE = &vPD->entries[offset]; pPT = pt_locate(pPD, vADDR); @@ -384,7 +356,7 @@ static volatile struct pt *pt_alloc(volatile struct pd *pPD, void *vADDR, if (pPD == NULL) return NULL; - vPT = pt_map(pPT); + vPT = PT_MAP(pPT); memsetv(vPT, 0, sizeof(struct pt)); vPDE->address = (uintptr_t)pPT >> 12; vPDE->flags = F_PRESENT | flags; @@ -400,7 +372,7 @@ static void pt_free(volatile struct pt *pPT, bool force) volatile struct pt *vPT; uint64_t count; - vPT = pt_map(pPT); + vPT = PT_MAP(pPT); count = (vPT->count_high << 2) | vPT->count_low; if (!count) @@ -434,7 +406,7 @@ static void pd_free(volatile struct pd *pPD, bool force) volatile struct pd *vPD; uint64_t count; - vPD = pd_map(pPD); + vPD = PD_MAP(pPD); count = vPD->count; if (!count) @@ -467,7 +439,7 @@ static void pdpt_free(volatile struct pdpt *pPDPT, bool force) volatile struct pdpt *vPDPT; uint64_t count; - vPDPT = pdpt_map(pPDPT); + vPDPT = PDPT_MAP(pPDPT); count = vPDPT->count; if (!count) @@ -500,7 +472,7 @@ static void pml4_free(volatile struct pml4 *pPML4, bool force) volatile struct pml4 *vPML4; uint64_t count; - vPML4 = pml4_map(pPML4); + vPML4 = PML4_MAP(pPML4); count = vPML4->count; if (!count) @@ -528,6 +500,220 @@ free: free_phys_page((void *)(uintptr_t)pPML4); } +/* clone */ + +volatile void *page_clone(volatile void *old_pADDR, bool cow) +{ + volatile const void *old_vADDR; + volatile void *new_pADDR, *new_vADDR; + + // TODO: cow + (void) cow; + + // dont reallocate kernel memeory!! + if ((volatile char *) old_pADDR <= kernel_end) + return old_pADDR; + + new_pADDR = alloc_phys_page(); + if (new_pADDR == NULL) + return NULL; + + old_vADDR = PAGE_MAPC(old_pADDR); + new_vADDR = PAGE_MAP(new_pADDR); + memcpyv(new_vADDR, old_vADDR, PAGE_SIZE); + return new_pADDR; +} + +volatile struct pt *pt_clone(volatile const struct pt *old_pPT, + bool cow) +{ + volatile const struct pt *old_vPT; + volatile struct pt *new_pPT, *new_vPT; + + new_pPT = alloc_phys_page(); + if (new_pPT == NULL) + return NULL; + + old_vPT = PT_MAPC(old_pPT); + new_vPT = PT_MAP(new_pPT); + memsetv(new_vPT, 0, PAGE_SIZE); + + new_vPT->count_high = old_vPT->count_high; + new_vPT->count_low = old_vPT->count_low; + + for (size_t i = 0; i < 512; i++) { + volatile const struct pte *old_vPTE; + volatile struct pte *new_vPTE; + volatile void *old_pADDR, *new_pADDR; + + old_vPTE = &old_vPT->entries[i]; + new_vPTE = &new_vPT->entries[i]; + + new_vPTE->execute_disable = old_vPTE->execute_disable; + new_vPTE->flags = old_vPTE->flags; + if (!(old_vPTE->flags & F_PRESENT)) + continue; + + new_vPTE->execute_disable = old_vPTE->execute_disable; + new_vPTE->flags = old_vPTE->flags; + + old_pADDR = + (volatile void *)((uintptr_t)old_vPTE->address + << 12); + new_pADDR = page_clone(old_pADDR, cow); + if (new_pADDR == NULL) + goto fail; + + new_vPTE->address = (uint64_t)new_pADDR >> 12; + } + + return new_pPT; + +fail: + pt_free(new_pPT, true); + return NULL; +} + +volatile struct pd *pd_clone(volatile const struct pd *old_pPD, + bool cow) +{ + volatile const struct pd *old_vPD; + volatile struct pd *new_pPD, *new_vPD; + + new_pPD = alloc_phys_page(); + if (new_pPD == NULL) + return NULL; + + old_vPD = PD_MAPC(old_pPD); + new_vPD = PD_MAP(new_pPD); + memsetv(new_vPD, 0, PAGE_SIZE); + + new_vPD->count = old_vPD->count; + + for (size_t i = 0; i < 512; i++) { + volatile const struct pde *old_vPDE; + volatile struct pde *new_vPDE; + volatile const struct pt *old_pPT; + volatile struct pt *new_pPT; + + old_vPDE = &old_vPD->entries[i]; + new_vPDE = &new_vPD->entries[i]; + + new_vPDE->execute_disable = old_vPDE->execute_disable; + new_vPDE->flags = old_vPDE->flags; + if (!(old_vPDE->flags & F_PRESENT)) + continue; + + old_pPT = + (volatile const struct pt *)((uintptr_t)old_vPDE->address + << 12); + new_pPT = pt_clone(old_pPT, cow); + if (new_pPT == NULL) + goto fail; + + new_vPDE->address = (uint64_t)new_pPT >> 12; + } + + return new_pPD; + +fail: + pd_free(new_pPD, true); + return NULL; +} + +volatile struct pdpt *pdpt_clone(volatile const struct pdpt *old_pPDPT, + bool cow) +{ + volatile const struct pdpt *old_vPDPT; + volatile struct pdpt *new_pPDPT, *new_vPDPT; + + new_pPDPT = alloc_phys_page(); + if (new_pPDPT == NULL) + return NULL; + + old_vPDPT = PDPT_MAPC(old_pPDPT); + new_vPDPT = PDPT_MAP(new_pPDPT); + memsetv(new_vPDPT, 0, PAGE_SIZE); + + new_vPDPT->count = old_vPDPT->count; + + for (size_t i = 0; i < 512; i++) { + volatile const struct pdpte *old_vPDPTE; + volatile struct pdpte *new_vPDPTE; + volatile const struct pd *old_pPD; + volatile struct pd *new_pPD; + + old_vPDPTE = &old_vPDPT->entries[i]; + new_vPDPTE = &new_vPDPT->entries[i]; + + new_vPDPTE->execute_disable = old_vPDPTE->execute_disable; + new_vPDPTE->flags = old_vPDPTE->flags; + if (!(old_vPDPTE->flags & F_PRESENT)) + continue; + + old_pPD = + (volatile const struct pd *)((uintptr_t)old_vPDPTE->address + << 12); + new_pPD = pd_clone(old_pPD, cow); + if (new_pPD == NULL) + goto fail; + + new_vPDPTE->address = (uint64_t)new_pPD >> 12; + } + + return new_pPDPT; + +fail: + pdpt_free(new_pPDPT, true); + return NULL; +} + +volatile struct pml4 *pml4_clone(volatile const struct pml4 *old_pPML4, + bool cow) +{ + volatile const struct pml4 *old_vPML4; + volatile struct pml4 *new_pPML4, *new_vPML4; + + new_pPML4 = pml4_alloc(); + if (new_pPML4 == NULL) + return NULL; + + old_vPML4 = PML4_MAPC(old_pPML4); + new_vPML4 = PML4_MAP(new_pPML4); + + new_vPML4->count = old_vPML4->count; + + for (size_t i = 0; i < 512; i++) { + volatile const struct pml4e *old_vPML4E; + volatile struct pml4e *new_vPML4E; + volatile const struct pdpt *old_pPDPT; + volatile struct pdpt *new_pPDPT; + + old_vPML4E = &old_vPML4->entries[i]; + new_vPML4E = &new_vPML4->entries[i]; + + new_vPML4E->execute_disable = old_vPML4E->execute_disable; + new_vPML4E->flags = old_vPML4E->flags; + if (!(old_vPML4E->flags & F_PRESENT)) + continue; + + old_pPDPT = + (volatile const struct pdpt *)((uintptr_t)old_vPML4E->address + << 12); + new_pPDPT = pdpt_clone(old_pPDPT, cow); + if (new_pPDPT == NULL) + goto fail; + + new_vPML4E->address = (uint64_t)new_pPDPT >> 12; + } + + return new_pPML4; + +fail: + pml4_free(new_pPML4, true); + return NULL; +} + /* page specific */ // locate a pte for a vitural address @@ -554,7 +740,7 @@ static volatile struct pte *page_locate(volatile struct pml4 *pPML4, return NULL; offset = ((uint64_t)vADDR >> 12) & 0x1ff; - vPT = pt_map(pPT); + vPT = PT_MAP(pPT); vPTE = &vPT->entries[offset]; if (vPTE->flags & F_PRESENT) @@ -587,7 +773,7 @@ static volatile struct pte *page_alloc(volatile struct pml4 *pPML4, void *vADDR, return NULL; offset = ((uint64_t)vADDR >> 12) & 0x1ff; - vPT = pt_map(pPT); + vPT = PT_MAP(pPT); vPTE = &vPT->entries[offset]; memsetv(vPTE, 0, sizeof(struct pte)); @@ -707,10 +893,7 @@ volatile void *pgdir_alloc(void) volatile void *pgdir_clone(volatile const void *old_pgdir, bool cow) { - // TODO: - (void)old_pgdir; - (void)cow; - return NULL; + return pml4_clone((volatile const struct pml4 *)old_pgdir, cow); } void pgdir_free(volatile void *addr) diff --git a/kernel/memory/physalloc.c b/kernel/memory/physalloc.c index f47f875..8971bcf 100644 --- a/kernel/memory/physalloc.c +++ b/kernel/memory/physalloc.c @@ -182,11 +182,11 @@ static bool segment_invalid(const struct memory_segment *segment) return true; if (segment->type != SEG_TYPE_FREE) return true; - if (segment->addr < (uintptr_t) kernel_start) + if (segment->addr < (uintptr_t)kernel_start) return true; if (segment->addr + segment->len < memory_start) return true; - if (segment->addr + segment->len < (uintptr_t) kernel_start) + if (segment->addr + segment->len < (uintptr_t)kernel_start) return true; return false; } @@ -200,7 +200,7 @@ static struct memory_segment clamp_segment(const struct memory_segment *segment) if (memory_start) start = memory_start; else - start = (uintptr_t) kernel_end; + start = (uintptr_t)kernel_end; if (segment->addr < start) { addr = start; diff --git a/kernel/procs.c b/kernel/procs.c index f3d855c..e2455ea 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -474,6 +474,7 @@ __attribute__((noreturn)) void dispatch(void) panic("dispatch queue remove failed, code %d", status); // set the process up for success + current_pcb->regs.cr3 = (uint64_t) mem_ctx_pgdir(current_pcb->memctx); current_pcb->state = PROC_STATE_RUNNING; current_pcb->ticks = 3; // ticks per process -- cgit v1.2.3-freya From d28c5ba100cbc8a4ea6e4f4da16f5c8319a02a72 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 17:28:02 -0400 Subject: fork syscall --- kernel/include/comus/user.h | 5 +++++ kernel/syscall.c | 18 ++++++++++++++++-- kernel/user.c | 31 +++++++++++++++++++++++++++++++ user/fork.c | 20 ++++++++++++++++++++ 4 files changed, 72 insertions(+), 2 deletions(-) create mode 100644 user/fork.c (limited to 'kernel') diff --git a/kernel/include/comus/user.h b/kernel/include/comus/user.h index 29c978c..f51ada5 100644 --- a/kernel/include/comus/user.h +++ b/kernel/include/comus/user.h @@ -17,6 +17,11 @@ */ int user_load(struct pcb *pcb, struct disk *disk); +/** + * Clone a user process. Used for fork(). + */ +struct pcb *user_clone(struct pcb *pcb); + /** * Clean up all loaded userland data from a pcb */ diff --git a/kernel/syscall.c b/kernel/syscall.c index dd9bc16..2dd6460 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -1,4 +1,4 @@ -#include "lib/kio.h" +#include #include #include #include @@ -44,6 +44,20 @@ static int sys_waitpid(void) dispatch(); } +static int sys_fork(void) +{ + struct pcb *child; + + child = user_clone(pcb); + if (child == NULL) + return -1; + + child->regs.rax = 0; + pcb->regs.rax = child->pid; + schedule(child); + return 0; +} + static int sys_write(void) { ARG1(int, fd); @@ -313,7 +327,7 @@ static int sys_ticks(void) static int (*syscall_tbl[N_SYSCALLS])(void) = { [SYS_exit] = sys_exit, [SYS_waitpid] = sys_waitpid, - [SYS_fork] = NULL, [SYS_exec] = NULL, + [SYS_fork] = sys_fork, [SYS_exec] = NULL, [SYS_open] = NULL, [SYS_close] = NULL, [SYS_read] = NULL, [SYS_write] = sys_write, [SYS_getpid] = sys_getpid, [SYS_getppid] = sys_getppid, diff --git a/kernel/user.c b/kernel/user.c index fc1167d..f9b541c 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -230,6 +230,37 @@ fail: return 1; } +struct pcb *user_clone(struct pcb *pcb) +{ + struct pcb *child; + + if (pcb_alloc(&child)) + return NULL; + + // copy context + memcpy(&child->regs, &pcb->regs, sizeof(struct cpu_regs)); + child->memctx = mem_ctx_clone(pcb->memctx, true); + if (child->memctx == NULL) + return NULL; + + // set metadata + child->parent = pcb; + child->state = PROC_STATE_READY; + child->priority = pcb->priority; + child->ticks = 0; + + // copy heap + child->heap_start = pcb->heap_start; + child->heap_len = pcb->heap_len; + + // copy elf data + memcpy(&child->elf_header, &pcb->elf_header, sizeof(Elf64_Ehdr)); + memcpy(&child->elf_segments, &pcb->elf_segments, sizeof(Elf64_Ehdr)); + child->n_elf_segments = pcb->n_elf_segments; + + return child; +} + void user_cleanup(struct pcb *pcb) { if (pcb == NULL) diff --git a/user/fork.c b/user/fork.c new file mode 100644 index 0000000..d534fcf --- /dev/null +++ b/user/fork.c @@ -0,0 +1,20 @@ +#include +#include + +int main(void) +{ + printf("im going to print some a's and b's. get ready\n"); + + int pid = fork(); + if (pid < 0) { + fprintf(stderr, "fork failed!\n"); + return 1; + } + + for (int i = 0; i < 10; i++) { + putchar(pid == 0 ? 'a' : 'b'); + putchar('\n'); + } + + return 0; +} -- cgit v1.2.3-freya From 747546a0bd92d98988741ce9868791735bbd9044 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 21:30:43 -0400 Subject: change struct gpu to gpu_dev --- kernel/drivers/gpu.c | 2 +- kernel/drivers/gpu/bochs.c | 4 ++-- kernel/drivers/gpu/gop.c | 4 ++-- kernel/include/comus/drivers/gpu.h | 4 ++-- kernel/include/comus/drivers/gpu/bochs.h | 2 +- kernel/include/comus/drivers/gpu/gop.h | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) (limited to 'kernel') diff --git a/kernel/drivers/gpu.c b/kernel/drivers/gpu.c index 3d79b99..fc6ec8e 100644 --- a/kernel/drivers/gpu.c +++ b/kernel/drivers/gpu.c @@ -7,7 +7,7 @@ #include #include -struct gpu *gpu_dev = NULL; +struct gpu_dev *gpu_dev = NULL; int gpu_init(void) { diff --git a/kernel/drivers/gpu/bochs.c b/kernel/drivers/gpu/bochs.c index f8e5820..2dfe62e 100644 --- a/kernel/drivers/gpu/bochs.c +++ b/kernel/drivers/gpu/bochs.c @@ -31,7 +31,7 @@ #define BOCHS_HEIGHT 768 #define BOCHS_BIT_DEPTH 32 -struct gpu bochs_dev = { 0 }; +struct gpu_dev bochs_dev = { 0 }; static void write(uint16_t index, uint16_t data) { @@ -45,7 +45,7 @@ static uint16_t read(uint16_t value) return inw(DATA); } -int bochs_init(struct gpu **gpu_dev) +int bochs_init(struct gpu_dev **gpu_dev) { struct pci_device bochs = { 0 }; bool found = diff --git a/kernel/drivers/gpu/gop.c b/kernel/drivers/gpu/gop.c index 47da952..a57766d 100644 --- a/kernel/drivers/gpu/gop.c +++ b/kernel/drivers/gpu/gop.c @@ -5,11 +5,11 @@ #include #include -struct gpu gop_dev = { 0 }; +struct gpu_dev gop_dev = { 0 }; static EFI_GRAPHICS_OUTPUT_PROTOCOL *gop; -int gop_init(struct gpu **gpu_dev) +int gop_init(struct gpu_dev **gpu_dev) { gop = efi_get_gop(); if (gop == NULL || gop->Mode == NULL) diff --git a/kernel/include/comus/drivers/gpu.h b/kernel/include/comus/drivers/gpu.h index 39c633f..0a8f4fa 100644 --- a/kernel/include/comus/drivers/gpu.h +++ b/kernel/include/comus/drivers/gpu.h @@ -11,7 +11,7 @@ #include -struct gpu { +struct gpu_dev { const char *name; uint16_t width; uint16_t height; @@ -31,7 +31,7 @@ struct psf2_font { uint8_t data[]; }; -extern struct gpu *gpu_dev; +extern struct gpu_dev *gpu_dev; extern struct psf2_font en_font; /** diff --git a/kernel/include/comus/drivers/gpu/bochs.h b/kernel/include/comus/drivers/gpu/bochs.h index 7d26b60..ec70060 100644 --- a/kernel/include/comus/drivers/gpu/bochs.h +++ b/kernel/include/comus/drivers/gpu/bochs.h @@ -15,6 +15,6 @@ * Loads the bochs graphics driver * @returns 0 on success, NULL on error */ -int bochs_init(struct gpu **gpu_dev); +int bochs_init(struct gpu_dev **gpu_dev); #endif /* bochs.h */ diff --git a/kernel/include/comus/drivers/gpu/gop.h b/kernel/include/comus/drivers/gpu/gop.h index 6475f05..d3af921 100644 --- a/kernel/include/comus/drivers/gpu/gop.h +++ b/kernel/include/comus/drivers/gpu/gop.h @@ -15,6 +15,6 @@ * Loads the uefi gop graphics driver * @returns 0 on success, NULL on error */ -int gop_init(struct gpu **gpu_dev); +int gop_init(struct gpu_dev **gpu_dev); #endif /* gop.h */ -- cgit v1.2.3-freya From c0a391cb11fe1b14f6622bad5697a72de1781eb2 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Mon, 28 Apr 2025 21:55:40 -0400 Subject: fmt --- kernel/memory/paging.c | 20 +++++++------------- kernel/procs.c | 2 +- kernel/syscall.c | 2 +- 3 files changed, 9 insertions(+), 15 deletions(-) (limited to 'kernel') diff --git a/kernel/memory/paging.c b/kernel/memory/paging.c index b089895..763bdce 100644 --- a/kernel/memory/paging.c +++ b/kernel/memory/paging.c @@ -508,10 +508,10 @@ volatile void *page_clone(volatile void *old_pADDR, bool cow) volatile void *new_pADDR, *new_vADDR; // TODO: cow - (void) cow; + (void)cow; // dont reallocate kernel memeory!! - if ((volatile char *) old_pADDR <= kernel_end) + if ((volatile char *)old_pADDR <= kernel_end) return old_pADDR; new_pADDR = alloc_phys_page(); @@ -524,8 +524,7 @@ volatile void *page_clone(volatile void *old_pADDR, bool cow) return new_pADDR; } -volatile struct pt *pt_clone(volatile const struct pt *old_pPT, - bool cow) +volatile struct pt *pt_clone(volatile const struct pt *old_pPT, bool cow) { volatile const struct pt *old_vPT; volatile struct pt *new_pPT, *new_vPT; @@ -557,9 +556,7 @@ volatile struct pt *pt_clone(volatile const struct pt *old_pPT, new_vPTE->execute_disable = old_vPTE->execute_disable; new_vPTE->flags = old_vPTE->flags; - old_pADDR = - (volatile void *)((uintptr_t)old_vPTE->address - << 12); + old_pADDR = (volatile void *)((uintptr_t)old_vPTE->address << 12); new_pADDR = page_clone(old_pADDR, cow); if (new_pADDR == NULL) goto fail; @@ -574,8 +571,7 @@ fail: return NULL; } -volatile struct pd *pd_clone(volatile const struct pd *old_pPD, - bool cow) +volatile struct pd *pd_clone(volatile const struct pd *old_pPD, bool cow) { volatile const struct pd *old_vPD; volatile struct pd *new_pPD, *new_vPD; @@ -605,8 +601,7 @@ volatile struct pd *pd_clone(volatile const struct pd *old_pPD, continue; old_pPT = - (volatile const struct pt *)((uintptr_t)old_vPDE->address - << 12); + (volatile const struct pt *)((uintptr_t)old_vPDE->address << 12); new_pPT = pt_clone(old_pPT, cow); if (new_pPT == NULL) goto fail; @@ -652,8 +647,7 @@ volatile struct pdpt *pdpt_clone(volatile const struct pdpt *old_pPDPT, continue; old_pPD = - (volatile const struct pd *)((uintptr_t)old_vPDPTE->address - << 12); + (volatile const struct pd *)((uintptr_t)old_vPDPTE->address << 12); new_pPD = pd_clone(old_pPD, cow); if (new_pPD == NULL) goto fail; diff --git a/kernel/procs.c b/kernel/procs.c index e2455ea..5b03e73 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -474,7 +474,7 @@ __attribute__((noreturn)) void dispatch(void) panic("dispatch queue remove failed, code %d", status); // set the process up for success - current_pcb->regs.cr3 = (uint64_t) mem_ctx_pgdir(current_pcb->memctx); + current_pcb->regs.cr3 = (uint64_t)mem_ctx_pgdir(current_pcb->memctx); current_pcb->state = PROC_STATE_RUNNING; current_pcb->ticks = 3; // ticks per process diff --git a/kernel/syscall.c b/kernel/syscall.c index 2dd6460..403b3bd 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -327,7 +327,7 @@ static int sys_ticks(void) static int (*syscall_tbl[N_SYSCALLS])(void) = { [SYS_exit] = sys_exit, [SYS_waitpid] = sys_waitpid, - [SYS_fork] = sys_fork, [SYS_exec] = NULL, + [SYS_fork] = sys_fork, [SYS_exec] = NULL, [SYS_open] = NULL, [SYS_close] = NULL, [SYS_read] = NULL, [SYS_write] = sys_write, [SYS_getpid] = sys_getpid, [SYS_getppid] = sys_getppid, -- cgit v1.2.3-freya From a7079cf0f66f01434bf0860c3020bcdbcf267317 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Tue, 29 Apr 2025 10:27:05 -0400 Subject: dispatch(): wait for a process to schedule --- kernel/procs.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'kernel') diff --git a/kernel/procs.c b/kernel/procs.c index 5b03e73..1668bef 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -1,8 +1,9 @@ #include +#include #include #include #include -#include +#include #define PCB_QUEUE_EMPTY(q) ((q)->head == NULL) @@ -467,11 +468,17 @@ void schedule(struct pcb *pcb) __attribute__((noreturn)) void dispatch(void) { + int status; + assert(current_pcb == NULL, "dispatch: current process is not null"); - int status = pcb_queue_pop(ready, ¤t_pcb); - if (status != SUCCESS) - panic("dispatch queue remove failed, code %d", status); + // wait for a process to schedule + do { + status = pcb_queue_pop(ready, ¤t_pcb); + if (status == SUCCESS) + break; + int_wait(); + } while (1); // set the process up for success current_pcb->regs.cr3 = (uint64_t)mem_ctx_pgdir(current_pcb->memctx); -- 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') 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 From 4e6384d8153f1476701638e2277043d59755306d Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Tue, 29 Apr 2025 11:13:58 -0400 Subject: change queue structures --- kernel/include/comus/procs.h | 12 ++++---- kernel/procs.c | 67 ++++++++++++++++++++++++++------------------ kernel/syscall.c | 35 ++++++++++++----------- 3 files changed, 62 insertions(+), 52 deletions(-) (limited to 'kernel') diff --git a/kernel/include/comus/procs.h b/kernel/include/comus/procs.h index cf3f90d..7b1a70a 100644 --- a/kernel/include/comus/procs.h +++ b/kernel/include/comus/procs.h @@ -12,6 +12,7 @@ #include #include #include +#include #include #include @@ -34,11 +35,8 @@ enum proc_state { PROC_STATE_READY, PROC_STATE_RUNNING, // runnable, but waiting for some event - PROC_STATE_SLEEPING, PROC_STATE_BLOCKED, - PROC_STATE_WAITING, // no longer runnalbe - PROC_STATE_KILLED, PROC_STATE_ZOMBIE, // sentinel N_PROC_STATES, @@ -70,6 +68,7 @@ struct pcb { struct pcb *next; // next PDB in queue // process state information + uint64_t syscall; uint64_t wakeup; uint8_t exit_status; }; @@ -89,10 +88,9 @@ typedef struct pcb_queue_s *pcb_queue_t; /// public facing pcb queues extern pcb_queue_t pcb_freelist; -extern pcb_queue_t ready; -extern pcb_queue_t waiting; -extern pcb_queue_t sleeping; -extern pcb_queue_t zombie; +extern pcb_queue_t ready_queue; +extern pcb_queue_t zombie_queue; +extern pcb_queue_t syscall_queue[N_SYSCALLS]; /// pointer to the currently-running process extern struct pcb *current_pcb; diff --git a/kernel/procs.c b/kernel/procs.c index 1668bef..9bf7508 100644 --- a/kernel/procs.c +++ b/kernel/procs.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -14,18 +15,16 @@ struct pcb_queue_s { }; // collection of queues -static struct pcb_queue_s pcb_freelist_queue; -static struct pcb_queue_s ready_queue; -static struct pcb_queue_s waiting_queue; -static struct pcb_queue_s sleeping_queue; -static struct pcb_queue_s zombie_queue; +static struct pcb_queue_s _pcb_freelist; +static struct pcb_queue_s _ready_queue; +static struct pcb_queue_s _zombie_queue; +static struct pcb_queue_s _syscall_queue[N_SYSCALLS]; // public facing queue handels pcb_queue_t pcb_freelist; -pcb_queue_t ready; -pcb_queue_t waiting; -pcb_queue_t sleeping; -pcb_queue_t zombie; +pcb_queue_t ready_queue; +pcb_queue_t zombie_queue; +pcb_queue_t syscall_queue[N_SYSCALLS]; /// pointer to the currently-running process struct pcb *current_pcb = NULL; @@ -86,7 +85,7 @@ static struct pcb *find_prev_pid(pcb_queue_t queue, struct pcb *pcb) // a macro to simplify queue setup #define QINIT(q, s) \ - q = &q##_queue; \ + q = &_##q; \ if (pcb_queue_reset(q, s) != SUCCESS) { \ panic("pcb_init can't reset " #q); \ } @@ -98,10 +97,11 @@ void pcb_init(void) // set up the external links to the queues QINIT(pcb_freelist, O_PCB_FIFO); - QINIT(ready, O_PCB_PRIO); - QINIT(waiting, O_PCB_PID); - QINIT(sleeping, O_PCB_WAKEUP); - QINIT(zombie, O_PCB_PID); + QINIT(ready_queue, O_PCB_PRIO); + QINIT(zombie_queue, O_PCB_PID); + for (size_t i = 0; i < N_SYSCALLS; i++) { + QINIT(syscall_queue[i], O_PCB_PID); + } // setup pcb linked list (free list) // this can be done by calling pcb_free :) @@ -122,6 +122,7 @@ int pcb_alloc(struct pcb **pcb) return E_NO_PCBS; tmp->pid = next_pid++; + tmp->state = PROC_STATE_NEW; *pcb = tmp; return SUCCESS; } @@ -180,13 +181,14 @@ void pcb_zombify(struct pcb *victim) } // schedule init if zombie child found - if (zchild != NULL && init_pcb->state == PROC_STATE_WAITING) { + if (zchild != NULL && init_pcb->syscall == SYS_waitpid) { pid_t pid; int *status; - assert(pcb_queue_remove(zombie, zchild) == SUCCESS, + assert(pcb_queue_remove(zombie_queue, zchild) == SUCCESS, "pcb_zombify: cannot remove zombie process from queue"); - assert(pcb_queue_remove(waiting, init_pcb) == SUCCESS, + assert(pcb_queue_remove(syscall_queue[SYS_waitpid], init_pcb) == + SUCCESS, "pcb_zombify: cannot remove waiting process from queue"); pid = (pid_t)PCB_ARG1(init_pcb); @@ -208,7 +210,7 @@ void pcb_zombify(struct pcb *victim) // 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) { + if (parent->syscall == SYS_waitpid) { pid_t pid; int *status; @@ -217,6 +219,11 @@ void pcb_zombify(struct pcb *victim) if (pid == 0 || pid == victim->pid) { PCB_RET(parent) = zchild->pid; + + assert( + pcb_queue_remove(syscall_queue[SYS_waitpid], parent) == SUCCESS, + "pcb_zombify: cannot remove parent process from waitpid queue"); + if (status != NULL) { mem_ctx_switch(parent->memctx); *status = victim->exit_status; @@ -229,7 +236,7 @@ void pcb_zombify(struct pcb *victim) } victim->state = PROC_STATE_ZOMBIE; - assert(pcb_queue_insert(zombie, victim) == SUCCESS, + assert(pcb_queue_insert(zombie_queue, victim) == SUCCESS, "cannot insert victim process into zombie queue"); } @@ -456,13 +463,15 @@ struct pcb *pcb_queue_peek(const pcb_queue_t queue) void schedule(struct pcb *pcb) { assert(pcb != NULL, "schedule: pcb is null"); - - if (pcb->state == PROC_STATE_KILLED) - panic("attempted to schedule killed process %d", pcb->pid); + assert(pcb->state != PROC_STATE_UNUSED, + "attempted to schedule invalid process %d", pcb->pid); + assert(pcb->state != PROC_STATE_ZOMBIE, + "attempted to schedule killed process %d", pcb->pid); pcb->state = PROC_STATE_READY; + pcb->syscall = 0; - if (pcb_queue_insert(ready, pcb) != SUCCESS) + if (pcb_queue_insert(ready_queue, pcb) != SUCCESS) panic("schedule insert fail"); } @@ -474,9 +483,10 @@ __attribute__((noreturn)) void dispatch(void) // wait for a process to schedule do { - status = pcb_queue_pop(ready, ¤t_pcb); - if (status == SUCCESS) + status = pcb_queue_pop(ready_queue, ¤t_pcb); + if (status == SUCCESS) { break; + } int_wait(); } while (1); @@ -484,6 +494,7 @@ __attribute__((noreturn)) void dispatch(void) current_pcb->regs.cr3 = (uint64_t)mem_ctx_pgdir(current_pcb->memctx); current_pcb->state = PROC_STATE_RUNNING; current_pcb->ticks = 3; // ticks per process + current_pcb->syscall = 0; syscall_return(); } @@ -498,16 +509,16 @@ void pcb_on_tick(void) do { struct pcb *pcb; - if (pcb_queue_empty(sleeping)) + if (pcb_queue_empty(syscall_queue[SYS_sleep])) break; - pcb = pcb_queue_peek(sleeping); + pcb = pcb_queue_peek(syscall_queue[SYS_sleep]); assert(pcb != NULL, "sleeping queue should not be empty"); if (pcb->wakeup >= ticks) break; - if (pcb_queue_remove(sleeping, pcb)) + if (pcb_queue_remove(syscall_queue[SYS_sleep], pcb)) panic("failed to wake sleeping process: %d", pcb->pid); schedule(pcb); diff --git a/kernel/syscall.c b/kernel/syscall.c index 403b3bd..96d2fcf 100644 --- a/kernel/syscall.c +++ b/kernel/syscall.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -37,8 +38,9 @@ static int sys_waitpid(void) { // arguments are read later // by procs.c - pcb->state = PROC_STATE_WAITING; - pcb_queue_insert(waiting, pcb); + pcb->state = PROC_STATE_BLOCKED; + assert(pcb_queue_insert(syscall_queue[SYS_waitpid], pcb) == SUCCESS, + "sys_waitpid: could not add process to waitpid queue"); // call next process dispatch(); @@ -149,17 +151,22 @@ static int sys_kill(void) return 1; switch (victim->state) { - case PROC_STATE_KILLED: case PROC_STATE_ZOMBIE: // you can't kill it if it's already dead return 0; case PROC_STATE_READY: - case PROC_STATE_SLEEPING: + // remove from ready queue + victim->exit_status = 1; + pcb_queue_remove(ready_queue, victim); + pcb_zombify(victim); + return 0; + case PROC_STATE_BLOCKED: - // here, the process is on a queue somewhere; mark - // it as "killed", and let the scheduler deal with it - victim->state = PROC_STATE_KILLED; + // remove from syscall queue + victim->exit_status = 1; + pcb_queue_remove(syscall_queue[victim->syscall], victim); + pcb_zombify(victim); return 0; case PROC_STATE_RUNNING: @@ -170,14 +177,6 @@ static int sys_kill(void) dispatch(); break; - case PROC_STATE_WAITING: - // similar to the 'running' state, but we don't need - // to dispatch a new process - victim->exit_status = 1; - pcb_queue_remove(waiting, pcb); - pcb_zombify(victim); - break; - default: // cannot kill a previable process return 1; @@ -198,11 +197,11 @@ static int sys_sleep(void) } pcb->wakeup = ticks + ms; - if (pcb_queue_insert(sleeping, pcb)) { + if (pcb_queue_insert(syscall_queue[SYS_sleep], pcb)) { WARN("sleep pcb insert failed"); return 1; } - pcb->state = PROC_STATE_SLEEPING; + pcb->state = PROC_STATE_BLOCKED; // calling pcb is in sleeping queue, // we must call a new one @@ -348,6 +347,7 @@ void syscall_handler(void) pcb = current_pcb; num = pcb->regs.rax; pcb->regs.rax = 0; + pcb->syscall = num; current_pcb = NULL; // check for invalid syscall @@ -369,5 +369,6 @@ void syscall_handler(void) pcb->regs.rax = ret; // return to current pcb + pcb->syscall = 0; current_pcb = pcb; } -- cgit v1.2.3-freya From 7602ce3b97c893359406655afa515a616084655e Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Tue, 29 Apr 2025 12:17:32 -0400 Subject: input manager --- kernel/drivers/ps2.c | 62 +++++++------------------ kernel/include/comus/drivers/ps2.h | 22 --------- kernel/include/comus/input.h | 36 +++++++++++++++ kernel/include/comus/keycodes.h | 5 -- kernel/include/comus/limits.h | 4 ++ kernel/input.c | 93 ++++++++++++++++++++++++++++++++++++++ 6 files changed, 150 insertions(+), 72 deletions(-) create mode 100644 kernel/include/comus/input.h create mode 100644 kernel/input.c (limited to 'kernel') diff --git a/kernel/drivers/ps2.c b/kernel/drivers/ps2.c index 5c18b5b..e260f6b 100644 --- a/kernel/drivers/ps2.c +++ b/kernel/drivers/ps2.c @@ -1,5 +1,6 @@ #include #include +#include #include #include @@ -78,22 +79,10 @@ 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) @@ -170,6 +159,7 @@ static int ps2mouse_init(void) void ps2kb_recv(void) { + static struct keycode keycode; uint8_t code; if (!has_kbd) @@ -177,40 +167,28 @@ void ps2kb_recv(void) code = ps2ctrl_in(); if (code == 0x00 || code == 0x0F) { - last_keycode.key = KEY_NONE; - last_keycode.flags = KC_FLAG_ERROR; + keycode.key = KEY_NONE; + 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; + uint8_t kcode = scancode_table[code]; + if (kcode != KEY_NONE) { + keycode.key = kcode; + keycode.flags = state_keyup ? KC_FLAG_KEY_UP : KC_FLAG_KEY_DOWN; + keycode_push(&keycode); } 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 struct mouse_event mouse_ev; static uint8_t packet_num = 0; uint8_t code; @@ -231,14 +209,15 @@ void ps2mouse_recv(void) third_b = code; state = first_b; d = second_b; - last_mouse_ev.relx = d - ((state << 4) & 0x100); + mouse_ev.relx = d - ((state << 4) & 0x100); d = third_b; - last_mouse_ev.rely = d - ((state << 3) & 0x100); + 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; + mouse_ev.lmb = first_b & 0x01; + mouse_ev.rmb = first_b & 0x02; + mouse_ev.mmb = first_b & 0x04; + mouse_ev.updated = true; + mouse_event_push(&mouse_ev); break; } } @@ -247,13 +226,6 @@ void ps2mouse_recv(void) 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; diff --git a/kernel/include/comus/drivers/ps2.h b/kernel/include/comus/drivers/ps2.h index 6e594e9..7634e5f 100644 --- a/kernel/include/comus/drivers/ps2.h +++ b/kernel/include/comus/drivers/ps2.h @@ -9,18 +9,6 @@ #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 */ @@ -31,19 +19,9 @@ int ps2_init(void); */ 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/input.h b/kernel/include/comus/input.h new file mode 100644 index 0000000..b2b3053 --- /dev/null +++ b/kernel/include/comus/input.h @@ -0,0 +1,36 @@ +/** + * @file input.h + */ + +#ifndef INPUT_H_ +#define INPUT_H_ + +#include +#include +#include +#include + +struct keycode { + char key; + char flags; +}; + +struct mouse_event { + bool updated; + bool lmb; + bool rmb; + bool mmb; + int relx; + int rely; +}; + +void keycode_push(struct keycode *ev); +int keycode_pop(struct keycode *ev); +size_t keycode_len(void); +char keycode_to_char(struct keycode *ev); + +void mouse_event_push(struct mouse_event *ev); +int mouse_event_pop(struct mouse_event *ev); +size_t mouse_event_len(void); + +#endif /* input.h */ diff --git a/kernel/include/comus/keycodes.h b/kernel/include/comus/keycodes.h index 8930937..ebf296a 100644 --- a/kernel/include/comus/keycodes.h +++ b/kernel/include/comus/keycodes.h @@ -9,11 +9,6 @@ #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 diff --git a/kernel/include/comus/limits.h b/kernel/include/comus/limits.h index cadfc93..732873e 100644 --- a/kernel/include/comus/limits.h +++ b/kernel/include/comus/limits.h @@ -25,6 +25,10 @@ /// elf limits #define N_ELF_SEGMENTS 16 +/// input buffer +#define N_KEYCODE 64 +#define N_MOUSEEV 64 + /// length of terminal buffer #define TERM_MAX_WIDTH 1920 #define TERM_MAX_HEIGHT 1080 diff --git a/kernel/input.c b/kernel/input.c new file mode 100644 index 0000000..2073950 --- /dev/null +++ b/kernel/input.c @@ -0,0 +1,93 @@ +#include + +struct mouse_event_buf { + struct mouse_event data[N_MOUSEEV]; + size_t start; + size_t end; + size_t len; +}; + +struct keycode_buf { + struct keycode data[N_KEYCODE]; + size_t start; + size_t end; + size_t len; +}; + +static struct keycode_buf keycode_buffer = { + .start = 0, + .end = 0, + .len = 0, +}; + +static struct mouse_event_buf mouse_event_buffer = { + .start = 0, + .end = 0, + .len = 0, +}; + +void keycode_push(struct keycode *ev) +{ + // save keycode + keycode_buffer.data[keycode_buffer.end] = *ev; + + // update pointers + keycode_buffer.end++; + keycode_buffer.end %= N_KEYCODE; + if (keycode_buffer.len < N_KEYCODE) { + keycode_buffer.len++; + } else { + keycode_buffer.start++; + keycode_buffer.start %= N_KEYCODE; + } +} + +int keycode_pop(struct keycode *ev) +{ + if (keycode_buffer.len < 1) + return 1; + + *ev = keycode_buffer.data[keycode_buffer.start]; + keycode_buffer.len--; + keycode_buffer.start++; + keycode_buffer.start %= N_KEYCODE; + return 0; +} + +size_t keycode_len(void) +{ + return keycode_buffer.len; +} + +void mouse_event_push(struct mouse_event *ev) +{ + // save mouse_event + mouse_event_buffer.data[mouse_event_buffer.end] = *ev; + + // update pointers + mouse_event_buffer.end++; + mouse_event_buffer.end %= N_KEYCODE; + if (mouse_event_buffer.len < N_KEYCODE) { + mouse_event_buffer.len++; + } else { + mouse_event_buffer.start++; + mouse_event_buffer.start %= N_KEYCODE; + } +} + +int mouse_event_pop(struct mouse_event *ev) +{ + if (mouse_event_buffer.len < 1) + return 1; + + *ev = mouse_event_buffer.data[mouse_event_buffer.start]; + mouse_event_buffer.len--; + mouse_event_buffer.start++; + mouse_event_buffer.start %= N_KEYCODE; + return 0; +} + +size_t mouse_event_len(void) +{ + return mouse_event_buffer.len; +} -- cgit v1.2.3-freya From 7145e635cd6012db7f5ab80d0c896502ba467600 Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Tue, 29 Apr 2025 14:09:11 -0400 Subject: fs header changes --- kernel/fs/fs.c | 2 +- kernel/include/comus/fs.h | 147 +++++++++++------------------------------- kernel/include/comus/limits.h | 1 + 3 files changed, 38 insertions(+), 112 deletions(-) (limited to 'kernel') diff --git a/kernel/fs/fs.c b/kernel/fs/fs.c index b46450d..ea47e38 100644 --- a/kernel/fs/fs.c +++ b/kernel/fs/fs.c @@ -68,7 +68,7 @@ struct file_system *fs_get_root_file_system(void) for (int i = 0; i < N_DISKS; i++) { struct file_system *fs = &fs_loaded_file_systems[i]; - if (fs->present) + if (fs->fs_present) return fs; } diff --git a/kernel/include/comus/fs.h b/kernel/include/comus/fs.h index 872c298..c48e3e1 100644 --- a/kernel/include/comus/fs.h +++ b/kernel/include/comus/fs.h @@ -9,7 +9,6 @@ #ifndef FS_H_ #define FS_H_ -#include #include #include #include @@ -65,104 +64,55 @@ enum file_type { F_REG = 0, // directory F_DIR = 1, - // symbolic link - F_SYM = 2, }; -/// TODO: file name queue or storage area??? -/// hash map?!? (performance !!! :) ) +struct dirent { + int d_id; + unsigned long d_offset; + unsigned short d_namelen; + char d_name[N_FILE_NAME]; +}; + +struct stat { + /// file id + int s_id; + /// file type + enum file_type s_type; + /// file length + unsigned long s_length; +}; struct file { - /// name of the file - char name[N_FILE_NAME]; - /// parent directory of the file - struct file_s *parent; - /// type of the file - enum file_type type; - /// the filesystem of this file - struct file_system *fsys; + /// file id + int f_id; + /// read from the file + int (*read)(struct file *, char *, size_t); + /// write into the file + int (*write)(struct file *, char *, size_t); + /// seeks the file + int (*seek)(struct file *, long); + /// get directory entry at index + int (*ents)(struct file *, struct dirent *, size_t); }; -/// vtable for filesystem functions -/// NOTE: feel free to change this as needed -/// its just stuff that i thought may be good struct file_system { /// set to 1 in fs array to state that fs is defined /// system use only - int present; + int fs_present; /// index into the loaded filesystems array /// system use only - int id; + int fs_id; + /// mount point of this filesystem + /// system use only + char fs_mount[N_FILE_NAME]; /// the disk this filesystem is hooked up to struct disk disk; - /// get root file in file file_system - /// @param fs - the file system - /// @returns the root file or NULL on failure - struct file *(*fs_get_root_file)(struct file_system *fs); - /// rename a file - /// @param fs - the file system - /// @param file - the file to rename - /// @param name - the new file name - /// @returns 0 on success, or an negative fs error code on failure - int (*fs_rename_file)(struct file_system *fs, struct file *file, - char *name); - /// get length of file - /// @param fs - the file system - /// @param file - the file to get the length of - /// @param length - the pointer to save the length to - /// @return 0 on success, or an negative fs error code on failure - int (*fs_get_file_length)(struct file_system *fs, struct file *file, - uint64_t *length); - /// get created date of file - /// @param fs - the file system - /// @param file - the file to get the date created - /// @param created - the pointer to save the created date to - /// @param modified - the pointer to save the modified date to - /// @param accessed - the pointer to save the accessed date to - /// @return 0 on success, or an negative fs error code on failure - int (*fs_get_file_dates)(struct file_system *fs, struct file *file, - uint64_t *created, uint64_t *modified, - uint64_t *accessed); - /// delete a file in the file system - /// @param fs - the file system - /// @param file - the file to delete - /// @returns 0 on success, or an negative fs error code on failure - int (*fs_delete_file)(struct file_system *fs, struct file *file); - /// create a file with a given name and type - /// @param fs - the file system - /// @param res - the new file structure to save the new file into - /// @param parent - the parent (directory) of the file to create - /// @param type - the type of file to create - /// @returns 0 on success, or an negative fs error code on failure - int (*fs_new_file)(struct file_system *fs, struct file *res, - struct file *parent, enum file_type type); - /// get files in a directory - /// @param fs - the file system - /// @param dir - the directory to search into - /// @param start - the directory entry to start at - /// @param len - the max number of entrys to save starting at `start` - /// @param res - the list of structures to save into - /// @returns number of entries read, or an negative fs error code on failure - int (*fs_get_dir_ents)(struct file_system *fs, struct file *dir, - size_t start, size_t len, struct file res[]); - /// read from a file - /// @param fs - the file system - /// @param file - the file to read from - /// @param offset - the offset of the file to read into - /// @param length - the length of the file to read starting at `offset` - /// @param buffer - the buffer to save the data into - /// @returns number of bytes read, or an negative fs error code on failure - int (*fs_read_file)(struct file_system *fs, struct file *file, - size_t offset, size_t length, uint8_t *buffer); - /// write into a file - /// @param fs - the file system - /// @param file - the file to write to - /// @param offset - the offset of the file to write into - /// @param length - the length of the data to write - /// @param buffer - the buffer the data to write is stored in - /// @returns number of bytes written, or an negative fs error code on failure - int (*fs_write_file)(struct file_system *fs, struct file *file, - size_t offset, size_t length, uint8_t *buffer); + /// opens a file + int (*open)(const char *, struct file **); + /// closes a file + void (*close)(struct file *); + /// stats a file + int (*stat)(const char *, struct stat *); }; // list of all disks on the system @@ -190,29 +140,4 @@ struct disk *fs_get_root_disk(void); */ struct file_system *fs_get_root_file_system(void); -/** - * Find a file in the given file system, traversing the path - * Always use this function to find files globally - * - * @param fs - the file system to search - * @param name - the absolute path of the file to look for - * @param res - where to store the file structure - * @returns 0 on success, or an negative fs error code on failure - */ -int fs_find_file_abs(struct file_system *fs, char *abs_path, struct file *res); - -/** - * Find a file in the given file system, traversing the path, relative to - * another file. - * Always use this function to find files globally - * - * @param rel - the relative file to search from - * @param name - the absolute path of the file to look for - * @param res - where to store the file structure - * @returns 0 on success, or an negative fs error code on failure - */ -int fs_find_file_rel(struct file *rel, char *rel_path, struct file *res); - -// NOTE: fell free to add more functions if needed :) - #endif /* fs.h */ diff --git a/kernel/include/comus/limits.h b/kernel/include/comus/limits.h index 732873e..4cb348d 100644 --- a/kernel/include/comus/limits.h +++ b/kernel/include/comus/limits.h @@ -20,6 +20,7 @@ /// max fs limits #define N_FILE_NAME 256 +#define N_DIR_ENTS 256 #define N_DISKS 8 /// elf limits -- cgit v1.2.3-freya