diff options
53 files changed, 1771 insertions, 638 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d909e45..9e9c29f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -10,7 +10,7 @@ jobs: - name: Checkout uses: actions/checkout@v2 - name: Install - run: sudo apt-get update && sudo apt-get install -y build-essential bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo libcloog-isl-dev libisl-0.18-dev ccache curl nasm grub-common qemu qemu-kvm mtools ctags + run: sudo apt-get update && sudo apt-get install -y build-essential bison flex libgmp3-dev libmpc-dev libmpfr-dev texinfo ccache curl nasm grub-common qemu qemu-kvm mtools ctags - name: Get cross compiler id: cache-cross uses: actions/cache@v1 @@ -1,12 +1,14 @@ # MIT License, Copyright (c) 2020 Marvin Borner CFLAGS_OPTIMIZATION = -finline -finline-functions -Ofast -CFLAGS_WARNINGS = -Wall -Wextra -Werror -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wformat=2 -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wswitch-default -Wswitch-enum -Wlogical-op -Wunreachable-code -Wundef -Wold-style-definition -pedantic-errors +CFLAGS_WARNINGS = -Wall -Wextra -Werror -Wshadow -Wpointer-arith -Wwrite-strings -Wredundant-decls -Wnested-externs -Wformat=2 -Wmissing-declarations -Wstrict-prototypes -Wmissing-prototypes -Wcast-qual -Wswitch-default -Wswitch-enum -Wlogical-op -Wunreachable-code -Wundef -Wold-style-definition -Wvla -pedantic-errors CFLAGS_DEFAULT = $(CFLAGS_WARNINGS) $(CFLAGS_OPTIMIZATION) -std=c99 -m32 -nostdlib -nostdinc -fno-builtin -fno-profile-generate -fno-omit-frame-pointer -fno-common -fno-asynchronous-unwind-tables -mno-red-zone -mno-80387 -mno-mmx -mno-sse -mno-sse2 # Everything after -fno-builtin is optional all: compile -debug: CFLAGS_DEFAULT += -Wno-error -ggdb3 -s -fstack-protector-all -fsanitize=undefined +# TODO: Fix stack protector in userspace +# TODO: Fix ubsan in userspace (probably due to kernel size) +debug: CFLAGS_DEFAULT += -Wno-error -ggdb3 -s #-fsanitize=undefined # -fstack-protector-all debug: compile export @@ -84,14 +84,14 @@ This project is somewhat of a coding playground for me. It doesn't have any usef Melvix is released under the MIT License and uses parts of the following 3rd party projects: -Inspiration/usage: +Inspiration/usage (documented in the respective files): - [OSDev wiki](https://wiki.osdev.org) - Very helpful! - [James Molloy's tutorials](http://jamesmolloy.co.uk/tutorial_html/) - [virtix - tasking inspiration](https://github.com/16Bitt/virtix/) - [MIT License](https://github.com/16Bitt/virtix/blob/85a3c58f3d3b8932354e85a996a79c377139c201/LICENSE) - [studix - FS inspiration](https://github.com/orodley/studix) - [MIT License](https://github.com/orodley/studix/blob/d1b1d006010120551df58ff3faaf97484dfa9806/LICENSE) +- [skiftOS - Memory management inspiration](https://github.com/skiftOS/skift) - [MIT License](https://github.com/skiftOS/skift/blob/ea0e1cf0d7b07302370fc1519be2e072a4cad70c/license.md) - [ToAruOS - PCI and network driver inspiration](https://github.com/klange/toaruos) - [NCSA License](https://github.com/klange/toaruos/blob/351d5d38f22b570459931475d36468bf4e37f45a/LICENSE) -- [SHMALL - Heap allocator inspiration](https://github.com/CCareaga/heap_allocator) - [MIT License](https://github.com/CCareaga/heap_allocator/blob/fc423c6113df598ac8d10bc1f2954d51248e6443/LICENSE) Resources: diff --git a/apps/Makefile b/apps/Makefile index 8426b9c..2c6c643 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,6 +1,6 @@ # MIT License, Copyright (c) 2020 Marvin Borner -COBJS = init.o wm.o test.o window.o #mandelbrot.o window.o exec.o files.o test.o cc.o browser.o server.o +COBJS = init.o idle.o wm.o test.o window.o #mandelbrot.o window.o exec.o files.o test.o cc.o browser.o server.o CC = ccache ../cross/opt/bin/i686-elf-gcc LD = ccache ../cross/opt/bin/i686-elf-ld OC = ccache ../cross/opt/bin/i686-elf-objcopy diff --git a/apps/idle.c b/apps/idle.c new file mode 100644 index 0000000..3f10c3e --- /dev/null +++ b/apps/idle.c @@ -0,0 +1,7 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +int main(void) +{ + while (1) + ; +} diff --git a/apps/init.c b/apps/init.c index 87f0d82..c59e3bf 100644 --- a/apps/init.c +++ b/apps/init.c @@ -6,12 +6,14 @@ #include <str.h> #include <sys.h> +#include <cpu.h> + int main(int argc, char **argv) { - (void)argc; - log("%s loaded\n", argv[0]); + UNUSED(argc); + UNUSED(argv); - int wm = exec("/bin/wm", "wm", argv[1], NULL); + int wm = exec("/bin/wm", "wm", NULL); int test = exec("/bin/window", "test", NULL); return wm + test; diff --git a/apps/test.c b/apps/test.c index 80f24ad..d64e224 100644 --- a/apps/test.c +++ b/apps/test.c @@ -82,11 +82,7 @@ int main(void) else log("All tests passed\n"); - // Try emulator shutdown - outw(0xB004, 0x2000); - outw(0x604, 0x2000); - outw(0x4004, 0x3400); + boot(SYS_BOOT_SHUTDOWN); - loop(); return 0; } diff --git a/apps/window.c b/apps/window.c index ac29ba1..90a414c 100644 --- a/apps/window.c +++ b/apps/window.c @@ -8,6 +8,9 @@ int main(void) { struct gui_window win = { 0 }; assert(gui_new_window(&win) > 0); + while (1) + ; +#if 0 gfx_fill(win.ctx, COLOR_GREEN); // Professional testing for (int i = 0; i < 12; i++) { @@ -16,5 +19,6 @@ int main(void) } assert(gui_redraw_window(win.id) > 0); log("%d\n", win.ctx->size.x); +#endif return 0; } @@ -5,8 +5,10 @@ #include <gfx.h> #include <gui.h> #include <input.h> +#include <ioctl.h> #include <keymap.h> #include <list.h> +#include <msg.h> #include <random.h> #include <vesa.h> @@ -307,46 +309,34 @@ static void handle_event_mouse(struct event_mouse *event) window_redraw(cursor); } -static void handle_message_new_window(struct message *msg) +static void handle_message_new_window(struct message_new_window *msg) { - if (!msg->data) { - msg_send(msg->src, GUI_NEW_WINDOW | MSG_FAILURE, NULL); - return; - } - struct gui_window *buf = msg->data; - struct window *win = window_new((struct client){ .pid = msg->src }, "idk", vec2(500, 600), - vec2(600, 400), 0); - buf->id = win->id; - buf->ctx = &win->ctx; - buf->pos = &win->pos; - msg_send(msg->src, GUI_NEW_WINDOW | MSG_SUCCESS, NULL); + struct window *win = window_new((struct client){ .pid = msg->header.src }, "idk", + vec2(500, 600), vec2(600, 400), 0); + msg->ctx = win->ctx; + msg->id = win->id; + msg_send(msg->header.src, GUI_NEW_WINDOW | MSG_SUCCESS, msg, sizeof(*msg)); /* window_redraw(win); */ } -static void handle_message_redraw_window(struct message *msg) +static void handle_message_redraw_window(struct message_redraw_window *msg) { - if (!msg->data) { - msg_send(msg->src, GUI_REDRAW_WINDOW | MSG_FAILURE, NULL); - return; - } - u32 id = *(u32 *)msg->data; + u32 id = msg->id; struct window *win = window_find(id); if (!win) { - msg_send(msg->src, GUI_REDRAW_WINDOW | MSG_FAILURE, NULL); + msg_send(msg->header.src, GUI_REDRAW_WINDOW | MSG_FAILURE, NULL, + sizeof(msg->header)); return; } - msg_send(msg->src, GUI_REDRAW_WINDOW | MSG_SUCCESS, NULL); + msg_send(msg->header.src, GUI_REDRAW_WINDOW | MSG_SUCCESS, NULL, sizeof(msg->header)); window_redraw(win); } -static void handle_message(struct message *msg) +static void handle_message(void *msg) { - if (msg->magic != MSG_MAGIC) { - log("Message magic doesn't match!\n"); - return; - } + struct message_header *header = msg; - switch (msg->type) { + switch (header->type) { case GUI_NEW_WINDOW: handle_message_new_window(msg); break; @@ -354,18 +344,19 @@ static void handle_message(struct message *msg) handle_message_redraw_window(msg); break; default: - log("Message type %d not implemented!\n", msg->type); - msg_send(msg->src, MSG_FAILURE, NULL); + log("Message type %d not implemented!\n", header->type); + msg_send(header->src, MSG_FAILURE, NULL, sizeof(*header)); } } int main(int argc, char **argv) { - (void)argc; - screen = *(struct vbe *)argv[1]; + UNUSED(argc); + UNUSED(argv); + assert(ioctl("/dev/fb", IO_FB_GET, &screen) == 0); + log("WM loaded: %dx%d\n", screen.width, screen.height); wm_client = (struct client){ .pid = getpid() }; bypp = (screen.bpp >> 3); - log("WM loaded: %dx%d\n", screen.width, screen.height); windows = list_new(); keymap = keymap_parse("/res/keymaps/en.keymap"); @@ -387,32 +378,34 @@ int main(int argc, char **argv) gfx_load_wallpaper(&cursor->ctx, "/res/cursor.png"); window_redraw(wallpaper); - struct message msg = { 0 }; + u8 msg[1024] = { 0 }; struct event_keyboard event_keyboard = { 0 }; struct event_mouse event_mouse = { 0 }; - const char *listeners[] = { "/dev/kbd", "/dev/mouse", "/proc/self/msg" }; + const char *listeners[] = { "/dev/kbd", "/dev/mouse", "/proc/self/msg", NULL }; while (1) { int poll_ret = 0; if ((poll_ret = poll(listeners)) >= 0) { if (poll_ret == 0) { if (read(listeners[poll_ret], &event_keyboard, 0, - sizeof(event_keyboard)) > 0) + sizeof(event_keyboard)) > 0) { handle_event_keyboard(&event_keyboard); - continue; + continue; + } } else if (poll_ret == 1) { if (read(listeners[poll_ret], &event_mouse, 0, - sizeof(event_mouse)) > 0) + sizeof(event_mouse)) > 0) { handle_event_mouse(&event_mouse); - continue; + continue; + } } else if (poll_ret == 2) { - if (read(listeners[poll_ret], &msg, 0, sizeof(msg)) > 0) - handle_message(&msg); - continue; + if (msg_receive(msg, 1024) > 0) { + handle_message(msg); + continue; + } } - } else { - err(1, "POLL ERROR!\n"); } - }; + panic("Poll/read error!\n"); + } // TODO: Execute? free(keymap); diff --git a/boot/entry.asm b/boot/entry.asm index 1f421ea..92a8406 100644 --- a/boot/entry.asm +++ b/boot/entry.asm @@ -70,6 +70,12 @@ %define VESA_FRAMEBUFFER_OFFSET 0x2a ; Framebuffer offset in mode info %define VESA_LFB_FLAG 0x4000 ; Enable LFB flag +; MMAP constants +%define MMAP_START 0x500 ; Starts at 0x500, ends at 0x600 +%define MMAP_SIZE 0x18 ; Struct size +%define MMAP_SIG 0x0534d4150 ; Signature ("SMAP") +%define MMAP_BIOS_MAGIC 0xe820 ; BIOS int 15h code to get address map + ; A20 constants %define A20_GATE 0x92 ; Fast A20 gate %define A20_ENABLED 0b10 ; Bit 1 defines whether A20 is enabled @@ -88,7 +94,7 @@ %define GDT_DATA_OFFSET 0x10 ; Offset to GDT data segment ; Kernel constants -%define STACK_POINTER 0x00900000 ; The initial stack pointer in kernel mode +%define STACK_POINTER 0x00500000 ; The initial stack pointer in kernel mode %define KERNEL_POSITION 0x00040000 ; Loaded kernel position in protected mode (* 0x10) ; ENOUGH, let's go! @@ -234,6 +240,54 @@ video_map: .bpp dw VIDEO_BPP .framebuffer dd 0 +; Tries to load a memory map using BIOS INT 15h and e820h +memory_map: + xor ebx, ebx ; Must be 0 by spec + xor bp, bp + mov edx, MMAP_SIG ; "SMAP" in hex + mov eax, MMAP_BIOS_MAGIC ; Specify MMAP information + mov [es:di + 20], dword 1 ; Force a valid ACPI entry + mov ecx, MMAP_SIZE ; Request struct size + int MISC_INT ; BIOS interrupt + jc .fail ; Carry means "unsupported function" + mov edx, MMAP_SIG ; Mov for verification + cmp eax, edx ; Verification: Must be "SMAP" + jne .fail ; Result wasn't correct signature + test ebx, ebx ; Is size >1 + je .fail ; Nope, worthless :( + jmp .loop +.next: + mov eax, MMAP_BIOS_MAGIC ; Re-move because 0x15 clears or sth + mov [es:di + 20], dword 1 ; Force a valid ACPI entry + mov ecx, MMAP_SIZE ; Request struct size + int MISC_INT ; BIOS interrupt + jc .done ; Carry means "end of list already reached" + mov edx, MMAP_SIG ; Repair register (safety first!) +.loop: + jcxz .skip ; Skip 0-length entries + cmp cl, 20 ; Is the response correct ACPI spec (24 byte)? + jbe .notext ; Nope? Jump! + test byte [es:di + 20], 1 ; Is the "ignore this data" bit clear? + je .skip ; Yep? Skip! +.notext: + mov ecx, [es:di + 8] ; Get lower 32 bits of region + or ecx, [es:di + 12] ; "Or" with upper 32 bits to test for zero + jz .skip ; It's zero, skip! + inc bp + add di, MMAP_SIZE ; Else, next! +.skip: + test ebx, ebx ; If ebx is 0, list is complete + jne .next ; Else, next! +.done: + mov [mmap_cnt], bp + clc ; Clear carry + ret ; Finished! +.fail: + stc ; Set "unsupported function" + ret ; Finished! + +mmap_cnt: dd 0 + ; Variables disk_error_msg db "Disk error!", NEWLINE, RETURN, NULL lba_error_msg db "LBA error!", NEWLINE, RETURN, NULL @@ -329,6 +383,14 @@ stage_two: mov [dest], bx call inode_load + ; Load mmap + xor eax, eax + mov es, eax + mov edi, MMAP_START + push edi + call memory_map + push edi + ; Set video mode call video_map @@ -373,6 +435,13 @@ protected_mode_enter: bits 32 ; Woah, so big! protected_mode: + mov ecx, [mmap_cnt] ; Get mmap entry count + mov [mem_info + 8], ecx ; Count of maps + pop ecx ; End of memory map + mov [mem_info + 4], ecx ; Ending boundary of struct + pop ecx ; Start of memory map + mov [mem_info], ecx ; Starting boundary of struct + mov ax, GDT_DATA_OFFSET ; Data segment offset of GDT mov ds, ax mov es, ax @@ -388,10 +457,20 @@ protected_mode: mov eax, vid_info ; Pass VBE struct to kernel push eax ; Push as second kernel parameter + mov eax, mem_info ; Pass meminfo to kernel + push eax ; Push as first kernel parameter + mov edx, KERNEL_POSITION lea eax, [edx] call eax +; Memory map +align 16 +mem_info: + dd 0 ; Start address + dd 0 ; End address + dd 0 ; Count + ; GDT align 32 gdt: ; GDTs start @@ -466,7 +545,7 @@ tss_entry: dd 0 ; gs dd 0 ; ldt dw 0 ; trap - dw 0 ; iomap base + dw -1 ; iomap base tss_entry_end: times 1024 - ($ - $$) db 0 diff --git a/boot/load.c b/boot/load.c index b243629..34c6af8 100644 --- a/boot/load.c +++ b/boot/load.c @@ -133,16 +133,16 @@ int find_inode(const char *name, int dir_inode); void serial_install(void); void serial_print(const char *data); -int main(void *data) +int main(void *data1, void *data2) { serial_install(); serial_print("Loaded bootloader!\n"); heap = 0xf00000; - void (*entry)(void *); + void (*entry)(void *, void *); *(void **)(&entry) = read_inode(get_inode(find_inode("kernel.bin", 2))); if (entry) { serial_print("Loaded kernel!\n"); - entry(data); + entry(data1, data2); } else { serial_print("Couldn't find kernel!\n"); } diff --git a/kernel/Makefile b/kernel/Makefile index 9cf18e5..e9ade73 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -8,8 +8,10 @@ COBJS = main.o \ drivers/mouse.o \ drivers/pci.o \ drivers/ide.o \ + drivers/fb.o \ drivers/timer.o \ drivers/rtl8139.o \ + features/mm.o \ features/fs.o \ features/load.o \ features/proc.o \ @@ -34,5 +36,5 @@ all: compile compile: $(COBJS) @mkdir -p ../build/ - @$(LD) -N -ekernel_main -Ttext 0x00050000 -o ../build/kernel.elf -L../build/ $+ -lk + @$(LD) -N -z undefs -ekernel_main -Ttext 0x00050000 -o ../build/kernel.elf -L../build/ $+ -lk @$(LD) -N -Tlink.ld -o ../build/kernel.bin -L../build/ $+ -lk diff --git a/kernel/drivers/fb.c b/kernel/drivers/fb.c new file mode 100644 index 0000000..8e73f5b --- /dev/null +++ b/kernel/drivers/fb.c @@ -0,0 +1,64 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <assert.h> +#include <def.h> +#include <fb.h> +#include <fs.h> +#include <ioctl.h> +#include <mem.h> +#include <mm.h> +#include <str.h> +#include <sys.h> + +struct vbe_basic { + u8 stuff1[16]; + u16 pitch; + u16 width; + u16 height; + u8 stuff2[18]; + u8 *fb; + u8 stuff3[212]; +}; + +static u32 dev_id = 0; +static struct vid_info *info = NULL; + +static s32 fb_ioctl(u32 request, void *arg1, void *arg2, void *arg3, struct device *dev) +{ + UNUSED(arg2); + UNUSED(arg3); + UNUSED(dev); + + switch (request) { + case IO_FB_GET: { + if (!info) + return -1; + struct vbe_basic *vbe = (struct vbe_basic *)info->vbe; + memcpy(arg1, info->vbe, sizeof(struct vbe_basic)); + u32 size = vbe->height * vbe->pitch; + memory_map_identity(proc_current()->page_dir, + memory_range_around((u32)vbe->fb, size), MEMORY_USER); + return 0; + } + default: + return -1; + } +} + +static u8 fb_ready(void) +{ + return 1; +} + +void fb_install(struct vid_info *boot) +{ + info = boot; + + struct device *dev = zalloc(sizeof(*dev)); + dev->name = strdup("fb"); + dev->type = DEV_CHAR; + dev->ioctl = fb_ioctl; + dev->ready = fb_ready; + device_add(dev); + dev_id = dev->id; +} diff --git a/kernel/drivers/interrupts.c b/kernel/drivers/interrupts.c index fa455d7..2e1444f 100644 --- a/kernel/drivers/interrupts.c +++ b/kernel/drivers/interrupts.c @@ -5,6 +5,7 @@ #include <def.h> #include <interrupts.h> #include <mem.h> +#include <mm.h> #include <print.h> #include <proc.h> #include <serial.h> @@ -169,26 +170,30 @@ void isr_uninstall_handler(int isr) isr_routines[isr] = 0; } -void isr_handler(struct regs *r); -void isr_handler(struct regs *r) +void isr_panic(struct regs *r) { - if (r->int_no <= 32) { - struct proc *proc = proc_current(); - printf("%s Exception at 0x%x, exiting!\n", isr_exceptions[r->int_no], r->eip); - if (proc) { - printf("\t-> Exception occurred in %s at addr 0x%x\n", proc->name, - r->eip - proc->entry); - proc_exit(proc, 1); - } else { - __asm__ volatile("cli\nhlt"); - } - proc_yield(r); + printf("%s Exception (%x) at 0x%x (ring %d), exiting!\n", isr_exceptions[r->int_no], + r->err_code, r->eip, r->cs & 3); + struct proc *proc = proc_current(); + if (proc) { + printf("\t-> Exception occurred in %s at addr 0x%x\n", proc->name, + r->eip - proc->entry); + proc_exit(proc, 1); } else { - // Execute fault handler if exists - void (*handler)(struct regs * r) = isr_routines[r->int_no]; - if (handler) - handler(r); + __asm__ volatile("cli\nhlt"); } + proc_yield(r); +} + +void isr_handler(struct regs *r); +void isr_handler(struct regs *r) +{ + // Execute fault handler if exists + void (*handler)(struct regs * r) = isr_routines[r->int_no]; + if (handler) + handler(r); + else + isr_panic(r); } static void isr_install(void) @@ -228,6 +233,13 @@ static void isr_install(void) idt_set_gate(29, (u32)isr29, 0x08, 0x8E); idt_set_gate(30, (u32)isr30, 0x08, 0x8E); idt_set_gate(31, (u32)isr31, 0x08, 0x8E); + + // Set default routines + for (u32 i = 0; i < 256; i++) + isr_routines[i] = isr_panic; + + // Set page fault handler + isr_install_handler(14, page_fault_handler); } /** diff --git a/kernel/drivers/keyboard.c b/kernel/drivers/keyboard.c index 3ae3c0e..dbee8e1 100644 --- a/kernel/drivers/keyboard.c +++ b/kernel/drivers/keyboard.c @@ -66,10 +66,10 @@ static s32 keyboard_read(void *buf, u32 offset, u32 count, struct device *dev) if (stack_empty(queue)) return -1; - struct event *e = stack_pop(queue); - memcpy(buf, (u8 *)e + offset, count); + struct event_keyboard *e = stack_pop(queue); + memcpy(buf, (u8 *)e + offset, MIN(count, sizeof(*e))); free(e); - return count; + return MIN(count, sizeof(*e)); } static u8 keyboard_ready(void) diff --git a/kernel/drivers/mouse.c b/kernel/drivers/mouse.c index 40094d1..5c481da 100644 --- a/kernel/drivers/mouse.c +++ b/kernel/drivers/mouse.c @@ -94,10 +94,10 @@ static s32 mouse_read(void *buf, u32 offset, u32 count, struct device *dev) if (stack_empty(queue)) return -1; - struct event *e = stack_pop(queue); - memcpy(buf, (u8 *)e + offset, count); + struct event_mouse *e = stack_pop(queue); + memcpy(buf, (u8 *)e + offset, MIN(count, sizeof(*e))); free(e); - return count; + return MIN(count, sizeof(*e)); } void mouse_install(void) diff --git a/kernel/features/fs.c b/kernel/features/fs.c index 687d7ad..c8ad317 100644 --- a/kernel/features/fs.c +++ b/kernel/features/fs.c @@ -62,13 +62,15 @@ static struct mount_info *vfs_recursive_find(char *path) static struct mount_info *vfs_find_mount_info(const char *path) { - assert(path[0] == '/'); + if (path[0] != '/') + return NULL; return vfs_recursive_find(strdup(path)); } struct device *vfs_find_dev(const char *path) { - assert(path[0] == '/'); + if (path[0] != '/') + return NULL; struct mount_info *m = vfs_find_mount_info(path); if (m->dev->vfs->type == VFS_DEVFS) // TODO: ? return device_get_by_name(path + strlen(m->path) + 1); @@ -120,7 +122,7 @@ s32 vfs_mount(struct device *dev, const char *path) s32 vfs_read(const char *path, void *buf, u32 offset, u32 count) { - /* printf("%s READ: %s\n", proc_current()->name, path); */ + /* printf("%s READ: %s\n", proc_current() ? proc_current()->name : "Unknown", path); */ if (!count) return 0; @@ -131,7 +133,8 @@ s32 vfs_read(const char *path, void *buf, u32 offset, u32 count) path++; struct mount_info *m = vfs_find_mount_info(path); - assert(m && m->dev && m->dev->vfs && m->dev->vfs->read && m->dev->vfs->perm); + if (!(m && m->dev && m->dev->vfs && m->dev->vfs->read && m->dev->vfs->perm)) + return -1; u32 len = strlen(m->path); if (len > 1) @@ -145,7 +148,7 @@ s32 vfs_read(const char *path, void *buf, u32 offset, u32 count) s32 vfs_write(const char *path, void *buf, u32 offset, u32 count) { - /* printf("%s WRITE: %s\n", proc_current()->name, path); */ + /* printf("%s WRITE: %s\n", proc_current() ? proc_current()->name : "Unknown", path); */ if (!count) return 0; @@ -156,7 +159,8 @@ s32 vfs_write(const char *path, void *buf, u32 offset, u32 count) path++; struct mount_info *m = vfs_find_mount_info(path); - assert(m && m->dev && m->dev->vfs && m->dev->vfs->write && m->dev->vfs->perm); + if (!(m && m->dev && m->dev->vfs && m->dev->vfs->write && m->dev->vfs->perm)) + return -1; u32 len = strlen(m->path); if (len > 1) @@ -168,6 +172,25 @@ s32 vfs_write(const char *path, void *buf, u32 offset, u32 count) return m->dev->vfs->write(path, buf, offset, count, m->dev); } +s32 vfs_ioctl(const char *path, u32 request, void *arg1, void *arg2, void *arg3) +{ + while (*path == ' ') + path++; + + struct mount_info *m = vfs_find_mount_info(path); + if (!(m && m->dev && m->dev->vfs && m->dev->vfs->ioctl && m->dev->vfs->perm)) + return -1; + + u32 len = strlen(m->path); + if (len > 1) + path += len; + + if (!m->dev->vfs->perm(path, VFS_WRITE, m->dev) && !proc_super()) + return -1; + + return m->dev->vfs->ioctl(path, request, arg1, arg2, arg3, m->dev); +} + s32 vfs_stat(const char *path, struct stat *buf) { while (*path == ' ') @@ -177,12 +200,16 @@ s32 vfs_stat(const char *path, struct stat *buf) return -1; struct mount_info *m = vfs_find_mount_info(path); - assert(m && m->dev && m->dev->vfs && m->dev->vfs->stat); + if (!(m && m->dev && m->dev->vfs && m->dev->vfs->stat && m->dev->vfs->perm)) + return -1; u32 len = strlen(m->path); if (len > 1) path += len; + if (!m->dev->vfs->perm(path, VFS_WRITE, m->dev) && !proc_super()) + return -1; + return m->dev->vfs->stat(path, buf, m->dev); } @@ -192,7 +219,8 @@ s32 vfs_wait(const char *path, u32 func_ptr) path++; struct mount_info *m = vfs_find_mount_info(path); - assert(m && m->dev && m->dev->vfs); + if (!(m && m->dev && m->dev->vfs)) + return -1; // Default wait if (!m->dev->vfs->wait) { @@ -280,10 +308,19 @@ static s32 devfs_read(const char *path, void *buf, u32 offset, u32 count, struct { struct device *target = device_get_by_name(path + 1); if (!target || !target->read) - return 0; + return -1; return target->read(buf, offset, count, dev); } +static s32 devfs_ioctl(const char *path, u32 request, void *arg1, void *arg2, void *arg3, + struct device *dev) +{ + struct device *target = device_get_by_name(path + 1); + if (!target || !target->ioctl) + return -1; + return target->ioctl(request, arg1, arg2, arg3, dev); +} + static u8 devfs_perm(const char *path, enum vfs_perm perm, struct device *dev) { (void)path; @@ -309,6 +346,7 @@ void device_install(void) struct vfs *vfs = zalloc(sizeof(*vfs)); vfs->type = VFS_DEVFS; vfs->read = devfs_read; + vfs->ioctl = devfs_ioctl; vfs->perm = devfs_perm; vfs->ready = devfs_ready; struct device *dev = zalloc(sizeof(*dev)); diff --git a/kernel/features/load.c b/kernel/features/load.c index 8a4aae3..9e6db79 100644 --- a/kernel/features/load.c +++ b/kernel/features/load.c @@ -3,28 +3,36 @@ #include <fs.h> #include <load.h> #include <mem.h> +#include <mm.h> #include <str.h> -void proc_load(struct proc *proc, void *data) -{ - u32 stack = (u32)malloc(0x2000) + 0x1000; - - proc->regs.ebp = (u32)stack; - proc->regs.useresp = (u32)stack; - proc->regs.eip = (u32)data; - proc->entry = (u32)data; -} +#define PROC_STACK_SIZE 0x4000 int bin_load(const char *path, struct proc *proc) { struct stat s = { 0 }; vfs_stat(path, &s); - char *data = malloc(s.size); - if (!vfs_read(path, data, 0, s.size)) - return 1; strcpy(proc->name, path); - proc_load(proc, data); + struct page_dir *prev; + memory_backup_dir(&prev); + memory_switch_dir(proc->page_dir); + + u32 size = PAGE_ALIGN_UP(s.size); + u32 data = (u32)memory_alloc(proc->page_dir, size, MEMORY_USER | MEMORY_CLEAR); + + if (!vfs_read(proc->name, (void *)data, 0, s.size)) { + memory_switch_dir(prev); + return 1; + } + + u32 stack = (u32)memory_alloc(proc->page_dir, PROC_STACK_SIZE, MEMORY_USER | MEMORY_CLEAR); + proc->regs.ebp = stack; + proc->regs.useresp = stack; + proc->regs.eip = data; + proc->entry = data; + + memory_switch_dir(prev); return 0; } diff --git a/kernel/features/mm.c b/kernel/features/mm.c new file mode 100644 index 0000000..9eca438 --- /dev/null +++ b/kernel/features/mm.c @@ -0,0 +1,498 @@ +// Hugely inspired by the implementation in skiftOS: MIT License, Copyright (c) 2020 N. Van Bossuyt +// MIT License, Copyright (c) 2021 Marvin Borner + +#include <assert.h> +#include <cpu.h> +#include <def.h> +#include <mem.h> +#include <mm.h> +#include <print.h> + +static struct page_dir kernel_dir ALIGNED(PAGE_SIZE) = { 0 }; +static struct page_table kernel_tables[256] ALIGNED(PAGE_SIZE) = { 0 }; + +/** + * Lowlevel paging + */ + +/*static void paging_disable(void) +{ + cr0_set(cr0_get() | 0x7fffffff); +}*/ + +static void paging_enable(void) +{ + cr0_set(cr0_get() | 0x80000000); +} + +static void paging_switch_dir(u32 dir) +{ + cr3_set(dir); +} + +extern void paging_invalidate_tlb(void); + +void page_fault_handler(struct regs *r) +{ + // Check error code + const char *type = (r->err_code & 1) ? "present" : "non-present"; + const char *operation = (r->err_code & 2) ? "write" : "read"; + const char *super = (r->err_code & 4) ? "User" : "Super"; + + // Check cr2 address + u32 vaddr; + __asm__ volatile("movl %%cr2, %%eax" : "=a"(vaddr)); + struct proc *proc = proc_current(); + struct page_dir *dir = NULL; + if (proc && proc->page_dir) { + dir = proc->page_dir; + printf("Stack is at %x, entry at %x\n", virtual_to_physical(dir, proc->regs.ebp), + virtual_to_physical(dir, proc->entry)); + } else { + dir = &kernel_dir; + } + u32 paddr = virtual_to_physical(dir, vaddr); + + // Print! + printf("%s process tried to %s a %s page at [vaddr=%x; paddr=%x]\n", super, operation, type, + vaddr, paddr); + + isr_panic(r); +} + +/** + * Physical + */ + +static u32 memory_used = 0; +static u32 memory_total = 0; +static u32 best_bet = 0; +static u8 memory[PAGE_COUNT * PAGE_COUNT / 8] = { 0 }; + +static u8 physical_page_is_used(u32 addr) +{ + u32 page = addr / PAGE_SIZE; + return memory[page / 8] & (1 << (page % 8)); +} + +static void physical_page_set_used(u32 address) +{ + u32 page = address / PAGE_SIZE; + + if (page == best_bet) + best_bet++; + + memory[page / 8] |= 1 << (page % 8); +} + +static void physical_page_set_free(u32 address) +{ + u32 page = address / PAGE_SIZE; + + if (page < best_bet) + best_bet = page; + + memory[page / 8] &= ~(1 << (page % 8)); +} + +static void physical_set_used(struct memory_range range) +{ + assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); + + for (u32 i = 0; i < range.size / PAGE_SIZE; i++) { + u32 addr = range.base + i * PAGE_SIZE; + if (!physical_page_is_used(addr)) { + memory_used += PAGE_SIZE; + physical_page_set_used(addr); + } + } +} + +static void physical_set_free(struct memory_range range) +{ + assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); + + for (u32 i = 0; i < range.size / PAGE_SIZE; i++) { + u32 addr = range.base + i * PAGE_SIZE; + + if (physical_page_is_used(addr)) { + memory_used -= PAGE_SIZE; + physical_page_set_free(addr); + } + } +} + +static u8 physical_is_used(struct memory_range range) +{ + assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); + + for (u32 i = 0; i < range.size / PAGE_SIZE; i++) { + u32 addr = range.base + i * PAGE_SIZE; + + if (physical_page_is_used(addr)) + return 1; + } + + return 0; +} + +struct memory_range physical_alloc(u32 size) +{ + assert(PAGE_ALIGNED(size)); + + for (u32 i = best_bet; i < ((memory_total - size) / PAGE_SIZE); i++) { + struct memory_range range = memory_range(i * PAGE_SIZE, size); + + if (!physical_is_used(range)) { + physical_set_used(range); + return range; + } + } + + panic("Out of physical memory!\n"); + return memory_range(0, 0); +} + +void physical_free(struct memory_range range) +{ + assert(PAGE_ALIGNED(range.base) && PAGE_ALIGNED(range.size)); + physical_set_free(range); +} + +/** + * Virtual + */ + +#define PDI(vaddr) (((vaddr) >> 22) & 0x03ff) +#define PTI(vaddr) (((vaddr) >> 12) & 0x03ff) + +u8 virtual_present(struct page_dir *dir, u32 vaddr) +{ + u32 pdi = PDI(vaddr); + union page_dir_entry *dir_entry = &dir->entries[pdi]; + if (!dir_entry->bits.present) + return 0; + + struct page_table *table = (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + + u32 pti = PTI(vaddr); + union page_table_entry *table_entry = &table->entries[pti]; + + return table_entry->bits.present; +} + +u32 virtual_to_physical(struct page_dir *dir, u32 vaddr) +{ + u32 pdi = PDI(vaddr); + union page_dir_entry *dir_entry = &dir->entries[pdi]; + if (!dir_entry->bits.present) + return 0; + + struct page_table *table = (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + + u32 pti = PTI(vaddr); + union page_table_entry *table_entry = &table->entries[pti]; + if (!table_entry->bits.present) + return 0; + + return (table_entry->bits.address * PAGE_SIZE) + (vaddr & (PAGE_SIZE - 1)); +} + +void virtual_map(struct page_dir *dir, struct memory_range prange, u32 vaddr, u32 flags) +{ + for (u32 i = 0; i < prange.size / PAGE_SIZE; i++) { + u32 offset = i * PAGE_SIZE; + + u32 pdi = PDI(vaddr + offset); + union page_dir_entry *dir_entry = &dir->entries[pdi]; + struct page_table *table = + (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + + if (!dir_entry->bits.present) { + table = memory_alloc_identity(dir, MEMORY_CLEAR); + dir_entry->bits.present = 1; + dir_entry->bits.writable = 1; + dir_entry->bits.user = 1; + dir_entry->bits.address = (u32)(table) >> 12; + } + + u32 pti = PTI(vaddr + offset); + union page_table_entry *table_entry = &table->entries[pti]; + table_entry->bits.present = 1; + table_entry->bits.writable = 1; + table_entry->bits.user = flags & MEMORY_USER; + table_entry->bits.address = (prange.base + offset) >> 12; + } + + paging_invalidate_tlb(); +} + +struct memory_range virtual_alloc(struct page_dir *dir, struct memory_range prange, u32 flags) +{ + u8 user = flags & MEMORY_USER; + u32 vaddr = 0; + u32 size = 0; + + for (u32 i = (user ? 256 : 1) * PAGE_COUNT; i < (user ? PAGE_COUNT : 256) * PAGE_COUNT; + i++) { + u32 addr = i * PAGE_SIZE; + if (!virtual_present(dir, addr)) { + if (size == 0) + vaddr = addr; + + size += PAGE_SIZE; + + if (size == prange.size) { + virtual_map(dir, prange, vaddr, flags); + return memory_range(vaddr, size); + } + } else { + size = 0; + } + } + + panic("Out of virtual memory!\n"); + return memory_range(0, 0); +} + +void virtual_free(struct page_dir *dir, struct memory_range vrange) +{ + for (u32 i = 0; i < vrange.size / PAGE_SIZE; i++) { + u32 offset = i * PAGE_SIZE; + + u32 pdi = PDI(vrange.base + offset); + union page_dir_entry *dir_entry = &dir->entries[pdi]; + if (!dir_entry->bits.present) + continue; + + struct page_table *table = + (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + + u32 pti = PTI(vrange.base + offset); + union page_table_entry *table_entry = &table->entries[pti]; + + if (table_entry->bits.present) + table_entry->uint = 0; + } + + paging_invalidate_tlb(); +} + +struct page_dir *virtual_create_dir(void) +{ + struct page_dir *dir = memory_alloc(&kernel_dir, sizeof(*dir), MEMORY_CLEAR); + + memset(dir, 0, sizeof(*dir)); + + for (u32 i = 0; i < 256; i++) { + union page_dir_entry *dir_entry = &dir->entries[i]; + + dir_entry->bits.present = 1; + dir_entry->bits.writable = 1; + dir_entry->bits.user = 0; + dir_entry->bits.address = (u32)&kernel_tables[i] / PAGE_SIZE; + } + + return dir; +} + +void virtual_destroy_dir(struct page_dir *dir) +{ + assert(dir != &kernel_dir); + + for (u32 i = 256; i < PAGE_COUNT; i++) { + union page_dir_entry *dir_entry = &dir->entries[i]; + if (dir_entry->bits.present) { + struct page_table *table = + (struct page_table *)(dir_entry->bits.address * PAGE_SIZE); + for (u32 j = 0; j < PAGE_COUNT; j++) { + union page_table_entry *table_entry = &table->entries[j]; + if (table_entry->bits.present) { + u32 paddr = table_entry->bits.address * PAGE_SIZE; + physical_free(memory_range(paddr, PAGE_SIZE)); + } + } + + memory_free(&kernel_dir, memory_range((u32)table, sizeof(*table))); + } + } + + memory_free(&kernel_dir, memory_range((u32)dir, sizeof(*dir))); +} + +struct page_dir *virtual_kernel_dir(void) +{ + return &kernel_dir; +} + +/** + * Memory wrappers + */ + +void *memory_alloc(struct page_dir *dir, u32 size, u32 flags) +{ + assert(PAGE_ALIGNED(size)); + + if (!size) + goto err; + + struct memory_range prange = physical_alloc(size); + if (prange.size == 0) + goto err; + + u32 vaddr = virtual_alloc(dir, prange, flags).base; + if (!vaddr) { + physical_free(prange); + goto err; + } + + if (flags & MEMORY_CLEAR) + memset((void *)vaddr, 0, size); + + return (void *)vaddr; + +err: + print("Memory allocation error!\n"); + return 0; +} + +void *memory_alloc_identity(struct page_dir *dir, u32 flags) +{ + for (u32 i = 1; i < 256 * PAGE_COUNT; i++) { + struct memory_range range = memory_range(i * PAGE_SIZE, PAGE_SIZE); + + if (!virtual_present(dir, range.base) && !physical_is_used(range)) { + physical_set_used(range); + virtual_map(dir, range, range.base, flags); + if (flags & MEMORY_CLEAR) + memset((void *)range.base, 0, PAGE_SIZE); + return (void *)range.base; + } + } + + return 0; +} + +void memory_free(struct page_dir *dir, struct memory_range vrange) +{ + assert(PAGE_ALIGNED(vrange.base) && PAGE_ALIGNED(vrange.size)); + + for (u32 i = 0; i < vrange.size / PAGE_SIZE; i++) { + u32 vaddr = vrange.base + i * PAGE_SIZE; + if (virtual_present(dir, vaddr)) { + struct memory_range page_prange = + memory_range(virtual_to_physical(dir, vaddr), PAGE_SIZE); + struct memory_range page_vrange = memory_range(vaddr, PAGE_SIZE); + physical_free(page_prange); + virtual_free(dir, page_vrange); + } + } +} + +void memory_map_identity(struct page_dir *dir, struct memory_range prange, u32 flags) +{ + assert(PAGE_ALIGNED(prange.base) && PAGE_ALIGNED(prange.size)); + + physical_set_used(prange); + virtual_map(dir, prange, prange.base, flags); + if (flags & MEMORY_CLEAR) + memset((void *)prange.base, 0, prange.size); +} + +void memory_switch_dir(struct page_dir *dir) +{ + paging_switch_dir(virtual_to_physical(&kernel_dir, (u32)dir)); +} + +void memory_backup_dir(struct page_dir **backup) +{ + struct proc *proc = proc_current(); + struct page_dir *dir = proc ? proc->page_dir : virtual_kernel_dir(); + *backup = dir; +} + +struct memory_range memory_range_from(u32 base, u32 size) +{ + u32 align = PAGE_SIZE - base % PAGE_SIZE; + + if (base % PAGE_SIZE == 0) { + align = 0; + } + + base += align; + size -= align; + + size -= size % PAGE_SIZE; + + return memory_range(base, size); +} + +struct memory_range memory_range_around(u32 base, u32 size) +{ + u32 align = base % PAGE_SIZE; + + base -= align; + size += align; + + size += PAGE_SIZE - size % PAGE_SIZE; + + return memory_range(base, size); +} + +extern u32 kernel_start; +extern u32 kernel_end; +static struct memory_range kernel_memory_range(void) +{ + return memory_range_around((u32)&kernel_start, (u32)&kernel_end - (u32)&kernel_start); +} + +void memory_install(struct mem_info *mem_info, struct vid_info *vid_info) +{ + for (struct mmap_boot *p = mem_info->start; (u32)(p - mem_info->start) < mem_info->size; + p++) { + if (p->hbase || !p->acpi || !p->type) + continue; + + u32 size = p->lsize; + if (p->hsize) + size = U32_MAX - p->lbase; + + /* printf("Memory region: %x-%x\n", p->lbase, p->lbase + size); */ + if (p->type == MEMORY_AVAILABLE) { + physical_set_free(memory_range_around(p->lbase, size / PAGE_SIZE)); + memory_total += size; + } else if (p->type == MEMORY_DEFECT) { + printf("Defect memory at 0x%x-0x%x!\n", p->lbase, p->lbase + size); + } + } + + for (u32 i = 0; i < 256; i++) { + union page_dir_entry *dir_entry = &kernel_dir.entries[i]; + dir_entry->bits.present = 1; + dir_entry->bits.writable = 1; + dir_entry->bits.user = 0; + dir_entry->bits.address = (u32)&kernel_tables[i] / PAGE_SIZE; + } + + memory_used = 0; + printf("Detected memory: %dKiB (%dMiB)\n", memory_total >> 10, memory_total >> 20); + + // Map kernel + memory_map_identity(&kernel_dir, kernel_memory_range(), MEMORY_NONE); + + // Map kernel stack + memory_map_identity(&kernel_dir, memory_range_around(STACK_START - STACK_SIZE, STACK_SIZE), + MEMORY_NONE); + + // Map VBE data + memory_map_identity(&kernel_dir, memory_range_around((u32)vid_info->vbe, 0x1000), + MEMORY_NONE); + + // Unmap NULL byte/page + struct memory_range zero = memory_range(0, PAGE_SIZE); + virtual_free(&kernel_dir, zero); + physical_set_used(zero); + + memory_switch_dir(&kernel_dir); + paging_enable(); +} diff --git a/kernel/features/proc.asm b/kernel/features/proc.asm index 1a2ba65..dfc3448 100644 --- a/kernel/features/proc.asm +++ b/kernel/features/proc.asm @@ -28,3 +28,9 @@ proc_jump_userspace: push dword [_eip] iret + +global paging_invalidate_tlb +paging_invalidate_tlb: + mov eax, cr3 + mov cr3, eax + ret diff --git a/kernel/features/proc.c b/kernel/features/proc.c index cdbe8b1..b93f7c8 100644 --- a/kernel/features/proc.c +++ b/kernel/features/proc.c @@ -6,6 +6,7 @@ #include <fs.h> #include <load.h> #include <mem.h> +#include <mm.h> #include <print.h> #include <proc.h> #include <stack.h> @@ -19,7 +20,7 @@ struct list *proc_list = NULL; struct node *idle_proc = NULL; struct node *current = NULL; -// TODO: Use less memcpy and only copy relevant registers +// TODO: Use less memcpy and only copy relevant registers (rewrite for efficiency argh) // TODO: 20 priority queues (https://www.kernel.org/doc/html/latest/scheduler/sched-nice-design.html) void scheduler(struct regs *regs) { @@ -56,6 +57,7 @@ void scheduler(struct regs *regs) } } + memory_switch_dir(((struct proc *)current->data)->page_dir); memcpy(regs, &((struct proc *)current->data)->regs, sizeof(struct regs)); if (regs->cs != GDT_USER_CODE_OFFSET) { @@ -74,12 +76,6 @@ void scheduler(struct regs *regs) /* printf("{%d}", ((struct proc *)current->data)->pid); */ } -static void kernel_idle(void) -{ - while (1) - ; -} - void proc_print(void) { struct node *node = proc_list->head; @@ -103,7 +99,7 @@ u8 proc_super(void) { struct proc *proc = proc_current(); if (proc) - return proc->super; + return proc->priv == PROC_PRIV_ROOT || proc->priv == PROC_PRIV_KERNEL; else if (current_pid == 0) return 1; // Kernel has super permissions else @@ -161,6 +157,9 @@ void proc_yield(struct regs *r) void proc_enable_waiting(u32 id, enum proc_wait_type type) { + struct page_dir *dir_bak; + memory_backup_dir(&dir_bak); + struct proc *proc_bak = proc_current(); if (!proc_bak) return; @@ -183,8 +182,11 @@ void proc_enable_waiting(u32 id, enum proc_wait_type type) struct regs *r = &p->regs; u32 (*func)(u32, u32, u32, u32) = (u32(*)(u32, u32, u32, u32))w->ids[i].func_ptr; - if (w->ids[i].func_ptr) + if (w->ids[i].func_ptr) { + memory_switch_dir(p->page_dir); r->eax = func(r->ebx, r->ecx, r->edx, r->esi); + memory_switch_dir(dir_bak); + } memset(&w->ids[i], 0, sizeof(w->ids[i])); p->wait.id_cnt--; p->state = PROC_RUNNING; @@ -237,20 +239,37 @@ end: p->state = PROC_SLEEPING; } -struct proc *proc_make(void) +struct proc *proc_make(enum proc_priv priv) { struct proc *proc = zalloc(sizeof(*proc)); proc->pid = current_pid++; - proc->super = 0; + proc->priv = priv; proc->messages = stack_new(); proc->state = PROC_RUNNING; + if (priv == PROC_PRIV_KERNEL) + proc->page_dir = virtual_kernel_dir(); + else + proc->page_dir = virtual_create_dir(); + if (current) list_add(proc_list, proc); return proc; } +void proc_stack_push(struct proc *proc, u32 data) +{ + struct page_dir *prev; + memory_backup_dir(&prev); + memory_switch_dir(proc->page_dir); + + proc->regs.useresp -= sizeof(data); + *(u32 *)proc->regs.useresp = data; + + memory_switch_dir(prev); +} + // TODO: Procfs needs a simpler interface structure (memcmp and everything sucks) static const char *procfs_parse_path(const char **path, u32 *pid) @@ -286,6 +305,11 @@ static enum stream_defaults procfs_stream(const char *path) } } +struct procfs_message { + u8 *data; + u32 size; +}; + static s32 procfs_write(const char *path, void *buf, u32 offset, u32 count, struct device *dev) { u32 pid = 0; @@ -299,7 +323,10 @@ static s32 procfs_write(const char *path, void *buf, u32 offset, u32 count, stru if (!memcmp(path, "msg", 4)) { void *msg_data = malloc(count); memcpy(msg_data, buf, count); - stack_push_bot(p->messages, msg_data); // TODO: Use offset + struct procfs_message *msg = malloc(sizeof(*msg)); + msg->data = msg_data; + msg->size = count; + stack_push_bot(p->messages, msg); // TODO: Use offset proc_enable_waiting(pid, PROC_WAIT_MSG); return count; } else if (!memcmp(path, "io/", 3)) { @@ -321,7 +348,7 @@ static s32 procfs_write(const char *path, void *buf, u32 offset, u32 count, stru } } - printf("%s - off: %d, cnt: %d, buf: %x, dev %x\n", path, offset, count, buf, dev); + printf("ERR: %s - off: %d, cnt: %d, buf: %x, dev %x\n", path, offset, count, buf, dev); return -1; } @@ -352,12 +379,13 @@ static s32 procfs_read(const char *path, void *buf, u32 offset, u32 count, struc if (stack_empty(p->messages)) { return -1; // This shouldn't happen } else { - u8 *msg = stack_pop(p->messages); + struct procfs_message *msg = stack_pop(p->messages); if (!msg) return -1; - memcpy(buf, msg + offset, count); + memcpy(buf, msg->data + offset, MIN(count, msg->size)); + free(msg->data); free(msg); - return count; + return MIN(count, msg->size); } } else if (!memcmp(path, "io/", 3)) { path += 3; @@ -465,32 +493,26 @@ void proc_init(void) vfs_mount(dev, "/proc/"); // Idle proc - struct proc *kernel_proc = proc_make(); - void (*func)(void) = kernel_idle; - proc_load(kernel_proc, *(void **)&func); - strcpy(kernel_proc->name, "idle"); + struct proc *kernel_proc = proc_make(PROC_PRIV_NONE); + bin_load("/bin/idle", kernel_proc); kernel_proc->state = PROC_SLEEPING; idle_proc = list_add(proc_list, kernel_proc); - struct node *new = list_add(proc_list, proc_make()); + // Init proc (root) + struct node *new = list_add(proc_list, proc_make(PROC_PRIV_ROOT)); bin_load("/bin/init", new->data); current = new; + proc_stack_push(new->data, 0); _eip = ((struct proc *)new->data)->regs.eip; _esp = ((struct proc *)new->data)->regs.useresp; - ((struct proc *)new->data)->super = 1; - - u32 argc = 2; - char **argv = malloc(sizeof(*argv) * (argc + 1)); - argv[0] = strdup("init"); - argv[1] = (char *)boot_passed->vbe; - argv[2] = NULL; - - ((u32 *)_esp)[0] = argc; // First argument (argc) - ((u32 *)_esp)[1] = (u32)argv; // Second argument (argv) printf("Jumping to userspace!\n"); + memory_switch_dir(((struct proc *)new->data)->page_dir); + + // You're waiting for a train. A train that will take you far away... proc_jump_userspace(); + while (1) { }; } diff --git a/kernel/features/syscall.c b/kernel/features/syscall.c index 61c7479..68bcbaa 100644 --- a/kernel/features/syscall.c +++ b/kernel/features/syscall.c @@ -5,6 +5,7 @@ #include <interrupts.h> #include <load.h> #include <mem.h> +#include <mm.h> #include <net.h> #include <print.h> #include <proc.h> @@ -25,12 +26,13 @@ static void syscall_handler(struct regs *r) loop(); break; } - case SYS_MALLOC: { - r->eax = (u32)malloc(r->ebx); + case SYS_ALLOC: { + r->eax = (u32)memory_alloc(proc_current()->page_dir, r->ebx, + MEMORY_CLEAR | MEMORY_USER); break; } case SYS_FREE: { - free((void *)r->ebx); + memory_free(proc_current()->page_dir, memory_range(r->ebx, r->ecx)); break; } case SYS_STAT: { @@ -52,6 +54,11 @@ static void syscall_handler(struct regs *r) r->eax = (u32)vfs_write((char *)r->ebx, (void *)r->ecx, r->edx, r->esi); break; } + case SYS_IOCTL: { + r->eax = (u32)vfs_ioctl((char *)r->ebx, r->ecx, (void *)r->edx, (void *)r->esi, + (void *)r->edi); + break; + } case SYS_POLL: { s32 ret = vfs_poll((const char **)r->ebx); if (ret == PROC_MAX_WAIT_IDS + 1) @@ -62,17 +69,10 @@ static void syscall_handler(struct regs *r) } case SYS_EXEC: { char *path = (char *)r->ebx; - struct proc *proc = proc_make(); + struct proc *proc = proc_make(PROC_PRIV_NONE); r->eax = (u32)bin_load(path, proc); - u32 argc = 3; // TODO: Add argc evaluator - char **argv = malloc(sizeof(*argv) * (argc + 1)); - argv[0] = (char *)r->ecx; - argv[1] = (char *)r->edx; - argv[2] = (char *)r->esi; - argv[3] = (char *)r->edi; - argv[4] = NULL; - ((u32 *)proc->regs.useresp)[0] = argc; - ((u32 *)proc->regs.useresp)[1] = (u32)argv; + // TODO: Reimplement argc,argv + proc_stack_push(proc, 0); if (r->eax) proc_exit(proc, (int)r->eax); proc_yield(r); @@ -82,6 +82,30 @@ static void syscall_handler(struct regs *r) proc_exit(proc_current(), (int)r->ebx); break; } + case SYS_BOOT: { // TODO: Move + if (r->ebx != SYS_BOOT_MAGIC || !proc_super()) { + r->eax = -1; + break; + } + switch (r->ecx) { + case SYS_BOOT_REBOOT: + print("Rebooting...\n"); + outb(0x64, 0xfe); + __asm__ volatile("ud2"); + break; + case SYS_BOOT_SHUTDOWN: + print("Shutting down...\n"); + outw(0xB004, 0x2000); + outw(0x604, 0x2000); + outw(0x4004, 0x3400); + outb(0x64, 0xfe); + __asm__ volatile("ud2"); + break; + default: + r->eax = -1; + } + break; + } case SYS_YIELD: { proc_yield(r); break; @@ -123,7 +147,7 @@ static void syscall_handler(struct regs *r) break; } default: { - print("Unknown syscall!\n"); + printf("Unknown syscall %d!\n", num); break; } } diff --git a/kernel/inc/boot.h b/kernel/inc/boot.h index 6bacc31..7f085cd 100644 --- a/kernel/inc/boot.h +++ b/kernel/inc/boot.h @@ -6,10 +6,33 @@ #include <def.h> -extern struct vid_info *boot_passed; struct vid_info { u32 mode; u32 *vbe; }; +enum mmap_type { + MEMORY_AVAILABLE = 1, + MEMORY_RESERVED, + MEMORY_ACPI, + MEMORY_NVS, + MEMORY_DEFECT, + MEMORY_DISABLED +}; + +struct mmap_boot { + u32 lbase; + u32 hbase; + u32 lsize; + u32 hsize; + u32 type; + u32 acpi; +}; + +struct mem_info { + struct mmap_boot *start; + u32 *end; + u32 size; +}; + #endif diff --git a/kernel/inc/fb.h b/kernel/inc/fb.h new file mode 100644 index 0000000..3e7b08f --- /dev/null +++ b/kernel/inc/fb.h @@ -0,0 +1,10 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef FB +#define FB + +#include <boot.h> + +void fb_install(struct vid_info *boot); + +#endif diff --git a/kernel/inc/fs.h b/kernel/inc/fs.h index 33b1afb..cd97b99 100644 --- a/kernel/inc/fs.h +++ b/kernel/inc/fs.h @@ -20,6 +20,7 @@ struct device { void *data; s32 (*read)(void *buf, u32 offset, u32 count, struct device *dev); s32 (*write)(void *buf, u32 offset, u32 count, struct device *dev); + s32 (*ioctl)(u32 request, void *arg1, void *arg2, void *arg3, struct device *dev); u8 (*ready)(void); }; @@ -40,6 +41,8 @@ struct vfs { void *data; s32 (*read)(const char *path, void *buf, u32 offset, u32 count, struct device *dev); s32 (*write)(const char *path, void *buf, u32 offset, u32 count, struct device *dev); + s32 (*ioctl)(const char *path, u32 request, void *arg1, void *arg2, void *arg3, + struct device *dev); s32 (*stat)(const char *path, struct stat *buf, struct device *dev); s32 (*wait)(const char *path, u32 func_ptr, struct device *dev); u8 (*perm)(const char *path, enum vfs_perm perm, struct device *dev); @@ -60,6 +63,7 @@ struct device *vfs_find_dev(const char *path); s32 vfs_read(const char *path, void *buf, u32 offset, u32 count); s32 vfs_write(const char *path, void *buf, u32 offset, u32 count); +s32 vfs_ioctl(const char *path, u32 request, void *arg1, void *arg2, void *arg3); s32 vfs_stat(const char *path, struct stat *buf); s32 vfs_wait(const char *path, u32 func_ptr); s32 vfs_poll(const char **files); diff --git a/kernel/inc/interrupts.h b/kernel/inc/interrupts.h index 30c91c3..fc00402 100644 --- a/kernel/inc/interrupts.h +++ b/kernel/inc/interrupts.h @@ -32,6 +32,7 @@ void irq_uninstall_handler(int irq); void isr_install_handler(int isr, void (*handler)(struct regs *r)); void isr_uninstall_handler(int isr); +void isr_panic(struct regs *r); void interrupts_install(void); diff --git a/kernel/inc/load.h b/kernel/inc/load.h index 407fbeb..f493e84 100644 --- a/kernel/inc/load.h +++ b/kernel/inc/load.h @@ -5,7 +5,6 @@ #include <proc.h> -void proc_load(struct proc *proc, void *data); int bin_load(const char *path, struct proc *proc); #endif diff --git a/kernel/inc/mm.h b/kernel/inc/mm.h new file mode 100644 index 0000000..d3e37f6 --- /dev/null +++ b/kernel/inc/mm.h @@ -0,0 +1,108 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef PAGING_H +#define PAGING_H + +#include <boot.h> +#include <def.h> +#include <interrupts.h> + +struct memory_range { + u32 base; + u32 size; +}; + +/** + * Physical + */ + +struct memory_range physical_alloc(u32 size); +void physical_free(struct memory_range range); + +/** + * Virtual + */ + +#define PAGE_SIZE 0x1000 +#define PAGE_COUNT 1024 +#define PAGE_ALIGN(x) ((x) + PAGE_SIZE - ((x) % PAGE_SIZE)) +#define PAGE_ALIGNED(x) ((x) % PAGE_SIZE == 0) +#define PAGE_ALIGN_UP(x) (((x) % PAGE_SIZE == 0) ? (x) : (x) + PAGE_SIZE - ((x) % PAGE_SIZE)) +#define PAGE_ALIGN_DOWN(x) ((x) - ((x) % PAGE_SIZE)) + +union page_table_entry { + struct PACKED { + u32 present : 1; + u32 writable : 1; + u32 user : 1; + u32 write_through : 1; + u32 cache_disable : 1; + u32 accessed : 1; + u32 dirty : 1; + u32 attribute : 1; + u32 global : 1; + u32 available : 3; + u32 address : 20; + } bits; + u32 uint; +} PACKED; + +struct page_table { + union page_table_entry entries[PAGE_COUNT]; +} PACKED; + +union page_dir_entry { + struct PACKED { + u32 present : 1; + u32 writable : 1; + u32 user : 1; + u32 write_through : 1; + u32 cache_disable : 1; + u32 accessed : 1; + u32 reserved : 1; + u32 page_size : 1; + u32 global : 1; + u32 available : 3; + u32 address : 20; + } bits; + u32 uint; +} PACKED; + +struct page_dir { + union page_dir_entry entries[PAGE_COUNT]; +} PACKED; + +u8 virtual_present(struct page_dir *dir, u32 vaddr); +u32 virtual_to_physical(struct page_dir *dir, u32 vaddr); +void virtual_map(struct page_dir *dir, struct memory_range prange, u32 vaddr, u32 flags); +struct memory_range virtual_alloc(struct page_dir *dir, struct memory_range physical_range, + u32 flags); +void virtual_free(struct page_dir *dir, struct memory_range vrange); +struct page_dir *virtual_create_dir(void); +void virtual_destroy_dir(struct page_dir *dir); +struct page_dir *virtual_kernel_dir(void); + +/** + * Memory wrappers + */ + +#define MEMORY_NONE (0 << 0) +#define MEMORY_USER (1 << 0) +#define MEMORY_CLEAR (1 << 1) +#define memory_range(base, size) ((struct memory_range){ (base), (size) }) + +struct memory_range memory_range_from(u32 base, u32 size); +struct memory_range memory_range_around(u32 base, u32 size); + +void *memory_alloc(struct page_dir *dir, u32 size, u32 flags); +void *memory_alloc_identity(struct page_dir *dir, u32 flags); +void memory_map_identity(struct page_dir *dir, struct memory_range prange, u32 flags); +void memory_free(struct page_dir *dir, struct memory_range vrange); +void memory_switch_dir(struct page_dir *dir); +void memory_backup_dir(struct page_dir **backup); + +void memory_install(struct mem_info *mem_info, struct vid_info *vid_info); + +void page_fault_handler(struct regs *r); + +#endif diff --git a/kernel/inc/proc.h b/kernel/inc/proc.h index 272a3ac..a44fd68 100644 --- a/kernel/inc/proc.h +++ b/kernel/inc/proc.h @@ -9,7 +9,7 @@ #include <stack.h> #include <sys.h> -#define PROC_QUANTUM 10 // Milliseconds or something // TODO +#define PROC_QUANTUM 42 // Milliseconds or something // TODO #define EFLAGS_ALWAYS 0x2 // Always one #define EFLAGS_INTERRUPTS 0x200 // Enable interrupts @@ -23,6 +23,7 @@ #define STREAM_MAX_SIZE 4096 enum stream_defaults { STREAM_IN, STREAM_OUT, STREAM_ERR, STREAM_LOG, STREAM_UNKNOWN = -1 }; +enum proc_priv { PROC_PRIV_NONE, PROC_PRIV_ROOT, PROC_PRIV_KERNEL }; enum proc_state { PROC_RUNNING, PROC_SLEEPING }; enum proc_wait_type { PROC_WAIT_DEV, PROC_WAIT_MSG }; @@ -47,9 +48,10 @@ struct stream { struct proc { u32 pid; u32 entry; - u8 super; + u8 priv; char name[32]; struct stream streams[4]; + struct page_dir *page_dir; struct regs regs; struct proc_wait wait; // dev_id enum proc_state state; @@ -67,6 +69,7 @@ void proc_yield(struct regs *r); void proc_clear_quantum(void); void proc_enable_waiting(u32 id, enum proc_wait_type type); void proc_wait_for(u32 id, enum proc_wait_type type, u32 func_ptr); -struct proc *proc_make(void); +struct proc *proc_make(enum proc_priv priv); +void proc_stack_push(struct proc *proc, u32 data); #endif diff --git a/kernel/link.ld b/kernel/link.ld index 0d8d865..5a63e33 100644 --- a/kernel/link.ld +++ b/kernel/link.ld @@ -6,6 +6,7 @@ phys = 0x00050000; SECTIONS { .text phys : AT(phys) { + kernel_start = .; code = .; *(.text) *(.rodata) @@ -26,5 +27,5 @@ SECTIONS . = ALIGN(4096); } - end = .; + kernel_end = .; } diff --git a/kernel/main.c b/kernel/main.c index 6be31bd..3b75c7d 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -2,12 +2,14 @@ #include <boot.h> #include <cpu.h> +#include <fb.h> #include <fs.h> #include <ide.h> #include <interrupts.h> #include <keyboard.h> #include <load.h> #include <mem.h> +#include <mm.h> #include <mouse.h> #include <net.h> #include <pci.h> @@ -16,22 +18,23 @@ #include <syscall.h> #include <timer.h> -struct vid_info *boot_passed; - -void kernel_main(struct vid_info *vid_info); // Decl -void kernel_main(struct vid_info *vid_info) +void kernel_main(struct mem_info *mem_info, struct vid_info *vid_info); // Decl +void kernel_main(struct mem_info *mem_info, struct vid_info *vid_info) { + // Clear stack + for (u32 i = 0; i < STACK_SIZE; i++) + ((u8 *)STACK_START)[-i] = 0; + // Serial connection serial_install(); serial_print("\nKernel was compiled at " __TIME__ " on " __DATE__ "\n"); serial_print("Serial connected.\n"); - heap_init(0x00f00000); - - boot_passed = vid_info; + memory_install(mem_info, vid_info); cpu_enable_features(); cpu_print(); + srand(rdseed()); // Install drivers vfs_install(); @@ -42,6 +45,7 @@ void kernel_main(struct vid_info *vid_info) timer_install(); keyboard_install(); mouse_install(); + fb_install(vid_info); /* net_install(); */ // Enable drivers diff --git a/libc/Makefile b/libc/Makefile index 9ac6c67..3bf4473 100644 --- a/libc/Makefile +++ b/libc/Makefile @@ -3,6 +3,7 @@ # TODO: Remove serial and cpu from libc? COBJS = sanitize.o \ str.o \ + alloc.o \ mem.o \ math.o \ conv.o \ diff --git a/libc/alloc.c b/libc/alloc.c new file mode 100644 index 0000000..be986dc --- /dev/null +++ b/libc/alloc.c @@ -0,0 +1,425 @@ +// MIT License, Copyright (c) 2021 Marvin Borner +// Mostly by Durand Miller, released into public domain + +#include <assert.h> +#include <cpu.h> +#include <mem.h> + +#ifdef kernel + +#include <mm.h> + +static void *liballoc_alloc(u32 p) +{ + return memory_alloc(virtual_kernel_dir(), p, MEMORY_CLEAR); +} + +static int liballoc_free(void *ptr, u32 p) +{ + memory_free(virtual_kernel_dir(), memory_range((u32)ptr, (u32)p)); + return 0; +} + +#else + +#include <sys.h> + +#define sys_alloc(size) (void *)sys1(SYS_ALLOC, size) +#define sys_free(ptr, size) (u32) sys2(SYS_FREE, ptr, size) + +static void *liballoc_alloc(u32 p) +{ + return sys_alloc((u32)p); +} + +static int liballoc_free(void *ptr, u32 p) +{ + sys_free((u32)ptr, (u32)p); + return 0; +} + +#endif + +static int locked = 0; + +static int liballoc_lock(void) +{ + spinlock(&locked); + return 0; +} + +static int liballoc_unlock(void) +{ + locked = 0; + return 0; +} + +#define ALIGNMENT 16 +#define ALIGN_UP(__addr, __align) (((__addr) + (__align)-1) & ~((__align)-1)) +#define ALIGN_DOWN(__addr, __align) ((__addr) & ~((__align)-1)) + +#define USE_CASE1 +#define USE_CASE2 +#define USE_CASE3 +#define USE_CASE4 +#define USE_CASE5 +#define LIBALLOC_MAGIC 0x900df00d +#define LIBALLOC_DEAD 0xbaadf00d + +struct liballoc_major { + struct liballoc_major *prev; + struct liballoc_major *next; + u32 pages; + u32 size; + u32 usage; + struct liballoc_minor *first; +}; + +struct liballoc_minor { + struct liballoc_minor *prev; + struct liballoc_minor *next; + struct liballoc_major *block; + u32 magic; + u32 size; + u32 req_size; +}; + +#define MAJOR_SIZE (ALIGN_UP(sizeof(struct liballoc_major), 16)) +#define MINOR_SIZE (ALIGN_UP(sizeof(struct liballoc_minor), 16)) + +static struct liballoc_major *l_mem_root = NULL; +static struct liballoc_major *l_best_bet = NULL; + +static u32 l_page_size = 4096; +static u32 l_page_count = 16; + +static struct liballoc_major *allocate_new_page(u32 size) +{ + u32 st = size + MAJOR_SIZE + MINOR_SIZE; + + if ((st % l_page_size) == 0) + st = st / (l_page_size); + else + st = st / (l_page_size) + 1; + + st = MAX(st, l_page_count); + + struct liballoc_major *maj = (struct liballoc_major *)liballoc_alloc(st * l_page_size); + + if (maj == NULL) + return NULL; + + maj->prev = NULL; + maj->next = NULL; + maj->pages = st; + maj->size = st * l_page_size; + maj->usage = MAJOR_SIZE; + maj->first = NULL; + + return maj; +} + +static void *_malloc(u32 req_size) +{ + req_size = ALIGN_UP(req_size, 16); + + u32 best_size = 0; + u32 size = req_size; + + liballoc_lock(); + + if (size == 0) { + liballoc_unlock(); + return malloc(1); + } + + if (l_mem_root == NULL) { + l_mem_root = allocate_new_page(size); + if (l_mem_root == NULL) { + liballoc_unlock(); + panic("Malloc failed!\n"); + } + } + + struct liballoc_major *maj = l_mem_root; + u8 started_bet = 0; + + if (l_best_bet != NULL) { + best_size = l_best_bet->size - l_best_bet->usage; + + if (best_size > (size + MINOR_SIZE)) { + maj = l_best_bet; + started_bet = 1; + } + } + + while (maj != NULL) { + u32 diff = maj->size - maj->usage; + if (best_size < diff) { + l_best_bet = maj; + best_size = diff; + } + +#ifdef USE_CASE1 + if (diff < (size + MINOR_SIZE)) { + if (maj->next != NULL) { + maj = maj->next; + continue; + } + + if (started_bet == 1) { + maj = l_mem_root; + started_bet = 0; + continue; + } + + maj->next = allocate_new_page(size); + if (maj->next == NULL) + break; + maj->next->prev = maj; + maj = maj->next; + } +#endif + +#ifdef USE_CASE2 + if (maj->first == NULL) { + maj->first = (struct liballoc_minor *)((u32)maj + MAJOR_SIZE); + + maj->first->magic = LIBALLOC_MAGIC; + maj->first->prev = NULL; + maj->first->next = NULL; + maj->first->block = maj; + maj->first->size = size; + maj->first->req_size = req_size; + maj->usage += size + MINOR_SIZE; + void *p = (void *)((u32)(maj->first) + MINOR_SIZE); + liballoc_unlock(); + return p; + } +#endif + +#ifdef USE_CASE3 + diff = (u32)(maj->first); + diff -= (u32)maj; + diff -= MAJOR_SIZE; + + if (diff >= (size + MINOR_SIZE)) { + maj->first->prev = (struct liballoc_minor *)((u32)maj + MAJOR_SIZE); + maj->first->prev->next = maj->first; + maj->first = maj->first->prev; + maj->first->magic = LIBALLOC_MAGIC; + maj->first->prev = NULL; + maj->first->block = maj; + maj->first->size = size; + maj->first->req_size = req_size; + maj->usage += size + MINOR_SIZE; + void *p = (void *)((u32)(maj->first) + MINOR_SIZE); + liballoc_unlock(); + return p; + } +#endif + +#ifdef USE_CASE4 + struct liballoc_minor *min = maj->first; + + while (min != NULL) { + if (min->next == NULL) { + diff = (u32)(maj) + maj->size; + diff -= (u32)min; + diff -= MINOR_SIZE; + diff -= min->size; + if (diff >= (size + MINOR_SIZE)) { + min->next = + (struct liballoc_minor *)((u32)min + MINOR_SIZE + + min->size); + min->next->prev = min; + min = min->next; + min->next = NULL; + min->magic = LIBALLOC_MAGIC; + min->block = maj; + min->size = size; + min->req_size = req_size; + maj->usage += size + MINOR_SIZE; + void *p = (void *)((u32)min + MINOR_SIZE); + liballoc_unlock(); + return p; + } + } + + if (min->next != NULL) { + diff = (u32)(min->next); + diff -= (u32)min; + diff -= MINOR_SIZE; + diff -= min->size; + + if (diff >= (size + MINOR_SIZE)) { + struct liballoc_minor *new_min = + (struct liballoc_minor *)((u32)min + MINOR_SIZE + + min->size); + new_min->magic = LIBALLOC_MAGIC; + new_min->next = min->next; + new_min->prev = min; + new_min->size = size; + new_min->req_size = req_size; + new_min->block = maj; + min->next->prev = new_min; + min->next = new_min; + maj->usage += size + MINOR_SIZE; + void *p = (void *)((u32)new_min + MINOR_SIZE); + liballoc_unlock(); + return p; + } + } + + min = min->next; + } +#endif + +#ifdef USE_CASE5 + if (maj->next == NULL) { + if (started_bet == 1) { + maj = l_mem_root; + started_bet = 0; + continue; + } + maj->next = allocate_new_page(size); + if (maj->next == NULL) + break; + maj->next->prev = maj; + } +#endif + maj = maj->next; + } + + liballoc_unlock(); + + panic("Malloc failed!\n"); + return NULL; +} + +static void _free(void *ptr) +{ + if (ptr == NULL) { + return; + } + + liballoc_lock(); + + struct liballoc_minor *min = (struct liballoc_minor *)((u32)ptr - MINOR_SIZE); + + if (min->magic != LIBALLOC_MAGIC) { + liballoc_unlock(); + return; + } + + struct liballoc_major *maj = min->block; + maj->usage -= (min->size + MINOR_SIZE); + min->magic = LIBALLOC_DEAD; + + if (min->next != NULL) + min->next->prev = min->prev; + if (min->prev != NULL) + min->prev->next = min->next; + if (min->prev == NULL) + maj->first = min->next; + if (maj->first == NULL) { + if (l_mem_root == maj) + l_mem_root = maj->next; + if (l_best_bet == maj) + l_best_bet = NULL; + if (maj->prev != NULL) + maj->prev->next = maj->next; + if (maj->next != NULL) + maj->next->prev = maj->prev; + liballoc_free(maj, maj->pages * l_page_size); + } else { + if (l_best_bet != NULL) { + int best_size = l_best_bet->size - l_best_bet->usage; + int maj_size = maj->size - maj->usage; + if (maj_size > best_size) + l_best_bet = maj; + } + } + liballoc_unlock(); +} + +static void *_realloc(void *ptr, u32 size) +{ + size = ALIGN_UP(size, 16); + + if (size == 0) { + free(ptr); + return NULL; + } + + if (ptr == NULL) + return malloc(size); + + liballoc_lock(); + struct liballoc_minor *min = (struct liballoc_minor *)((u32)ptr - MINOR_SIZE); + + if (min->magic != LIBALLOC_MAGIC) { + liballoc_unlock(); + panic("Malloc failed!\n"); + return NULL; + } + + if (min->size >= size) { + min->req_size = size; + liballoc_unlock(); + return ptr; + } + + liballoc_unlock(); + + void *new_ptr = malloc(size); + memcpy(new_ptr, ptr, min->req_size); + free(ptr); + + return new_ptr; +} + +#ifdef kernel +#define PREFIX "K" +#define FUNC printf +#else +#define PREFIX "U" +#define FUNC log +#endif + +void *zalloc(u32 size) +{ + void *ret = malloc(size); + memset(ret, 0, size); + return ret; +} + +void *realloc(void *ptr, u32 size) +{ + return _realloc(ptr, size); +} + +void *malloc_debug(u32 size, const char *file, int line, const char *func, const char *inp) +{ + assert(size < (100 << 20)); // Don't brag with memory pls + void *ret = _malloc(size); + + (void)file; + (void)line; + (void)func; + (void)inp; + /* FUNC(PREFIX "MALLOC\t%s:%d: %s: 0x%x %dB (%s)\n", file, line, func, ret, size, inp); */ + return ret; +} + +void free_debug(void *ptr, const char *file, int line, const char *func, const char *inp) +{ + if (ptr) + _free(ptr); + + (void)file; + (void)line; + (void)func; + (void)inp; + /* FUNC(PREFIX "FREE\t%s:%d: %s: 0x%x (%s)\n", file, line, func, ptr, inp); */ +} @@ -70,34 +70,52 @@ void cpu_print(void) printf("CPU vendor: %s\n", cpu_string(buf)); } -static u32 cr0_get(void) +u32 cr0_get(void) { u32 cr0; __asm__ volatile("movl %%cr0, %%eax" : "=a"(cr0)); return cr0; } -static void cr0_set(u32 cr0) +void cr0_set(u32 cr0) { __asm__ volatile("movl %%eax, %%cr0" ::"a"(cr0)); } -static u32 cr4_get(void) +u32 cr3_get(void) +{ + u32 cr3; + __asm__ volatile("movl %%cr0, %%eax" : "=a"(cr3)); + return cr3; +} + +void cr3_set(u32 cr3) +{ + __asm__ volatile("movl %%eax, %%cr3" ::"a"(cr3)); +} + +u32 cr4_get(void) { u32 cr4; __asm__ volatile("movl %%cr4, %%eax" : "=a"(cr4)); return cr4; } -static void cr4_set(u32 cr4) +void cr4_set(u32 cr4) { __asm__ volatile("movl %%eax, %%cr4" ::"a"(cr4)); } -static u32 cpu_features = 0; -static u8 cpu_has_feature(u32 feature) +static u32 cpu_cfeatures = 0; +u8 cpu_has_cfeature(enum cpuid_features feature) +{ + return (cpu_cfeatures & feature) != 0; +} + +static u32 cpu_dfeatures = 0; +u8 cpu_has_dfeature(enum cpuid_features feature) { - return (cpu_features & feature) != 0; + return (cpu_dfeatures & feature) != 0; } static void fpu_handler(struct regs *r) @@ -116,8 +134,9 @@ void cpu_enable_features(void) { u32 a, b, c, d; cpuid(CPUID_FEATURES, &a, &b, &c, &d); - cpu_features = d; - if (cpu_has_feature(CPUID_FEAT_EDX_SSE)) { + cpu_cfeatures = c; + cpu_dfeatures = d; + if (cpu_has_dfeature(CPUID_FEAT_EDX_SSE)) { cr0_set(cr0_get() & ~(1 << 2)); cr0_set(cr0_get() | (1 << 1)); cr4_set(cr4_get() | (3 << 9)); @@ -125,7 +144,7 @@ void cpu_enable_features(void) panic("No SSE support!\n"); } - if (cpu_has_feature(CPUID_FEAT_EDX_FPU)) { + if (cpu_has_dfeature(CPUID_FEAT_EDX_FPU)) { __asm__ volatile("fninit"); __asm__ volatile("fxsave %0" : "=m"(fpu_state)); irq_install_handler(7, fpu_handler); diff --git a/libc/crt/crt0.asm b/libc/crt/crt0.asm index a0621ff..0f8024d 100644 --- a/libc/crt/crt0.asm +++ b/libc/crt/crt0.asm @@ -10,6 +10,6 @@ _start: call main push eax - push 8 + push 9 call sys1 jmp $ diff --git a/libc/inc/cpu.h b/libc/inc/cpu.h index fa82fbe..d709d86 100644 --- a/libc/inc/cpu.h +++ b/libc/inc/cpu.h @@ -27,6 +27,13 @@ void cpu_print(void); void cpu_enable_features(void); void fpu_restore(void); +u32 cr0_get(void); +void cr0_set(u32 cr0); +u32 cr3_get(void); +void cr3_set(u32 cr3); +u32 cr4_get(void); +void cr4_set(u32 cr4); + void cli(void); void sti(void); void hlt(void); @@ -35,63 +42,69 @@ void loop(void); enum cpuid_requests { CPUID_VENDOR_STRING, CPUID_FEATURES, CPUID_TLB, CPUID_SERIAL }; enum cpuid_features { - CPUID_FEAT_ECX_SSE3 = 1 << 0, - CPUID_FEAT_ECX_PCLMUL = 1 << 1, - CPUID_FEAT_ECX_DTES64 = 1 << 2, - CPUID_FEAT_ECX_MONITOR = 1 << 3, - CPUID_FEAT_ECX_DS_CPL = 1 << 4, - CPUID_FEAT_ECX_VMX = 1 << 5, - CPUID_FEAT_ECX_SMX = 1 << 6, - CPUID_FEAT_ECX_EST = 1 << 7, - CPUID_FEAT_ECX_TM2 = 1 << 8, - CPUID_FEAT_ECX_SSSE3 = 1 << 9, - CPUID_FEAT_ECX_CID = 1 << 10, - CPUID_FEAT_ECX_FMA = 1 << 12, - CPUID_FEAT_ECX_CX16 = 1 << 13, - CPUID_FEAT_ECX_ETPRD = 1 << 14, - CPUID_FEAT_ECX_PDCM = 1 << 15, - CPUID_FEAT_ECX_PCIDE = 1 << 17, - CPUID_FEAT_ECX_DCA = 1 << 18, - CPUID_FEAT_ECX_SSE4_1 = 1 << 19, - CPUID_FEAT_ECX_SSE4_2 = 1 << 20, - CPUID_FEAT_ECX_x2APIC = 1 << 21, - CPUID_FEAT_ECX_MOVBE = 1 << 22, - CPUID_FEAT_ECX_POPCNT = 1 << 23, - CPUID_FEAT_ECX_AES = 1 << 25, - CPUID_FEAT_ECX_XSAVE = 1 << 26, - CPUID_FEAT_ECX_OSXSAVE = 1 << 27, - CPUID_FEAT_ECX_AVX = 1 << 28, + CPUID_FEAT_ECX_SSE3 = 1u << 0, + CPUID_FEAT_ECX_PCLMUL = 1u << 1, + CPUID_FEAT_ECX_DTES64 = 1u << 2, + CPUID_FEAT_ECX_MONITOR = 1u << 3, + CPUID_FEAT_ECX_DS_CPL = 1u << 4, + CPUID_FEAT_ECX_VMX = 1u << 5, + CPUID_FEAT_ECX_SMX = 1u << 6, + CPUID_FEAT_ECX_EST = 1u << 7, + CPUID_FEAT_ECX_TM2 = 1u << 8, + CPUID_FEAT_ECX_SSSE3 = 1u << 9, + CPUID_FEAT_ECX_CID = 1u << 10, + CPUID_FEAT_ECX_FMA = 1u << 12, + CPUID_FEAT_ECX_CX16 = 1u << 13, + CPUID_FEAT_ECX_ETPRD = 1u << 14, + CPUID_FEAT_ECX_PDCM = 1u << 15, + CPUID_FEAT_ECX_PCIDE = 1u << 17, + CPUID_FEAT_ECX_DCA = 1u << 18, + CPUID_FEAT_ECX_SSE4_1 = 1u << 19, + CPUID_FEAT_ECX_SSE4_2 = 1u << 20, + CPUID_FEAT_ECX_x2APIC = 1u << 21, + CPUID_FEAT_ECX_MOVBE = 1u << 22, + CPUID_FEAT_ECX_POPCNT = 1u << 23, + CPUID_FEAT_ECX_AES = 1u << 25, + CPUID_FEAT_ECX_XSAVE = 1u << 26, + CPUID_FEAT_ECX_OSXSAVE = 1u << 27, + CPUID_FEAT_ECX_AVX = 1u << 28, + CPUID_FEAT_ECX_F16C = 1u << 29, + CPUID_FEAT_ECX_RDRND = 1u << 30, - CPUID_FEAT_EDX_FPU = 1 << 0, - CPUID_FEAT_EDX_VME = 1 << 1, - CPUID_FEAT_EDX_DE = 1 << 2, - CPUID_FEAT_EDX_PSE = 1 << 3, - CPUID_FEAT_EDX_TSC = 1 << 4, - CPUID_FEAT_EDX_MSR = 1 << 5, - CPUID_FEAT_EDX_PAE = 1 << 6, - CPUID_FEAT_EDX_MCE = 1 << 7, - CPUID_FEAT_EDX_CX8 = 1 << 8, - CPUID_FEAT_EDX_APIC = 1 << 9, - CPUID_FEAT_EDX_SEP = 1 << 11, - CPUID_FEAT_EDX_MTRR = 1 << 12, - CPUID_FEAT_EDX_PGE = 1 << 13, - CPUID_FEAT_EDX_MCA = 1 << 14, - CPUID_FEAT_EDX_CMOV = 1 << 15, - CPUID_FEAT_EDX_PAT = 1 << 16, - CPUID_FEAT_EDX_PSE36 = 1 << 17, - CPUID_FEAT_EDX_PSN = 1 << 18, - CPUID_FEAT_EDX_CLF = 1 << 19, - CPUID_FEAT_EDX_DTES = 1 << 21, - CPUID_FEAT_EDX_ACPI = 1 << 22, - CPUID_FEAT_EDX_MMX = 1 << 23, - CPUID_FEAT_EDX_FXSR = 1 << 24, - CPUID_FEAT_EDX_SSE = 1 << 25, - CPUID_FEAT_EDX_SSE2 = 1 << 26, - CPUID_FEAT_EDX_SS = 1 << 27, - CPUID_FEAT_EDX_HTT = 1 << 28, - CPUID_FEAT_EDX_TM1 = 1 << 29, - CPUID_FEAT_EDX_IA64 = 1 << 30, + CPUID_FEAT_EDX_FPU = 1u << 0, + CPUID_FEAT_EDX_VME = 1u << 1, + CPUID_FEAT_EDX_DE = 1u << 2, + CPUID_FEAT_EDX_PSE = 1u << 3, + CPUID_FEAT_EDX_TSC = 1u << 4, + CPUID_FEAT_EDX_MSR = 1u << 5, + CPUID_FEAT_EDX_PAE = 1u << 6, + CPUID_FEAT_EDX_MCE = 1u << 7, + CPUID_FEAT_EDX_CX8 = 1u << 8, + CPUID_FEAT_EDX_APIC = 1u << 9, + CPUID_FEAT_EDX_SEP = 1u << 11, + CPUID_FEAT_EDX_MTRR = 1u << 12, + CPUID_FEAT_EDX_PGE = 1u << 13, + CPUID_FEAT_EDX_MCA = 1u << 14, + CPUID_FEAT_EDX_CMOV = 1u << 15, + CPUID_FEAT_EDX_PAT = 1u << 16, + CPUID_FEAT_EDX_PSE36 = 1u << 17, + CPUID_FEAT_EDX_PSN = 1u << 18, + CPUID_FEAT_EDX_CLF = 1u << 19, + CPUID_FEAT_EDX_DTES = 1u << 21, + CPUID_FEAT_EDX_ACPI = 1u << 22, + CPUID_FEAT_EDX_MMX = 1u << 23, + CPUID_FEAT_EDX_FXSR = 1u << 24, + CPUID_FEAT_EDX_SSE = 1u << 25, + CPUID_FEAT_EDX_SSE2 = 1u << 26, + CPUID_FEAT_EDX_SS = 1u << 27, + CPUID_FEAT_EDX_HTT = 1u << 28, + CPUID_FEAT_EDX_TM1 = 1u << 29, + CPUID_FEAT_EDX_IA64 = 1u << 30, }; + +u8 cpu_has_cfeature(enum cpuid_features feature); +u8 cpu_has_dfeature(enum cpuid_features feature); + #endif #endif diff --git a/libc/inc/def.h b/libc/inc/def.h index c8b9dbf..c334fcb 100644 --- a/libc/inc/def.h +++ b/libc/inc/def.h @@ -25,7 +25,13 @@ typedef unsigned long long u64; #define UNUSED(a) ((void)(a)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#define NORETURN __attribute__((noreturn)) #define NO_SANITIZE __attribute__((no_sanitize("undefined"))) +#define PACKED __attribute__((packed)) +#define ALIGNED(align) __attribute__((aligned(align))) #define EOF (-1) #define NULL ((void *)0) diff --git a/libc/inc/ioctl.h b/libc/inc/ioctl.h new file mode 100644 index 0000000..c3eec56 --- /dev/null +++ b/libc/inc/ioctl.h @@ -0,0 +1,11 @@ +// MIT License, Copyright (c) 2021 Marvin Borner + +#ifndef IOCTL +#define IOCTL + +// FB interface +#define IO_FB_GET 0 + +int ioctl_is_awesome; // GCC is not + +#endif diff --git a/libc/inc/mem.h b/libc/inc/mem.h index 6c37844..ec00628 100644 --- a/libc/inc/mem.h +++ b/libc/inc/mem.h @@ -13,7 +13,8 @@ void *realloc(void *ptr, u32 size); void *zalloc(u32 size); #ifdef kernel -void heap_init(u32 start); +#define STACK_START 0x00500000 // Defined it bootloader +#define STACK_SIZE 0x1000 // idk #elif defined(userspace) #else #error "No lib target specified. Please use -Dkernel or -Duserspace" diff --git a/libc/inc/print.h b/libc/inc/print.h index 90a715c..58b5dc6 100644 --- a/libc/inc/print.h +++ b/libc/inc/print.h @@ -4,13 +4,14 @@ #define PRINT_H #include "arg.h" +#include <def.h> int printf(const char *format, ...); int vprintf(const char *format, va_list ap); int sprintf(char *str, const char *format, ...); int vsprintf(char *str, const char *format, va_list ap); int print(const char *str); -void panic(const char *format, ...); +NORETURN void panic(const char *format, ...); #ifdef userspace int vfprintf(const char *path, const char *format, va_list ap); @@ -20,6 +21,7 @@ int err(int code, const char *format, ...); #else #include <proc.h> int print_app(enum stream_defaults id, const char *proc_name, const char *str); +void print_trace(u32 count); #endif #endif diff --git a/libc/inc/random.h b/libc/inc/random.h index 59add9b..a82524c 100644 --- a/libc/inc/random.h +++ b/libc/inc/random.h @@ -6,6 +6,8 @@ #include <def.h> void srand(u32 seed); +u32 rdrand(void); +u32 rdseed(void); u32 rand(void); char *randstr(u32 size); diff --git a/libc/inc/sys.h b/libc/inc/sys.h index 5858579..8add0de 100644 --- a/libc/inc/sys.h +++ b/libc/inc/sys.h @@ -9,16 +9,22 @@ #define KEYBOARD_MAGIC 0x555555 #define MOUSE_MAGIC 0xaaaaaa +#define SYS_BOOT_MAGIC 0x18122002 +#define SYS_BOOT_REBOOT 0xeeb007 +#define SYS_BOOT_SHUTDOWN 0xdead + enum sys { SYS_LOOP, // To infinity and beyond (debug)! - SYS_MALLOC, // Allocate memory + SYS_ALLOC, // Allocate memory SYS_FREE, // Free memory SYS_STAT, // Get file information SYS_READ, // Read file SYS_WRITE, // Write to file + SYS_IOCTL, // Interact with a file/device SYS_POLL, // Wait for multiple files SYS_EXEC, // Execute path - SYS_EXIT, // Exit current process // TODO: Free all memory of process + SYS_EXIT, // Exit current process + SYS_BOOT, // Boot functions (e.g. reboot/shutdown) SYS_YIELD, // Switch to next process SYS_TIME, // Get kernel time SYS_NET_OPEN, // Open network socket @@ -70,6 +76,7 @@ int sysv(enum sys num, ...); (s32) sys4(SYS_READ, (int)(path), (int)(buf), (int)(offset), (int)(count)) #define write(path, buf, offset, count) \ (s32) sys4(SYS_WRITE, (int)(path), (int)(buf), (int)(offset), (int)(count)) +#define ioctl(path, ...) (s32) sysv(SYS_IOCTL, (int)(path), ##__VA_ARGS__) #define stat(path, stat) (s32) sys2(SYS_STAT, (int)(path), (int)(stat)) #define poll(files) (s32) sys1(SYS_POLL, (int)(files)) #define exec(path, ...) (s32) sysv(SYS_EXEC, (int)(path), ##__VA_ARGS__) @@ -80,12 +87,15 @@ int sysv(enum sys num, ...); yield(); \ } \ } -#define yield(void) (int)sys0(SYS_YIELD) +#define boot(cmd) (s32) sys2(SYS_BOOT, SYS_BOOT_MAGIC, cmd) +#define yield(void) (s32) sys0(SYS_YIELD) #define time(void) (u32) sys0(SYS_TIME) static inline u32 getpid(void) { - u32 buf = 0; + static u32 buf = 0; + if (buf) + return buf; read("/proc/self/pid", &buf, 0, sizeof(buf)); return buf; } @@ -66,12 +66,13 @@ void *memcpy(void *dest, const void *src, u32 n) void *memset(void *dest, int val, u32 n) { + u32 uval = val; u32 num_dwords = n / 4; u32 num_bytes = n % 4; u32 *dest32 = (u32 *)dest; u8 *dest8 = ((u8 *)dest) + num_dwords * 4; u8 val8 = (u8)val; - u32 val32 = val | (val << 8) | (val << 16) | (val << 24); + u32 val32 = uval | (uval << 8) | (uval << 16) | (uval << 24); // TODO: What's faster? __asm__ volatile("rep stosl\n" @@ -118,351 +119,3 @@ int mememp(const u8 *buf, u32 n) { return buf[0] == 0 && !memcmp(buf, buf + 1, n - 1); } - -/** - * Heap allocator - * Inspired by SHMALL (MIT License) - * Copyright (c) 2017 Chris Careaga - * Copyright (c) 2021 Marvin Borner - */ - -#ifdef kernel - -#define HEAP_MAGIC 0x424242 -#define HEAP_INIT_SIZE 0xf000000 -#define HEAP_MIN_SIZE HEAP_INIT_SIZE -#define MIN_ALLOC_SZ 4 -#define BIN_COUNT 9 -#define BIN_MAX_IDX (BIN_COUNT - 1) -#define OVERHEAD (sizeof(struct h_footer) + sizeof(struct h_node)) -/* #define MIN_WILDERNESS 0x2000 */ -/* #define MAX_WILDERNESS 0x1000000 */ - -struct h_node { - u32 magic; - u32 hole; - u32 size; - struct h_node *next; - struct h_node *prev; -}; - -struct h_footer { - struct h_node *header; -}; - -struct h_bin { - struct h_node *head; -}; - -struct heap { - u32 start; - u32 end; - struct h_bin bins[BIN_COUNT]; -}; - -static void node_add(struct h_bin *bin, struct h_node *node) -{ - node->magic = HEAP_MAGIC; - node->next = NULL; - node->prev = NULL; - if (!bin->head) { - bin->head = node; - return; - } - struct h_node *curr = bin->head; - struct h_node *prev = NULL; - while (curr && curr->size <= node->size) { - prev = curr; - curr = curr->next; - } - if (!curr) { - prev->next = node; - node->prev = prev; - } else if (prev) { - node->next = curr; - prev->next = node; - node->prev = prev; - curr->prev = node; - } else { - node->next = bin->head; - bin->head->prev = node; - bin->head = node; - } -} - -static void node_remove(struct h_bin *bin, struct h_node *node) -{ - if (!bin->head) - return; - if (bin->head == node) { - bin->head = bin->head->next; - return; - } - - struct h_node *temp = bin->head->next; - while (temp) { - if (temp == node) { - if (!temp->next) { - temp->prev->next = NULL; - } else { - temp->prev->next = temp->next; - temp->next->prev = temp->prev; - } - return; - } - temp = temp->next; - } -} - -static struct h_node *node_best_fit(struct h_bin *bin, u32 size) -{ - if (!bin->head) - return NULL; - - struct h_node *temp = bin->head; - while (temp) { - if (temp->size >= size) - return temp; - temp = temp->next; - } - return NULL; -} - -/* static struct h_node *node_last(struct h_bin *bin) */ -/* { */ -/* struct h_node *temp = bin->head; */ -/* while (temp->next) */ -/* temp = temp->next; */ -/* return temp; */ -/* } */ - -static struct h_footer *node_foot(struct h_node *node) -{ - return (struct h_footer *)((char *)node + sizeof(*node) + node->size); -} - -static void node_create_foot(struct h_node *head) -{ - struct h_footer *foot = node_foot(head); - foot->header = head; -} - -static u32 bin_index(u32 sz) -{ - u32 index = 0; - sz = sz < 4 ? 4 : sz; - while (sz >>= 1) - index++; - index -= 2; - if (index > BIN_MAX_IDX) - index = BIN_MAX_IDX; - return index; -} - -/* struct h_node *wilderness_get(struct heap *heap) */ -/* { */ -/* struct h_footer *wild_foot = (struct h_footer *)((char *)heap->end - sizeof(*wild_foot)); */ -/* return wild_foot->header; */ -/* } */ - -/* static u32 expand(struct heap *heap, u32 sz) */ -/* { */ -/* (void)heap; */ -/* (void)sz; */ -/* return 0; */ -/* } */ - -/* static u32 contract(struct heap *heap, u32 sz) */ -/* { */ -/* (void)heap; */ -/* (void)sz; */ -/* return 0; */ -/* } */ - -static struct heap heap = { 0 }; -void heap_init(u32 start) -{ - struct h_node *init_region = (struct h_node *)start; - init_region->hole = 1; - init_region->size = HEAP_INIT_SIZE - OVERHEAD; - node_create_foot(init_region); - node_add(&heap.bins[bin_index(init_region->size)], init_region); - heap.start = (u32)start; - heap.end = (u32)start + HEAP_INIT_SIZE; -} - -#define ALIGN sizeof(long) -static void *_malloc(u32 size) -{ - size = ((size + ALIGN - 1) / ALIGN) * ALIGN; // Alignment - u32 index = bin_index(size); - struct h_bin *temp = (struct h_bin *)&heap.bins[index]; - struct h_node *found = node_best_fit(temp, size); - - while (!found) { - assert(index + 1 < BIN_COUNT); - - temp = &heap.bins[++index]; - found = node_best_fit(temp, size); - } - - assert(found->magic == HEAP_MAGIC); - - if ((found->size - size) > (OVERHEAD + MIN_ALLOC_SZ)) { - struct h_node *split = (struct h_node *)(((char *)found + OVERHEAD) + size); - split->magic = HEAP_MAGIC; - split->size = found->size - size - OVERHEAD; - split->hole = 1; - - node_create_foot(split); - - u32 new_idx = bin_index(split->size); - - node_add(&heap.bins[new_idx], split); - - found->size = size; - node_create_foot(found); - } - - found->hole = 0; - node_remove(&heap.bins[index], found); - - // TODO: Implement expand/contract - /* struct h_node *wild = wilderness_get(&heap); */ - /* if (wild->size < MIN_WILDERNESS) { */ - /* assert(expand(&heap, 0x1000)); */ - /* } else if (wild->size > MAX_WILDERNESS) { */ - /* assert(contract(&heap, 0x1000)); */ - /* } */ - - found->prev = NULL; - found->next = NULL; - return &found->next; -} - -static void _free(void *p) -{ - if (!p) - return; - - struct h_bin *list; - struct h_footer *new_foot, *old_foot; - - struct h_node *head = (struct h_node *)((char *)p - 12); - assert(head->magic == HEAP_MAGIC && head->hole == 0); - if (head == (struct h_node *)(u32 *)heap.start) { - head->hole = 1; - node_add(&heap.bins[bin_index(head->size)], head); - return; - } - - struct h_node *next = (struct h_node *)((char *)node_foot(head) + sizeof(struct h_footer)); - struct h_footer *f = (struct h_footer *)((char *)head - sizeof(struct h_footer)); - struct h_node *prev = f->header; - - if (prev->hole) { - list = &heap.bins[bin_index(prev->size)]; - node_remove(list, prev); - - prev->size += OVERHEAD + head->size; - new_foot = node_foot(head); - new_foot->header = prev; - - head = prev; - } - - if (next->hole) { - list = &heap.bins[bin_index(next->size)]; - node_remove(list, next); - - head->size += OVERHEAD + next->size; - - old_foot = node_foot(next); - old_foot->header = 0; - next->size = 0; - next->hole = 0; - - new_foot = node_foot(head); - new_foot->header = head; - } - - head->hole = 1; - node_add(&heap.bins[bin_index(head->size)], head); -} - -#elif defined(userspace) - -#define kmalloc(n) (void *)sys1(SYS_MALLOC, n) -#define kfree(ptr) (void)(sys1(SYS_FREE, (int)ptr)) - -static void *_malloc(u32 size) -{ - return kmalloc(size); -} - -static void _free(void *ptr) -{ - kfree(ptr); -} - -#endif - -#ifdef kernel -#define PREFIX "K" -#define FUNC printf -#else -#define PREFIX "U" -#define FUNC log -#endif - -void *zalloc(u32 size) -{ - void *ret = malloc(size); - memset(ret, 0, size); - return ret; -} - -// Naive realloc implementation - TODO! -void *realloc(void *ptr, u32 size) -{ - if (!ptr) - return malloc(size); - - FUNC("Realloc not implemented!\n"); - return NULL; - /* // This could work; untested - struct h_node *node = (struct h_node *)((char *)ptr - 12); - u32 old_size = node->size; - - void *new = malloc(size); - memcpy(new, ptr, old_size); - - free(ptr); - return new; - */ -} - -void *malloc_debug(u32 size, const char *file, int line, const char *func, const char *inp) -{ - assert(size < (100 << 20)); // Don't brag with memory pls - void *ret = _malloc(size); - - (void)file; - (void)line; - (void)func; - (void)inp; - /* FUNC(PREFIX "MALLOC\t%s:%d: %s: 0x%x %dB (%s)\n", file, line, func, ret, size, inp); */ - return ret; -} - -void free_debug(void *ptr, const char *file, int line, const char *func, const char *inp) -{ - if (ptr) - _free(ptr); - - (void)file; - (void)line; - (void)func; - (void)inp; - /* FUNC(PREFIX "FREE\t%s:%d: %s: 0x%x (%s)\n", file, line, func, ptr, inp); */ -} diff --git a/libc/print.c b/libc/print.c index 91ecf8f..1c577e5 100644 --- a/libc/print.c +++ b/libc/print.c @@ -214,9 +214,23 @@ int print(const char *str) return strlen(str); } +void print_trace(u32 count) +{ + struct frame { + struct frame *ebp; + u32 eip; + } * stk; + __asm__ volatile("movl %%ebp, %0;" : "=r"(stk)); + print("EBP\tEIP\n"); + for (u32 i = 0; stk && i < count; i++) { + printf("0x%x\t0x%x\n", stk->ebp, stk->eip); + stk = stk->ebp; + } +} + #endif -void panic(const char *format, ...) +NORETURN void panic(const char *format, ...) { char buf[1024] = { 0 }; va_list ap; @@ -224,6 +238,7 @@ void panic(const char *format, ...) vsprintf(buf, format, ap); va_end(ap); #ifdef kernel + print("--- DON'T PANIC! ---\n"); print(buf); loop(); #else diff --git a/libc/random.c b/libc/random.c index 8c8076f..cfd082d 100644 --- a/libc/random.c +++ b/libc/random.c @@ -1,5 +1,6 @@ // MIT License, Copyright (c) 2020 Marvin Borner +#include <cpu.h> #include <def.h> #include <mem.h> #include <random.h> @@ -11,6 +12,34 @@ void srand(u32 seed) g_seed = seed; } +u32 rdrand(void) +{ +#ifdef kernel + if (!cpu_has_cfeature(CPUID_FEAT_ECX_RDRND)) + return rand(); + + u32 rd; + __asm__ volatile("rdrand %%eax" : "=a"(rd)); + return rd; +#else + return rand(); +#endif +} + +u32 rdseed(void) +{ +#ifdef kernel + if (!cpu_has_cfeature(CPUID_FEAT_ECX_RDRND)) + return rand(); + + u32 rd; + __asm__ volatile("rdseed %%eax" : "=a"(rd)); + return rd; +#else + return rand(); +#endif +} + u32 rand(void) { g_seed = g_seed * 1103515245 + 12345; diff --git a/libc/sanitize.c b/libc/sanitize.c index 983b10f..8514e49 100644 --- a/libc/sanitize.c +++ b/libc/sanitize.c @@ -13,13 +13,13 @@ u32 __stack_chk_guard = STACK_CHK_GUARD; void __stack_chk_fail(void); -void __stack_chk_fail(void) +NORETURN void __stack_chk_fail(void) { panic("FATAL: Stack smashing detected\n"); } void __stack_chk_fail_local(void); -void __stack_chk_fail_local(void) +NORETURN void __stack_chk_fail_local(void) { panic("FATAL: Local stack smashing detected\n"); } @@ -97,28 +97,40 @@ void __ubsan_handle_vla_bound_not_positive(void) panic("UBSAN: vla-bound-not-positive\n"); } -void __ubsan_handle_add_overflow(void); -void __ubsan_handle_add_overflow(void) +void __ubsan_handle_add_overflow(struct overflow *data, void *left, void *right); +void __ubsan_handle_add_overflow(struct overflow *data, void *left, void *right) { - panic("UBSAN: add-overflow\n"); + UNUSED(left); + UNUSED(right); + struct source_location *loc = &data->location; + panic("%s:%d: UBSAN: add-overflow [type: %s]\n", loc->file, loc->line, data->type->name); } -void __ubsan_handle_sub_overflow(void); -void __ubsan_handle_sub_overflow(void) +void __ubsan_handle_sub_overflow(struct overflow *data, void *left, void *right); +void __ubsan_handle_sub_overflow(struct overflow *data, void *left, void *right) { - panic("UBSAN: sub-overflow\n"); + UNUSED(left); + UNUSED(right); + struct source_location *loc = &data->location; + panic("%s:%d: UBSAN: sub-overflow [type: %s]\n", loc->file, loc->line, data->type->name); } -void __ubsan_handle_negate_overflow(void); -void __ubsan_handle_negate_overflow(void) +void __ubsan_handle_negate_overflow(struct overflow *data, void *left, void *right); +void __ubsan_handle_negate_overflow(struct overflow *data, void *left, void *right) { - panic("UBSAN: negate-overflow\n"); + UNUSED(left); + UNUSED(right); + struct source_location *loc = &data->location; + panic("%s:%d: UBSAN: negate-overflow [type: %s]\n", loc->file, loc->line, data->type->name); } -void __ubsan_handle_mul_overflow(void); -void __ubsan_handle_mul_overflow(void) +void __ubsan_handle_mul_overflow(struct overflow *data, void *left, void *right); +void __ubsan_handle_mul_overflow(struct overflow *data, void *left, void *right) { - panic("UBSAN: mul-overflow\n"); + UNUSED(left); + UNUSED(right); + struct source_location *loc = &data->location; + panic("%s:%d: UBSAN: mul-overflow [type: %s]\n", loc->file, loc->line, data->type->name); } void __ubsan_handle_shift_out_of_bounds(void); diff --git a/libgui/gfx.c b/libgui/gfx.c index d9457c7..dad8b88 100644 --- a/libgui/gfx.c +++ b/libgui/gfx.c @@ -98,10 +98,11 @@ static void draw_rectangle(struct context *ctx, vec2 pos1, vec2 pos2, u32 c) struct context *gfx_new_ctx(struct context *ctx) { - struct message msg = { 0 }; - assert(msg_send(pidof(WM_PATH), GFX_NEW_CONTEXT, ctx) > 0); - assert(msg_receive(&msg) > 0); - memcpy(ctx, msg.data, sizeof(*ctx)); + /* struct message msg = { 0 }; */ + assert(0); + /* assert(msg_send(pidof(WM_PATH), GFX_NEW_CONTEXT, ctx) > 0); */ + /* assert(msg_receive(&msg) > 0); */ + /* memcpy(ctx, msg.data, sizeof(*ctx)); */ return ctx; } diff --git a/libgui/gui.c b/libgui/gui.c index 2083f23..bc8adb1 100644 --- a/libgui/gui.c +++ b/libgui/gui.c @@ -2,24 +2,30 @@ #include <def.h> #include <gui.h> +#include <msg.h> #include <print.h> #define WM_PATH "/bin/wm" s32 gui_new_window(struct gui_window *win) { - struct message msg = { 0 }; - if (msg_send(pidof(WM_PATH), GUI_NEW_WINDOW, win) > 0 && msg_receive(&msg) > 0 && - msg.type == (GUI_NEW_WINDOW | MSG_SUCCESS)) + struct message_new_window msg = { 0 }; + if (msg_send(pidof(WM_PATH), GUI_NEW_WINDOW, &msg, sizeof(msg)) > 0 && + msg_receive(&msg, sizeof(msg)) > 0 && + msg.header.type == (GUI_NEW_WINDOW | MSG_SUCCESS)) { + win->id = msg.id; + win->ctx = msg.ctx; return win->id; + } return -1; } s32 gui_redraw_window(u32 id) { - struct message msg = { 0 }; - if (msg_send(pidof(WM_PATH), GUI_REDRAW_WINDOW, &id) > 0 && msg_receive(&msg) > 0 && - msg.type == (GUI_REDRAW_WINDOW | MSG_SUCCESS)) + struct message_redraw_window msg = { .id = id }; + if (msg_send(pidof(WM_PATH), GUI_REDRAW_WINDOW, &msg, sizeof(msg)) > 0 && + msg_receive(&msg, sizeof(msg)) > 0 && + msg.header.type == (GUI_REDRAW_WINDOW | MSG_SUCCESS)) return id; return -1; } diff --git a/libgui/inc/gfx.h b/libgui/inc/gfx.h index 4a358ca..f3555a4 100644 --- a/libgui/inc/gfx.h +++ b/libgui/inc/gfx.h @@ -5,7 +5,6 @@ #define GFX_H #include <def.h> -#include <msg.h> #include <sys.h> #include <vec.h> #include <vesa.h> @@ -82,8 +81,8 @@ int gfx_font_width(enum font_type); * Wrappers */ -#define gfx_redraw() \ - (msg_send(pidof(WM_PATH), GFX_REDRAW, NULL)) // TODO: Partial redraw (optimization) -#define gfx_redraw_focused() (msg_send(pidof(WM_PATH), GFX_REDRAW_FOCUSED, NULL)) +/* #define gfx_redraw() \ */ +/* (msg_send(pidof(WM_PATH), GFX_REDRAW, NULL)) // TODO: Partial redraw (optimization) */ +/* #define gfx_redraw_focused() (msg_send(pidof(WM_PATH), GFX_REDRAW_FOCUSED, NULL)) */ #endif diff --git a/libgui/inc/gui.h b/libgui/inc/gui.h index 460bf88..d160333 100644 --- a/libgui/inc/gui.h +++ b/libgui/inc/gui.h @@ -8,8 +8,7 @@ struct gui_window { u32 id; - struct context *ctx; - vec2 *pos; + struct context ctx; }; s32 gui_new_window(struct gui_window *win); diff --git a/libgui/inc/msg.h b/libgui/inc/msg.h index db00460..7cbfa2c 100644 --- a/libgui/inc/msg.h +++ b/libgui/inc/msg.h @@ -4,16 +4,28 @@ #define MSG_H #include <def.h> +#include <gfx.h> #define MSG_MAGIC 0x42042069 #define MSG_SUCCESS (1 << 29) #define MSG_FAILURE (1 << 30) -struct message { +struct message_header { u32 magic; - int src; - int type; - void *data; + u32 src; + u32 type; + u32 size; +}; + +struct message_new_window { + struct message_header header; + u32 id; + struct context ctx; +}; + +struct message_redraw_window { + struct message_header header; + u32 id; }; enum message_type { @@ -32,7 +44,7 @@ enum message_type { GUI_MAX }; -int msg_send(u32 pid, enum message_type, void *data); -int msg_receive(struct message *msg); +int msg_send(u32 pid, enum message_type type, void *data, u32 size); +int msg_receive(void *buf, u32 size); #endif diff --git a/libgui/msg.c b/libgui/msg.c index 8448e73..3f58267 100644 --- a/libgui/msg.c +++ b/libgui/msg.c @@ -5,23 +5,23 @@ #include <print.h> #include <sys.h> -int msg_send(u32 pid, enum message_type type, void *data) +int msg_send(u32 pid, enum message_type type, void *data, u32 size) { - struct message msg = { 0 }; - assert((signed)pid != -1); + assert((signed)pid != -1 && size >= sizeof(struct message_header)); char path[32] = { 0 }; sprintf(path, "/proc/%d/msg", pid); - msg.magic = MSG_MAGIC; - msg.src = getpid(); - msg.type = type; - msg.data = data; - return write(path, &msg, 0, sizeof(msg)); + struct message_header *header = data; + header->magic = MSG_MAGIC; + header->src = getpid(); + header->type = type; + return write(path, data, 0, size); } -int msg_receive(struct message *msg) +int msg_receive(void *buf, u32 size) { - int ret = read("/proc/self/msg", msg, 0, sizeof(*msg)); - if (msg->magic == MSG_MAGIC && ret == sizeof(*msg)) + int ret = read("/proc/self/msg", buf, 0, size); + struct message_header *header = buf; + if (header->magic == MSG_MAGIC) return ret; else return -1; @@ -26,7 +26,7 @@ no_ask="${2}" # TODO: Support -enable-kvm: GPF?! qemu_with_flags() { network="rtl8139" - qemu-system-i386 -cpu max -no-reboot -vga std -rtc base=localtime -m 256M -netdev user,id=net0,hostfwd=tcp:127.0.0.1:8000-10.0.2.15:8000 -device $network,netdev=net0 -object filter-dump,id=dump,netdev=net0,file=dump.pcap "$@" + qemu-system-i386 -d guest_errors -cpu max -no-reboot -vga std -rtc base=localtime -m 256M -netdev user,id=net0,hostfwd=tcp:127.0.0.1:8000-10.0.2.15:8000 -device $network,netdev=net0 -object filter-dump,id=dump,netdev=net0,file=dump.pcap "$@" } make_cross() { @@ -126,7 +126,7 @@ make_build() { $SUDO dd if=build/boot.bin of=/dev/${VND}i conv=notrunc status=none else - $SUDO mke2fs -q build/disk.img + $SUDO mke2fs -b 1024 -q build/disk.img dd if=build/boot.bin of=build/disk.img conv=notrunc status=none fi @@ -186,7 +186,11 @@ make_addr() { echo "Usage: './run addr kernel 0x50042'" exit 1 fi - addr2line -e build/"$1".elf "$2" + addr2line -e build/"$1".elf -f -p "$2" +} + +make_cloc() { + cloc . --exclude-dir=build,iso,disk,res,cross } make_append_commands() { @@ -239,6 +243,8 @@ elif [ "${mode}" = "disasm" ]; then make_disasm "$2" "$3" elif [ "${mode}" = "addr" ]; then make_addr "$2" "$3" +elif [ "${mode}" = "cloc" ]; then + make_cloc elif [ "${mode}" = "sync" ]; then make_sync elif [ "${mode}" = "disk" ]; then @@ -267,6 +273,7 @@ else printf "again\t\tOpens QEMU again using the previous build\n" printf "disasm\t\tDisassembles a given part of Melvix\n" printf "addr\t\tResolves an address to a line of code\n" + printf "cloc\t\tCount the total lines of code\n" printf "sync\t\tSyncs the 'tags' and 'compile_commands.json' file\n" printf "disk\t\tPrepares the userspace disk (e.g. fonts)\n" printf "*\t\tAnything else prints this help\n" |