├── screenshot.png ├── src ├── fs │ ├── fs.h │ ├── fs.c │ └── devfs │ │ └── devfs.h ├── lib │ ├── bitmap_font.fnt │ ├── bitmap_font.asm │ ├── asm_macros.inc │ ├── part.h │ ├── cmdline.h │ ├── qemu.h │ ├── alloc.h │ ├── bitmap_font.h │ ├── cstring.h │ ├── cmem.h │ ├── types.h │ ├── endian.h │ ├── qemu.c │ ├── cmdline.c │ ├── rand.h │ ├── scsi.h │ ├── time.h │ ├── bit.h │ ├── cstring.c │ ├── cmem.c │ ├── time.c │ ├── klib.h │ ├── alloc.c │ ├── event.h │ ├── signal.h │ ├── rand.c │ ├── errno.h │ ├── cio.h │ ├── dynarray.h │ ├── lock.h │ └── ht.h ├── devices │ ├── dev.h │ ├── storage │ │ └── nvme │ │ │ └── nvme.h │ ├── usb │ │ ├── mass_storage.h │ │ └── mass_storage.c │ ├── display │ │ └── vbe │ │ │ ├── vbe.h │ │ │ └── vbe.c │ ├── dev.c │ ├── streams │ │ └── streams.c │ └── term │ │ └── tty │ │ ├── tty.h │ │ └── tty.c ├── fd │ ├── pipe │ │ ├── pipe.h │ │ └── pipe.c │ ├── socket │ │ └── socket.h.ignore │ ├── vfs │ │ └── vfs.h │ ├── fd.h │ └── fd.c ├── sys │ ├── gdt.h │ ├── pic.h │ ├── hpet.h │ ├── pit.h │ ├── smp.h │ ├── idt.h │ ├── trace.h │ ├── pic_8259.h │ ├── ipi.h │ ├── urm.h │ ├── pic.c │ ├── panic.h │ ├── pit.c │ ├── exceptions.h │ ├── apic.h │ ├── trace.c │ ├── isrs.h │ ├── smp.asm │ ├── pic_8259.c │ ├── exceptions.c │ ├── pci.h │ ├── smp_trampoline.real │ ├── cpu.c │ ├── panic.c │ ├── hpet.c │ ├── gdt.c │ ├── cpu.h │ ├── idt.c │ ├── smp.c │ ├── apic.c │ └── urm.c ├── net │ ├── hostname.h │ └── hostname.c ├── symlist.h ├── startup │ ├── header.asm │ └── stivale.h ├── linker.ld ├── acpi │ ├── acpi.h │ ├── madt.h │ ├── madt.c │ └── acpi.c ├── mm │ ├── mm.h │ └── pmm.c ├── proc │ ├── elf.h │ ├── task.asm │ ├── task.h │ ├── elf.c │ └── userspace.c ├── usb │ ├── usb.h │ └── usb.c └── main.c ├── run └── limine.cfg ├── .gitignore ├── .clang-format ├── AUTHORS.md ├── gensyms.sh ├── LICENSE ├── README.md └── Makefile /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qword-os/qword/HEAD/screenshot.png -------------------------------------------------------------------------------- /src/fs/fs.h: -------------------------------------------------------------------------------- 1 | #ifndef __FS_H__ 2 | #define __FS_H__ 3 | 4 | void init_fs(void); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/lib/bitmap_font.fnt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qword-os/qword/HEAD/src/lib/bitmap_font.fnt -------------------------------------------------------------------------------- /src/devices/dev.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEV_H__ 2 | #define __DEV_H__ 3 | 4 | void init_dev(void); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/fd/pipe/pipe.h: -------------------------------------------------------------------------------- 1 | #ifndef __PIPE_H__ 2 | #define __PIPE_H__ 3 | 4 | int pipe(int *); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/sys/gdt.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | void init_gdt(void); 6 | void load_tss(size_t addr); 7 | -------------------------------------------------------------------------------- /src/devices/storage/nvme/nvme.h: -------------------------------------------------------------------------------- 1 | #ifndef __NVME_H__ 2 | #define __NVME_H__ 3 | 4 | void init_dev_nvme(void); 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /src/lib/bitmap_font.asm: -------------------------------------------------------------------------------- 1 | global bitmap_font 2 | 3 | section .data 4 | align 8 5 | bitmap_font: incbin "lib/bitmap_font.fnt" 6 | -------------------------------------------------------------------------------- /src/sys/pic.h: -------------------------------------------------------------------------------- 1 | #ifndef __PIC_H__ 2 | #define __PIC_H__ 3 | 4 | #include 5 | 6 | void init_pic(void); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /run/limine.cfg: -------------------------------------------------------------------------------- 1 | TIMEOUT=0 2 | :Qword 3 | KERNEL_PARTITION=0 4 | KERNEL_PATH=qword.elf 5 | KERNEL_PROTO=stivale 6 | KERNEL_CMDLINE=none 7 | -------------------------------------------------------------------------------- /src/sys/hpet.h: -------------------------------------------------------------------------------- 1 | #ifndef __HPET_H__ 2 | #define __HPET_H__ 3 | 4 | #define HPET_FREQUENCY_HZ 1000 5 | 6 | void init_hpet(void); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/sys/pit.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS__PIT_H__ 2 | #define __SYS__PIT_H__ 3 | 4 | #define PIT_FREQUENCY_HZ 1000 5 | 6 | int init_pit(void); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/lib/asm_macros.inc: -------------------------------------------------------------------------------- 1 | %ifndef __LIB__ASM_MACROS_INC__ 2 | %define __LIB__ASM_MACROS_INC__ 3 | 4 | %define kernel_phys_offset 0xffffffff80000000 5 | 6 | %endif 7 | -------------------------------------------------------------------------------- /src/lib/part.h: -------------------------------------------------------------------------------- 1 | #ifndef __PART_H__ 2 | #define __PART_H__ 3 | 4 | #include 5 | 6 | int enum_partitions(const char *, struct device_t *); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/sys/smp.h: -------------------------------------------------------------------------------- 1 | #ifndef __SMP_H__ 2 | #define __SMP_H__ 3 | 4 | void init_smp(void); 5 | 6 | extern int smp_cpu_count; 7 | extern int smp_ready; 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /**/*.o 2 | /**/*.bin 3 | /**/*.d 4 | qword.bin 5 | qword.elf 6 | src/acpi/lai 7 | symlist.gen 8 | limine 9 | 10 | # IDE related 11 | .idea 12 | CMake* 13 | cmake* 14 | -------------------------------------------------------------------------------- /src/lib/cmdline.h: -------------------------------------------------------------------------------- 1 | #ifndef __CMDLINE_H__ 2 | #define __CMDLINE_H__ 3 | 4 | void init_cmdline(const char *cmd); 5 | char *cmdline_get_value(char *buf, size_t limit, const char *key); 6 | 7 | #endif 8 | -------------------------------------------------------------------------------- /src/lib/qemu.h: -------------------------------------------------------------------------------- 1 | #ifndef __QEMU_H__ 2 | #define __QEMU_H__ 3 | 4 | void qemu_debug_puts(const char *); 5 | void qemu_debug_putc(char); 6 | void qemu_debug_puts_urgent(const char *); 7 | 8 | #endif 9 | -------------------------------------------------------------------------------- /src/net/hostname.h: -------------------------------------------------------------------------------- 1 | #ifndef __HOSTNAME_H__ 2 | #define __HOSTNAME_H__ 3 | 4 | #define MAX_HOSTNAME_LEN 256 5 | 6 | extern char hostname[MAX_HOSTNAME_LEN]; 7 | 8 | void init_hostname(void); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/sys/idt.h: -------------------------------------------------------------------------------- 1 | #ifndef __IDT_H__ 2 | #define __IDT_H__ 3 | 4 | #include 5 | 6 | extern event_t int_event[256]; 7 | 8 | void init_idt(void); 9 | int get_empty_int_vector(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/sys/trace.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS__TRACE_H__ 2 | #define __SYS__TRACE_H__ 3 | 4 | #include 5 | 6 | char *trace_address(size_t *off, size_t addr); 7 | void print_stacktrace(int type); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/lib/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef __ALLOC_H__ 2 | #define __ALLOC_H__ 3 | 4 | #include 5 | 6 | void init_alloc(void); 7 | void *kalloc(size_t); 8 | void kfree(void *); 9 | void *krealloc(void *, size_t); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/symlist.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYMLIST_H__ 2 | #define __SYMLIST_H__ 3 | 4 | #include 5 | 6 | struct symlist_t { 7 | size_t addr; 8 | char *name; 9 | }; 10 | 11 | extern struct symlist_t symlist[]; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/devices/usb/mass_storage.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_MASS_STORAGE_H__ 2 | #define __USB_MASS_STORAGE_H__ 3 | 4 | #include 5 | 6 | int init_mass_storage(struct usb_dev_t *device, 7 | struct usb_endpoint_t *endpoints); 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /src/sys/pic_8259.h: -------------------------------------------------------------------------------- 1 | #ifndef __PIC_8259_H__ 2 | #define __PIC_8259_H__ 3 | 4 | #include 5 | 6 | void pic_8259_eoi(uint8_t); 7 | void pic_8259_remap(uint8_t, uint8_t); 8 | void pic_8259_set_mask(uint8_t, int); 9 | void pic_8259_mask_all(void); 10 | 11 | #endif 12 | -------------------------------------------------------------------------------- /src/sys/ipi.h: -------------------------------------------------------------------------------- 1 | #ifndef __IPI_H__ 2 | #define __IPI_H__ 3 | 4 | #define IPI_BASE 0x40 5 | #define IPI_ABORT (IPI_BASE + 0) 6 | #define IPI_RESCHED (IPI_BASE + 1) 7 | #define IPI_ABORTEXEC (IPI_BASE + 2) 8 | 9 | void ipi_abort(void); 10 | void ipi_resched(void); 11 | void ipi_abortexec(void); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/sys/urm.h: -------------------------------------------------------------------------------- 1 | #ifndef __URM_H__ 2 | #define __URM_H__ 3 | 4 | #include 5 | #include 6 | 7 | void execve_send_request(pid_t, tid_t, const char *, const char **, const char **, event_t **, int **); 8 | void exit_send_request(pid_t, int, int); 9 | void userspace_request_monitor(void *); 10 | 11 | #define WNOHANG 2 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/devices/display/vbe/vbe.h: -------------------------------------------------------------------------------- 1 | #ifndef __VBE_H__ 2 | #define __VBE_H__ 3 | 4 | #include 5 | #include 6 | 7 | extern int vbe_available; 8 | 9 | extern uint32_t *vbe_framebuffer; 10 | extern int vbe_width; 11 | extern int vbe_height; 12 | extern int vbe_pitch; 13 | 14 | void init_vbe(struct stivale_framebuffer_t *); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/lib/bitmap_font.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIB__BITMAP_FONT_H__ 2 | #define __LIB__BITMAP_FONT_H__ 3 | 4 | #include 5 | 6 | #define bitmap_font_width 8 7 | #define bitmap_font_height 16 8 | #define bitmap_font_glyphs 256 9 | #define bitmap_font_max (bitmap_font_height * bitmap_font_glyphs) 10 | 11 | extern uint8_t bitmap_font[bitmap_font_max]; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/sys/pic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void init_pic(void) { 8 | if (apic_supported()) { 9 | pic_8259_remap(0xa0, 0xa8); 10 | pic_8259_mask_all(); 11 | init_apic(); 12 | } else { 13 | panic(NULL, 0, "APIC not available"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/lib/cstring.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIB__CSTRING_H__ 2 | #define __LIB__CSTRING_H__ 3 | 4 | #include 5 | 6 | char *strchrnul(const char *s, int c); 7 | char *strcpy(char *dest, const char *src); 8 | char *strncpy(char *dest, const char *src, size_t n); 9 | int strcmp(const char *s1, const char *s2); 10 | int strncmp(const char *s1, const char *s2, size_t n); 11 | size_t strlen(const char *str); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | BasedOnStyle: LLVM 3 | AccessModifierOffset: '0' 4 | AlignConsecutiveMacros: 'true' 5 | AlignEscapedNewlines: Left 6 | AlignOperands: 'true' 7 | AlignTrailingComments: 'true' 8 | IndentCaseLabels: 'true' 9 | IndentWidth: '4' 10 | Language: Cpp 11 | SpaceBeforeParens: ControlStatements 12 | SpacesInCStyleCastParentheses: 'false' 13 | SpacesInSquareBrackets: 'false' 14 | TabWidth: '4' 15 | UseTab: Never 16 | 17 | ... 18 | -------------------------------------------------------------------------------- /src/lib/cmem.h: -------------------------------------------------------------------------------- 1 | #ifndef __LIB__CMEM_H__ 2 | #define __LIB__CMEM_H__ 3 | 4 | #include 5 | 6 | void *memcpy(void *dest, const void *src, size_t n); 7 | void *memcpy64(void *dest, const void *src, size_t n); 8 | void *memset(void *s, int c, size_t n); 9 | void *memset64(void *s, uint64_t c, size_t n); 10 | void *memmove(void *dest, const void *src, size_t n); 11 | int memcmp(const void *s1, const void *s2, size_t n); 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /src/startup/header.asm: -------------------------------------------------------------------------------- 1 | section .stivalehdr 2 | 3 | align 4 4 | 5 | stivale_header: 6 | .stack: dq entry_stack.top ; Stack pointer. 7 | .videomode: dw 1 ; VESA. 8 | .fbwidth: dw 0 ; Framebuffer info: 0 for default. 9 | .fbheight: dw 0 ; Ditto. 10 | .fbbpp: dw 0 ; Ditto. 11 | .entry: dq 0 12 | 13 | section .bss 14 | 15 | align 16 16 | entry_stack: 17 | resb 8192 18 | .top: 19 | -------------------------------------------------------------------------------- /src/fs/fs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void init_fs_devfs(void); 6 | void init_fs_echfs(void); 7 | void init_fs_iso9660(void); 8 | void init_fs_fat32(void); 9 | 10 | void init_fs(void) { 11 | init_fs_devfs(); 12 | init_fs_echfs(); 13 | init_fs_iso9660(); 14 | init_fs_fat32(); 15 | 16 | /* Launch the fs cache sync worker */ 17 | task_tcreate(0, tcreate_fn_call, tcreate_fn_call_data(0, vfs_sync_worker, 0)); 18 | } 19 | -------------------------------------------------------------------------------- /src/lib/types.h: -------------------------------------------------------------------------------- 1 | #ifndef __TYPES_H__ 2 | #define __TYPES_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef int64_t ssize_t; 8 | typedef int64_t off_t; 9 | 10 | typedef uint64_t dev_t; 11 | typedef uint64_t ino_t; 12 | typedef int32_t mode_t; 13 | typedef int32_t nlink_t; 14 | typedef int64_t blksize_t; 15 | typedef int64_t blkcnt_t; 16 | 17 | typedef int32_t pid_t; 18 | typedef int32_t tid_t; 19 | typedef int32_t uid_t; 20 | typedef int32_t gid_t; 21 | 22 | typedef int event_t; 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /src/linker.ld: -------------------------------------------------------------------------------- 1 | ENTRY(kmain) 2 | 3 | SECTIONS 4 | { 5 | kernel_phys_offset = 0xffffffff80000000; 6 | . = kernel_phys_offset + 0x100000; 7 | 8 | .stivalehdr ALIGN(4K) : 9 | { 10 | KEEP(*(.stivalehdr)) 11 | } 12 | 13 | .text ALIGN(4K) : 14 | { 15 | KEEP(*(.text*)) 16 | } 17 | 18 | .rodata ALIGN(4K) : 19 | { 20 | KEEP(*(.rodata*)) 21 | } 22 | 23 | .data ALIGN(4K) : 24 | { 25 | KEEP(*(.data*)) 26 | } 27 | 28 | .bss ALIGN(4K) : 29 | { 30 | KEEP(*(COMMON)) 31 | KEEP(*(.bss*)) 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /AUTHORS.md: -------------------------------------------------------------------------------- 1 | # List of `qword` authors. 2 | 3 | Names should be added to this file as one of 4 | - Organization/Individual's name 5 | - Organization/Individual's name: any way of contact, 6 | - Organization/Individual's name: any way of contact, contact2, ..., contactN 7 | 8 | Mintsuki: 9 | Toor: , 10 | Geert: 11 | Alexander van der Grinten: , 12 | Streaks: , 13 | Qookie: 14 | -------------------------------------------------------------------------------- /src/devices/dev.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | void init_dev_streams(void); 8 | void init_dev_tty(void); 9 | void init_dev_ide(void); 10 | void init_dev_sata(void); 11 | void init_dev_vesafb(void); 12 | 13 | void init_dev(void) { 14 | init_dev_streams(); 15 | init_dev_tty(); 16 | init_dev_ide(); 17 | init_dev_nvme(); 18 | init_dev_sata(); 19 | init_dev_vesafb(); 20 | init_usb(); 21 | 22 | /* Launch the device cache sync worker */ 23 | task_tcreate(0, tcreate_fn_call, tcreate_fn_call_data(0, device_sync_worker, 0)); 24 | } 25 | -------------------------------------------------------------------------------- /gensyms.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | TMP1=$(mktemp) 6 | TMP2=$(mktemp) 7 | TMP3=$(mktemp) 8 | 9 | if [ -z "$OBJDUMP" ]; then 10 | OBJDUMP=objdump 11 | fi 12 | 13 | ${OBJDUMP} -t qword.elf | sed '/\bd\b/d' | sort > "$TMP1" 14 | grep "\.text" < "$TMP1" | cut -d' ' -f1 > "$TMP2" 15 | grep "\.text" < "$TMP1" | awk 'NF{ print $NF }' > "$TMP3" 16 | 17 | cat <symlist.gen 18 | #include 19 | 20 | struct symlist_t symlist[] = { 21 | EOF 22 | 23 | paste -d'$' "$TMP2" "$TMP3" | sed 's/^/ {0x/g' | sed 's/\$/, "/g' | sed 's/$/"},/g' >> symlist.gen 24 | 25 | cat <> symlist.gen 26 | {0xffffffffffffffff, ""} 27 | }; 28 | EOF 29 | 30 | rm "$TMP1" "$TMP2" "$TMP3" 31 | -------------------------------------------------------------------------------- /src/sys/panic.h: -------------------------------------------------------------------------------- 1 | #ifndef __PANIC_H__ 2 | #define __PANIC_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define panic_unless(c) ({ \ 12 | if(!(c)) \ 13 | panic(NULL, 1, "panic_unless(" #c ") triggered in " \ 14 | __FILE__ ":" expand_stringify(__LINE__)); \ 15 | }) 16 | 17 | #define panic_if(c) ({ \ 18 | if((c)) \ 19 | panic(NULL, 1, "panic_if(" #c ") triggered in " \ 20 | __FILE__ ":" expand_stringify(__LINE__)); \ 21 | }) 22 | 23 | __attribute__((noreturn)) 24 | void panic(struct regs_t *regs, int print_trace, const char *fmt, ...); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/sys/pit.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | int init_pit(void) { 8 | kprint(KPRN_INFO, "pit: Setting frequency to %uHz", PIT_FREQUENCY_HZ); 9 | 10 | uint16_t x = 1193182 / PIT_FREQUENCY_HZ; 11 | if ((1193182 % PIT_FREQUENCY_HZ) > (PIT_FREQUENCY_HZ / 2)) 12 | x++; 13 | 14 | port_out_b(0x40, (uint8_t)(x & 0x00ff)); 15 | io_wait(); 16 | port_out_b(0x40, (uint8_t)((x & 0xff00) >> 8)); 17 | io_wait(); 18 | 19 | kprint(KPRN_INFO, "pit: Frequency updated"); 20 | 21 | kprint(KPRN_INFO, "pit: Unmasking PIT IRQ"); 22 | io_apic_set_up_legacy_irq(0, 0, 1); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /src/lib/endian.h: -------------------------------------------------------------------------------- 1 | #ifndef __ENDIAN_H__ 2 | #define __ENDIAN_H__ 3 | 4 | #include 5 | 6 | #define bswap16(x) ({ \ 7 | uint16_t ret = x; \ 8 | asm volatile ( \ 9 | "xchg ah, al" \ 10 | : "+a"(ret) \ 11 | ); \ 12 | ret; \ 13 | }) 14 | 15 | #define bswap32(x) ({ \ 16 | uint32_t ret = x; \ 17 | asm volatile ( \ 18 | "bswap %0" \ 19 | : "+r"(ret) \ 20 | ); \ 21 | ret; \ 22 | }) 23 | 24 | #define bswap64(x) ({ \ 25 | uint64_t ret = x; \ 26 | asm volatile ( \ 27 | "bswap %0" \ 28 | : "+r"(ret) \ 29 | ); \ 30 | ret; \ 31 | }) 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /src/sys/exceptions.h: -------------------------------------------------------------------------------- 1 | #ifndef __EXCEPTIONS_H__ 2 | #define __EXCEPTIONS_H__ 3 | 4 | /* Assembly routines */ 5 | void exc_div0_handler(void); 6 | void exc_debug_handler(void); 7 | void exc_nmi_handler(void); 8 | void exc_breakpoint_handler(void); 9 | void exc_overflow_handler(void); 10 | void exc_bound_range_handler(void); 11 | void exc_inv_opcode_handler(void); 12 | void exc_no_dev_handler(void); 13 | void exc_double_fault_handler(void); 14 | void exc_inv_tss_handler(void); 15 | void exc_no_segment_handler(void); 16 | void exc_ss_fault_handler(void); 17 | void exc_gpf_handler(void); 18 | void exc_page_fault_handler(void); 19 | void exc_x87_fp_handler(void); 20 | void exc_alignment_check_handler(void); 21 | void exc_machine_check_handler(void); 22 | void exc_simd_fp_handler(void); 23 | void exc_virt_handler(void); 24 | void exc_security_handler(void); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /src/lib/qemu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static lock_t qemu_debug_lock = new_lock; 8 | static int block = 0; 9 | 10 | void qemu_debug_puts_urgent(const char *str) { 11 | locked_inc(&block); 12 | for (size_t i = 0; str[i]; i++) 13 | port_out_b(0xe9, str[i]); 14 | locked_dec(&block); 15 | } 16 | 17 | void qemu_debug_puts(const char *str) { 18 | spinlock_acquire(&qemu_debug_lock); 19 | for (size_t i = 0; str[i]; i++) { 20 | while (locked_read(int, &block)); 21 | port_out_b(0xe9, str[i]); 22 | } 23 | spinlock_release(&qemu_debug_lock); 24 | } 25 | 26 | void qemu_debug_putc(char c) { 27 | spinlock_acquire(&qemu_debug_lock); 28 | while (locked_read(int, &block)); 29 | port_out_b(0xe9, c); 30 | spinlock_release(&qemu_debug_lock); 31 | } 32 | -------------------------------------------------------------------------------- /src/net/hostname.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #define DEFAULT_HOSTNAME "qword" 8 | 9 | char hostname[MAX_HOSTNAME_LEN]; 10 | 11 | void init_hostname(void) { 12 | int fd = open("/etc/hostname", O_RDONLY); 13 | if (fd == -1) { 14 | kprint(KPRN_WARN, "net/hostname: Failed to open \"/etc/hostname\", using default hostname: %s", DEFAULT_HOSTNAME); 15 | strcpy(hostname, DEFAULT_HOSTNAME); 16 | return; 17 | } 18 | read(fd, hostname, MAX_HOSTNAME_LEN-1); 19 | for (int i = 0; i < MAX_HOSTNAME_LEN; i++) { 20 | if (hostname[i] == '\n') { 21 | hostname[i] = 0; 22 | break; 23 | } 24 | } 25 | hostname[MAX_HOSTNAME_LEN-1] = 0; 26 | close(fd); 27 | kprint(KPRN_INFO, "net/hostname: Hostname set to \"%s\"", hostname); 28 | } 29 | -------------------------------------------------------------------------------- /src/sys/apic.h: -------------------------------------------------------------------------------- 1 | #ifndef __APIC_H__ 2 | #define __APIC_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define APICREG_ICR0 0x300 8 | #define APICREG_ICR1 0x310 9 | 10 | #define IPI_BASE 0x40 11 | #define IPI_RESCHED (IPI_BASE + 1) 12 | #define IPI_ABORT (IPI_BASE + 0) 13 | 14 | int apic_supported(void); 15 | 16 | uint32_t lapic_read(uint32_t); 17 | void lapic_write(uint32_t, uint32_t); 18 | void lapic_set_nmi(uint8_t, uint16_t, uint8_t); 19 | void lapic_enable(void); 20 | void lapic_eoi(void); 21 | void lapic_send_ipi(int, uint8_t); 22 | 23 | uint32_t io_apic_read(size_t, uint32_t); 24 | void io_apic_write(size_t, uint32_t, uint32_t); 25 | size_t io_apic_from_redirect(uint32_t); 26 | uint32_t io_apic_get_max_redirect(size_t); 27 | void io_apic_set_up_legacy_irq(int cpu, uint8_t irq, int status); 28 | void io_apic_connect_gsi_to_vec(int cpu, uint8_t vec, uint32_t gsi, uint16_t flags, int status); 29 | 30 | void init_apic(void); 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/sys/trace.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | char *trace_address(size_t *off, size_t addr) { 7 | for (size_t i = 0; ; i++) { 8 | if (symlist[i].addr >= addr) { 9 | *off = addr - symlist[i-1].addr; 10 | return symlist[i-1].name; 11 | } 12 | } 13 | } 14 | 15 | void print_stacktrace(int type) { 16 | size_t *base_ptr; 17 | asm volatile ( 18 | "mov %0, rbp;" 19 | : "=r"(base_ptr) 20 | ); 21 | kprint(type, "Stacktrace:"); 22 | for (;;) { 23 | size_t old_bp = base_ptr[0]; 24 | size_t ret_addr = base_ptr[1]; 25 | size_t off; 26 | if (!ret_addr) 27 | break; 28 | char *name = trace_address(&off, ret_addr); 29 | kprint(type, " [%16X] <%s+%X>", ret_addr, name, off); 30 | if (!old_bp) 31 | break; 32 | base_ptr = (void*)old_bp; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/lib/cmdline.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | static const char *cmdline; 7 | 8 | void init_cmdline(const char *cmd) { 9 | cmdline = cmd; 10 | } 11 | 12 | char *cmdline_get_value(char *buf, size_t limit, const char *key) { 13 | if (!limit || !buf) 14 | return NULL; 15 | 16 | size_t key_len = strlen(key); 17 | 18 | for (size_t i = 0; cmdline[i]; i++) { 19 | if (!strncmp(&cmdline[i], key, key_len) && cmdline[i + key_len] == '=') { 20 | if (i && cmdline[i - 1] != ' ') 21 | continue; 22 | i += key_len + 1; 23 | size_t j; 24 | for (j = 0; cmdline[i + j] != ' ' && cmdline[i + j]; j++) { 25 | if (j == limit - 1) 26 | break; 27 | buf[j] = cmdline[i + j]; 28 | } 29 | buf[j] = 0; 30 | return buf; 31 | } 32 | } 33 | 34 | return NULL; 35 | } 36 | -------------------------------------------------------------------------------- /src/lib/rand.h: -------------------------------------------------------------------------------- 1 | #ifndef __RAND_H__ 2 | #define __RAND_H__ 3 | 4 | #include 5 | 6 | void init_rand(void); 7 | uint32_t rand32(void); 8 | uint64_t rand64(void); 9 | void srand(uint32_t); 10 | 11 | #define rdrand_supported ({ \ 12 | int ret; \ 13 | uint32_t a = 1, c = 0; \ 14 | asm volatile ( \ 15 | "cpuid;" \ 16 | "bt ecx, 30;" \ 17 | : "=@ccc" (ret), "+a" (a), "+c" (c) \ 18 | : \ 19 | : "rbx", "rdx" \ 20 | ); \ 21 | ret; \ 22 | }) 23 | 24 | #define rdrand(type) ({ \ 25 | type ret; \ 26 | asm volatile ( \ 27 | "1: " \ 28 | "rdrand %0;" \ 29 | "jnc 1b;" \ 30 | : "=r" (ret) \ 31 | : \ 32 | : "cc" \ 33 | ); \ 34 | ret; \ 35 | }) 36 | 37 | #define rdtsc(type) ({ \ 38 | type ret; \ 39 | asm volatile ( \ 40 | "rdtsc;" \ 41 | "shl rdx, 32;" \ 42 | "or rax, rdx;" \ 43 | : "=a" (ret) \ 44 | : \ 45 | : "rdx" \ 46 | ); \ 47 | ret; \ 48 | }) 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/sys/isrs.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS__ISRS_H__ 2 | #define __SYS__ISRS_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | extern void irq0_handler(void); 11 | 12 | __attribute__((interrupt)) static void pic0_generic_handler(void *p) { 13 | (void)p; 14 | port_out_b(0x20, 0x20); 15 | kprint(KPRN_WARN, "pic_8259: Spurious interrupt occured."); 16 | } 17 | 18 | __attribute__((interrupt)) static void pic1_generic_handler(void *p) { 19 | (void)p; 20 | port_out_b(0xa0, 0x20); 21 | port_out_b(0x20, 0x20); 22 | kprint(KPRN_WARN, "pic_8259: Spurious interrupt occured."); 23 | } 24 | 25 | __attribute__((interrupt)) static void apic_nmi_handler(void *p) { 26 | (void)p; 27 | lapic_eoi(); 28 | kprint(KPRN_WARN, "apic: Non-maskable interrupt occured. Possible hardware issue..."); 29 | } 30 | 31 | __attribute__((interrupt)) static void apic_spurious_handler(void *p) { 32 | (void)p; 33 | lapic_eoi(); 34 | kprint(KPRN_WARN, "apic: Spurious interrupt occurred."); 35 | } 36 | 37 | #endif 38 | -------------------------------------------------------------------------------- /src/lib/scsi.h: -------------------------------------------------------------------------------- 1 | #ifndef __SCSI_H__ 2 | #define __SCSI_H__ 3 | 4 | #include 5 | #include 6 | 7 | struct scsi_read_capacity_10_t { 8 | uint8_t op_code; 9 | uint8_t reserved; 10 | uint32_t lba; 11 | uint16_t reserved1; 12 | uint8_t reserved2; 13 | uint8_t control; 14 | } __attribute__((packed)); 15 | 16 | struct scsi_read_10_t { 17 | uint8_t op_code; 18 | uint8_t options; 19 | uint8_t lba[4]; 20 | uint8_t group_number; 21 | uint8_t length[2]; 22 | uint8_t control; 23 | } __attribute__((packed)); 24 | 25 | struct scsi_read_12_t { 26 | uint8_t op_code; 27 | uint8_t flags; 28 | uint32_t lba; 29 | uint32_t length; 30 | uint8_t group_number; 31 | uint8_t control; 32 | } __attribute__((packed)); 33 | 34 | struct scsi_read_capacity_16_t { 35 | uint8_t op_code; 36 | uint8_t flags; 37 | uint64_t lba; 38 | uint32_t length; 39 | uint8_t group_number; 40 | uint8_t control; 41 | } __attribute__((packed)); 42 | 43 | int scsi_register(int, char *, int (*)(int, char *, size_t, char *, size_t, int)); 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /src/fs/devfs/devfs.h: -------------------------------------------------------------------------------- 1 | #ifndef __DEVFS_H__ 2 | #define __DEVFS_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define MAX_DEVICES 128 12 | 13 | struct device_calls_t { 14 | int (*read)(int, void *, uint64_t, size_t); 15 | int (*write)(int, const void *, uint64_t, size_t); 16 | int (*flush)(int); 17 | int (*tcgetattr)(int, struct termios *); 18 | int (*tcsetattr)(int, int, struct termios *); 19 | int (*tcflow)(int, int); 20 | int (*isatty)(int); 21 | }; 22 | 23 | __attribute__((unused)) static struct device_calls_t default_device_calls = { 24 | (void *)bogus_read, 25 | (void *)bogus_write, 26 | (void *)bogus_flush, 27 | (void *)bogus_tcgetattr, 28 | (void *)bogus_tcsetattr, 29 | (void *)bogus_tcflow, 30 | (void *)bogus_isatty 31 | }; 32 | 33 | struct device_t { 34 | char name[128]; 35 | int intern_fd; 36 | size_t size; 37 | struct device_calls_t calls; 38 | }; 39 | 40 | dev_t device_add(struct device_t *); 41 | 42 | void device_sync_worker(void *); 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /src/acpi/acpi.h: -------------------------------------------------------------------------------- 1 | #ifndef __ACPI_H__ 2 | #define __ACPI_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define ACPI_TABLES_MAX 256 8 | 9 | struct rsdp_t { 10 | char signature[8]; 11 | uint8_t checksum; 12 | char oem_id[6]; 13 | uint8_t rev; 14 | uint32_t rsdt_addr; 15 | /* ver 2.0 only */ 16 | uint32_t length; 17 | uint64_t xsdt_addr; 18 | uint8_t ext_checksum; 19 | uint8_t reserved[3]; 20 | } __attribute__((packed)); 21 | 22 | struct sdt_t { 23 | char signature[4]; 24 | uint32_t length; 25 | uint8_t rev; 26 | uint8_t checksum; 27 | char oem_id[6]; 28 | char oem_table_id[8]; 29 | uint32_t oem_rev; 30 | uint32_t creator_id; 31 | uint32_t creator_rev; 32 | } __attribute__((packed)); 33 | 34 | struct rsdt_t { 35 | struct sdt_t sdt; 36 | uint32_t sdt_ptr[]; 37 | } __attribute__((packed)); 38 | 39 | struct xsdt_t { 40 | struct sdt_t sdt; 41 | uint64_t sdt_ptr[]; 42 | } __attribute__((packed)); 43 | 44 | extern struct rsdp_t *rsdp; 45 | extern struct rsdt_t *rsdt; 46 | extern struct xsdt_t *xsdt; 47 | 48 | void init_acpi(void); 49 | void *acpi_find_sdt(const char *, int); 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /src/lib/time.h: -------------------------------------------------------------------------------- 1 | #ifndef __TIME_H__ 2 | #define __TIME_H__ 3 | 4 | #include 5 | #include 6 | 7 | typedef int64_t time_t; 8 | typedef int64_t clockid_t; 9 | 10 | #define CLOCK_REALTIME 0 11 | #define CLOCK_MONOTONIC 1 12 | #define CLOCK_PROCESS_CPUTIME_ID 2 13 | #define CLOCK_THREAD_CPUTIME_ID 3 14 | #define CLOCK_MONOTONIC_RAW 4 15 | #define CLOCK_REALTIME_COARSE 5 16 | #define CLOCK_MONOTONIC_COARSE 6 17 | #define CLOCK_BOOTTIME 7 18 | 19 | struct timespec { 20 | time_t tv_sec; 21 | long tv_nsec; 22 | }; 23 | 24 | struct timeval { 25 | time_t tv_sec; 26 | long tv_usec; 27 | }; 28 | 29 | #define RUSAGE_SELF 1 30 | #define RUSAGE_CHILDREN 2 31 | 32 | struct rusage_t { 33 | struct timeval ru_utime; /* user CPU time used */ 34 | struct timeval ru_stime; /* system CPU time used */ 35 | }; 36 | 37 | extern volatile uint64_t uptime_raw; 38 | extern volatile uint64_t uptime_sec; 39 | extern volatile uint64_t unix_epoch; 40 | 41 | void ksleep(uint64_t); 42 | uint64_t get_jdn(int, int, int); 43 | uint64_t get_unix_epoch(int, int, int, int, int, int); 44 | void add_timeval(struct timeval *, struct timeval *); 45 | void add_usage(struct rusage_t *, struct rusage_t *); 46 | 47 | #endif 48 | -------------------------------------------------------------------------------- /src/startup/stivale.h: -------------------------------------------------------------------------------- 1 | #ifndef __STIVALE__H 2 | #define __STIVALE__H 3 | 4 | #include 5 | 6 | enum stivale_memmap_entry_type_t { 7 | USABLE = 1, 8 | RESERVED = 2, 9 | ACPIRECLAIM = 3, 10 | ACPINVS = 4 11 | }; 12 | 13 | struct stivale_memmap_entry_t { 14 | uint64_t base; 15 | uint64_t size; 16 | uint32_t type; 17 | uint32_t unused; 18 | } __attribute__((packed)); 19 | 20 | struct stivale_memmap_t { 21 | struct stivale_memmap_entry_t *address; 22 | uint64_t entries; 23 | } __attribute__((packed)); 24 | 25 | struct stivale_framebuffer_t { 26 | uint64_t address; 27 | uint16_t pitch; 28 | uint16_t width; 29 | uint16_t height; 30 | uint16_t bpp; 31 | } __attribute__((packed)); 32 | 33 | struct stivale_module_t { 34 | uint64_t begin; 35 | uint64_t end; 36 | char name[128]; 37 | uint64_t next; 38 | } __attribute__((packed)); 39 | 40 | struct stivale_struct_t { 41 | char* cmdline; 42 | struct stivale_memmap_t memmap; 43 | struct stivale_framebuffer_t fb; 44 | uint64_t rsdp; 45 | uint64_t module_count; 46 | struct stivale_module_t module; 47 | uint64_t epoch; 48 | } __attribute__((packed)); 49 | 50 | #endif 51 | -------------------------------------------------------------------------------- /src/lib/bit.h: -------------------------------------------------------------------------------- 1 | #ifndef __BIT_H__ 2 | #define __BIT_H__ 3 | 4 | #define bit_test(var, offset) ({ \ 5 | int __ret; \ 6 | asm volatile ( \ 7 | "bt %1, %2;" \ 8 | : "=@ccc" (__ret) \ 9 | : "r" ((uint32_t)(var)), "r" ((uint32_t)(offset)) \ 10 | ); \ 11 | __ret; \ 12 | }) 13 | 14 | #define test_bit(base, offset) ({ \ 15 | int ret; \ 16 | asm volatile ( \ 17 | "bt [%1], %2;" \ 18 | : "=@ccc" (ret) \ 19 | : "r" (base), "r" (offset) \ 20 | : "memory" \ 21 | ); \ 22 | ret; \ 23 | }) 24 | 25 | #define set_bit(base, offset) ({ \ 26 | int ret; \ 27 | asm volatile ( \ 28 | "bts [%1], %2;" \ 29 | : "=@ccc" (ret) \ 30 | : "r" (base), "r" (offset) \ 31 | : "memory" \ 32 | ); \ 33 | ret; \ 34 | }) 35 | 36 | #define reset_bit(base, offset) ({ \ 37 | int ret; \ 38 | asm volatile ( \ 39 | "btr [%1], %2;" \ 40 | : "=@ccc" (ret) \ 41 | : "r" (base), "r" (offset) \ 42 | : "memory" \ 43 | ); \ 44 | ret; \ 45 | }) 46 | 47 | #define bswap(type, value) ({ \ 48 | type ret = value; \ 49 | asm volatile( \ 50 | "bswap %0" \ 51 | : "+r" (ret)); \ 52 | ret; \ 53 | }) 54 | 55 | #endif 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018-2020, the qword authors (AUTHORS.md) 2 | All rights reserved. 3 | 4 | Redistribution and use in source form, or binary form with accompanying source, 5 | with or without modification, are permitted provided that the following conditions 6 | are met: 7 | * The redistribution of the source code must retain the above copyright 8 | notice, this list of conditions and the following disclaimer. 9 | * Modified versions of the source code MUST be licensed under a verbatim 10 | copy of the present License Agreement. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 16 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 19 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | -------------------------------------------------------------------------------- /src/lib/cstring.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | char *strchrnul(const char *s, int c) { 5 | while (*s) 6 | if ((*s++) == c) 7 | break; 8 | return (char *)s; 9 | } 10 | 11 | char *strcpy(char *dest, const char *src) { 12 | size_t i; 13 | 14 | for (i = 0; src[i]; i++) 15 | dest[i] = src[i]; 16 | 17 | dest[i] = 0; 18 | 19 | return dest; 20 | } 21 | 22 | char *strncpy(char *dest, const char *src, size_t n) { 23 | size_t i; 24 | 25 | for (i = 0; i < n && src[i]; i++) 26 | dest[i] = src[i]; 27 | for ( ; i < n; i++) 28 | dest[i] = 0; 29 | 30 | return dest; 31 | } 32 | 33 | int strcmp(const char *s1, const char *s2) { 34 | for (size_t i = 0; ; i++) { 35 | char c1 = s1[i], c2 = s2[i]; 36 | if (c1 != c2) 37 | return c1 - c2; 38 | if (!c1) 39 | return 0; 40 | } 41 | } 42 | 43 | int strncmp(const char *s1, const char *s2, size_t n) { 44 | for (size_t i = 0; i < n; i++) { 45 | char c1 = s1[i], c2 = s2[i]; 46 | if (c1 != c2) 47 | return c1 - c2; 48 | if (!c1) 49 | return 0; 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | size_t strlen(const char *str) { 56 | size_t len; 57 | 58 | for (len = 0; str[len]; len++); 59 | 60 | return len; 61 | } 62 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # The qword kernel 2 | 3 | [![goto counter](https://img.shields.io/github/search/qword-os/qword/goto.svg)](https://github.com/qword-os/qword/search?q=goto) 4 | 5 | ![Reference screenshot](/screenshot.png?raw=true "Reference screenshot") 6 | 7 | # THIS PROJECT IS DEFUNCT. 8 | Sorry about that. 9 | 10 | Please do not send PRs or open issues against this defunct project which will 11 | no longer be updated. 12 | 13 | You're free to check out the code, fork it, and all that, as long as the license 14 | (LICENSE.md) is respected. 15 | 16 | # Moving on 17 | As the name implies, this is just the kernel. To build the whole system, follow the 18 | instructions at . 19 | 20 | ## Build requirements 21 | 22 | These are the tools needed for the build: 23 | - `git` (only for the initial download). 24 | - `bash`. 25 | - `make`. 26 | - `gcc`, 8 or higher. 27 | - `nasm`. 28 | - `objcopy`. 29 | - `qemu` (to test it). 30 | - `clang` (to test it). 31 | - `llvm` (to test it). 32 | 33 | ## Building 34 | 35 | ```bash 36 | # Clone repo wherever you like and enter. 37 | git clone https://github.com/qword-os/qword.git 38 | cd qword 39 | # Make the kernel, you can replace the 4 in -j4 with your number of cores + 1. 40 | make clean && make -j4 41 | # Install in PREFIX, may need root permissions depending on the place. 42 | sudo make install PREFIX=.. 43 | # Uninstall if needed in the specified PREFIX. 44 | sudo make uninstall PREFIX=.. 45 | ``` 46 | -------------------------------------------------------------------------------- /src/mm/mm.h: -------------------------------------------------------------------------------- 1 | #ifndef __MM_H__ 2 | #define __MM_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define PAGE_SIZE ((size_t)4096) 10 | 11 | #define PAGE_TABLE_ENTRIES 512 12 | #define KERNEL_PHYS_OFFSET ((size_t)0xffffffff80000000) 13 | #define MEM_PHYS_OFFSET ((size_t)0xffff800000000000) 14 | 15 | typedef uint64_t pt_entry_t; 16 | 17 | struct page_attributes_t { 18 | char name[18]; 19 | int attr; 20 | int refcount; 21 | size_t phys_addr; 22 | size_t virt_addr; 23 | size_t flags; 24 | }; 25 | 26 | struct pagemap_t { 27 | ht_new(struct page_attributes_t, page_attributes); 28 | pt_entry_t *pml4; 29 | lock_t lock; 30 | }; 31 | 32 | extern struct pagemap_t *kernel_pagemap; 33 | 34 | void pmm_change_allocation_method(void); 35 | 36 | extern void *(*pmm_alloc)(size_t); 37 | void *pmm_allocz(size_t); 38 | void pmm_free(void *, size_t); 39 | void init_pmm(struct stivale_memmap_t *); 40 | 41 | int map_page(struct pagemap_t *, size_t, size_t, size_t); 42 | int unmap_page(struct pagemap_t *, size_t); 43 | int remap_page(struct pagemap_t *, size_t, size_t); 44 | void init_vmm(struct stivale_memmap_t *); 45 | 46 | struct pagemap_t *new_address_space(void); 47 | struct pagemap_t *fork_address_space(struct pagemap_t *); 48 | void free_address_space(struct pagemap_t *); 49 | 50 | struct memstats { 51 | size_t total; 52 | size_t used; 53 | }; 54 | 55 | int getmemstats(struct memstats *); 56 | 57 | #endif 58 | -------------------------------------------------------------------------------- /src/proc/elf.h: -------------------------------------------------------------------------------- 1 | #ifndef __ELF_H__ 2 | #define __ELF_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define PT_LOAD 0x00000001 10 | #define PT_INTERP 0x00000003 11 | #define PT_PHDR 0x00000006 12 | 13 | #define ABI_SYSV 0x00 14 | #define ARCH_X86_64 0x3e 15 | #define BITS_LE 0x01 16 | 17 | /* Indices into identification array */ 18 | #define EI_CLASS 4 19 | #define EI_DATA 5 20 | #define EI_VERSION 6 21 | #define EI_OSABI 7 22 | 23 | struct elf_hdr_t { 24 | uint8_t ident[16]; 25 | uint16_t type; 26 | uint16_t machine; 27 | uint32_t version; 28 | uint64_t entry; 29 | uint64_t phoff; 30 | uint64_t shoff; 31 | uint32_t flags; 32 | uint16_t hdr_size; 33 | uint16_t phdr_size; 34 | uint16_t ph_num; 35 | uint16_t shdr_size; 36 | uint16_t sh_num; 37 | uint16_t shstrndx; 38 | }; 39 | 40 | #define PF_X 1 41 | #define PF_W 2 42 | #define PF_R 4 43 | 44 | struct elf_phdr_t { 45 | uint32_t p_type; 46 | uint32_t p_flags; 47 | uint64_t p_offset; 48 | uint64_t p_vaddr; 49 | uint64_t p_paddr; 50 | uint64_t p_filesz; 51 | uint64_t p_memsz; 52 | uint64_t p_align; 53 | }; 54 | 55 | struct elf_shdr_t { 56 | uint32_t sh_name; 57 | uint32_t sh_type; 58 | uint64_t sh_flags; 59 | uint64_t sh_addr; 60 | uint64_t sh_offset; 61 | uint64_t sh_size; 62 | uint32_t sh_link; 63 | uint32_t sh_info; 64 | uint64_t sh_addr_align; 65 | uint64_t sh_entsize; 66 | }; 67 | 68 | int elf_load(int, struct pagemap_t *, size_t, struct auxval_t *, char **); 69 | 70 | #endif 71 | -------------------------------------------------------------------------------- /src/acpi/madt.h: -------------------------------------------------------------------------------- 1 | #ifndef __MADT_H__ 2 | #define __MADT_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | struct madt_t { 9 | struct sdt_t sdt; 10 | uint32_t local_controller_addr; 11 | uint32_t flags; 12 | uint8_t madt_entries_begin; 13 | } __attribute__((packed)); 14 | 15 | struct madt_header_t { 16 | uint8_t type; 17 | uint8_t length; 18 | } __attribute__((packed)); 19 | 20 | struct madt_local_apic_t { 21 | struct madt_header_t header; 22 | uint8_t processor_id; 23 | uint8_t apic_id; 24 | uint32_t flags; 25 | } __attribute__((packed)); 26 | 27 | struct madt_io_apic_t { 28 | struct madt_header_t header; 29 | uint8_t apic_id; 30 | uint8_t reserved; 31 | uint32_t addr; 32 | uint32_t gsib; 33 | } __attribute__((packed)); 34 | 35 | struct madt_iso_t { 36 | struct madt_header_t header; 37 | uint8_t bus_source; 38 | uint8_t irq_source; 39 | uint32_t gsi; 40 | uint16_t flags; 41 | } __attribute__((packed)); 42 | 43 | struct madt_nmi_t { 44 | struct madt_header_t header; 45 | uint8_t processor; 46 | uint16_t flags; 47 | uint8_t lint; 48 | } __attribute__((packed)); 49 | 50 | extern int madt_available; 51 | 52 | extern struct madt_t *madt; 53 | 54 | extern struct madt_local_apic_t **madt_local_apics; 55 | extern size_t madt_local_apic_i; 56 | 57 | extern struct madt_io_apic_t **madt_io_apics; 58 | extern size_t madt_io_apic_i; 59 | 60 | extern struct madt_iso_t **madt_isos; 61 | extern size_t madt_iso_i; 62 | 63 | extern struct madt_nmi_t **madt_nmis; 64 | extern size_t madt_nmi_i; 65 | 66 | void init_madt(void); 67 | 68 | #endif 69 | -------------------------------------------------------------------------------- /src/fd/socket/socket.h.ignore: -------------------------------------------------------------------------------- 1 | #ifndef __FD__SOCKET__SOCKET_H__ 2 | #define __FD__SOCKET__SOCKET_H__ 3 | 4 | #include 5 | #include 6 | 7 | enum socket_domain { 8 | AF_INET = 2, 9 | AF_PACKET = 17 10 | }; 11 | 12 | enum socket_type { 13 | SOCK_STREAM = 1, 14 | SOCK_DGRAM = 2 15 | }; 16 | 17 | struct socket_buffer_t { 18 | struct socket_buffer_t* next; 19 | char* buf; 20 | size_t len; 21 | }; 22 | 23 | struct socket_t { 24 | int domain; 25 | int type; 26 | int proto; 27 | 28 | // context for the domain 29 | union { 30 | struct { 31 | ipv4_addr_t remote_address; 32 | } inet; 33 | } domain_ctx; 34 | 35 | // protocol related context 36 | union { 37 | struct { 38 | uint16_t local_port; 39 | uint16_t remote_port; 40 | } udp; 41 | struct { 42 | uint16_t local_port; 43 | uint16_t remote_port; 44 | } tcp; 45 | } proto_ctx; 46 | 47 | // these hold the messages 48 | event_t has_buffers; 49 | struct socket_buffer_t* buffers; 50 | struct socket_buffer_t* last_buffer; 51 | lock_t buffers_lock; 52 | size_t buffer_offset; 53 | }; 54 | 55 | // TODO: we might wanna have different types of socket arrays 56 | // for better performance 57 | public_dynarray_prototype(struct socket_t, sockets); 58 | 59 | #define MSG_PEEK (0x2) 60 | #define MSG_DONTWAIT (0x40) 61 | 62 | /** 63 | * Process a packet at the socket level 64 | */ 65 | void socket_process_packet(struct packet_t* pkt); 66 | 67 | int socket(int domain, int type, int protocol); 68 | 69 | #endif //__NET__SOCKET_H__ 70 | -------------------------------------------------------------------------------- /src/sys/smp.asm: -------------------------------------------------------------------------------- 1 | global smp_prepare_trampoline 2 | global smp_init_cpu0_local 3 | global smp_check_ap_flag 4 | 5 | extern syscall_entry 6 | 7 | extern load_tss 8 | 9 | section .data 10 | 11 | %define smp_trampoline_size smp_trampoline_end - smp_trampoline 12 | smp_trampoline: incbin "sys/smp_trampoline.bin" 13 | smp_trampoline_end: 14 | 15 | section .text 16 | 17 | %define TRAMPOLINE_ADDR 0x1000 18 | %define PAGE_SIZE 4096 19 | 20 | ; Store trampoline data in low memory and return the page index of the 21 | ; trampoline code. 22 | smp_prepare_trampoline: 23 | ; entry point in rdi, page table in rsi 24 | ; stack pointer in rdx, cpu local in rcx 25 | ; tss in r8 26 | 27 | ; prepare variables 28 | mov byte [0x510], 0 29 | mov qword [0x520], rdi 30 | mov qword [0x540], rsi 31 | mov qword [0x550], rdx 32 | mov qword [0x560], rcx 33 | mov qword [0x570], syscall_entry 34 | sgdt [0x580] 35 | sidt [0x590] 36 | 37 | ; Copy trampoline blob to 0x1000 38 | mov rsi, smp_trampoline 39 | mov rdi, TRAMPOLINE_ADDR 40 | mov rcx, smp_trampoline_size 41 | rep movsb 42 | 43 | mov rdi, r8 44 | call load_tss 45 | 46 | mov rax, TRAMPOLINE_ADDR / PAGE_SIZE 47 | ret 48 | 49 | smp_check_ap_flag: 50 | xor rax, rax 51 | mov al, byte [0x510] 52 | ret 53 | 54 | smp_init_cpu0_local: 55 | ; Load GS with the CPU local struct base address 56 | mov ax, 0x1b 57 | mov fs, ax 58 | mov gs, ax 59 | mov rcx, 0xc0000101 60 | mov eax, edi 61 | shr rdi, 32 62 | mov edx, edi 63 | wrmsr 64 | 65 | mov rdi, rsi 66 | call load_tss 67 | 68 | mov ax, 0x28 69 | ltr ax 70 | 71 | ret 72 | -------------------------------------------------------------------------------- /src/lib/cmem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void *memcpy(void *dest, const void *src, size_t n) { 6 | uint8_t *pdest = dest; 7 | const uint8_t *psrc = src; 8 | 9 | for (size_t i = 0; i < n; i++) { 10 | pdest[i] = psrc[i]; 11 | } 12 | 13 | return dest; 14 | } 15 | 16 | void *memcpy64(void *dest, const void *src, size_t n) { 17 | uint64_t *pdest = dest; 18 | const uint64_t *psrc = src; 19 | 20 | for (size_t i = 0; i < (n / sizeof(uint64_t)); i++) { 21 | pdest[i] = psrc[i]; 22 | } 23 | 24 | return dest; 25 | } 26 | 27 | void *memset(void *s, int c, size_t n) { 28 | uint8_t *p = s; 29 | 30 | for (size_t i = 0; i < n; i++) { 31 | p[i] = (uint8_t)c; 32 | } 33 | 34 | return s; 35 | } 36 | 37 | void *memset64(void *s, uint64_t c, size_t n) { 38 | uint64_t *p = s; 39 | 40 | for (size_t i = 0; i < n; i++) { 41 | p[i] = c; 42 | } 43 | 44 | return s; 45 | } 46 | 47 | void *memmove(void *dest, const void *src, size_t n) { 48 | uint8_t *pdest = dest; 49 | const uint8_t *psrc = src; 50 | 51 | if (src > dest) { 52 | for (size_t i = 0; i < n; i++) { 53 | pdest[i] = psrc[i]; 54 | } 55 | } else if (src < dest) { 56 | for (size_t i = n; i > 0; i--) { 57 | pdest[i-1] = psrc[i-1]; 58 | } 59 | } 60 | 61 | return dest; 62 | } 63 | 64 | int memcmp(const void *s1, const void *s2, size_t n) { 65 | const uint8_t *p1 = s1; 66 | const uint8_t *p2 = s2; 67 | 68 | for (size_t i = 0; i < n; i++) { 69 | if (p1[i] != p2[i]) 70 | return p1[i] < p2[i] ? -1 : 1; 71 | } 72 | 73 | return 0; 74 | } 75 | -------------------------------------------------------------------------------- /src/lib/time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | volatile uint64_t uptime_raw = 0; 7 | volatile uint64_t uptime_sec = 0; 8 | volatile uint64_t unix_epoch = 0; 9 | 10 | void tick_handler(void) { 11 | if (!(++uptime_raw % PIT_FREQUENCY_HZ)) { 12 | uptime_sec++; 13 | unix_epoch++; 14 | } 15 | } 16 | 17 | void ksleep(uint64_t time) { 18 | /* implements sleep in milliseconds */ 19 | 20 | uint64_t final_time = uptime_raw + (time * (PIT_FREQUENCY_HZ / 1000)); 21 | 22 | final_time++; 23 | 24 | while (uptime_raw < final_time); 25 | } 26 | 27 | uint64_t get_jdn(int days, int months, int years) { 28 | return (1461 * (years + 4800 + (months - 14)/12))/4 + (367 * 29 | (months - 2 - 12 * ((months - 14)/12)))/12 - (3 * ( 30 | (years + 4900 + (months - 14)/12)/100))/4 31 | + days - 32075; 32 | } 33 | 34 | uint64_t get_unix_epoch(int seconds, int minutes, int hours, 35 | int days, int months, int years) { 36 | 37 | uint64_t jdn_current = get_jdn(days, months, years); 38 | uint64_t jdn_1970 = get_jdn(1, 1, 1970); 39 | 40 | uint64_t jdn_diff = jdn_current - jdn_1970; 41 | 42 | return (jdn_diff * (60 * 60 * 24)) + hours*3600 + minutes*60 + seconds; 43 | } 44 | 45 | void add_timeval(struct timeval *val, struct timeval *to_add) { 46 | val->tv_sec += to_add->tv_sec; 47 | val->tv_usec += to_add->tv_usec; 48 | if (val->tv_usec >= 1000000) { 49 | val->tv_usec -= 1000000; 50 | val->tv_sec += 1; 51 | } 52 | } 53 | 54 | void add_usage(struct rusage_t *usage, struct rusage_t *to_add) { 55 | add_timeval(&usage->ru_stime, &to_add->ru_stime); 56 | add_timeval(&usage->ru_utime, &to_add->ru_utime); 57 | } 58 | -------------------------------------------------------------------------------- /src/lib/klib.h: -------------------------------------------------------------------------------- 1 | #ifndef __KLIB_H__ 2 | #define __KLIB_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define KPRN_MAX_TYPE 3 10 | 11 | #define KPRN_INFO 0 12 | #define KPRN_WARN 1 13 | #define KPRN_ERR 2 14 | #define KPRN_DBG 3 15 | #define KPRN_PANIC 4 16 | 17 | #define EMPTY ((void *)(size_t)(-1)) 18 | 19 | #define stringify(x) #x 20 | #define expand_stringify(x) stringify(x) 21 | 22 | #define DIV_ROUNDUP(a, b) (((a) + ((b) - 1)) / (b)) 23 | 24 | __attribute__((always_inline)) inline void memory_barrier() { 25 | asm volatile ("" ::: "memory"); 26 | } 27 | 28 | __attribute__((always_inline)) inline int is_printable(char c) { 29 | return (c >= 0x20 && c <= 0x7e); 30 | } 31 | 32 | __attribute__((always_inline)) inline void atomic_fetch_add_int(int *p, int *v, int x) { 33 | int h = x; 34 | asm volatile ( 35 | "lock xadd dword ptr [%1], %0;" 36 | : "+r" (h) 37 | : "r" (p) 38 | : "memory" 39 | ); 40 | *v = h; 41 | } 42 | 43 | __attribute__((always_inline)) inline void atomic_add_uint64_relaxed(uint64_t *p, uint64_t x) { 44 | asm volatile ( 45 | "lock xadd qword ptr [%1], %0;" 46 | : "+r" (x) 47 | : "r" (p) 48 | : "memory" 49 | ); 50 | } 51 | 52 | int exec(pid_t, const char *, const char **, const char **); 53 | 54 | pid_t kexec(const char *, const char **, const char **, 55 | const char *, const char *, const char *); 56 | 57 | char *prefixed_itoa(const char *, int64_t, int); 58 | int islower(int); 59 | int tolower(int); 60 | int toupper(int); 61 | void kprint(int type, const char *fmt, ...); 62 | void kvprint(int type, const char *fmt, va_list args); 63 | 64 | void readline(int, const char *, char *, size_t); 65 | 66 | #endif 67 | -------------------------------------------------------------------------------- /src/proc/task.asm: -------------------------------------------------------------------------------- 1 | global task_spinup 2 | global force_resched 3 | 4 | extern scheduler_lock 5 | extern resched_lock 6 | 7 | extern task_resched 8 | 9 | section .data 10 | 11 | signal_trampoline_size equ signal_trampoline.end - signal_trampoline 12 | global signal_trampoline_size 13 | global signal_trampoline 14 | signal_trampoline: 15 | mov rax, rdi 16 | shr rdi, 48 ; signum 17 | mov rdx, 0x0000ffffffffffff 18 | and rax, rdx 19 | call rax ; handler address 20 | mov rax, 28 21 | syscall ; end of signal syscall 22 | .end: 23 | 24 | section .text 25 | 26 | task_spinup: 27 | test rsi, rsi 28 | jz .dont_load_cr3 29 | mov cr3, rsi 30 | .dont_load_cr3: 31 | 32 | mov rsp, rdi 33 | 34 | pop r15 35 | pop r14 36 | pop r13 37 | pop r12 38 | pop r11 39 | pop r10 40 | pop r9 41 | pop r8 42 | pop rbp 43 | pop rdi 44 | pop rsi 45 | pop rdx 46 | pop rcx 47 | pop rbx 48 | 49 | mov rax, qword [rsp+32+8] 50 | mov ds, ax 51 | mov es, ax 52 | 53 | ; release relevant locks 54 | lock inc qword [scheduler_lock] 55 | lock inc qword [resched_lock] 56 | 57 | pop rax 58 | 59 | iretq 60 | 61 | force_resched: 62 | cli 63 | 64 | mov rax, rsp 65 | 66 | push 0x10 67 | push rax 68 | push 0x202 69 | push 0x08 70 | mov rax, .done 71 | push rax 72 | push rax 73 | push rbx 74 | push rcx 75 | push rdx 76 | push rsi 77 | push rdi 78 | push rbp 79 | push r8 80 | push r9 81 | push r10 82 | push r11 83 | push r12 84 | push r13 85 | push r14 86 | push r15 87 | 88 | ; release relevant locks 89 | lock inc qword [scheduler_lock] 90 | 91 | mov rdi, rsp 92 | .retry: 93 | xor rbp, rbp 94 | call task_resched 95 | jmp .retry 96 | 97 | .done: 98 | ret 99 | -------------------------------------------------------------------------------- /src/devices/display/vbe/vbe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | int vbe_available = 0; 12 | 13 | uint32_t *vbe_framebuffer; 14 | int vbe_width; 15 | int vbe_height; 16 | int vbe_pitch; 17 | 18 | void init_vbe(struct stivale_framebuffer_t *fb) { 19 | kprint(KPRN_INFO, "vbe: Initialising..."); 20 | 21 | vbe_framebuffer = (uint32_t *)(fb->address + MEM_PHYS_OFFSET); 22 | vbe_width = (int)fb->width; 23 | vbe_height = (int)fb->height; 24 | vbe_pitch = (int)fb->pitch; 25 | vbe_available = 1; 26 | 27 | kprint(KPRN_INFO, "vbe: Init done."); 28 | } 29 | 30 | static lock_t vesafb_lock = new_lock; 31 | 32 | static int vesafb_write(int unused1, const void *buf, uint64_t loc, size_t count) { 33 | (void)unused1; 34 | 35 | spinlock_acquire(&vesafb_lock); 36 | for (size_t i = 0; i < count; i++) 37 | ((uint8_t *)vbe_framebuffer + loc)[i] = ((uint8_t *)buf)[i]; 38 | spinlock_release(&vesafb_lock); 39 | 40 | return (int)count; 41 | } 42 | 43 | static int vesafb_read(int unused1, void *buf, uint64_t loc, size_t count) { 44 | (void)unused1; 45 | 46 | spinlock_acquire(&vesafb_lock); 47 | for (size_t i = 0; i < count; i++) 48 | ((uint8_t *)buf)[i] = ((uint8_t *)vbe_framebuffer + loc)[i]; 49 | spinlock_release(&vesafb_lock); 50 | 51 | return (int)count; 52 | } 53 | 54 | void init_dev_vesafb(void) { 55 | struct device_t device = {0}; 56 | 57 | device.calls = default_device_calls; 58 | 59 | strcpy(device.name, "vesafb"); 60 | device.size = vbe_pitch * vbe_height; 61 | device.calls.read = vesafb_read; 62 | device.calls.write = vesafb_write; 63 | device_add(&device); 64 | } 65 | -------------------------------------------------------------------------------- /src/lib/alloc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | typedef struct { 8 | size_t pages; 9 | size_t size; 10 | } alloc_metadata_t; 11 | 12 | void *kalloc(size_t size) { 13 | size_t page_count = size / PAGE_SIZE; 14 | 15 | if (size % PAGE_SIZE) page_count++; 16 | 17 | char *ptr = pmm_allocz(page_count + 1); 18 | 19 | if (!ptr) { 20 | return (void *)0; 21 | } 22 | 23 | ptr += MEM_PHYS_OFFSET; 24 | 25 | alloc_metadata_t *metadata = (alloc_metadata_t *)ptr; 26 | ptr += PAGE_SIZE; 27 | 28 | metadata->pages = page_count; 29 | metadata->size = size; 30 | 31 | return (void *)ptr; 32 | } 33 | 34 | void kfree(void *ptr) { 35 | alloc_metadata_t *metadata = (alloc_metadata_t *)((size_t)ptr - PAGE_SIZE); 36 | 37 | pmm_free((void *)((size_t)metadata - MEM_PHYS_OFFSET), metadata->pages + 1); 38 | } 39 | 40 | void *krealloc(void *ptr, size_t new) { 41 | /* check if 0 */ 42 | if (!ptr) return kalloc(new); 43 | if (!new) { 44 | kfree(ptr); 45 | return (void *)0; 46 | } 47 | 48 | /* Reference metadata page */ 49 | alloc_metadata_t *metadata = (alloc_metadata_t *)((size_t)ptr - PAGE_SIZE); 50 | 51 | if ((metadata->size + PAGE_SIZE - 1) / PAGE_SIZE 52 | == (new + PAGE_SIZE - 1) / PAGE_SIZE) { 53 | metadata->size = new; 54 | return ptr; 55 | } 56 | 57 | char *new_ptr; 58 | if ((new_ptr = kalloc(new)) == 0) { 59 | return (void *)0; 60 | } 61 | 62 | if (metadata->size > new) 63 | /* Copy all the data from the old pointer to the new pointer, 64 | * within the range specified by `size`. */ 65 | memcpy(new_ptr, (char *)ptr, new); 66 | else 67 | memcpy(new_ptr, (char *)ptr, metadata->size); 68 | 69 | kfree(ptr); 70 | 71 | return new_ptr; 72 | } 73 | -------------------------------------------------------------------------------- /src/lib/event.h: -------------------------------------------------------------------------------- 1 | #ifndef __EVENT_H__ 2 | #define __EVENT_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | static inline int events_await(event_t **event, int *out_events, int n) { 11 | int wake = 0; 12 | 13 | for(int i = 0; i < n; i++) { 14 | if(locked_read(event_t, event[i])) { 15 | wake = 1; 16 | locked_dec(event[i]); 17 | out_events[i] = 1; 18 | } 19 | } 20 | if(wake) { 21 | return 0; 22 | } 23 | 24 | struct thread_t *current_thread = task_table[cpu_locals[current_cpu].current_task]; 25 | current_thread->event_num = n; 26 | current_thread->out_event_ptr = out_events; 27 | locked_write(event_t **, ¤t_thread->event_ptr, event); 28 | yield(); 29 | if (locked_read(int, ¤t_thread->event_abrt)) 30 | return -1; 31 | return 0; 32 | } 33 | 34 | static inline int events_await_timeout(event_t **event, int *out_events, int n, size_t timeout) { 35 | uint64_t yield_target = (uptime_raw + (timeout * (PIT_FREQUENCY_HZ / 1000))) + 1; 36 | struct thread_t *current_thread = task_table[cpu_locals[current_cpu].current_task]; 37 | current_thread->event_timeout = yield_target; 38 | 39 | int ret = events_await(event, out_events, n); 40 | if(ret == -1) { 41 | return -1; 42 | } else { 43 | return current_thread->event_timeout == 0; 44 | } 45 | } 46 | 47 | static inline int event_await_timeout(event_t *event, size_t timeout) { 48 | event_t *evts[1] = {event}; 49 | event_t evts_out[1] = {0}; 50 | return events_await_timeout(evts, evts_out, 1, timeout); 51 | } 52 | 53 | static inline int event_await(event_t *event) { 54 | event_t *evts[1] = {event}; 55 | event_t out_evts[1] = {0}; 56 | return events_await(evts, out_evts, 1); 57 | } 58 | 59 | static inline void event_trigger(event_t *event) { 60 | locked_inc(event); 61 | } 62 | 63 | #endif 64 | -------------------------------------------------------------------------------- /src/sys/pic_8259.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define CMD_INIT 0x11 7 | #define MODE_8086 0x01 8 | #define EOI 0x20 9 | 10 | /* EOI for PICS */ 11 | void pic_8259_eoi(uint8_t current_vector) { 12 | if (current_vector >= 8) { 13 | port_out_b(0xa0, 0x20); 14 | } 15 | 16 | port_out_b(0x20, 0x20); 17 | } 18 | 19 | /* Remap the PIC IRQs to the given vector offsets */ 20 | void pic_8259_remap(uint8_t pic0_offset, uint8_t pic1_offset) { 21 | kprint(KPRN_INFO,"pic_8259: Initialising with offsets %x and %x", 22 | (uint32_t)pic0_offset, 23 | (uint32_t)pic1_offset); 24 | 25 | /* Save masks */ 26 | uint8_t pic0_mask = port_in_b(0x21); 27 | uint8_t pic1_mask = port_in_b(0xa1); 28 | 29 | port_out_b(0x20, CMD_INIT); 30 | io_wait(); 31 | port_out_b(0xa0, CMD_INIT); 32 | io_wait(); 33 | 34 | port_out_b(0x21, pic0_offset); 35 | io_wait(); 36 | port_out_b(0xa1, pic1_offset); 37 | io_wait(); 38 | 39 | port_out_b(0x21, 4); 40 | io_wait(); 41 | port_out_b(0xa1, 2); 42 | io_wait(); 43 | 44 | port_out_b(0x21, MODE_8086); 45 | io_wait(); 46 | port_out_b(0xa1, MODE_8086); 47 | io_wait(); 48 | 49 | /* Restore masks */ 50 | port_out_b(0x21, pic0_mask); 51 | io_wait(); 52 | port_out_b(0xa1, pic1_mask); 53 | io_wait(); 54 | } 55 | 56 | /* Mask IRQ `line`. */ 57 | void pic_8259_set_mask(uint8_t line, int status) { 58 | uint16_t port; 59 | uint8_t value; 60 | 61 | if (line < 8) { 62 | port = 0x21; 63 | } else { 64 | port = 0xa1; 65 | line -= 8; 66 | } 67 | 68 | if (!status) 69 | value = port_in_b(port) & ~((uint8_t)1 << line); 70 | else 71 | value = port_in_b(port) | ((uint8_t)1 << line); 72 | 73 | port_out_b(port, value); 74 | io_wait(); 75 | } 76 | 77 | void pic_8259_mask_all(void) { 78 | port_out_b(0xa1, 0xff); 79 | port_out_b(0x21, 0xff); 80 | } 81 | -------------------------------------------------------------------------------- /src/lib/signal.h: -------------------------------------------------------------------------------- 1 | #ifndef __SIGNAL_H__ 2 | #define __SIGNAL_H__ 3 | 4 | #define SIGNAL_MAX (sizeof(signames) / sizeof(char *)) 5 | 6 | #define SIGNAL_TRAMPOLINE_VADDR ((size_t)0x0000740000000000) 7 | 8 | typedef long sigset_t; 9 | 10 | struct sigaction { 11 | void (*sa_handler)(int); 12 | sigset_t sa_mask; 13 | int sa_flags; 14 | void (*sa_sigaction)(int, /*siginfo_t*/void *, void *); 15 | }; 16 | 17 | #define SA_NOCLDSTOP (1 << 0) 18 | #define SA_ONSTACK (1 << 1) 19 | #define SA_RESETHAND (1 << 2) 20 | #define SA_RESTART (1 << 3) 21 | #define SA_SIGINFO (1 << 4) 22 | #define SA_NOCLDWAIT (1 << 5) 23 | #define SA_NODEFER (1 << 6) 24 | 25 | // from: mlibc/options/ansi/include/signal.h 26 | 27 | #define SIG_ERR (void *)(-1) 28 | #define SIG_DFL (void *)(-2) 29 | #define SIG_IGN (void *)(-3) 30 | 31 | // XXX fix these once they're fixed in mlibc 32 | #define SIGABRT 1 33 | #define SIGFPE 2 34 | #define SIGILL 3 35 | #define SIGINT 4 36 | #define SIGSEGV 5 37 | #define SIGTERM 6 38 | #define SIGPROF 7 39 | #define SIGALRM 8 40 | #define SIGBUS 9 41 | #define SIGCHLD 10 42 | #define SIGCONT 11 43 | #define SIGHUP 12 44 | #define SIGKILL 13 45 | #define SIGPIPE 14 46 | #define SIGQUIT 15 47 | #define SIGSTOP 16 48 | #define SIGTSTP 17 49 | #define SIGTTIN 18 50 | #define SIGTTOU 19 51 | #define SIGUSR1 20 52 | #define SIGUSR2 21 53 | #define SIGSYS 22 54 | #define SIGTRAP 23 55 | #define SIGURG 24 56 | #define SIGVTALRM 25 57 | #define SIGXCPU 26 58 | #define SIGXFSZ 27 59 | #define SIGWINCH 28 60 | 61 | __attribute__((unused)) static const char *signames[] = { 62 | "0", 63 | "SIGABRT", 64 | "SIGFPE", 65 | "SIGILL", 66 | "SIGINT", 67 | "SIGSEGV", 68 | "SIGTERM", 69 | "SIGPROF", 70 | "SIGALRM", 71 | "SIGBUS", 72 | "SIGCHLD", 73 | "SIGCONT", 74 | "SIGHUP", 75 | "SIGKILL", 76 | "SIGPIPE", 77 | "SIGQUIT", 78 | "SIGSTOP", 79 | "SIGTSTP", 80 | "SIGTTIN", 81 | "SIGTTOU", 82 | "SIGUSR1", 83 | "SIGUSR2", 84 | "SIGSYS", 85 | "SIGTRAP", 86 | "SIGURG", 87 | "SIGVTALRM", 88 | "SIGXCPU", 89 | "SIGXFSZ", 90 | "SIGWINCH" 91 | }; 92 | 93 | #endif 94 | -------------------------------------------------------------------------------- /src/devices/streams/streams.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | /** /dev/urandom **/ 7 | 8 | static int urandom_write(int unused1, const void *unused2, uint64_t unused3, size_t count) { 9 | (void)unused1; 10 | (void)unused2; 11 | (void)unused3; 12 | 13 | return (int)count; 14 | } 15 | 16 | static int urandom_read(int unused1, void *buf, uint64_t unused2, size_t count) { 17 | (void)unused1; 18 | (void)unused2; 19 | 20 | uint8_t *buf1 = buf; 21 | 22 | for (size_t i = 0; i < count; i++) 23 | buf1[i] = (uint8_t)(rand32() % 0x100); 24 | 25 | return count; 26 | } 27 | 28 | /** /dev/null **/ 29 | 30 | static int null_write(int unused1, const void *unused2, uint64_t unused3, size_t count) { 31 | (void)unused1; 32 | (void)unused2; 33 | (void)unused3; 34 | 35 | return (int)count; 36 | } 37 | 38 | static int null_read(int unused1, void *unused2, uint64_t unused3, size_t unused4) { 39 | (void)unused1; 40 | (void)unused2; 41 | (void)unused3; 42 | (void)unused4; 43 | 44 | return 0; 45 | } 46 | 47 | /** /dev/zero **/ 48 | 49 | static int zero_write(int unused1, const void *unused2, uint64_t unused3, size_t count) { 50 | (void)unused1; 51 | (void)unused2; 52 | (void)unused3; 53 | 54 | return (int)count; 55 | } 56 | 57 | static int zero_read(int unused1, void *buf, uint64_t unused2, size_t count) { 58 | (void)unused1; 59 | (void)unused2; 60 | 61 | uint8_t *buf1 = buf; 62 | 63 | for (size_t i = 0; i < count; i++) 64 | buf1[i] = 0; 65 | 66 | return (int)count; 67 | } 68 | 69 | /** initialise **/ 70 | 71 | void init_dev_streams(void) { 72 | struct device_t device = {0}; 73 | 74 | device.calls = default_device_calls; 75 | 76 | strcpy(device.name, "null"); 77 | device.calls.read = null_read; 78 | device.calls.write = null_write; 79 | device_add(&device); 80 | 81 | strcpy(device.name, "zero"); 82 | device.calls.read = zero_read; 83 | device.calls.write = zero_write; 84 | device_add(&device); 85 | 86 | strcpy(device.name, "urandom"); 87 | device.calls.read = urandom_read; 88 | device.calls.write = urandom_write; 89 | device_add(&device); 90 | } 91 | -------------------------------------------------------------------------------- /src/lib/rand.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void init_rand(void) { 6 | uint32_t seed = ((uint32_t)0xc597060c * rdtsc(uint32_t)) 7 | * ((uint32_t)0xce86d624) 8 | ^ ((uint32_t)0xee0da130 * rdtsc(uint32_t)); 9 | 10 | if (!rdrand_supported) { 11 | kprint(KPRN_INFO, "rand: rdrand instruction not supported"); 12 | srand(seed); 13 | } else { 14 | kprint(KPRN_INFO, "rand: rdrand instruction supported"); 15 | seed *= (seed ^ rdrand(uint32_t)); 16 | srand(seed); 17 | } 18 | } 19 | 20 | #define n ((int)624) 21 | #define m ((int)397) 22 | #define matrix_a ((uint32_t)0x9908b0df) 23 | #define msb ((uint32_t)0x80000000) 24 | #define lsbs ((uint32_t)0x7fffffff) 25 | 26 | static uint32_t status[n]; 27 | static int ctr; 28 | 29 | static lock_t rand_lock = new_lock; 30 | 31 | void srand(uint32_t s) { 32 | spinlock_acquire(&rand_lock); 33 | status[0] = s; 34 | for (ctr = 1; ctr < n; ctr++) 35 | status[ctr] = (1812433253 * (status[ctr - 1] ^ (status[ctr - 1] >> 30)) + ctr); 36 | spinlock_release(&rand_lock); 37 | } 38 | 39 | uint32_t rand32(void) { 40 | spinlock_acquire(&rand_lock); 41 | 42 | const uint32_t mag01[2] = {0, matrix_a}; 43 | 44 | if (ctr >= n) { 45 | for (int kk = 0; kk < n - m; kk++) { 46 | uint32_t y = (status[kk] & msb) | (status[kk + 1] & lsbs); 47 | status[kk] = status[kk + m] ^ (y >> 1) ^ mag01[y & 1]; 48 | } 49 | 50 | for (int kk = n - m; kk < n - 1; kk++) { 51 | uint32_t y = (status[kk] & msb) | (status[kk + 1] & lsbs); 52 | status[kk] = status[kk + (m - n)] ^ (y >> 1) ^ mag01[y & 1]; 53 | } 54 | 55 | uint32_t y = (status[n - 1] & msb) | (status[0] & lsbs); 56 | status[n - 1] = status[m - 1] ^ (y >> 1) ^ mag01[y & 1]; 57 | 58 | ctr = 0; 59 | } 60 | 61 | uint32_t res = status[ctr++]; 62 | 63 | res ^= (res >> 11); 64 | res ^= (res << 7) & 0x9d2c5680; 65 | res ^= (res << 15) & 0xefc60000; 66 | res ^= (res >> 18); 67 | 68 | spinlock_release(&rand_lock); 69 | return res; 70 | } 71 | 72 | uint64_t rand64(void) { 73 | return (((uint64_t)rand32()) << 32) | (uint64_t)rand32(); 74 | } 75 | -------------------------------------------------------------------------------- /src/lib/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef __ERRNO_H__ 2 | #define __ERRNO_H__ 3 | 4 | #include 5 | 6 | #define errno (cpu_locals[current_cpu].thread_errno) 7 | 8 | /* Definitions from "options/posix/include/bits/posix/posix_errno.h" in mlibc */ 9 | 10 | #define EDOM 1 11 | #define EILSEQ 2 12 | #define ERANGE 3 13 | 14 | #define E2BIG 1001 15 | #define EACCES 1002 16 | #define EADDRINUSE 1003 17 | #define EADDRNOTAVAIL 1004 18 | #define EAFNOSUPPORT 1005 19 | #define EAGAIN 1006 20 | #define EALREADY 1007 21 | #define EBADF 1008 22 | #define EBADMSG 1009 23 | #define EBUSY 1010 24 | #define ECANCELED 1011 25 | #define ECHILD 1012 26 | #define ECONNABORTED 1013 27 | #define ECONNREFUSED 1014 28 | #define ECONNRESET 1015 29 | #define EDEADLK 1016 30 | #define EDESTADDRREQ 1017 31 | #define EDQUOT 1018 32 | #define EEXIST 1019 33 | #define EFAULT 1020 34 | #define EFBIG 1021 35 | #define EHOSTUNREACH 1022 36 | #define EIDRM 1023 37 | #define EINPROGRESS 1024 38 | #define EINTR 1025 39 | #define EINVAL 1026 40 | #define EIO 1027 41 | #define EISCONN 1028 42 | #define EISDIR 1029 43 | #define ELOOP 1030 44 | #define EMFILE 1031 45 | #define EMLINK 1032 46 | #define EMSGSIZE 1034 47 | #define EMULTIHOP 1035 48 | #define ENAMETOOLONG 1036 49 | #define ENETDOWN 1037 50 | #define ENETRESET 1038 51 | #define ENETUNREACH 1039 52 | #define ENFILE 1040 53 | #define ENOBUFS 1041 54 | #define ENODEV 1042 55 | #define ENOENT 1043 56 | #define ENOEXEC 1044 57 | #define ENOLCK 1045 58 | #define ENOLINK 1046 59 | #define ENOMEM 1047 60 | #define ENOMSG 1048 61 | #define ENOPROTOOPT 1049 62 | #define ENOSPC 1050 63 | #define ENOSYS 1051 64 | #define ENOTCONN 1052 65 | #define ENOTDIR 1053 66 | #define ENOTEMPTY 1054 67 | #define ENOTRECOVERABLE 1055 68 | #define ENOTSOCK 1056 69 | #define ENOTSUP 1057 70 | #define ENOTTY 1058 71 | #define ENXIO 1059 72 | #define EOPNOTSUPP 1060 73 | #define EOVERFLOW 1061 74 | #define EOWNERDEAD 1062 75 | #define EPERM 1063 76 | #define EPIPE 1064 77 | #define EPROTO 1065 78 | #define EPROTONOSUPPORT 1066 79 | #define EPROTOTYPE 1067 80 | #define EROFS 1068 81 | #define ESPIPE 1069 82 | #define ESRCH 1070 83 | #define ESTALE 1071 84 | #define ETIMEDOUT 1072 85 | #define ETXTBSY 1073 86 | #define EWOULDBLOCK EAGAIN 87 | #define EXDEV 1075 88 | #define ENODATA 1076 89 | #define ETIME 1077 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/acpi/madt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int madt_available = 0; 9 | struct madt_t *madt; 10 | 11 | struct madt_local_apic_t **madt_local_apics; 12 | size_t madt_local_apic_i = 0; 13 | 14 | struct madt_io_apic_t **madt_io_apics; 15 | size_t madt_io_apic_i = 0; 16 | 17 | struct madt_iso_t **madt_isos; 18 | size_t madt_iso_i = 0; 19 | 20 | struct madt_nmi_t **madt_nmis; 21 | size_t madt_nmi_i = 0; 22 | 23 | void init_madt(void) { 24 | /* search for MADT table */ 25 | if ((madt = acpi_find_sdt("APIC", 0))) { 26 | madt_available = 1; 27 | } else { 28 | madt_available = 0; 29 | return; 30 | } 31 | 32 | madt_local_apics = kalloc(ACPI_TABLES_MAX); 33 | madt_io_apics = kalloc(ACPI_TABLES_MAX); 34 | madt_isos = kalloc(ACPI_TABLES_MAX); 35 | madt_nmis = kalloc(ACPI_TABLES_MAX); 36 | 37 | /* parse the MADT entries */ 38 | for (uint8_t *madt_ptr = (uint8_t *)(&madt->madt_entries_begin); 39 | (size_t)madt_ptr < (size_t)madt + madt->sdt.length; 40 | madt_ptr += *(madt_ptr + 1)) { 41 | switch (*(madt_ptr)) { 42 | case 0: 43 | /* processor local APIC */ 44 | kprint(KPRN_INFO, "acpi/madt: Found local APIC #%u", madt_local_apic_i); 45 | madt_local_apics[madt_local_apic_i++] = (struct madt_local_apic_t *)madt_ptr; 46 | break; 47 | case 1: 48 | /* I/O APIC */ 49 | kprint(KPRN_INFO, "acpi/madt: Found I/O APIC #%u", madt_io_apic_i); 50 | madt_io_apics[madt_io_apic_i++] = (struct madt_io_apic_t *)madt_ptr; 51 | break; 52 | case 2: 53 | /* interrupt source override */ 54 | kprint(KPRN_INFO, "acpi/madt: Found ISO #%u", madt_iso_i); 55 | madt_isos[madt_iso_i++] = (struct madt_iso_t *)madt_ptr; 56 | break; 57 | case 4: 58 | /* NMI */ 59 | kprint(KPRN_INFO, "acpi/madt: Found NMI #%u", madt_nmi_i); 60 | madt_nmis[madt_nmi_i++] = (struct madt_nmi_t *)madt_ptr; 61 | break; 62 | default: 63 | break; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/lib/cio.h: -------------------------------------------------------------------------------- 1 | #ifndef __CIO_H__ 2 | #define __CIO_H__ 3 | 4 | #include 5 | 6 | static inline uint8_t mmio_read8(uint64_t address) { 7 | return *((volatile uint8_t*)(address)); 8 | } 9 | 10 | static inline uint16_t mmio_read16(uint64_t address) { 11 | return *((volatile uint16_t*)(address)); 12 | } 13 | 14 | static inline uint32_t mmio_read32(uint64_t address) { 15 | return *((volatile uint32_t*)(address)); 16 | } 17 | 18 | static inline uint64_t mmio_read64(uint64_t address) { 19 | return *((volatile uint64_t*)(address)); 20 | } 21 | 22 | static inline void mmio_write8(uint64_t address, uint8_t value) { 23 | (*((volatile uint8_t*)(address))) = value; 24 | } 25 | 26 | static inline void mmio_write16(uint64_t address, uint16_t value) { 27 | (*((volatile uint16_t*)(address))) = value; 28 | } 29 | 30 | static inline void mmio_write32(uint64_t address, uint32_t value) { 31 | (*((volatile uint32_t*)(address))) = value; 32 | } 33 | 34 | static inline void mmio_write64(uint64_t address, uint64_t value) { 35 | (*((volatile uint64_t*)(address)))= value; 36 | } 37 | 38 | #define port_out_b(port, value) ({ \ 39 | asm volatile ( "out dx, al" \ 40 | : \ 41 | : "a" (value), "d" (port) \ 42 | : ); \ 43 | }) 44 | 45 | #define port_out_w(port, value) ({ \ 46 | asm volatile ( "out dx, ax" \ 47 | : \ 48 | : "a" (value), "d" (port) \ 49 | : ); \ 50 | }) 51 | 52 | #define port_out_d(port, value) ({ \ 53 | asm volatile ( "out dx, eax" \ 54 | : \ 55 | : "a" (value), "d" (port) \ 56 | : ); \ 57 | }) 58 | 59 | #define port_in_b(port) ({ \ 60 | uint8_t value; \ 61 | asm volatile ( "in al, dx" \ 62 | : "=a" (value) \ 63 | : "d" (port) \ 64 | : ); \ 65 | value; \ 66 | }) 67 | 68 | #define port_in_w(port) ({ \ 69 | uint16_t value; \ 70 | asm volatile ( "in ax, dx" \ 71 | : "=a" (value) \ 72 | : "d" (port) \ 73 | : ); \ 74 | value; \ 75 | }) 76 | 77 | #define port_in_d(port) ({ \ 78 | uint32_t value; \ 79 | asm volatile ( "in eax, dx" \ 80 | : "=a" (value) \ 81 | : "d" (port) \ 82 | : ); \ 83 | value; \ 84 | }) 85 | 86 | #define io_wait() ({ port_out_b(0x80, 0x00); }) 87 | 88 | #define disable_interrupts() ({ asm volatile ("cli"); }) 89 | #define enable_interrupts() ({ asm volatile ("sti"); }) 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/sys/exceptions.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define EXC_DIV0 0x0 12 | #define EXC_DEBUG 0x1 13 | #define EXC_NMI 0x2 14 | #define EXC_BREAKPOINT 0x3 15 | #define EXC_OVERFLOW 0x4 16 | #define EXC_BOUND 0x5 17 | #define EXC_INVOPCODE 0x6 18 | #define EXC_NODEV 0x7 19 | #define EXC_DBFAULT 0x8 20 | #define EXC_INVTSS 0xa 21 | #define EXC_NOSEGMENT 0xb 22 | #define EXC_SSFAULT 0xc 23 | #define EXC_GPF 0xd 24 | #define EXC_PAGEFAULT 0xe 25 | #define EXC_FP 0x10 26 | #define EXC_ALIGN 0x11 27 | #define EXC_MACHINECHK 0x12 28 | #define EXC_SIMD 0x13 29 | #define EXC_VIRT 0x14 30 | #define EXC_SECURITY 0x1e 31 | 32 | static const char *exception_names[] = { 33 | "Division by 0", 34 | "Debug", 35 | "NMI", 36 | "Breakpoint", 37 | "Overflow", 38 | "Bound range exceeded", 39 | "Invalid opcode", 40 | "Device not available", 41 | "Double fault", 42 | "???", 43 | "Invalid TSS", 44 | "Segment not present", 45 | "Stack-segment fault", 46 | "General protection fault", 47 | "Page fault", 48 | "???", 49 | "x87 exception", 50 | "Alignment check", 51 | "Machine check", 52 | "SIMD exception", 53 | "Virtualisation", 54 | "???", 55 | "???", 56 | "???", 57 | "???", 58 | "???", 59 | "???", 60 | "???", 61 | "???", 62 | "???", 63 | "Security" 64 | }; 65 | 66 | void exception_handler(int exception, struct regs_t *regs, size_t error_code) { 67 | if (regs->cs == 0x23) { 68 | // userspace 69 | switch (exception) { 70 | case 0: 71 | case 16: 72 | case 19: 73 | asm volatile ("sti"); 74 | kill(cpu_locals[current_cpu].current_process, SIGFPE); 75 | return; 76 | case 6: 77 | asm volatile ("sti"); 78 | kill(cpu_locals[current_cpu].current_process, SIGILL); 79 | return; 80 | case 13: 81 | case 14: 82 | asm volatile ("sti"); 83 | kill(cpu_locals[current_cpu].current_process, SIGSEGV); 84 | return; 85 | } 86 | } 87 | 88 | // this is a kernel exception/unhandled exception, ouch! 89 | panic(regs, 1, "%s, Number: %X, Error code: %X", exception_names[exception], 90 | exception, error_code); 91 | } 92 | -------------------------------------------------------------------------------- /src/fd/vfs/vfs.h: -------------------------------------------------------------------------------- 1 | #ifndef __VFS_H__ 2 | #define __VFS_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /* FIXME: Inherit struct fd_t */ 9 | 10 | /* A filesystem, defined by the function pointers that allow us to access it */ 11 | struct fs_t { 12 | char name[256]; 13 | int (*mount)(const char *, unsigned long, const void *); 14 | int (*umount)(int); 15 | int (*open)(const char *, int, int); 16 | int (*close)(int); 17 | int (*fstat)(int, struct stat *); 18 | int (*read)(int, void *, size_t); 19 | int (*write)(int, const void *, size_t); 20 | int (*lseek)(int, off_t, int); 21 | int (*dup)(int); 22 | int (*readdir)(int, struct dirent *); 23 | int (*sync)(void); 24 | int (*tcgetattr)(int, struct termios *); 25 | int (*tcsetattr)(int, int, struct termios *); 26 | int (*tcflow)(int, int); 27 | int (*isatty)(int); 28 | int (*unlink)(int); 29 | int (*mkdir)(const char *, int); 30 | int (*getpath)(int, char *); 31 | }; 32 | 33 | __attribute__((unused)) static int bogus_mount() { 34 | errno = EIO; 35 | return -1; 36 | } 37 | 38 | __attribute__((unused)) static int bogus_umount() { 39 | errno = EIO; 40 | return -1; 41 | } 42 | 43 | __attribute__((unused)) static int bogus_open() { 44 | errno = EIO; 45 | return -1; 46 | } 47 | 48 | __attribute__((unused)) static int bogus_sync() { 49 | errno = EIO; 50 | return -1; 51 | } 52 | 53 | __attribute__((unused)) static int bogus_mkdir() { 54 | errno = EIO; 55 | return -1; 56 | } 57 | 58 | __attribute__((unused)) static struct fs_t default_fs_handler = { 59 | "bogusfs", 60 | (void *)bogus_mount, 61 | (void *)bogus_umount, 62 | (void *)bogus_open, 63 | (void *)bogus_close, 64 | (void *)bogus_fstat, 65 | (void *)bogus_read, 66 | (void *)bogus_write, 67 | (void *)bogus_lseek, 68 | (void *)bogus_dup, 69 | (void *)bogus_readdir, 70 | (void *)bogus_sync, 71 | (void *)bogus_tcgetattr, 72 | (void *)bogus_tcsetattr, 73 | (void *)bogus_tcflow, 74 | (void *)bogus_isatty, 75 | (void *)bogus_unlink, 76 | (void *)bogus_mkdir, 77 | (void *)bogus_getpath 78 | }; 79 | 80 | /* VFS calls */ 81 | int mount(const char *, const char *, const char *, unsigned long, const void *); 82 | int umount(const char *); 83 | int open(const char *, int); 84 | int mkdir(const char *); 85 | 86 | int vfs_sync(void); 87 | void vfs_sync_worker(void *); 88 | void vfs_get_absolute_path(char *, const char *, const char *); 89 | int vfs_install_fs(struct fs_t *); 90 | 91 | #endif 92 | -------------------------------------------------------------------------------- /src/sys/pci.h: -------------------------------------------------------------------------------- 1 | #ifndef __PCI_H__ 2 | #define __PCI_H__ 3 | 4 | #include 5 | #include 6 | 7 | struct pci_device_t { 8 | int64_t parent; 9 | uint8_t bus; 10 | uint8_t func; 11 | uint8_t device; 12 | uint16_t device_id; 13 | uint16_t vendor_id; 14 | uint8_t rev_id; 15 | uint8_t subclass; 16 | uint8_t device_class; 17 | uint8_t prog_if; 18 | int multifunction; 19 | uint8_t irq_pin; 20 | int has_prt; 21 | uint32_t gsi; 22 | uint16_t gsi_flags; 23 | }; 24 | 25 | struct pci_bar_t { 26 | uintptr_t base; 27 | size_t size; 28 | 29 | int is_mmio; 30 | int is_prefetchable; 31 | }; 32 | 33 | #define MSI_OPT 2 34 | #define MSI_ADDR_LOW 0x4 35 | #define MSI_DATA_32 0x8 36 | #define MSI_DATA_64 0xC 37 | #define MSI_64BIT_SUPPORTED (1 << 7) 38 | 39 | union msi_address_t { 40 | struct { 41 | uint32_t _reserved0 : 2; 42 | uint32_t destination_mode : 1; 43 | uint32_t redirection_hint : 1; 44 | uint32_t _reserved1 : 8; 45 | uint32_t destination_id : 8; 46 | // must be 0xFEE 47 | uint32_t base_address : 12; 48 | }; 49 | uint32_t raw; 50 | } __attribute__((packed)); 51 | 52 | union msi_data_t { 53 | struct { 54 | uint32_t vector : 8; 55 | uint32_t delivery_mode : 3; 56 | uint32_t _reserved0 : 3; 57 | uint32_t level : 1; 58 | uint32_t trigger_mode : 1; 59 | uint32_t _reserved1 : 16; 60 | }; 61 | uint32_t raw; 62 | } __attribute__((packed)); 63 | 64 | 65 | uint8_t pci_read_device_byte(struct pci_device_t *device, uint32_t offset); 66 | void pci_write_device_byte(struct pci_device_t *device, uint32_t offset, uint8_t value); 67 | uint16_t pci_read_device_word(struct pci_device_t *device, uint32_t offset); 68 | void pci_write_device_word(struct pci_device_t *device, uint32_t offset, uint16_t value); 69 | uint32_t pci_read_device_dword(struct pci_device_t *device, uint32_t offset); 70 | void pci_write_device_dword(struct pci_device_t *device, uint32_t offset, uint32_t value); 71 | 72 | int pci_read_bar(struct pci_device_t *device, int bar, struct pci_bar_t *out); 73 | void pci_enable_busmastering(struct pci_device_t *device); 74 | void pci_enable_interrupts(struct pci_device_t *device); 75 | int pci_register_msi(struct pci_device_t *device, uint8_t vector); 76 | 77 | struct pci_device_t *pci_get_device(uint8_t class, uint8_t subclass, uint8_t prog_if, size_t index); 78 | struct pci_device_t *pci_get_device_by_vendor(uint16_t vendor, uint16_t id, size_t index); 79 | 80 | void init_pci(void); 81 | 82 | #endif 83 | -------------------------------------------------------------------------------- /src/sys/smp_trampoline.real: -------------------------------------------------------------------------------- 1 | org 0x1000 2 | bits 16 3 | 4 | cli 5 | cld 6 | 7 | xor ax, ax 8 | mov ds, ax 9 | 10 | ; set the flag 11 | mov byte [0x510], 1 12 | 13 | jmp 0x0:fix_cs 14 | fix_cs: 15 | mov es, ax 16 | mov fs, ax 17 | mov gs, ax 18 | mov ss, ax 19 | 20 | lgdt [gdt_ptr] 21 | 22 | mov edx, dword [0x540] 23 | mov cr3, edx 24 | 25 | mov eax, cr4 26 | or eax, 1 << 5 27 | or eax, 1 << 7 28 | mov cr4, eax 29 | 30 | mov ecx, 0xc0000080 31 | rdmsr 32 | 33 | or eax, 0x00000100 34 | wrmsr 35 | 36 | mov eax, cr0 37 | or eax, 0x80000001 38 | and eax, ~(0x60000000) 39 | mov cr0, eax 40 | 41 | jmp 0x08:.mode64 42 | .mode64: 43 | bits 64 44 | mov ax, 0x10 45 | mov ds, ax 46 | mov es, ax 47 | mov ss, ax 48 | mov ax, 0x1b 49 | mov fs, ax 50 | mov gs, ax 51 | 52 | mov rsp, qword [0x550] 53 | 54 | lgdt [0x580] 55 | lidt [0x590] 56 | 57 | ; Load GS with the CPU local struct base address 58 | mov rcx, 0xc0000101 59 | mov eax, dword [0x560] 60 | mov edx, dword [0x560+4] 61 | wrmsr 62 | 63 | ; Load TSS 64 | mov ax, 0x28 65 | ltr ax 66 | 67 | ; jump to entry point 68 | mov rbx, qword [0x520] 69 | call rbx 70 | 71 | align 16 72 | 73 | gdt_ptr: 74 | dw .gdt_end - .gdt_start - 1 ; GDT size 75 | dq .gdt_start ; GDT start 76 | 77 | align 16 78 | .gdt_start: 79 | 80 | ; Null descriptor (required) 81 | .null_descriptor: 82 | dw 0x0000 ; Limit 83 | dw 0x0000 ; Base (low 16 bits) 84 | db 0x00 ; Base (mid 8 bits) 85 | db 00000000b ; Access 86 | db 00000000b ; Granularity 87 | db 0x00 ; Base (high 8 bits) 88 | 89 | ; 64 bit mode kernel 90 | .kernel_code_64: 91 | dw 0x0000 ; Limit 92 | dw 0x0000 ; Base (low 16 bits) 93 | db 0x00 ; Base (mid 8 bits) 94 | db 10011010b ; Access 95 | db 00100000b ; Granularity 96 | db 0x00 ; Base (high 8 bits) 97 | 98 | .kernel_data: 99 | dw 0x0000 ; Limit 100 | dw 0x0000 ; Base (low 16 bits) 101 | db 0x00 ; Base (mid 8 bits) 102 | db 10010010b ; Access 103 | db 00000000b ; Granularity 104 | db 0x00 ; Base (high 8 bits) 105 | 106 | .user_data_64: 107 | dw 0x0000 ; Limit 108 | dw 0x0000 ; Base (low 16 bits) 109 | db 0x00 ; Base (mid 8 bits) 110 | db 11110010b ; Access 111 | db 00000000b ; Granularity 112 | db 0x00 ; Base (high 8 bits) 113 | 114 | .gdt_end: 115 | -------------------------------------------------------------------------------- /src/sys/cpu.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | unsigned int cpu_simd_region_size; 6 | 7 | void (*cpu_save_simd)(void *); 8 | void (*cpu_restore_simd)(void *); 9 | 10 | #define XSAVE_BIT (1 << 26) 11 | #define AVX_BIT (1 << 28) 12 | #define AVX512_BIT (1 << 16) 13 | 14 | void syscall_entry(void); 15 | 16 | void init_cpu_features(void) { 17 | // First enable SSE/SSE2 as it is baseline for x86_64 18 | uint64_t cr0 = 0; 19 | cr0 = read_cr("0"); 20 | cr0 &= ~(1 << 2); 21 | cr0 |= (1 << 1); 22 | write_cr("0", cr0); 23 | 24 | uint64_t cr4 = 0; 25 | cr4 = read_cr("4"); 26 | cr4 |= (3 << 9); 27 | write_cr("4", cr4); 28 | 29 | // Initialise the PAT 30 | uint64_t pat_msr = rdmsr(0x277); 31 | pat_msr &= 0xffffffff; 32 | // write-protect / write-combining 33 | pat_msr |= (uint64_t)0x0105 << 32; 34 | wrmsr(0x277, pat_msr); 35 | 36 | // Enable syscall in EFER 37 | uint64_t efer = rdmsr(0xc0000080); 38 | efer |= 1; 39 | wrmsr(0xc0000080, efer); 40 | 41 | // Set up syscall 42 | wrmsr(0xc0000081, 0x0013000800000000); 43 | // Syscall entry address 44 | wrmsr(0xc0000082, (uint64_t)syscall_entry); 45 | // Flags mask 46 | wrmsr(0xc0000084, (uint64_t)~((uint32_t)0x002)); 47 | 48 | uint32_t a, b, c, d; 49 | cpuid(1, 0, &a, &b, &c, &d); 50 | 51 | if ((c & XSAVE_BIT)) { 52 | cr4 = read_cr("4"); 53 | cr4 |= (1 << 18); // Enable XSAVE and x{get, set}bv 54 | write_cr("4", cr4); 55 | 56 | uint64_t xcr0 = 0; 57 | xcr0 |= (1 << 0); // Save x87 state with xsave 58 | xcr0 |= (1 << 1); // Save SSE state with xsave 59 | 60 | if ((c & AVX_BIT)) 61 | xcr0 |= (1 << 2); // Enable AVX and save AVX state with xsave 62 | 63 | if (cpuid(7, 0, &a, &b, &c, &d)) { 64 | if((b & AVX512_BIT)) { 65 | xcr0 |= (1 << 5); // Enable AVX-512 66 | xcr0 |= (1 << 6); // Enable management of ZMM{0 -> 15} 67 | xcr0 |= (1 << 7); // Enable management of ZMM{16 -> 31} 68 | } 69 | } 70 | wrxcr(0, xcr0); 71 | 72 | if (cpuid(0xD, 0, &a, &b, &c, &d)) { 73 | cpu_simd_region_size = c; 74 | } else { 75 | panic(NULL, 0, "Enabled xsave but cpuid leaf doesn't exist"); 76 | } 77 | 78 | cpu_save_simd = xsave; 79 | cpu_restore_simd = xrstor; 80 | } else { 81 | cpu_simd_region_size = 512; // Legacy size for fxsave 82 | cpu_save_simd = fxsave; 83 | cpu_restore_simd = fxrstor; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/acpi/acpi.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static int use_xsdt = 0; 13 | 14 | struct rsdp_t *rsdp; 15 | struct rsdt_t *rsdt; 16 | struct xsdt_t *xsdt; 17 | 18 | /* This function should look for all the ACPI tables and index them for 19 | later use */ 20 | void init_acpi(void) { 21 | kprint(KPRN_INFO, "acpi: Initialising..."); 22 | 23 | /* look for the "RSD PTR " signature from 0x80000 to 0xa0000 and from 24 | 0xf0000 to 0x100000 */ 25 | for (size_t i = 0x80000 + MEM_PHYS_OFFSET; i < 0x100000 + MEM_PHYS_OFFSET; i += 16) { 26 | if (i == 0xa0000 + MEM_PHYS_OFFSET) { 27 | /* skip video mem and mapped hardware */ 28 | i = 0xe0000 - 16 + MEM_PHYS_OFFSET; 29 | continue; 30 | } 31 | if (!strncmp((char *)i, "RSD PTR ", 8)) { 32 | kprint(KPRN_INFO, "acpi: Found RSDP at %X", i); 33 | rsdp = (struct rsdp_t *)i; 34 | goto rsdp_found; 35 | } 36 | } 37 | 38 | panic(NULL, 0, "Non-ACPI compliant system"); 39 | return; 40 | 41 | rsdp_found: 42 | kprint(KPRN_INFO, "acpi: ACPI available"); 43 | 44 | kprint(KPRN_INFO, "acpi: Revision: %u", (uint32_t)rsdp->rev); 45 | 46 | if (rsdp->rev >= 2 && rsdp->xsdt_addr) { 47 | use_xsdt = 1; 48 | kprint(KPRN_INFO, "acpi: Found XSDT at %X", ((size_t)rsdp->xsdt_addr + MEM_PHYS_OFFSET)); 49 | xsdt = (struct xsdt_t *)((size_t)rsdp->xsdt_addr + MEM_PHYS_OFFSET); 50 | } else { 51 | kprint(KPRN_INFO, "acpi: Found RSDT at %X", ((size_t)rsdp->rsdt_addr + MEM_PHYS_OFFSET)); 52 | rsdt = (struct rsdt_t *)((size_t)rsdp->rsdt_addr + MEM_PHYS_OFFSET); 53 | } 54 | 55 | /* Call table inits */ 56 | init_madt(); 57 | } 58 | 59 | /* Find SDT by signature */ 60 | void *acpi_find_sdt(const char *signature, int index) { 61 | struct sdt_t *ptr; 62 | int cnt = 0; 63 | 64 | if (use_xsdt) { 65 | for (size_t i = 0; i < (xsdt->sdt.length - sizeof(struct sdt_t)) / 8; i++) { 66 | ptr = (struct sdt_t *)((size_t)xsdt->sdt_ptr[i] + MEM_PHYS_OFFSET); 67 | if (!strncmp(ptr->signature, signature, 4)) { 68 | if (cnt++ == index) { 69 | kprint(KPRN_INFO, "acpi: Found \"%s\" at %X", signature, (size_t)ptr); 70 | return (void *)ptr; 71 | } 72 | } 73 | } 74 | } else { 75 | for (size_t i = 0; i < (rsdt->sdt.length - sizeof(struct sdt_t)) / 4; i++) { 76 | ptr = (struct sdt_t *)((size_t)rsdt->sdt_ptr[i] + MEM_PHYS_OFFSET); 77 | if (!strncmp(ptr->signature, signature, 4)) { 78 | if (cnt++ == index) { 79 | kprint(KPRN_INFO, "acpi: Found \"%s\" at %X", signature, (size_t)ptr); 80 | return (void *)ptr; 81 | } 82 | } 83 | } 84 | } 85 | 86 | kprint(KPRN_INFO, "acpi: \"%s\" not found", signature); 87 | return NULL; 88 | } 89 | -------------------------------------------------------------------------------- /src/sys/panic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int panic_lock = 0; 14 | 15 | __attribute__((noreturn)) 16 | void panic(struct regs_t *regs, int print_trace, const char *fmt, ...) { 17 | asm volatile ("cli"); 18 | 19 | // Be the only one to panic no matter what, no double panics! 20 | if (locked_write(int, &panic_lock, 1)) { 21 | for (;;) { 22 | asm volatile ("hlt"); 23 | } 24 | } 25 | 26 | int _current_cpu = current_cpu; 27 | struct cpu_local_t *cpu_local = &cpu_locals[current_cpu]; 28 | 29 | // Send an abort IPI to all other APs 30 | if (smp_ready) { 31 | for (int i = 0; i < smp_cpu_count; i++) { 32 | if (i == _current_cpu) 33 | continue; 34 | locked_write(size_t, &cpu_locals[i].ipi_abort_received, 0); 35 | lapic_send_ipi(i, IPI_ABORT); 36 | while (!locked_read(size_t, &cpu_locals[i].ipi_abort_received)); 37 | } 38 | } 39 | 40 | va_list args; 41 | va_start(args, fmt); 42 | if (smp_ready) 43 | kprint(KPRN_PANIC, "KERNEL PANIC ON CPU #%d", _current_cpu); 44 | else 45 | kprint(KPRN_PANIC, "KERNEL PANIC ON THE BSP"); 46 | kvprint(KPRN_PANIC, fmt, args); 47 | va_end(args); 48 | 49 | if (regs) { 50 | kprint(KPRN_PANIC, "CPU status at fault:"); 51 | kprint(KPRN_PANIC, " RAX: %16X RBX: %16X RCX: %16X RDX: %16X", 52 | regs->rax, 53 | regs->rbx, 54 | regs->rcx, 55 | regs->rdx); 56 | kprint(KPRN_PANIC, " RSI: %16X RDI: %16X RBP: %16X RSP: %16X", 57 | regs->rsi, 58 | regs->rdi, 59 | regs->rbp, 60 | regs->rsp); 61 | kprint(KPRN_PANIC, " R8: %16X R9: %16X R10: %16X R11: %16X", 62 | regs->r8, 63 | regs->r9, 64 | regs->r10, 65 | regs->r11); 66 | kprint(KPRN_PANIC, " R12: %16X R13: %16X R14: %16X R15: %16X", 67 | regs->r12, 68 | regs->r13, 69 | regs->r14, 70 | regs->r15); 71 | kprint(KPRN_PANIC, " RFLAGS: %16X", regs->rflags); 72 | kprint(KPRN_PANIC, " RIP: %16X", regs->rip); 73 | kprint(KPRN_PANIC, " CS: %4X SS: %4X", 74 | regs->cs, 75 | regs->ss); 76 | kprint(KPRN_PANIC, " CR2: %16X", read_cr("2")); 77 | } 78 | 79 | if (smp_ready) { 80 | kprint(KPRN_PANIC, "Current task: %d", cpu_local->current_task); 81 | kprint(KPRN_PANIC, "Current process: %d", cpu_local->current_process); 82 | kprint(KPRN_PANIC, "Current thread: %d", cpu_local->current_thread); 83 | } else { 84 | kprint(KPRN_PANIC, "SMP and scheduler were NOT initialiased at panic."); 85 | } 86 | 87 | if (print_trace) 88 | print_stacktrace(KPRN_PANIC); 89 | 90 | kprint(KPRN_PANIC, "System halted"); 91 | 92 | for (;;) { 93 | asm volatile ("hlt"); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/devices/usb/mass_storage.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAX_CACHED_BLOCKS 8192 11 | #define CBW_SIGNATURE 0x43425355 12 | #define CBW_DEV_TO_HOST (1 << 7) 13 | 14 | extern int debug_xhci; 15 | 16 | /* command block wrapper */ 17 | struct cbw_t { 18 | uint32_t signature; 19 | uint32_t tag; 20 | uint32_t length; 21 | uint8_t direction; 22 | uint8_t lun; 23 | uint8_t command_length; 24 | uint8_t command[16]; 25 | } __attribute__((packed)); 26 | 27 | /* command status wrapper */ 28 | struct csw_t { 29 | uint32_t signature; 30 | uint32_t tag; 31 | uint32_t residue; 32 | uint8_t status; 33 | } __attribute__((packed)); 34 | 35 | struct mass_storage_dev_t { 36 | int in, out; /* endpoint numbers for in and out endpoints */ 37 | struct usb_dev_t device; 38 | }; 39 | 40 | dynarray_new(struct mass_storage_dev_t, devices); 41 | unsigned int msd_devices = 0; 42 | 43 | static int mass_storage_send_cmd(int drive, char *cmd, size_t cmd_length, 44 | char *buf, size_t request_length, int out) { 45 | 46 | struct cbw_t cbw = {0}; 47 | cbw.command_length = cmd_length; 48 | memcpy(&cbw.command, cmd, cmd_length); 49 | cbw.signature = CBW_SIGNATURE; 50 | cbw.tag = 1; 51 | cbw.length = request_length; 52 | cbw.direction = out ? 0 : CBW_DEV_TO_HOST; 53 | 54 | struct mass_storage_dev_t *device = 55 | dynarray_getelem(struct mass_storage_dev_t, devices, drive); 56 | if (!device) { 57 | errno = EINVAL; 58 | return -1; 59 | } 60 | 61 | int ret = device->device.controller->send_bulk( 62 | &device->device, (char *)&cbw, sizeof(struct cbw_t), device->out, 1); 63 | if (ret) { 64 | errno = EIO; 65 | return -1; 66 | } 67 | int endpoint = out ? device->out : device->in; 68 | ret = device->device.controller->send_bulk(&device->device, buf, 69 | request_length, endpoint, out); 70 | if (ret) { 71 | errno = EIO; 72 | return -1; 73 | } 74 | 75 | struct csw_t csw = {0}; 76 | ret = device->device.controller->send_bulk( 77 | &device->device, (char *)&csw, sizeof(struct csw_t), device->in, 0); 78 | if (ret || csw.status) { 79 | errno = EIO; 80 | return -1; 81 | } 82 | return 0; 83 | } 84 | 85 | int init_mass_storage(struct usb_dev_t *device, 86 | struct usb_endpoint_t *endpoints) { 87 | kprint(KPRN_INFO, "found mass storage device"); 88 | struct mass_storage_dev_t internal_dev = {0}; 89 | internal_dev.device = *device; 90 | 91 | internal_dev.out = usb_get_endpoint(endpoints, USB_EP_TYPE_BULK, 0); 92 | panic_if(internal_dev.out == -1); 93 | internal_dev.in = usb_get_endpoint(endpoints, USB_EP_TYPE_BULK, 1); 94 | panic_if(internal_dev.in == -1); 95 | 96 | int ret = dynarray_add(struct mass_storage_dev_t, devices, &internal_dev); 97 | if (ret < 0) 98 | return -1; 99 | 100 | char *dev_name = prefixed_itoa("usbd", msd_devices, 10); 101 | scsi_register(ret, dev_name, mass_storage_send_cmd); 102 | kfree(dev_name); 103 | msd_devices++; 104 | 105 | kprint(KPRN_INFO, "mass_storage: initiated device!"); 106 | return 0; 107 | } 108 | -------------------------------------------------------------------------------- /src/sys/hpet.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | struct hpet_table_t { 11 | struct sdt_t sdt; 12 | uint8_t hardware_rev_id; /* Hardware revision. */ 13 | uint8_t comparator_count:5; /* Comparator count. */ 14 | uint8_t counter_size:1; /* 1 -> 64 bits, 0 -> 32 bits. */ 15 | uint8_t reserved:1; /* Reserved. */ 16 | uint8_t legacy_replacement:1; /* Support legacy ISA interrupt, bool. */ 17 | uint16_t pci_vendor_id; 18 | uint8_t address_space_id; /* 0 - system memory, 1 - system I/O. */ 19 | uint8_t register_bit_width; /* Width of control registers */ 20 | uint8_t register_bit_offset; /* Offset of those registers */ 21 | uint8_t reserved1; /* Reserved (duh) */ 22 | uint64_t address; /* Address */ 23 | uint8_t hpet_number; /* Number of HPET. */ 24 | uint16_t minimum_tick; 25 | uint8_t page_protection; 26 | } __attribute__((packed)); 27 | 28 | struct hpet_timer_t { 29 | volatile uint64_t config_and_capabilities; 30 | volatile uint64_t comparator_value; 31 | volatile uint64_t fsb_interrupt_route; 32 | volatile uint64_t unused; 33 | }; 34 | 35 | struct hpet_t { 36 | volatile uint64_t general_capabilities; 37 | volatile uint64_t unused0; 38 | volatile uint64_t general_configuration; 39 | volatile uint64_t unused1; 40 | volatile uint64_t general_int_status; 41 | volatile uint64_t unused2; 42 | volatile uint64_t unused3[2][12]; 43 | volatile uint64_t main_counter_value; 44 | volatile uint64_t unused4; 45 | struct hpet_timer_t timers[]; 46 | }; 47 | 48 | static struct hpet_t *hpet; 49 | 50 | void init_hpet(void) { 51 | uint64_t tmp; 52 | 53 | /* Find the HPET description table. */ 54 | struct hpet_table_t *hpet_table = acpi_find_sdt("HPET", 0); 55 | 56 | if (!hpet_table) 57 | panic(NULL, 0, "HPET ACPI table not found"); 58 | 59 | hpet = (struct hpet_t *)(hpet_table->address + MEM_PHYS_OFFSET); 60 | tmp = hpet->general_capabilities; 61 | 62 | /* Check that the HPET is valid for our uses */ 63 | if (!(tmp & (1 << 15))) 64 | panic(NULL, 0, "HPET is not legacy replacement capable"); 65 | 66 | uint64_t counter_clk_period = tmp >> 32; 67 | uint64_t frequency = 1000000000000000 / counter_clk_period; 68 | 69 | kprint(KPRN_INFO, "hpet: Detected frequency of %UHz", frequency); 70 | 71 | kprint(KPRN_INFO, "hpet: Enabling legacy replacement mode"); 72 | tmp = hpet->general_configuration; 73 | tmp |= 0b10; 74 | hpet->general_configuration = tmp; 75 | 76 | hpet->main_counter_value = 0; 77 | 78 | kprint(KPRN_INFO, "hpet: Enabling interrupts on timer #0"); 79 | tmp = hpet->timers[0].config_and_capabilities; 80 | if (!(tmp & (1 << 4))) 81 | panic(NULL, 0, "HPET timer #0 does not support periodic mode"); 82 | 83 | tmp |= (1 << 2) | (1 << 3) | (1 << 6); 84 | hpet->timers[0].config_and_capabilities = tmp; 85 | hpet->timers[0].comparator_value = frequency / HPET_FREQUENCY_HZ; 86 | 87 | kprint(KPRN_INFO, "hpet: Enabling overall"); 88 | tmp = hpet->general_configuration; 89 | tmp |= 0b01; 90 | hpet->general_configuration = tmp; 91 | 92 | kprint(KPRN_INFO, "hpet: Unmasking IRQ #0"); 93 | io_apic_set_up_legacy_irq(0, 0, 1); 94 | } 95 | -------------------------------------------------------------------------------- /src/usb/usb.h: -------------------------------------------------------------------------------- 1 | #ifndef __USB_H__ 2 | #define __USB_H__ 3 | 4 | #include 5 | #include 6 | 7 | #define USB_EP_TYPE_CONTROL 0 8 | #define USB_EP_TYPE_ISOC 1 9 | #define USB_EP_TYPE_BULK 2 10 | #define USB_EP_TYPE_INTR 3 11 | 12 | struct usb_hc_t; 13 | 14 | struct usb_request_t { 15 | uint8_t request_type; 16 | uint8_t request; 17 | uint16_t value; 18 | uint16_t index; 19 | uint16_t length; 20 | } __attribute__((packed)); 21 | 22 | struct usb_device_descriptor_t { 23 | uint8_t length; 24 | uint8_t descriptor_type; 25 | uint16_t usb_version; 26 | uint8_t device_class; 27 | uint8_t device_sub_class; 28 | uint8_t protocol; 29 | uint8_t max_packet_size; 30 | uint16_t vendor_id; 31 | uint16_t product_id; 32 | uint16_t device_release; 33 | uint8_t manufacturer; 34 | uint8_t product; 35 | uint8_t serial_number; 36 | uint8_t num_configs; 37 | } __attribute__((packed)); 38 | 39 | struct usb_config_t { 40 | uint8_t length; 41 | uint8_t type; 42 | uint16_t total_length; 43 | uint8_t num_interfaces; 44 | uint8_t config_value; 45 | uint8_t config; 46 | uint8_t attributes; 47 | uint8_t max_power; 48 | } __attribute__((packed)); 49 | 50 | struct usb_interface_t { 51 | uint8_t length; 52 | uint8_t type; 53 | uint8_t number; 54 | uint8_t alternate_setting; 55 | uint8_t num_endpoints; 56 | uint8_t class; 57 | uint8_t sub_class; 58 | uint8_t protocol; 59 | uint8_t interface; 60 | } __attribute__((packed)); 61 | 62 | struct usb_endpoint_data_t { 63 | uint8_t length; 64 | uint8_t type; 65 | uint8_t address; 66 | uint8_t attributes; 67 | uint16_t max_packet_size; 68 | uint8_t interval; 69 | } __attribute__((packed)); 70 | 71 | struct usb_endpoint_t { 72 | uint8_t address; 73 | uint8_t attributes; 74 | int hcd_ep_num; 75 | }; 76 | 77 | struct usb_dev_t { 78 | int address; 79 | int low_speed; 80 | int speed; 81 | size_t max_packet_size; 82 | struct usb_hc_t *controller; 83 | void *internal_controller; 84 | int num_endpoints; 85 | int claimed; 86 | int hcd_devno; 87 | struct usb_interface_t interface; 88 | 89 | uint16_t vendor; 90 | uint16_t product; 91 | uint16_t usb_ver; 92 | uint16_t dev_ver; 93 | uint8_t class; 94 | uint8_t subclass; 95 | 96 | int num_configs; 97 | }; 98 | 99 | struct usb_hc_t { 100 | int (*send_control)(struct usb_dev_t *, void *, struct usb_request_t, int); 101 | int (*send_bulk)(struct usb_dev_t *, char *, size_t, int epno, int); 102 | int (*probe)(void *); 103 | int (*setup_endpoint)(struct usb_dev_t *, int, int); 104 | }; 105 | 106 | #define MATCH_VENDOR (1 << 0) 107 | #define MATCH_PRODUCT (1 << 1) 108 | #define MATCH_USB_VERSION (1 << 2) 109 | #define MATCH_DEV_VERSION (1 << 3) 110 | #define MATCH_CLASS (1 << 4) 111 | #define MATCH_SUBCLASS (1 << 5) 112 | 113 | struct usb_driver_t { 114 | uint8_t match; 115 | uint16_t vendor; 116 | uint16_t product; 117 | uint16_t usb_ver; 118 | uint16_t dev_ver; 119 | uint8_t class; 120 | uint8_t subclass; 121 | 122 | int (*probe)(struct usb_dev_t *, struct usb_endpoint_t *); 123 | }; 124 | 125 | int usb_make_request(struct usb_dev_t *, char *, size_t, uint8_t, uint8_t, 126 | uint16_t, uint16_t, uint8_t, uint8_t); 127 | int usb_add_device(struct usb_dev_t, int devno); 128 | int usb_get_endpoint(struct usb_endpoint_t *endpoints, int ep_type, int in); 129 | void usb_register_driver(struct usb_driver_t driver); 130 | void init_usb(void); 131 | 132 | #endif -------------------------------------------------------------------------------- /src/devices/term/tty/tty.h: -------------------------------------------------------------------------------- 1 | #ifndef __TTY_H__ 2 | #define __TTY_H__ 3 | 4 | #include 5 | 6 | typedef unsigned int cc_t; 7 | typedef unsigned int speed_t; 8 | typedef unsigned int tcflag_t; 9 | 10 | /* 11 | * Constants from mlibc/options/posix/include/termios.h 12 | */ 13 | 14 | // indices for the c_cc array in struct termios 15 | #define NCCS 11 16 | #define VEOF 0 17 | #define VEOL 1 18 | #define VERASE 2 19 | #define VINTR 3 20 | #define VKILL 4 21 | #define VMIN 5 22 | #define VQUIT 6 23 | #define VSTART 7 24 | #define VSTOP 8 25 | #define VSUSP 9 26 | #define VTIME 10 27 | 28 | // bitwise flags for c_iflag in struct termios 29 | #define BRKINT 0x0001 30 | #define ICRNL 0x0002 31 | #define IGNBRK 0x0004 32 | #define IGNCR 0x0008 33 | #define IGNPAR 0x0010 34 | #define INLCR 0x0020 35 | #define INPCK 0x0040 36 | #define ISTRIP 0x0080 37 | #define IXANY 0x0100 38 | #define IXOFF 0x0200 39 | #define IXON 0x0400 40 | #define PARMRK 0x0800 41 | 42 | // bitwise flags for c_oflag in struct termios 43 | #define OPOST 0x0001 44 | #define ONLCR 0x0002 45 | #define OCRNL 0x0004 46 | #define ONOCR 0x0008 47 | #define ONLRET 0x0010 48 | #define OFDEL 0x0020 49 | #define OFILL 0x0040 50 | 51 | #define NLDLY 0x0080 52 | #define NL0 0x0000 53 | #define NL1 0x0080 54 | 55 | #define CRDLY 0x0300 56 | #define CR0 0x0000 57 | #define CR1 0x0100 58 | #define CR2 0x0200 59 | #define CR3 0x0300 60 | 61 | #define TABDLY 0x0C00 62 | #define TAB0 0x0000 63 | #define TAB1 0x0400 64 | #define TAB2 0x0800 65 | #define TAB3 0x0C00 66 | 67 | #define BSDLY 0x1000 68 | #define BS0 0x0000 69 | #define BS1 0x1000 70 | 71 | #define VTDLY 0x2000 72 | #define VT0 0x0000 73 | #define VT1 0x2000 74 | 75 | #define FFDLY 0x4000 76 | #define FF0 0x0000 77 | #define FF1 0x4000 78 | 79 | // baud rate constants for speed_t 80 | #define B0 0 81 | #define B50 1 82 | #define B75 2 83 | #define B110 3 84 | #define B134 4 85 | #define B150 5 86 | #define B200 6 87 | #define B300 7 88 | #define B600 8 89 | #define B1200 9 90 | #define B1800 10 91 | #define B2400 11 92 | #define B4800 12 93 | #define B9600 13 94 | #define B19200 14 95 | #define B38400 15 96 | 97 | // bitwise constants for c_cflag in struct termios 98 | #define CSIZE 0x0003 99 | #define CS5 0x0000 100 | #define CS6 0x0001 101 | #define CS7 0x0002 102 | #define CS8 0x0003 103 | 104 | #define CSTOPB 0x0004 105 | #define CREAD 0x0008 106 | #define PARENB 0x0010 107 | #define PARODD 0x0020 108 | #define HUPCL 0x0040 109 | #define CLOCAL 0x0080 110 | 111 | // bitwise constants for c_lflag in struct termios 112 | #define ECHO 0x0001 113 | #define ECHOE 0x0002 114 | #define ECHOK 0x0004 115 | #define ECHONL 0x0008 116 | #define ICANON 0x0010 117 | #define IEXTEN 0x0020 118 | #define ISIG 0x0040 119 | #define NOFLSH 0x0080 120 | #define TOSTOP 0x0100 121 | 122 | // constants for tcsetattr() 123 | #define TCSANOW 1 124 | #define TCSADRAIN 2 125 | #define TCSAFLUSH 3 126 | 127 | // constants for tcflush() 128 | #define TCIFLUSH 1 129 | #define TCIOFLUSH 2 130 | #define TCOFLUSH 3 131 | 132 | // constants for tcflow() 133 | #define TCIOFF 1 134 | #define TCION 2 135 | #define TCOOFF 3 136 | #define TCOON 4 137 | 138 | struct termios { 139 | tcflag_t c_iflag; 140 | tcflag_t c_oflag; 141 | tcflag_t c_cflag; 142 | tcflag_t c_lflag; 143 | cc_t c_cc[NCCS]; 144 | speed_t ibaud; 145 | speed_t obaud; 146 | }; 147 | 148 | int tty_write(int, const void *, uint64_t, size_t); 149 | int tty_read(int, void *, uint64_t, size_t); 150 | void init_tty(void); 151 | 152 | #endif 153 | -------------------------------------------------------------------------------- /src/sys/gdt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | struct gdt_entry { 5 | uint16_t limit; 6 | uint16_t base_low16; 7 | uint8_t base_mid8; 8 | uint8_t access; 9 | uint8_t granularity; 10 | uint8_t base_high8; 11 | } __attribute__((packed)); 12 | 13 | struct tss_entry { 14 | uint16_t length; 15 | uint16_t base_low16; 16 | uint8_t base_mid8; 17 | uint8_t flags1; 18 | uint8_t flags2; 19 | uint8_t base_high8; 20 | uint32_t base_upper32; 21 | uint32_t reserved; 22 | } __attribute__((packed)); 23 | 24 | struct gdt { 25 | struct gdt_entry entries[5]; 26 | struct tss_entry tss; 27 | } __attribute__((packed)); 28 | 29 | struct gdt_pointer { 30 | uint16_t size; 31 | uint64_t address; 32 | } __attribute__((packed)); 33 | 34 | static struct gdt gdt; 35 | static struct gdt_pointer gdt_pointer; 36 | 37 | void init_gdt(void) { 38 | // Null descriptor. 39 | gdt.entries[0].limit = 0; 40 | gdt.entries[0].base_low16 = 0; 41 | gdt.entries[0].base_mid8 = 0; 42 | gdt.entries[0].access = 0; 43 | gdt.entries[0].granularity = 0; 44 | gdt.entries[0].base_high8 = 0; 45 | 46 | // Kernel code 64. 47 | gdt.entries[1].limit = 0; 48 | gdt.entries[1].base_low16 = 0; 49 | gdt.entries[1].base_mid8 = 0; 50 | gdt.entries[1].access = 0b10011010; 51 | gdt.entries[1].granularity = 0b00100000; 52 | gdt.entries[1].base_high8 = 0; 53 | 54 | // Kernel data 64. 55 | gdt.entries[2].limit = 0; 56 | gdt.entries[2].base_low16 = 0; 57 | gdt.entries[2].base_mid8 = 0; 58 | gdt.entries[2].access = 0b10010010; 59 | gdt.entries[2].granularity = 0; 60 | gdt.entries[2].base_high8 = 0; 61 | 62 | // User data 64. 63 | gdt.entries[3].limit = 0; 64 | gdt.entries[3].base_low16 = 0; 65 | gdt.entries[3].base_mid8 = 0; 66 | gdt.entries[3].access = 0b11110010; 67 | gdt.entries[3].granularity = 0; 68 | gdt.entries[3].base_high8 = 0; 69 | 70 | // User code 64. 71 | gdt.entries[4].limit = 0; 72 | gdt.entries[4].base_low16 = 0; 73 | gdt.entries[4].base_mid8 = 0; 74 | gdt.entries[4].access = 0b11111010; 75 | gdt.entries[4].granularity = 0b00100000; 76 | gdt.entries[4].base_high8 = 0; 77 | 78 | // TSS. 79 | gdt.tss.length = 104; 80 | gdt.tss.base_low16 = 0; 81 | gdt.tss.base_mid8 = 0; 82 | gdt.tss.flags1 = 0b10001001; 83 | gdt.tss.flags2 = 0; 84 | gdt.tss.base_high8 = 0; 85 | gdt.tss.base_upper32 = 0; 86 | gdt.tss.reserved = 0; 87 | 88 | // Set the pointer. 89 | gdt_pointer.size = sizeof(gdt) - 1; 90 | gdt_pointer.address = (uint64_t)&gdt; 91 | asm volatile ( 92 | "lgdt %0\n\t" 93 | "push rbp\n\t" 94 | "mov rbp, rsp\n\t" 95 | "push %1\n\t" 96 | "push rbp\n\t" 97 | "pushfq\n\t" 98 | "push %2\n\t" 99 | "push OFFSET 1f\n\t" 100 | "iretq\n\t" 101 | "1:\n\t" 102 | "pop rbp\n\t" 103 | "mov ds, %1\n\t" 104 | "mov es, %1\n\t" 105 | "mov fs, %1\n\t" 106 | "mov gs, %1\n\t" 107 | "mov ss, %1\n\t" 108 | : 109 | : "m"(gdt_pointer), "r"((uint64_t)0x10), "r"((uint64_t)0x08) 110 | : "memory" 111 | ); 112 | } 113 | 114 | void load_tss(size_t addr) { 115 | gdt.tss.base_low16 = (uint16_t)addr; 116 | gdt.tss.base_mid8 = (uint8_t)(addr >> 16); 117 | gdt.tss.flags1 = 0b10001001; 118 | gdt.tss.flags2 = 0; 119 | gdt.tss.base_high8 = (uint8_t)(addr >> 24); 120 | gdt.tss.base_upper32 = (uint32_t)(addr >> 32); 121 | gdt.tss.reserved = 0; 122 | } 123 | -------------------------------------------------------------------------------- /src/lib/dynarray.h: -------------------------------------------------------------------------------- 1 | #ifndef __DYNARRAY_H__ 2 | #define __DYNARRAY_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define dynarray_new(type, name) \ 9 | static struct { \ 10 | int refcount; \ 11 | int present; \ 12 | type data; \ 13 | } **name; \ 14 | static size_t name##_i = 0; \ 15 | static lock_t name##_lock = new_lock; 16 | 17 | #define public_dynarray_new(type, name) \ 18 | struct __##name##_struct **name; \ 19 | size_t name##_i = 0; \ 20 | lock_t name##_lock = new_lock; 21 | 22 | #define public_dynarray_prototype(type, name) \ 23 | struct __##name##_struct { \ 24 | int refcount; \ 25 | int present; \ 26 | type data; \ 27 | }; \ 28 | extern struct __##name##_struct **name; \ 29 | extern size_t name##_i; \ 30 | extern lock_t name##_lock; 31 | 32 | #define dynarray_remove(dynarray, element) ({ \ 33 | __label__ out; \ 34 | int ret; \ 35 | spinlock_acquire(&dynarray##_lock); \ 36 | if (!dynarray[element]) { \ 37 | ret = -1; \ 38 | goto out; \ 39 | } \ 40 | ret = 0; \ 41 | dynarray[element]->present = 0; \ 42 | if (!locked_dec(&dynarray[element]->refcount)) { \ 43 | kfree(dynarray[element]); \ 44 | dynarray[element] = 0; \ 45 | } \ 46 | out: \ 47 | spinlock_release(&dynarray##_lock); \ 48 | ret; \ 49 | }) 50 | 51 | #define dynarray_unref(dynarray, element) ({ \ 52 | spinlock_acquire(&dynarray##_lock); \ 53 | if (dynarray[element] && !locked_dec(&dynarray[element]->refcount)) { \ 54 | kfree(dynarray[element]); \ 55 | dynarray[element] = 0; \ 56 | } \ 57 | spinlock_release(&dynarray##_lock); \ 58 | }) 59 | 60 | #define dynarray_getelem(type, dynarray, element) ({ \ 61 | spinlock_acquire(&dynarray##_lock); \ 62 | type *ptr = NULL; \ 63 | if (dynarray[element] && dynarray[element]->present) { \ 64 | ptr = &dynarray[element]->data; \ 65 | locked_inc(&dynarray[element]->refcount); \ 66 | } \ 67 | spinlock_release(&dynarray##_lock); \ 68 | ptr; \ 69 | }) 70 | 71 | #define dynarray_add(type, dynarray, element) ({ \ 72 | __label__ fnd; \ 73 | __label__ out; \ 74 | int ret = -1; \ 75 | \ 76 | spinlock_acquire(&dynarray##_lock); \ 77 | \ 78 | size_t i; \ 79 | for (i = 0; i < dynarray##_i; i++) { \ 80 | if (!dynarray[i]) \ 81 | goto fnd; \ 82 | } \ 83 | \ 84 | dynarray##_i += 256; \ 85 | void *tmp = krealloc(dynarray, dynarray##_i * sizeof(void *)); \ 86 | if (!tmp) \ 87 | goto out; \ 88 | dynarray = tmp; \ 89 | \ 90 | fnd: \ 91 | dynarray[i] = kalloc(sizeof(**dynarray)); \ 92 | if (!dynarray[i]) \ 93 | goto out; \ 94 | dynarray[i]->refcount = 1; \ 95 | dynarray[i]->present = 1; \ 96 | dynarray[i]->data = *element; \ 97 | \ 98 | ret = i; \ 99 | \ 100 | out: \ 101 | spinlock_release(&dynarray##_lock); \ 102 | ret; \ 103 | }) 104 | 105 | #define dynarray_search(type, dynarray, i_ptr, cond, index) ({ \ 106 | __label__ fnd; \ 107 | __label__ out; \ 108 | type *ret = NULL; \ 109 | \ 110 | spinlock_acquire(&dynarray##_lock); \ 111 | \ 112 | size_t i; \ 113 | size_t j = 0; \ 114 | for (i = 0; i < dynarray##_i; i++) { \ 115 | if (!dynarray[i] || !dynarray[i]->present) \ 116 | continue; \ 117 | type *elem = &dynarray[i]->data; \ 118 | if ((cond) && j++ == (index)) \ 119 | goto fnd; \ 120 | } \ 121 | goto out; \ 122 | \ 123 | fnd: \ 124 | ret = &dynarray[i]->data; \ 125 | locked_inc(&dynarray[i]->refcount); \ 126 | *(i_ptr) = i; \ 127 | \ 128 | out: \ 129 | spinlock_release(&dynarray##_lock); \ 130 | ret; \ 131 | }) 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /src/sys/cpu.h: -------------------------------------------------------------------------------- 1 | #ifndef __SYS__CPU_H__ 2 | #define __SYS__CPU_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define MAX_CPUS 128 9 | 10 | #define current_cpu ({ \ 11 | size_t cpu_number; \ 12 | asm volatile ("mov %0, qword ptr gs:[0]" \ 13 | : "=r" (cpu_number) \ 14 | : \ 15 | : "memory", "cc"); \ 16 | (int)cpu_number; \ 17 | }) 18 | 19 | #define load_fs_base(base) wrmsr(0xc0000100, base) 20 | 21 | struct cpu_local_t { 22 | /* DO NOT MOVE THESE MEMBERS FROM THESE LOCATIONS */ 23 | /* DO NOT CHANGE THEIR TYPES */ 24 | size_t cpu_number; 25 | size_t kernel_stack; 26 | size_t thread_kstack; 27 | size_t thread_ustack; 28 | size_t thread_errno; 29 | size_t ipi_abort_received; 30 | /* Feel free to move every other member, and use any type as you see fit */ 31 | tid_t current_task; 32 | pid_t current_process; 33 | tid_t current_thread; 34 | int64_t last_schedule_time; 35 | uint8_t lapic_id; 36 | int ipi_abortexec_received; 37 | int ipi_resched_received; 38 | }; 39 | 40 | extern struct cpu_local_t cpu_locals[MAX_CPUS]; 41 | 42 | extern unsigned int cpu_simd_region_size; 43 | 44 | extern void (*cpu_save_simd)(void *); 45 | extern void (*cpu_restore_simd)(void *); 46 | 47 | void init_cpu_features(); 48 | 49 | #define write_cr(reg, val) ({ \ 50 | asm volatile ("mov cr" reg ", %0" : : "r" (val)); \ 51 | }) 52 | 53 | #define read_cr(reg) ({ \ 54 | size_t cr; \ 55 | asm volatile ("mov %0, cr" reg : "=r" (cr)); \ 56 | cr; \ 57 | }) 58 | 59 | #define invlpg(addr) ({ \ 60 | asm volatile ( \ 61 | "invlpg [%0];" \ 62 | : \ 63 | : "r" (addr) \ 64 | ); \ 65 | }) 66 | 67 | static inline int cpuid(uint32_t leaf, uint32_t subleaf, 68 | uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx) { 69 | uint32_t cpuid_max; 70 | asm volatile ("cpuid" 71 | : "=a" (cpuid_max) 72 | : "a" (leaf & 0x80000000) : "rbx", "rcx", "rdx"); 73 | if (leaf > cpuid_max) 74 | return 0; 75 | asm volatile ("cpuid" 76 | : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx) 77 | : "a" (leaf), "c" (subleaf)); 78 | return 1; 79 | } 80 | 81 | static inline uint64_t rdmsr(uint32_t msr) { 82 | uint32_t edx, eax; 83 | asm volatile ("rdmsr" 84 | : "=a" (eax), "=d" (edx) 85 | : "c" (msr)); 86 | return ((uint64_t)edx << 32) | eax; 87 | } 88 | 89 | static inline void wrmsr(uint32_t msr, uint64_t value) { 90 | uint32_t edx = value >> 32; 91 | uint32_t eax = (uint32_t)value; 92 | asm volatile ("wrmsr" 93 | : 94 | : "a" (eax), "d" (edx), "c" (msr)); 95 | } 96 | 97 | static inline void wrxcr(uint32_t i, uint64_t value) { 98 | uint32_t edx = value >> 32; 99 | uint32_t eax = (uint32_t)value; 100 | asm volatile ("xsetbv" 101 | : 102 | : "a" (eax), "d" (edx), "c" (i)); 103 | } 104 | 105 | static inline void xsave(void *region) { 106 | asm volatile ("xsave [%0]" 107 | : 108 | : "r" (region), "a" (0xFFFFFFFF), "d" (0xFFFFFFFF) 109 | : "memory"); 110 | } 111 | 112 | static inline void xrstor(void *region) { 113 | asm volatile ("xrstor [%0]" 114 | : 115 | : "r" (region), "a" (0xFFFFFFFF), "d" (0xFFFFFFFF) 116 | : "memory"); 117 | } 118 | 119 | static inline void fxsave(void *region) { 120 | asm volatile ("fxsave [%0]" 121 | : 122 | : "r" (region) 123 | : "memory"); 124 | } 125 | 126 | static inline void fxrstor(void *region) { 127 | asm volatile ("fxrstor [%0]" 128 | : 129 | : "r" (region) 130 | : "memory"); 131 | } 132 | 133 | #endif 134 | -------------------------------------------------------------------------------- /src/proc/task.h: -------------------------------------------------------------------------------- 1 | #ifndef __TASK_H__ 2 | #define __TASK_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAX_PROCESSES 65536 13 | #define MAX_THREADS 1024 14 | #define MAX_TASKS (MAX_PROCESSES*16) 15 | #define MAX_FILE_HANDLES 256 16 | 17 | #define CURRENT_PROCESS cpu_locals[current_cpu].current_process 18 | #define CURRENT_THREAD cpu_locals[current_cpu].current_thread 19 | #define CURRENT_TASK cpu_locals[current_cpu].current_task 20 | 21 | struct regs_t { 22 | uint64_t r15; 23 | uint64_t r14; 24 | uint64_t r13; 25 | uint64_t r12; 26 | uint64_t r11; 27 | uint64_t r10; 28 | uint64_t r9; 29 | uint64_t r8; 30 | uint64_t rbp; 31 | uint64_t rdi; 32 | uint64_t rsi; 33 | uint64_t rdx; 34 | uint64_t rcx; 35 | uint64_t rbx; 36 | uint64_t rax; 37 | uint64_t rip; 38 | uint64_t cs; 39 | uint64_t rflags; 40 | uint64_t rsp; 41 | uint64_t ss; 42 | }; 43 | 44 | struct ctx_t { 45 | struct regs_t regs; 46 | uint8_t *fxstate; 47 | }; 48 | 49 | struct thread_t { 50 | tid_t tid; 51 | tid_t task_id; 52 | pid_t process; 53 | lock_t lock; 54 | int in_syscall; 55 | int last_syscall; 56 | int event_abrt; 57 | uint64_t yield_target; 58 | int paused; 59 | int active_on_cpu; 60 | size_t kstack; 61 | size_t ustack; 62 | size_t thread_errno; 63 | size_t fs_base; 64 | struct ctx_t ctx; 65 | event_t **event_ptr; 66 | int *out_event_ptr; 67 | size_t event_timeout; 68 | int event_num; 69 | }; 70 | 71 | #define AT_ENTRY 10 72 | #define AT_PHDR 20 73 | #define AT_PHENT 21 74 | #define AT_PHNUM 22 75 | 76 | struct auxval_t { 77 | size_t at_entry; 78 | size_t at_phdr; 79 | size_t at_phent; 80 | size_t at_phnum; 81 | }; 82 | 83 | struct child_event_t { 84 | pid_t pid; 85 | int status; 86 | }; 87 | 88 | struct process_t { 89 | pid_t pid; 90 | pid_t ppid; 91 | pid_t pgid; 92 | uid_t uid; 93 | struct pagemap_t *pagemap; 94 | struct thread_t **threads; 95 | char cwd[2048]; 96 | lock_t cwd_lock; 97 | int *file_handles; 98 | lock_t file_handles_lock; 99 | size_t cur_brk; 100 | lock_t cur_brk_lock; 101 | struct child_event_t *child_events; 102 | size_t child_event_i; 103 | lock_t child_event_lock; 104 | event_t child_event; 105 | lock_t usage_lock; 106 | struct rusage_t own_usage; 107 | struct rusage_t child_usage; 108 | struct sigaction signal_handlers[SIGNAL_MAX]; 109 | sigset_t sigmask; 110 | }; 111 | 112 | int task_send_child_event(pid_t, struct child_event_t *); 113 | 114 | extern int64_t task_count; 115 | 116 | extern lock_t scheduler_lock; 117 | 118 | extern struct process_t **process_table; 119 | extern struct thread_t **task_table; 120 | 121 | void init_sched(void); 122 | void yield(void); 123 | void relaxed_sleep(uint64_t); 124 | 125 | enum tcreate_abi { 126 | tcreate_fn_call, 127 | tcreate_elf_exec 128 | }; 129 | 130 | struct tcreate_fn_call_data{ 131 | void *fsbase; 132 | void (*fn)(void *); 133 | void *arg; 134 | }; 135 | 136 | struct tcreate_elf_exec_data { 137 | void *entry; 138 | const char **argv; 139 | const char **envp; 140 | const struct auxval_t *auxval; 141 | }; 142 | 143 | #define tcreate_fn_call_data(fsbase_, fn_, arg_) \ 144 | &((struct tcreate_fn_call_data){.fsbase=fsbase_, .fn=fn_, .arg=arg_}) 145 | #define tcreate_elf_exec_data(entry_, argv_, envp_, auxval_) \ 146 | &((struct tcreate_elf_exec_data){.entry=entry_, .argv=argv_, .envp=envp_, .auxval=auxval_}) 147 | 148 | tid_t task_tcreate(pid_t, enum tcreate_abi, const void *); 149 | pid_t task_pcreate(void); 150 | int task_tkill(pid_t, tid_t); 151 | int task_tpause(pid_t, tid_t); 152 | int task_tresume(pid_t, tid_t); 153 | 154 | void force_resched(void); 155 | 156 | int kill(pid_t, int); 157 | 158 | #endif 159 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Globals and files to compile. 2 | KERNEL := qword 3 | KERNELELF := $(KERNEL).elf 4 | KERNELHDD := $(KERNEL).hdd 5 | SOURCEDIR := src 6 | RUNDIR := run 7 | 8 | LIMINE_URL := https://github.com/limine-bootloader/limine.git 9 | LIMINE_DIR := limine 10 | 11 | CFILES := $(shell find $(SOURCEDIR) -type f -name '*.c') 12 | ASMFILES := $(shell find $(SOURCEDIR) -type f -name '*.asm') 13 | REALFILES := $(shell find $(SOURCEDIR) -type f -name '*.real') 14 | BINS := $(REALFILES:.real=.bin) 15 | OBJ := $(CFILES:.c=.o) $(ASMFILES:.asm=.asm.o) 16 | DEPS := $(CFILES:.c=.d) 17 | 18 | # User options. 19 | DBGOUT = no 20 | DBGSYM = no 21 | 22 | PREFIX = $(shell pwd) 23 | 24 | CC = gcc 25 | LD = $(CC:gcc=ld) 26 | AS = nasm 27 | QEMU = qemu-system-x86_64 28 | 29 | CFLAGS = -O2 -pipe -Wall -Wextra 30 | LDFLAGS = -O2 31 | QEMUFLAGS = -m 2G -enable-kvm -smp 4 32 | 33 | # Flags for compilation. 34 | BUILD_TIME := $(shell date) 35 | 36 | CHARDFLAGS := $(CFLAGS) \ 37 | -DBUILD_TIME='"$(BUILD_TIME)"' \ 38 | -std=gnu99 \ 39 | -masm=intel \ 40 | -fno-pic \ 41 | -mno-sse \ 42 | -mno-sse2 \ 43 | -mno-mmx \ 44 | -mno-80387 \ 45 | -mno-red-zone \ 46 | -mcmodel=kernel \ 47 | -ffreestanding \ 48 | -fno-stack-protector \ 49 | -fno-omit-frame-pointer \ 50 | -I$(SOURCEDIR) 51 | 52 | ifeq ($(DBGOUT), tty) 53 | CHARDFLAGS := $(CHARDFLAGS) -D_DBGOUT_TTY_ 54 | else ifeq ($(DBGOUT), qemu) 55 | CHARDFLAGS := $(CHARDFLAGS) -D_DBGOUT_QEMU_ 56 | else ifeq ($(DBGOUT), both) 57 | CHARDFLAGS := $(CHARDFLAGS) -D_DBGOUT_TTY_ -D_DBGOUT_QEMU_ 58 | endif 59 | 60 | ifeq ($(DBGSYM), yes) 61 | CHARDFLAGS := $(CHARDFLAGS) -g -D_DEBUG_ 62 | endif 63 | 64 | LDHARDFLAGS := $(LDFLAGS) \ 65 | -nostdlib \ 66 | -no-pie \ 67 | -z max-page-size=0x1000 \ 68 | -T $(SOURCEDIR)/linker.ld 69 | 70 | QEMUHARDFLAGS := $(QEMUFLAGS) \ 71 | -debugcon stdio \ 72 | -hda $(KERNELHDD) 73 | 74 | .PHONY: symlist all prepare install uninstall clean run 75 | 76 | all: $(KERNELELF) 77 | 78 | $(KERNELELF): $(BINS) $(OBJ) symlist 79 | $(LD) $(LDHARDFLAGS) $(OBJ) symlist.o -o $@ 80 | OBJDUMP=$(CC:-gcc:-objdump) ./gensyms.sh 81 | $(CC) -x c $(CHARDFLAGS) -c symlist.gen -o symlist.o 82 | $(LD) $(LDHARDFLAGS) $(OBJ) symlist.o -o $@ 83 | 84 | symlist: 85 | echo '#include ' > symlist.gen 86 | echo 'struct symlist_t symlist[] = {{0xffffffffffffffff,""}};' >> symlist.gen 87 | $(CC) -x c $(CHARDFLAGS) -c symlist.gen -o symlist.o 88 | 89 | -include $(DEPS) 90 | 91 | %.o: %.c 92 | $(CC) $(CHARDFLAGS) -MMD -c $< -o $@ 93 | 94 | %.bin: %.real 95 | $(AS) $< -f bin -o $@ 96 | 97 | %.asm.o: %.asm 98 | $(AS) $< -I$(SOURCEDIR) -f elf64 -o $@ 99 | 100 | run: $(KERNELHDD) 101 | $(QEMU) $(QEMUHARDFLAGS) 102 | 103 | $(KERNELHDD): $(LIMINE_DIR) $(KERNELELF) 104 | dd if=/dev/zero bs=1M count=0 seek=64 of=$(KERNELHDD) 105 | parted -s $(KERNELHDD) mklabel msdos 106 | parted -s $(KERNELHDD) mkpart primary 1 100% 107 | echfs-utils -m -p0 $(KERNELHDD) quick-format 32768 108 | echfs-utils -m -p0 $(KERNELHDD) import $(KERNELELF) $(KERNELELF) 109 | echfs-utils -m -p0 $(KERNELHDD) import $(RUNDIR)/limine.cfg limine.cfg 110 | make -C $(LIMINE_DIR) 111 | $(LIMINE_DIR)/limine-install $(KERNELHDD) 112 | 113 | $(LIMINE_DIR): 114 | git clone $(LIMINE_URL) $(LIMINE_DIR) --depth=1 --branch=v0.4 115 | 116 | install: all 117 | install -d $(DESTDIR)$(PREFIX)/boot 118 | install $(KERNELBIN) $(DESTDIR)$(PREFIX)/boot/ 119 | 120 | uninstall: 121 | rm -f $(DESTDIR)$(PREFIX)/boot/$(KERNELBIN) 122 | 123 | clean: 124 | rm -f symlist.gen symlist.o $(OBJ) $(BINS) $(KERNELELF) $(KERNELHDD) $(DEPS) 125 | 126 | distclean: clean 127 | rm -rf $(LIMINE_DIR) 128 | 129 | format: 130 | find -type f -name "*.h" -exec clang-format -style=file -i {} \; 131 | find -type f -name "*.c" -exec clang-format -style=file -i {} \; 132 | -------------------------------------------------------------------------------- /src/proc/elf.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | /* Execute an ELF file given some file data 9 | out_ld_path: If non-null, returns path of the dynamic linker as kalloc()ed string */ 10 | int elf_load(int fd, struct pagemap_t *pagemap, size_t base, struct auxval_t *auxval, 11 | char **out_ld_path) { 12 | char *ld_path = NULL; 13 | 14 | int ret = lseek(fd, 0, SEEK_SET); 15 | if (ret == -1) return -1; 16 | 17 | char *magic = "\177ELF"; 18 | 19 | struct elf_hdr_t hdr; 20 | 21 | ret = read(fd, &hdr, sizeof(struct elf_hdr_t)); 22 | if (ret == -1) return -1; 23 | 24 | for (size_t i = 0; i < 4; i++) { 25 | if (hdr.ident[i] != magic[i]) return -1; 26 | } 27 | 28 | if (hdr.ident[EI_CLASS] != 0x02) return -1; 29 | if (hdr.ident[EI_DATA] != BITS_LE) return -1; 30 | if (hdr.ident[EI_OSABI] != ABI_SYSV) return -1; 31 | if (hdr.machine != ARCH_X86_64) return -1; 32 | 33 | uint64_t phoff = hdr.phoff; 34 | ret = lseek(fd, phoff, SEEK_SET); 35 | if (ret == -1) return -1; 36 | 37 | struct elf_phdr_t *phdr = kalloc(hdr.ph_num * sizeof(struct elf_phdr_t)); 38 | if (!phdr) return -1; 39 | 40 | ret = read(fd, phdr, hdr.ph_num * sizeof(struct elf_phdr_t)); 41 | if (ret == -1) { 42 | kfree(phdr); 43 | return -1; 44 | } 45 | 46 | auxval->at_phdr = 0; 47 | auxval->at_phent = sizeof(struct elf_phdr_t); 48 | auxval->at_phnum = hdr.ph_num; 49 | 50 | for (size_t i = 0; i < hdr.ph_num; i++) { 51 | if (phdr[i].p_type == PT_INTERP) { 52 | if (!out_ld_path) 53 | continue; 54 | 55 | ld_path = kalloc(phdr[i].p_filesz + 1); 56 | if (!ld_path) { 57 | kfree(phdr); 58 | return -1; 59 | } 60 | 61 | ret = lseek(fd, phdr[i].p_offset, SEEK_SET); 62 | if (ret == -1) { 63 | kfree(phdr); 64 | kfree(ld_path); 65 | return -1; 66 | } 67 | 68 | ret = read(fd, ld_path, phdr[i].p_filesz); 69 | if (ret == -1) { 70 | kfree(phdr); 71 | kfree(ld_path); 72 | return -1; 73 | } 74 | ld_path[phdr[i].p_filesz] = 0; 75 | } else if (phdr[i].p_type == PT_PHDR) { 76 | auxval->at_phdr = base + phdr[i].p_vaddr; 77 | } else if (phdr[i].p_type != PT_LOAD) 78 | continue; 79 | 80 | size_t misalign = phdr[i].p_vaddr & (PAGE_SIZE - 1); 81 | size_t page_count = (misalign + phdr[i].p_memsz + (PAGE_SIZE - 1)) / PAGE_SIZE; 82 | 83 | /* Allocate space */ 84 | void *addr = pmm_allocz(page_count); 85 | if (!addr) { 86 | kfree(phdr); 87 | kfree(ld_path); 88 | return -1; 89 | } 90 | 91 | size_t pf = 0x05; 92 | if(phdr[i].p_flags & PF_W) 93 | pf |= 0x02; 94 | for (size_t j = 0; j < page_count; j++) { 95 | size_t virt = base + phdr[i].p_vaddr + (j * PAGE_SIZE); 96 | size_t phys = (size_t)addr + (j * PAGE_SIZE); 97 | map_page(pagemap, phys, virt, pf); 98 | } 99 | 100 | ret = lseek(fd, phdr[i].p_offset, SEEK_SET); 101 | if (ret == -1) { 102 | kfree(phdr); 103 | kfree(ld_path); 104 | return -1; 105 | } 106 | 107 | /* Segments need to be cleared to zero; however, pmm_allocz() already returns 108 | zeroed pages. Thus we just need to read the file contents. */ 109 | char *buf = (char *)((size_t)addr + MEM_PHYS_OFFSET); 110 | ret = read(fd, buf + misalign, phdr[i].p_filesz); 111 | if (ret == -1) { 112 | kfree(phdr); 113 | kfree(ld_path); 114 | return -1; 115 | } 116 | } 117 | 118 | kfree(phdr); 119 | 120 | auxval->at_entry = base + hdr.entry; 121 | if (out_ld_path) 122 | *out_ld_path = ld_path; 123 | return 0; 124 | } 125 | -------------------------------------------------------------------------------- /src/sys/idt.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static lock_t get_empty_int_lock = new_lock; 8 | static int free_int_vect_base = 0x80; 9 | static const int free_int_vect_limit = 0xa0; 10 | 11 | int get_empty_int_vector(void) { 12 | spinlock_acquire(&get_empty_int_lock); 13 | int ret; 14 | if (free_int_vect_base == free_int_vect_limit) 15 | ret = -1; 16 | else 17 | ret = free_int_vect_base++; 18 | spinlock_release(&get_empty_int_lock); 19 | return ret; 20 | } 21 | 22 | struct idt_entry_t { 23 | uint16_t offset_lo; 24 | uint16_t selector; 25 | uint8_t ist; 26 | uint8_t type_attr; 27 | uint16_t offset_mid; 28 | uint32_t offset_hi; 29 | uint32_t zero; 30 | }; 31 | 32 | struct idt_ptr_t { 33 | uint16_t size; 34 | /* Start address */ 35 | uint64_t address; 36 | } __attribute((packed)); 37 | 38 | static struct idt_entry_t idt[256]; 39 | extern void *int_thunks[]; 40 | 41 | static int register_interrupt_handler(size_t vec, void *handler, uint8_t ist, uint8_t type) { 42 | uint64_t p = (uint64_t)handler; 43 | 44 | idt[vec].offset_lo = (uint16_t)p; 45 | idt[vec].selector = 0x08; 46 | idt[vec].ist = ist; 47 | idt[vec].type_attr = type; 48 | idt[vec].offset_mid = (uint16_t)(p >> 16); 49 | idt[vec].offset_hi = (uint32_t)(p >> 32); 50 | idt[vec].zero = 0; 51 | 52 | return 0; 53 | } 54 | 55 | void init_idt(void) { 56 | /* Register all interrupts */ 57 | for (size_t i = 0; i < 256; i++) 58 | register_interrupt_handler(i, int_thunks[i], 0, 0x8e); 59 | 60 | /* Exception handlers */ 61 | register_interrupt_handler(0x0, exc_div0_handler, 0, 0x8e); 62 | register_interrupt_handler(0x1, exc_debug_handler, 0, 0x8e); 63 | register_interrupt_handler(0x2, exc_nmi_handler, 0, 0x8e); 64 | register_interrupt_handler(0x3, exc_breakpoint_handler, 0, 0x8e); 65 | register_interrupt_handler(0x4, exc_overflow_handler, 0, 0x8e); 66 | register_interrupt_handler(0x5, exc_bound_range_handler, 0, 0x8e); 67 | register_interrupt_handler(0x6, exc_inv_opcode_handler, 0, 0x8e); 68 | register_interrupt_handler(0x7, exc_no_dev_handler, 0, 0x8e); 69 | register_interrupt_handler(0x8, exc_double_fault_handler, 1, 0x8e); 70 | register_interrupt_handler(0xa, exc_inv_tss_handler, 0, 0x8e); 71 | register_interrupt_handler(0xb, exc_no_segment_handler, 0, 0x8e); 72 | register_interrupt_handler(0xc, exc_ss_fault_handler, 0, 0x8e); 73 | register_interrupt_handler(0xd, exc_gpf_handler, 0, 0x8e); 74 | register_interrupt_handler(0xe, exc_page_fault_handler, 0, 0x8e); 75 | register_interrupt_handler(0x10, exc_x87_fp_handler, 0, 0x8e); 76 | register_interrupt_handler(0x11, exc_alignment_check_handler, 0, 0x8e); 77 | register_interrupt_handler(0x12, exc_machine_check_handler, 0, 0x8e); 78 | register_interrupt_handler(0x13, exc_simd_fp_handler, 0, 0x8e); 79 | register_interrupt_handler(0x14, exc_virt_handler, 0, 0x8e); 80 | /* 0x15 .. 0x1d resv. */ 81 | register_interrupt_handler(0x1e, exc_security_handler, 0, 0x8e); 82 | 83 | register_interrupt_handler(0x20, irq0_handler, 0, 0x8e); 84 | 85 | /* Inter-processor interrupts */ 86 | register_interrupt_handler(IPI_ABORT, ipi_abort, 1, 0x8e); 87 | register_interrupt_handler(IPI_RESCHED, ipi_resched, 1, 0x8e); 88 | register_interrupt_handler(IPI_ABORTEXEC, ipi_abortexec, 1, 0x8e); 89 | 90 | /* Register dummy legacy PIC handlers */ 91 | for (size_t i = 0; i < 8; i++) 92 | register_interrupt_handler(0xa0 + i, pic0_generic_handler, 1, 0x8e); 93 | for (size_t i = 0; i < 8; i++) 94 | register_interrupt_handler(0xa8 + i, pic1_generic_handler, 1, 0x8e); 95 | 96 | /* Register local APIC NMI handler */ 97 | register_interrupt_handler(0xf0, apic_nmi_handler, 1, 0x8e); 98 | 99 | register_interrupt_handler(0xff, apic_spurious_handler, 1, 0x8e); 100 | 101 | struct idt_ptr_t idt_ptr = { 102 | sizeof(idt) - 1, 103 | (uint64_t)idt 104 | }; 105 | 106 | asm volatile ( 107 | "lidt %0" 108 | : 109 | : "m" (idt_ptr) 110 | ); 111 | } 112 | -------------------------------------------------------------------------------- /src/sys/smp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define CPU_STACK_SIZE 16384 15 | 16 | int smp_ready = 0; 17 | 18 | /* External assembly routines */ 19 | void smp_init_cpu0_local(void *, void *); 20 | void *smp_prepare_trampoline(void *, void *, void *, void *, void *); 21 | int smp_check_ap_flag(void); 22 | 23 | int smp_cpu_count = 1; 24 | 25 | struct tss_t { 26 | uint32_t unused0 __attribute__((aligned(16))); 27 | uint64_t rsp0; 28 | uint64_t rsp1; 29 | uint64_t rsp2; 30 | uint64_t unused1; 31 | uint64_t ist1; 32 | uint64_t ist2; 33 | uint64_t ist3; 34 | uint64_t ist4; 35 | uint64_t ist5; 36 | uint64_t ist6; 37 | uint64_t ist7; 38 | uint64_t unused2; 39 | uint32_t iopb_offset; 40 | } __attribute__((packed)); 41 | 42 | struct cpu_local_t cpu_locals[MAX_CPUS]; 43 | static struct tss_t cpu_tss[MAX_CPUS] __attribute__((aligned(16))); 44 | 45 | struct stack_t { 46 | uint8_t guard_page[PAGE_SIZE] __attribute__((aligned(PAGE_SIZE))); 47 | uint8_t stack[CPU_STACK_SIZE] __attribute__((aligned(PAGE_SIZE))); 48 | }; 49 | 50 | static struct stack_t cpu_stacks[MAX_CPUS] __attribute__((aligned(PAGE_SIZE))); 51 | 52 | static void ap_kernel_entry(void) { 53 | /* APs jump here after initialisation */ 54 | 55 | kprint(KPRN_INFO, "smp: Started up AP #%u", current_cpu); 56 | 57 | /* Enable this AP's local APIC */ 58 | init_cpu_features(); 59 | lapic_enable(); 60 | 61 | /* Enable interrupts */ 62 | asm volatile ("sti"); 63 | 64 | /* Wait for some job to be scheduled */ 65 | for (;;) asm volatile ("hlt"); 66 | } 67 | 68 | static inline void setup_cpu_local(int cpu_number, uint8_t lapic_id) { 69 | /* Set up stack guard page */ 70 | unmap_page(kernel_pagemap, (size_t)&cpu_stacks[cpu_number].guard_page[0]); 71 | 72 | /* Prepare CPU local */ 73 | cpu_locals[cpu_number].cpu_number = cpu_number; 74 | cpu_locals[cpu_number].kernel_stack = (size_t)&cpu_stacks[cpu_number].stack[CPU_STACK_SIZE]; 75 | cpu_locals[cpu_number].current_process = -1; 76 | cpu_locals[cpu_number].current_thread = -1; 77 | cpu_locals[cpu_number].current_task = -1; 78 | cpu_locals[cpu_number].lapic_id = lapic_id; 79 | 80 | /* Prepare TSS */ 81 | cpu_tss[cpu_number].rsp0 = (uint64_t)&cpu_stacks[cpu_number].stack[CPU_STACK_SIZE]; 82 | cpu_tss[cpu_number].ist1 = (uint64_t)&cpu_stacks[cpu_number].stack[CPU_STACK_SIZE]; 83 | } 84 | 85 | static int start_ap(uint8_t target_apic_id, int cpu_number) { 86 | if (cpu_number == MAX_CPUS) { 87 | panic(NULL, 0, "smp: CPU limit exceeded"); 88 | } 89 | 90 | setup_cpu_local(cpu_number, target_apic_id); 91 | 92 | struct cpu_local_t *cpu_local = &cpu_locals[cpu_number]; 93 | struct tss_t *tss = &cpu_tss[cpu_number]; 94 | uint8_t *stack = &cpu_stacks[cpu_number].stack[CPU_STACK_SIZE]; 95 | 96 | void *trampoline = smp_prepare_trampoline(ap_kernel_entry, (void *)kernel_pagemap->pml4, 97 | stack, cpu_local, tss); 98 | 99 | /* Send the INIT IPI */ 100 | lapic_write(APICREG_ICR1, ((uint32_t)target_apic_id) << 24); 101 | lapic_write(APICREG_ICR0, 0x500); 102 | /* wait 10ms */ 103 | ksleep(10); 104 | /* Send the Startup IPI */ 105 | lapic_write(APICREG_ICR1, ((uint32_t)target_apic_id) << 24); 106 | lapic_write(APICREG_ICR0, 0x600 | (uint32_t)(size_t)trampoline); 107 | 108 | for (int i = 0; i < 1000; i++) { 109 | ksleep(1); 110 | if (smp_check_ap_flag()) 111 | return 0; 112 | } 113 | return -1; 114 | } 115 | 116 | static void init_cpu0(void) { 117 | setup_cpu_local(0, 0); 118 | 119 | struct cpu_local_t *cpu_local = &cpu_locals[0]; 120 | struct tss_t *tss = &cpu_tss[0]; 121 | 122 | smp_init_cpu0_local(cpu_local, tss); 123 | } 124 | 125 | void init_smp(void) { 126 | /* prepare CPU 0 first */ 127 | init_cpu0(); 128 | 129 | /* start up the APs and jump them into the kernel */ 130 | for (size_t i = 1; i < madt_local_apic_i; i++) { 131 | /* Check if LAPIC is marked as disabled */ 132 | uint32_t flags = madt_local_apics[i]->flags; 133 | if (!((flags & 1) ^ ((flags >> 1) & 1))) { 134 | kprint(KPRN_INFO, "smp: Theoretical AP #%u ignored", i); 135 | continue; 136 | } 137 | 138 | kprint(KPRN_INFO, "smp: Starting up AP #%u", i); 139 | 140 | if (start_ap(madt_local_apics[i]->apic_id, smp_cpu_count)) { 141 | kprint(KPRN_ERR, "smp: Failed to start AP #%u", i); 142 | continue; 143 | } 144 | 145 | smp_cpu_count++; 146 | /* wait a bit */ 147 | ksleep(10); 148 | } 149 | 150 | kprint(KPRN_INFO, "smp: Total CPU count: %u", smp_cpu_count); 151 | 152 | smp_ready = 1; 153 | } 154 | -------------------------------------------------------------------------------- /src/sys/apic.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define APIC_CPUID_BIT (1 << 9) 10 | 11 | int apic_supported(void) { 12 | unsigned int eax, ebx, ecx, edx = 0; 13 | 14 | kprint(KPRN_INFO, "apic: Checking for support..."); 15 | 16 | cpuid(1, 0, &eax, &ebx, &ecx, &edx); 17 | 18 | /* Check if the apic bit is set */ 19 | if ((edx & APIC_CPUID_BIT)) { 20 | kprint(KPRN_INFO, "apic: Supported!"); 21 | return 1; 22 | } else { 23 | kprint(KPRN_INFO, "apic: Unsupported!"); 24 | return 0; 25 | } 26 | } 27 | 28 | uint32_t lapic_read(uint32_t reg) { 29 | size_t lapic_base = (size_t)madt->local_controller_addr + MEM_PHYS_OFFSET; 30 | return *((volatile uint32_t *)(lapic_base + reg)); 31 | } 32 | 33 | void lapic_write(uint32_t reg, uint32_t data) { 34 | size_t lapic_base = (size_t)madt->local_controller_addr + MEM_PHYS_OFFSET; 35 | *((volatile uint32_t *)(lapic_base + reg)) = data; 36 | } 37 | 38 | void lapic_set_nmi(uint8_t vec, uint16_t flags, uint8_t lint) { 39 | uint32_t nmi = 0x400 | vec; 40 | 41 | if (flags & 2) { 42 | nmi |= (1 << 13); 43 | } 44 | 45 | if (flags & 8) { 46 | nmi |= (1 << 15); 47 | } 48 | 49 | if (lint == 1) { 50 | lapic_write(0x360, nmi); 51 | } else if (lint == 0) { 52 | lapic_write(0x350, nmi); 53 | } 54 | } 55 | 56 | void lapic_install_nmi(int vec, int nmi) { 57 | lapic_set_nmi(vec, madt_nmis[nmi]->flags, madt_nmis[nmi]->lint); 58 | } 59 | 60 | void lapic_enable(void) { 61 | lapic_write(0xf0, lapic_read(0xf0) | 0x1ff); 62 | } 63 | 64 | void lapic_eoi(void) { 65 | lapic_write(0xb0, 0); 66 | } 67 | 68 | void lapic_send_ipi(int cpu, uint8_t vector) { 69 | lapic_write(APICREG_ICR1, ((uint32_t)cpu_locals[cpu].lapic_id) << 24); 70 | lapic_write(APICREG_ICR0, vector); 71 | } 72 | 73 | /* Read from the `io_apic_num`'th I/O APIC as described by the MADT */ 74 | uint32_t io_apic_read(size_t io_apic_num, uint32_t reg) { 75 | volatile uint32_t *base = (volatile uint32_t *)((size_t)madt_io_apics[io_apic_num]->addr + MEM_PHYS_OFFSET); 76 | *base = reg; 77 | return *(base + 4); 78 | } 79 | 80 | /* Write to the `io_apic_num`'th I/O APIC as described by the MADT */ 81 | void io_apic_write(size_t io_apic_num, uint32_t reg, uint32_t data) { 82 | volatile uint32_t *base = (volatile uint32_t *)((size_t)madt_io_apics[io_apic_num]->addr + MEM_PHYS_OFFSET); 83 | *base = reg; 84 | *(base + 4) = data; 85 | } 86 | 87 | /* Return the index of the I/O APIC that handles this redirect */ 88 | size_t io_apic_from_redirect(uint32_t gsi) { 89 | for (size_t i = 0; i < madt_io_apic_i; i++) { 90 | if (madt_io_apics[i]->gsib <= gsi && madt_io_apics[i]->gsib + io_apic_get_max_redirect(i) > gsi) 91 | return i; 92 | } 93 | 94 | return -1; 95 | } 96 | 97 | /* Get the maximum number of redirects this I/O APIC can handle */ 98 | uint32_t io_apic_get_max_redirect(size_t io_apic_num) { 99 | return (io_apic_read(io_apic_num, 1) & 0xff0000) >> 16; 100 | } 101 | 102 | static void io_apic_set_redirect(uint8_t vec, uint32_t gsi, uint16_t flags, int cpu, int status) { 103 | size_t io_apic = io_apic_from_redirect(gsi); 104 | 105 | uint64_t redirect = vec; 106 | 107 | // Active high(0) or low(1) 108 | if (flags & 2) { 109 | redirect |= (1 << 13); 110 | } 111 | 112 | // Edge(0) or level(1) triggered 113 | if (flags & 8) { 114 | redirect |= (1 << 15); 115 | } 116 | 117 | if (!status) { 118 | /* Set mask bit */ 119 | redirect |= (1 << 16); 120 | } 121 | 122 | /* Set target APIC ID */ 123 | redirect |= ((uint64_t)cpu_locals[cpu].lapic_id) << 56; 124 | uint32_t ioredtbl = (gsi - madt_io_apics[io_apic]->gsib) * 2 + 16; 125 | 126 | io_apic_write(io_apic, ioredtbl + 0, (uint32_t)redirect); 127 | io_apic_write(io_apic, ioredtbl + 1, (uint32_t)(redirect >> 32)); 128 | } 129 | 130 | void io_apic_set_up_legacy_irq(int cpu, uint8_t irq, int status) { 131 | /* Redirect will handle whether the IRQ is masked or not, we just need to search the 132 | * MADT ISOs for a corresponding IRQ */ 133 | for (size_t i = 0; i < madt_iso_i; i++) { 134 | if (madt_isos[i]->irq_source == irq) { 135 | io_apic_set_redirect(madt_isos[i]->irq_source + 0x20, madt_isos[i]->gsi, 136 | madt_isos[i]->flags, cpu, status); 137 | return; 138 | } 139 | } 140 | io_apic_set_redirect(irq + 0x20, irq, 0, cpu, status); 141 | } 142 | 143 | void io_apic_connect_gsi_to_vec(int cpu, uint8_t vec, uint32_t gsi, uint16_t flags, int status) { 144 | io_apic_set_redirect(vec, gsi, flags, cpu, status); 145 | } 146 | 147 | uint32_t *lapic_eoi_ptr; 148 | 149 | void init_apic(void) { 150 | lapic_enable(); 151 | size_t lapic_base = (size_t)madt->local_controller_addr + MEM_PHYS_OFFSET; 152 | lapic_eoi_ptr = (uint32_t *)(lapic_base + 0xb0); 153 | kprint(KPRN_INFO, "apic: Done! APIC initialised."); 154 | } 155 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | void kmain_thread(void *arg) { 32 | (void)arg; 33 | 34 | /* Launch the urm */ 35 | task_tcreate(0, tcreate_fn_call, tcreate_fn_call_data(0, userspace_request_monitor, 0)); 36 | 37 | /* Initialise file descriptor handlers */ 38 | init_fd(); 39 | 40 | /* Initialise filesystem drivers */ 41 | init_fs(); 42 | 43 | /* Mount /dev */ 44 | mount("devfs", "/dev", "devfs", 0, 0); 45 | 46 | /* Initialise device drivers */ 47 | init_dev(); 48 | 49 | int tty = open("/dev/tty0", O_RDWR); 50 | 51 | char root[64]; 52 | if (!cmdline_get_value(root, 64, "root")) { 53 | kprint(KPRN_WARN, "kmain: Command line argument \"root\" not specified."); 54 | readline(tty, "Select root device: ", root, 64); 55 | } 56 | kprint(KPRN_INFO, "kmain: root=%s", root); 57 | 58 | char rootfs[64]; 59 | if (!cmdline_get_value(rootfs, 64, "rootfs")) { 60 | kprint(KPRN_WARN, "kmain: Command line argument \"rootfs\" not specified."); 61 | readline(tty, "Root filesystem to use: ", rootfs, 64); 62 | } 63 | kprint(KPRN_INFO, "kmain: rootfs=%s", rootfs); 64 | 65 | char init[64]; 66 | if (!cmdline_get_value(init, 64, "init")) { 67 | kprint(KPRN_WARN, "kmain: Command line argument \"init\" not specified."); 68 | readline(tty, "Location of init: ", init, 64); 69 | } 70 | kprint(KPRN_INFO, "kmain: init=%s", init); 71 | 72 | close(tty); 73 | 74 | /* Mount root partition */ 75 | if (mount(root, "/", rootfs, 0, 0)) { 76 | panic(NULL, 0, "Unable to mount root"); 77 | } 78 | 79 | /* Set hostname */ 80 | init_hostname(); 81 | 82 | /* Execute init process */ 83 | kprint(KPRN_INFO, "kmain: Starting init"); 84 | const char *args[] = { init, NULL }; 85 | const char *environ[] = { NULL }; 86 | if (kexec(init, args, environ, "/dev/tty0", "/dev/tty0", "/dev/tty0") == -1) { 87 | panic(NULL, 0, "Unable to launch init"); 88 | } 89 | if (kexec(init, args, environ, "/dev/tty1", "/dev/tty1", "/dev/tty1") == -1) { 90 | panic(NULL, 0, "Unable to launch init"); 91 | } 92 | if (kexec(init, args, environ, "/dev/tty2", "/dev/tty2", "/dev/tty2") == -1) { 93 | panic(NULL, 0, "Unable to launch init"); 94 | } 95 | if (kexec(init, args, environ, "/dev/tty3", "/dev/tty3", "/dev/tty3") == -1) { 96 | panic(NULL, 0, "Unable to launch init"); 97 | } 98 | if (kexec(init, args, environ, "/dev/tty4", "/dev/tty4", "/dev/tty4") == -1) { 99 | panic(NULL, 0, "Unable to launch init"); 100 | } 101 | if (kexec(init, args, environ, "/dev/tty5", "/dev/tty5", "/dev/tty5") == -1) { 102 | panic(NULL, 0, "Unable to launch init"); 103 | } 104 | 105 | kprint(KPRN_INFO, "kmain: End of kmain"); 106 | 107 | /* kill kmain now */ 108 | task_tkill(CURRENT_PROCESS, CURRENT_THREAD); 109 | 110 | for (;;) asm volatile ("hlt;"); 111 | } 112 | 113 | /* Main kernel entry point, only initialise essential services and scheduler */ 114 | void kmain(struct stivale_struct_t *stivale) { 115 | kprint(KPRN_INFO, "Kernel booted"); 116 | kprint(KPRN_INFO, "Build time: %s", BUILD_TIME); 117 | kprint(KPRN_INFO, "Command line: %s", stivale->cmdline); 118 | 119 | init_cmdline(stivale->cmdline); 120 | init_gdt(); 121 | init_idt(); 122 | init_cpu_features(); 123 | 124 | /* Memory-related stuff */ 125 | init_pmm(&(stivale->memmap)); 126 | init_rand(); 127 | init_vmm(&(stivale->memmap)); 128 | 129 | init_vbe(&(stivale->fb)); 130 | init_tty(); 131 | 132 | init_acpi(); 133 | init_pic(); 134 | 135 | unix_epoch = stivale->epoch; 136 | 137 | /* Init the PIT */ 138 | init_pit(); 139 | 140 | /* Initialise PCI */ 141 | init_pci(); 142 | 143 | /* Init Symmetric Multiprocessing */ 144 | asm volatile ("sti":::"memory"); 145 | init_smp(); 146 | asm volatile ("cli":::"memory"); 147 | 148 | /* Initialise scheduler */ 149 | init_sched(); 150 | 151 | /* Unlock the scheduler for the first time */ 152 | spinlock_release(&scheduler_lock); 153 | 154 | /* Start a main kernel thread which will take over when the scheduler is running */ 155 | task_tcreate(0, tcreate_fn_call, tcreate_fn_call_data(0, kmain_thread, 0)); 156 | 157 | /*** DO NOT ADD ANYTHING TO THIS FUNCTION AFTER THIS POINT, ADD TO kmain_thread 158 | INSTEAD! ***/ 159 | 160 | /* Pre-scheduler init done. Wait for the main kernel thread to be scheduled. */ 161 | asm volatile ("sti":::"memory"); 162 | for (;;) asm volatile ("hlt":::"memory"); 163 | } 164 | -------------------------------------------------------------------------------- /src/lib/lock.h: -------------------------------------------------------------------------------- 1 | #ifndef __LOCK_H__ 2 | #define __LOCK_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #ifdef _DEBUG_ 9 | 10 | #define DEADLOCK_MAX_ITER 0x4000000 11 | 12 | struct last_acquirer_t { 13 | const char *file; 14 | const char *func; 15 | int line; 16 | }; 17 | 18 | typedef struct { 19 | int lock; 20 | struct last_acquirer_t last_acquirer; 21 | } lock_t; 22 | 23 | #define new_lock (lock_t){ 1, { "N/A", "N/A", 0 } } 24 | #define new_lock_acquired (lock_t){ 0, { "N/A", "N/A", 0 } } 25 | 26 | #else /* _DEBUG_ */ 27 | 28 | typedef struct { 29 | int lock; 30 | } lock_t; 31 | 32 | #define new_lock (lock_t){ 1 } 33 | #define new_lock_acquired (lock_t){ 0 } 34 | 35 | #endif /* _DEBUG_ */ 36 | 37 | #define locked_read(type, var) ({ \ 38 | type ret = 0; \ 39 | asm volatile ( \ 40 | "lock xadd %1, %0;" \ 41 | : "+r" (ret) \ 42 | : "m" (*(var)) \ 43 | : "memory", "cc" \ 44 | ); \ 45 | ret; \ 46 | }) 47 | 48 | #define locked_write(type, var, val) ({ \ 49 | type ret = val; \ 50 | asm volatile ( \ 51 | "lock xchg %1, %0;" \ 52 | : "+r" ((ret)) \ 53 | : "m" (*(var)) \ 54 | : "memory" \ 55 | ); \ 56 | ret; \ 57 | }) 58 | 59 | #define locked_inc(var) ({ \ 60 | int ret; \ 61 | asm volatile ( \ 62 | "lock inc %1;" \ 63 | : "=@ccnz" (ret) \ 64 | : "m" (*(var)) \ 65 | : "memory" \ 66 | ); \ 67 | ret; \ 68 | }) 69 | 70 | #define locked_dec(var) ({ \ 71 | int ret; \ 72 | asm volatile ( \ 73 | "lock dec %1;" \ 74 | : "=@ccnz" (ret) \ 75 | : "m" (*(var)) \ 76 | : "memory" \ 77 | ); \ 78 | ret; \ 79 | }) 80 | 81 | // TODO: Move this somewhere else 82 | #define __puts_uint(val) ({ \ 83 | char buf[21] = {0}; \ 84 | int i; \ 85 | int val_copy = (uint64_t)(val); \ 86 | if (!val_copy) { \ 87 | buf[0] = '0'; \ 88 | buf[1] = 0; \ 89 | i = 0; \ 90 | } else { \ 91 | for (i = 19; val_copy; i--) { \ 92 | buf[i] = (val_copy % 10) + '0'; \ 93 | val_copy /= 10; \ 94 | } \ 95 | i++; \ 96 | } \ 97 | qemu_debug_puts_urgent(buf + i); \ 98 | }) 99 | 100 | #ifdef _DEBUG_ 101 | 102 | __attribute__((unused)) static int deadlock_detect_lock = 0; 103 | 104 | __attribute__((noinline)) __attribute__((unused)) static void deadlock_detect(const char *file, 105 | const char *function, 106 | int line, 107 | const char *lockname, 108 | lock_t *lock, 109 | size_t iter) { 110 | while (locked_write(int, &deadlock_detect_lock, 1)); 111 | qemu_debug_puts_urgent("\n---\npossible deadlock at: spinlock_acquire("); 112 | qemu_debug_puts_urgent(lockname); 113 | qemu_debug_puts_urgent(");"); 114 | qemu_debug_puts_urgent("\nfile: "); 115 | qemu_debug_puts_urgent(file); 116 | qemu_debug_puts_urgent("\nfunction: "); 117 | qemu_debug_puts_urgent(function); 118 | qemu_debug_puts_urgent("\nline: "); 119 | __puts_uint(line); 120 | qemu_debug_puts_urgent("\n---\nlast acquirer:"); 121 | qemu_debug_puts_urgent("\nfile: "); 122 | qemu_debug_puts_urgent(lock->last_acquirer.file); 123 | qemu_debug_puts_urgent("\nfunction: "); 124 | qemu_debug_puts_urgent(lock->last_acquirer.func); 125 | qemu_debug_puts_urgent("\nline: "); 126 | __puts_uint(lock->last_acquirer.line); 127 | qemu_debug_puts_urgent("\n---\nassumed locked after it spun for "); 128 | __puts_uint(iter); 129 | qemu_debug_puts_urgent(" iterations\n---\n"); 130 | locked_write(int, &deadlock_detect_lock, 0); 131 | } 132 | 133 | #define spinlock_acquire(lock) ({ \ 134 | __label__ retry; \ 135 | __label__ out; \ 136 | retry:; \ 137 | for (size_t i = 0; i < DEADLOCK_MAX_ITER; i++) \ 138 | if (spinlock_test_and_acquire(lock)) \ 139 | goto out; \ 140 | deadlock_detect(__FILE__, __func__, __LINE__, #lock, lock, DEADLOCK_MAX_ITER); \ 141 | goto retry; \ 142 | out:; \ 143 | }) 144 | 145 | #define spinlock_test_and_acquire(LOCK) ({ \ 146 | int ret; \ 147 | asm volatile ( \ 148 | "lock btr %0, 0;" \ 149 | : "+m" ((LOCK)->lock), "=@ccc" (ret) \ 150 | : \ 151 | : "memory" \ 152 | ); \ 153 | if (ret) { \ 154 | (LOCK)->last_acquirer.file = __FILE__; \ 155 | (LOCK)->last_acquirer.func = __func__; \ 156 | (LOCK)->last_acquirer.line = __LINE__; \ 157 | } \ 158 | ret; \ 159 | }) 160 | 161 | #else /* _DEBUG_ */ 162 | 163 | #define spinlock_acquire(LOCK) ({ \ 164 | asm volatile ( \ 165 | "1: " \ 166 | "lock btr %0, 0;" \ 167 | "jc 2f;" \ 168 | "pause;" \ 169 | "jmp 1b;" \ 170 | "2: " \ 171 | : "+m" ((LOCK)->lock) \ 172 | : \ 173 | : "memory", "cc" \ 174 | ); \ 175 | }) 176 | 177 | #define spinlock_test_and_acquire(LOCK) ({ \ 178 | int ret; \ 179 | asm volatile ( \ 180 | "lock btr %0, 0;" \ 181 | : "+m" ((LOCK)->lock), "=@ccc" (ret) \ 182 | : \ 183 | : "memory" \ 184 | ); \ 185 | ret; \ 186 | }) 187 | 188 | #endif /* _DEBUG_ */ 189 | 190 | __attribute__((always_inline)) __attribute__((unused)) static inline void spinlock_release(lock_t *lock) { 191 | asm volatile ( 192 | "lock bts %0, 0;" 193 | : "+m" (lock->lock) 194 | : 195 | : "memory", "cc" 196 | ); 197 | } 198 | 199 | #endif 200 | -------------------------------------------------------------------------------- /src/lib/ht.h: -------------------------------------------------------------------------------- 1 | #ifndef __HT_H__ 2 | #define __HT_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define ENTRIES_PER_HASHING_LEVEL 4096 12 | 13 | static inline uint64_t ht_hash_str(const char *str, uint64_t seed) { 14 | /* djb2 15 | * http://www.cse.yorku.ca/~oz/hash.html 16 | */ 17 | int c; 18 | while ((c = *str++)) 19 | seed = ((seed << 5) + seed) + c; 20 | return ((seed % (ENTRIES_PER_HASHING_LEVEL - 1)) + 1); 21 | } 22 | 23 | #define ht_new(type, name) \ 24 | type **name; \ 25 | lock_t name##_lock; 26 | 27 | #define ht_dump(type, hashtable, size) ({ \ 28 | void **buf = NULL; \ 29 | *size = 0; \ 30 | type **ret = (type **)__ht_dump((void **)hashtable, buf, size); \ 31 | ret; \ 32 | }) 33 | 34 | __attribute__((unused)) static void **__ht_dump(void **ht, void **buf, size_t *size) { 35 | for (size_t i = 1; i < ENTRIES_PER_HASHING_LEVEL; i++) { 36 | if (!ht[i]) { 37 | continue; 38 | } else if ((size_t)ht[i] & 1) { 39 | void **tmp = __ht_dump((void *)((size_t)ht[i] - 1), buf, size); 40 | if (!tmp) 41 | return NULL; 42 | buf = tmp; 43 | } else { 44 | void **tmp = krealloc(buf, sizeof(void *) * (*size + 1)); 45 | if (!tmp) { 46 | kfree(buf); 47 | return NULL; 48 | } 49 | buf = tmp; 50 | buf[(*size)++] = ht[i]; 51 | } 52 | } 53 | 54 | return buf; 55 | } 56 | 57 | #define ht_init(hashtable) ({ \ 58 | __label__ out; \ 59 | int ret = 0; \ 60 | hashtable = pmm_allocz((ENTRIES_PER_HASHING_LEVEL * sizeof(void *)) / PAGE_SIZE); \ 61 | if (!hashtable) { \ 62 | ret = -1; \ 63 | goto out; \ 64 | } \ 65 | hashtable = (void *)hashtable + MEM_PHYS_OFFSET; \ 66 | hashtable##_lock = new_lock; \ 67 | while (!(hashtable[0] = (void *)rand64())); \ 68 | out: \ 69 | ret; \ 70 | }) 71 | 72 | #define ht_get(type, hashtable, nname) ({ \ 73 | __label__ out; \ 74 | type *ret; \ 75 | \ 76 | spinlock_acquire(&hashtable##_lock); \ 77 | type **ht = hashtable; \ 78 | for (;;) { \ 79 | uint64_t hash = ht_hash_str(nname, (uint64_t)ht[0]); \ 80 | if (!ht[hash]) { \ 81 | ret = NULL; \ 82 | goto out; \ 83 | } else if ((size_t)ht[hash] & 1) { \ 84 | ht = (void *)((size_t)ht[hash] - 1); \ 85 | continue; \ 86 | } else { \ 87 | if (strcmp(nname, ((type **)ht)[hash]->name)) { \ 88 | ret = NULL; \ 89 | goto out; \ 90 | } \ 91 | ret = ht[hash]; \ 92 | goto out; \ 93 | } \ 94 | } \ 95 | out: \ 96 | spinlock_release(&hashtable##_lock); \ 97 | ret; \ 98 | }) 99 | 100 | #define ht_remove(type, hashtable, nname) ({ \ 101 | __label__ out; \ 102 | type *ret; \ 103 | \ 104 | spinlock_acquire(&hashtable##_lock); \ 105 | type **ht = hashtable; \ 106 | for (;;) { \ 107 | uint64_t hash = ht_hash_str(nname, (uint64_t)ht[0]); \ 108 | if (!ht[hash]) { \ 109 | ret = NULL; \ 110 | goto out; \ 111 | } else if ((size_t)ht[hash] & 1) { \ 112 | ht = (void *)((size_t)ht[hash] - 1); \ 113 | continue; \ 114 | } else { \ 115 | if (strcmp(nname, ((type **)ht)[hash]->name)) { \ 116 | ret = NULL; \ 117 | goto out; \ 118 | } \ 119 | ret = ht[hash]; \ 120 | ht[hash] = 0; \ 121 | goto out; \ 122 | } \ 123 | } \ 124 | out: \ 125 | spinlock_release(&hashtable##_lock); \ 126 | ret; \ 127 | }) 128 | 129 | // Adds an element to a hash table with these prerequisites: 130 | // the element shall be a pointer to a structure containing a "name" 131 | // element which is of type "char *". This "name" element shall be used 132 | // for hashing purposes. 133 | #define ht_add(type, hashtable, element) ({ \ 134 | __label__ out; \ 135 | int ret = 0; \ 136 | \ 137 | spinlock_acquire(&hashtable##_lock); \ 138 | type **ht = hashtable; \ 139 | \ 140 | for (;;) { \ 141 | uint64_t hash = ht_hash_str(element->name, (uint64_t)ht[0]); \ 142 | if (!ht[hash]) { \ 143 | ht[hash] = element; \ 144 | goto out; \ 145 | } else if ((size_t)ht[hash] & 1) { \ 146 | ht = (void *)((size_t)ht[hash] - 1); \ 147 | continue; \ 148 | } else { \ 149 | if (!strcmp(element->name, ht[hash]->name)) { \ 150 | ret = -1; \ 151 | goto out; \ 152 | } \ 153 | type **new_ht = pmm_allocz((ENTRIES_PER_HASHING_LEVEL * sizeof(void *)) / PAGE_SIZE); \ 154 | if (!new_ht) { \ 155 | ret = -1; \ 156 | goto out; \ 157 | } \ 158 | new_ht = (void *)new_ht + MEM_PHYS_OFFSET; \ 159 | type *old_elem = ht[hash]; \ 160 | ht[hash] = (void *)((size_t)new_ht + 1); \ 161 | ht = new_ht; \ 162 | while (!(ht[0] = (void *)rand64())); \ 163 | uint64_t old_elem_hash = ht_hash_str(old_elem->name, (uint64_t)ht[0]); \ 164 | ht[old_elem_hash] = old_elem; \ 165 | continue; \ 166 | } \ 167 | } \ 168 | \ 169 | out: \ 170 | spinlock_release(&hashtable##_lock); \ 171 | ret; \ 172 | }) 173 | 174 | #endif 175 | -------------------------------------------------------------------------------- /src/proc/userspace.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | extern void *signal_trampoline[]; 16 | extern void *signal_trampoline_size[]; 17 | 18 | static int parse_shebang(int fd, pid_t pid, const char *argv[], const char *envp[]) { 19 | kprint(KPRN_DBG, "Found shebang. Parsing."); 20 | 21 | char **shebang = kalloc(1024); 22 | int i = 0; 23 | int j = 0; 24 | 25 | for (;;) { 26 | char c; 27 | read(fd, &c, 1); 28 | switch (c) { 29 | case '\n': 30 | goto done; 31 | case ' ': 32 | case '\t': 33 | continue; 34 | default: 35 | j = 0; 36 | goto found_arg; 37 | } 38 | 39 | for (;;) { 40 | read(fd, &c, 1); 41 | if (c == ' ' || c == '\t' || c == '\n') { 42 | i++; 43 | if (c == '\n') 44 | goto done; 45 | else 46 | break; 47 | } 48 | found_arg: 49 | shebang[i] = krealloc(shebang[i], j + 1); 50 | shebang[i][j++] = c; 51 | } 52 | } 53 | 54 | done: 55 | // Append original arguments at the end 56 | for (j = 0; argv[j]; j++) { 57 | shebang[i] = kalloc(strlen(argv[j]) + 1); 58 | strcpy(shebang[i], argv[j]); 59 | i++; 60 | } 61 | 62 | int ret = exec(pid, shebang[0], (const char **)shebang, envp); 63 | for (i = 0; shebang[i]; i++) 64 | kfree(shebang[i]); 65 | kfree(shebang); 66 | return ret; 67 | } 68 | 69 | int exec(pid_t pid, const char *filename, const char *argv[], const char *envp[]) { 70 | int ret; 71 | size_t entry; 72 | 73 | struct process_t *process = process_table[pid]; 74 | 75 | struct pagemap_t *old_pagemap = process->pagemap; 76 | 77 | // Load the executable 78 | int fd = open(filename, O_RDONLY); 79 | if (fd < 0) { 80 | return -1; 81 | } 82 | 83 | // Check for a shebang 84 | char shebang[2]; 85 | read(fd, shebang, 2); 86 | if (!strncmp(shebang, "#!", 2)) { 87 | return parse_shebang(fd, pid, argv, envp); 88 | } 89 | 90 | struct pagemap_t *new_pagemap = new_address_space(); 91 | 92 | struct auxval_t auxval; 93 | char *ld_path; 94 | 95 | ret = elf_load(fd, new_pagemap, 0, &auxval, &ld_path); 96 | close(fd); 97 | if (ret == -1) { 98 | kprint(KPRN_DBG, "elf: Load of binary file %s failed.", filename); 99 | free_address_space(new_pagemap); 100 | return -1; 101 | } 102 | 103 | // If requested: Load the dynamic linker 104 | if (!ld_path) { 105 | entry = auxval.at_entry; 106 | } else { 107 | int ld_fd = open(ld_path, O_RDONLY); 108 | if (ld_fd < 0) { 109 | kprint(KPRN_DBG, "elf: Could not find dynamic linker."); 110 | free_address_space(new_pagemap); 111 | kfree(ld_path); 112 | return -1; 113 | } 114 | 115 | /* 1 GiB is chosen arbitrarily (as programs are expected to fit below 1 GiB). 116 | TODO: Dynamically find a virtual address range that is large enough */ 117 | struct auxval_t ld_auxval; 118 | ret = elf_load(ld_fd, new_pagemap, 0x40000000, &ld_auxval, NULL); 119 | close(ld_fd); 120 | if (ret == -1) { 121 | kprint(KPRN_DBG, "elf: Load of binary file %s failed.", ld_path); 122 | free_address_space(new_pagemap); 123 | kfree(ld_path); 124 | return -1; 125 | } 126 | kfree(ld_path); 127 | entry = ld_auxval.at_entry; 128 | } 129 | 130 | /* Map the higher half into the process */ 131 | for (size_t i = 256; i < 512; i++) { 132 | new_pagemap->pml4[i] = process_table[0]->pagemap->pml4[i]; 133 | } 134 | 135 | /* Destroy all previous threads */ 136 | for (size_t i = 0; i < MAX_THREADS; i++) 137 | task_tkill(pid, i); 138 | 139 | // Map the sig ret trampoline into process 140 | void *trampoline_ptr = pmm_allocz(1); 141 | memcpy(trampoline_ptr + MEM_PHYS_OFFSET, 142 | signal_trampoline, 143 | (size_t)signal_trampoline_size); 144 | map_page(new_pagemap, 145 | (size_t)trampoline_ptr, 146 | (size_t)(SIGNAL_TRAMPOLINE_VADDR), 147 | 0x05); 148 | 149 | /* Free previous address space */ 150 | free_address_space(old_pagemap); 151 | 152 | /* Load new pagemap */ 153 | process->pagemap = new_pagemap; 154 | 155 | /* Create main thread */ 156 | task_tcreate(pid, tcreate_elf_exec, tcreate_elf_exec_data((void *)entry, argv, envp, &auxval)); 157 | 158 | return 0; 159 | } 160 | 161 | pid_t kexec(const char *filename, const char *argv[], const char *envp[], 162 | const char *stdin, const char *stdout, const char *stderr) { 163 | 164 | /* Create a new process */ 165 | pid_t new_pid = task_pcreate(); 166 | if (new_pid == (pid_t)(-1)) return -1; 167 | 168 | process_table[new_pid]->ppid = 0; 169 | process_table[new_pid]->pgid = new_pid; 170 | process_table[new_pid]->uid = 0; 171 | 172 | /* Open stdio descriptors */ 173 | process_table[new_pid]->file_handles[0] = open(stdin, O_RDONLY); 174 | process_table[new_pid]->file_handles[1] = open(stdout, O_WRONLY); 175 | process_table[new_pid]->file_handles[2] = open(stderr, O_WRONLY); 176 | 177 | exec(new_pid, filename, argv, envp); 178 | 179 | return new_pid; 180 | } 181 | -------------------------------------------------------------------------------- /src/usb/usb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | static int num_drivers = 0; 8 | dynarray_new(struct usb_driver_t, usb_drivers); 9 | 10 | static int usb_get_descriptor(struct usb_dev_t *device, uint8_t desc_type, 11 | uint8_t desc_index, void *dest, uint16_t size) { 12 | struct usb_request_t req = {0}; 13 | req.length = size; 14 | req.request_type = 0b10000000; 15 | req.request = 6; 16 | req.value = (desc_type << 8) | desc_index; 17 | device->controller->send_control(device, dest, req, 0); 18 | return 0; 19 | } 20 | 21 | void *get_configuration_space(struct usb_dev_t *device, uint8_t num) { 22 | struct usb_config_t config = {0}; 23 | ; 24 | usb_get_descriptor(device, 2, 0, &config, sizeof(struct usb_config_t)); 25 | void *res = kalloc(config.total_length); 26 | usb_get_descriptor(device, 2, num, res, config.total_length); 27 | return res; 28 | } 29 | 30 | void usb_set_configuration(struct usb_dev_t *device, uint8_t num) { 31 | struct usb_request_t req = {0}; 32 | req.length = 0; 33 | req.request = 9; 34 | req.value = num; 35 | device->controller->send_control(device, NULL, req, 1); 36 | } 37 | 38 | void usb_set_interface(struct usb_dev_t *device, uint8_t int_num, 39 | uint8_t setting_num) { 40 | struct usb_request_t req = {0}; 41 | req.length = 0; 42 | req.request_type = 0b00000001; 43 | req.request = 11; 44 | req.value = setting_num; 45 | req.value = int_num; 46 | device->controller->send_control(device, NULL, req, 1); 47 | } 48 | 49 | int usb_get_endpoint(struct usb_endpoint_t *endpoints, int ep_type, int in) { 50 | for (int i = 0; i < 15; i++) { 51 | int is_in = (endpoints[i].address & 0x80) > 0; 52 | int type = endpoints[i].attributes & 0x3; 53 | if (is_in == in && ep_type == type) { 54 | return endpoints[i].hcd_ep_num; 55 | } 56 | } 57 | return -1; 58 | } 59 | 60 | int usb_add_device(struct usb_dev_t device, int devno) { 61 | kprint(KPRN_INFO, "usb: Adding device"); 62 | struct usb_device_descriptor_t descriptor = {0}; 63 | device.hcd_devno = devno; 64 | usb_get_descriptor(&device, 1, 0, &descriptor, 65 | sizeof(struct usb_device_descriptor_t)); 66 | ; 67 | kprint(KPRN_INFO, 68 | "Initialized device with vendor id: %x product id: %x class: %x " 69 | "subclass: %x", 70 | descriptor.vendor_id, descriptor.product_id, descriptor.device_class, 71 | descriptor.device_sub_class); 72 | device.num_configs = descriptor.num_configs; 73 | device.class = descriptor.device_class; 74 | device.subclass = descriptor.device_sub_class; 75 | device.vendor = descriptor.vendor_id; 76 | device.product = descriptor.product_id; 77 | device.usb_ver = descriptor.usb_version; 78 | device.dev_ver = descriptor.device_release; 79 | 80 | int assigned = 0; 81 | for (int i = 0; i < descriptor.num_configs; i++) { 82 | struct usb_config_t *config = get_configuration_space(&device, i); 83 | size_t interface_base = ((size_t)config + config->length); 84 | // TODO add support for matching vendor/product 85 | for (int j = 0; j < config->num_interfaces;) { 86 | struct usb_interface_t *interface = 87 | (struct usb_interface_t *)interface_base; 88 | interface_base += interface->length; 89 | if (interface->type != 0x04) { 90 | continue; 91 | } 92 | for (int k = 0; k < num_drivers; k++) { 93 | struct usb_driver_t *driver = 94 | dynarray_getelem(struct usb_driver_t, usb_drivers, k); 95 | if (!driver) { 96 | break; 97 | } 98 | 99 | uint8_t match = driver->match; 100 | if (((match & MATCH_CLASS) && 101 | (driver->class == interface->class)) && 102 | ((match & MATCH_SUBCLASS) && 103 | (driver->subclass == interface->sub_class))) { 104 | assigned = 1; 105 | 106 | struct usb_endpoint_t endpoints[15] = {0}; 107 | size_t base = (size_t)interface + interface->length; 108 | for (int l = 0; l < interface->num_endpoints;) { 109 | struct usb_endpoint_data_t *ep_info = 110 | (struct usb_endpoint_data_t *)base; 111 | base += ep_info->length; 112 | if (ep_info->type != 0x05) { 113 | continue; 114 | } else { 115 | endpoints[l].address = ep_info->address; 116 | endpoints[l].attributes = ep_info->attributes; 117 | endpoints[l].hcd_ep_num = 118 | device.controller->setup_endpoint( 119 | &device, ep_info->address, 120 | ep_info->max_packet_size); 121 | } 122 | l++; 123 | } 124 | 125 | usb_set_configuration(&device, config->config_value); 126 | driver->probe(&device, endpoints); 127 | } 128 | } 129 | j++; 130 | } 131 | if (assigned) { 132 | break; 133 | } 134 | } 135 | return 0; 136 | } 137 | 138 | void usb_register_driver(struct usb_driver_t driver) { 139 | dynarray_add(struct usb_driver_t, usb_drivers, &driver); 140 | num_drivers++; 141 | } 142 | 143 | void init_usb(void) { 144 | struct usb_driver_t driver = {0}; 145 | driver.match = MATCH_CLASS | MATCH_SUBCLASS; 146 | driver.probe = init_mass_storage; 147 | driver.class = 0x8; 148 | driver.subclass = 0x6; 149 | usb_register_driver(driver); 150 | usb_init_xhci(); 151 | } 152 | -------------------------------------------------------------------------------- /src/fd/pipe/pipe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define PIPE_BUFFER_STEP 32768 12 | 13 | struct pipe_t { 14 | lock_t lock; 15 | int flflags; 16 | void *buffer; 17 | size_t size; 18 | event_t event; 19 | int refcount; 20 | short *poll_status; 21 | }; 22 | 23 | dynarray_new(struct pipe_t, pipes); 24 | 25 | static int pipe_getflflags(int fd) { 26 | struct pipe_t *pipe = dynarray_getelem(struct pipe_t, pipes, fd); 27 | 28 | spinlock_acquire(&pipe->lock); 29 | int ret = pipe->flflags; 30 | spinlock_release(&pipe->lock); 31 | 32 | dynarray_unref(pipes, fd); 33 | return ret; 34 | } 35 | 36 | static int pipe_setflflags(int fd, int flflags) { 37 | struct pipe_t *pipe = dynarray_getelem(struct pipe_t, pipes, fd); 38 | 39 | spinlock_acquire(&pipe->lock); 40 | pipe->flflags = flflags; 41 | spinlock_release(&pipe->lock); 42 | 43 | dynarray_unref(pipes, fd); 44 | return 0; 45 | } 46 | 47 | static int pipe_close(int fd) { 48 | struct pipe_t *pipe = dynarray_getelem(struct pipe_t, pipes, fd); 49 | 50 | spinlock_acquire(&pipe->lock); 51 | pipe->refcount--; 52 | if (pipe->refcount) { 53 | event_trigger(&pipe->event); 54 | spinlock_release(&pipe->lock); 55 | dynarray_unref(pipes, fd); 56 | return 0; 57 | } 58 | if (pipe->size) 59 | kfree(pipe->buffer); 60 | 61 | dynarray_unref(pipes, fd); 62 | dynarray_remove(pipes, fd); 63 | return 0; 64 | } 65 | 66 | static int pipe_read(int fd, void *buf, size_t count) { 67 | struct pipe_t *pipe = dynarray_getelem(struct pipe_t, pipes, fd); 68 | 69 | spinlock_acquire(&pipe->lock); 70 | 71 | while (count > pipe->size) { 72 | if (pipe->flflags & O_NONBLOCK) { 73 | count = pipe->size; 74 | break; 75 | } else { 76 | if (pipe->refcount == 1) { 77 | count = pipe->size; 78 | break; 79 | } 80 | // block until there's enough data available 81 | spinlock_release(&pipe->lock); 82 | if (event_await(&pipe->event)) { 83 | // signal is aborting us, bail 84 | errno = EINTR; 85 | return -1; 86 | } 87 | spinlock_acquire(&pipe->lock); 88 | } 89 | } 90 | 91 | size_t pipe_size_in_steps = (pipe->size + PIPE_BUFFER_STEP - 1) / PIPE_BUFFER_STEP; 92 | size_t new_pipe_size = pipe->size - count; 93 | size_t new_pipe_size_in_steps = (new_pipe_size + PIPE_BUFFER_STEP - 1) / PIPE_BUFFER_STEP; 94 | 95 | memcpy(buf, pipe->buffer, count); 96 | 97 | memmove(pipe->buffer, pipe->buffer + count, count); 98 | 99 | if (new_pipe_size_in_steps < pipe_size_in_steps) 100 | pipe->buffer = krealloc(pipe->buffer, new_pipe_size_in_steps); 101 | 102 | pipe->size = new_pipe_size; 103 | 104 | if (!new_pipe_size) 105 | locked_write(short, pipe->poll_status, 0); 106 | 107 | spinlock_release(&pipe->lock); 108 | dynarray_unref(pipes, fd); 109 | return count; 110 | } 111 | 112 | static int pipe_write(int fd, const void *buf, size_t count) { 113 | struct pipe_t *pipe = dynarray_getelem(struct pipe_t, pipes, fd); 114 | 115 | spinlock_acquire(&pipe->lock); 116 | 117 | size_t pipe_size_in_steps = (pipe->size + PIPE_BUFFER_STEP - 1) / PIPE_BUFFER_STEP; 118 | size_t new_pipe_size = pipe->size + count; 119 | size_t new_pipe_size_in_steps = (new_pipe_size + PIPE_BUFFER_STEP - 1) / PIPE_BUFFER_STEP; 120 | 121 | if (new_pipe_size_in_steps > pipe_size_in_steps) 122 | pipe->buffer = krealloc(pipe->buffer, new_pipe_size_in_steps); 123 | 124 | memcpy(pipe->buffer + pipe->size, buf, count); 125 | 126 | pipe->size = new_pipe_size; 127 | 128 | locked_write(short, pipe->poll_status, POLLIN); 129 | event_trigger(&pipe->event); 130 | 131 | spinlock_release(&pipe->lock); 132 | dynarray_unref(pipes, fd); 133 | return count; 134 | } 135 | 136 | static int pipe_lseek(int fd, off_t offset, int type) { 137 | (void)fd; 138 | (void)offset; 139 | (void)type; 140 | 141 | errno = ESPIPE; 142 | return -1; 143 | } 144 | 145 | static int pipe_dup(int fd) { 146 | struct pipe_t *pipe = dynarray_getelem(struct pipe_t, pipes, fd); 147 | spinlock_acquire(&pipe->lock); 148 | pipe->refcount++; 149 | spinlock_release(&pipe->lock); 150 | dynarray_unref(pipes, fd); 151 | return fd; 152 | } 153 | 154 | static int pipe_fstat(int fd, struct stat *st) { 155 | (void)fd; 156 | st->st_dev = 0; 157 | st->st_ino = 0; 158 | st->st_nlink = 0; 159 | st->st_uid = 0; 160 | st->st_gid = 0; 161 | st->st_rdev = 0; 162 | st->st_size = 0; 163 | st->st_blksize = 0; 164 | st->st_blocks = 0; 165 | st->st_atim.tv_sec = unix_epoch; 166 | st->st_atim.tv_nsec = 0; 167 | st->st_mtim.tv_sec = unix_epoch; 168 | st->st_mtim.tv_nsec = 0; 169 | st->st_ctim.tv_sec = unix_epoch; 170 | st->st_ctim.tv_nsec = 0; 171 | st->st_mode = 0; 172 | st->st_mode |= S_IFIFO; 173 | return 0; 174 | } 175 | 176 | int pipe(int *pipefd) { 177 | struct pipe_t new_pipe = {0}; 178 | new_pipe.refcount = 2; 179 | new_pipe.lock = new_lock; 180 | 181 | struct file_descriptor_t fd_read = {0}; 182 | struct file_descriptor_t fd_write = {0}; 183 | 184 | new_pipe.poll_status = &fd_read.status; 185 | 186 | int fd = dynarray_add(struct pipe_t, pipes, &new_pipe); 187 | if (fd == -1) 188 | return -1; 189 | 190 | struct fd_handler_t pipe_functions = default_fd_handler; 191 | pipe_functions.close = pipe_close; 192 | pipe_functions.fstat = pipe_fstat; 193 | pipe_functions.read = pipe_read; 194 | pipe_functions.write = pipe_write; 195 | pipe_functions.lseek = pipe_lseek; 196 | pipe_functions.dup = pipe_dup; 197 | pipe_functions.getflflags = pipe_getflflags; 198 | pipe_functions.setflflags = pipe_setflflags; 199 | 200 | fd_read.intern_fd = fd; 201 | fd_read.fd_handler = pipe_functions; 202 | 203 | fd_write.intern_fd = fd; 204 | fd_write.fd_handler = pipe_functions; 205 | locked_write(short, &fd_write.status, POLLOUT); 206 | 207 | pipefd[0] = fd_create(&fd_read); 208 | pipefd[1] = fd_create(&fd_write); 209 | 210 | return 0; 211 | } 212 | -------------------------------------------------------------------------------- /src/fd/fd.h: -------------------------------------------------------------------------------- 1 | #ifndef __FD_H__ 2 | #define __FD_H__ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include // for termios 9 | #include 10 | 11 | /* from options/ansi/include/bits/ansi/seek.h in mlibc */ 12 | #define SEEK_CUR 1 13 | #define SEEK_END 2 14 | #define SEEK_SET 3 15 | 16 | /* from abi_bits */ 17 | // reserve 3 bits for the access mode 18 | #define O_ACCMODE 0x0007 19 | #define O_EXEC 1 20 | #define O_RDONLY 2 21 | #define O_RDWR 3 22 | #define O_SEARCH 4 23 | #define O_WRONLY 5 24 | // all remaining flags get their own bit 25 | #define O_APPEND 0x0008 26 | #define O_CREAT 0x0010 27 | #define O_DIRECTORY 0x0020 28 | #define O_EXCL 0x0040 29 | #define O_NOCTTY 0x0080 30 | #define O_NOFOLLOW 0x0100 31 | #define O_TRUNC 0x0200 32 | #define O_NONBLOCK 0x0400 33 | #define O_DSYNC 0x0800 34 | #define O_RSYNC 0x1000 35 | #define O_SYNC 0x2000 36 | #define O_CLOEXEC 0x4000 37 | 38 | #define S_IFMT 0x0F000 39 | #define S_IFBLK 0x06000 40 | #define S_IFCHR 0x02000 41 | #define S_IFIFO 0x01000 42 | #define S_IFREG 0x08000 43 | #define S_IFDIR 0x04000 44 | #define S_IFLNK 0x0A000 45 | #define S_IFSOCK 0x0C000 46 | 47 | #define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) 48 | #define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) 49 | #define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) 50 | #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) 51 | #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) 52 | #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) 53 | #define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) 54 | 55 | struct stat { 56 | dev_t st_dev; 57 | ino_t st_ino; 58 | mode_t st_mode; 59 | nlink_t st_nlink; 60 | uid_t st_uid; 61 | gid_t st_gid; 62 | dev_t st_rdev; 63 | off_t st_size; 64 | struct timespec st_atim; 65 | struct timespec st_mtim; 66 | struct timespec st_ctim; 67 | blksize_t st_blksize; 68 | blkcnt_t st_blocks; 69 | }; 70 | 71 | #define DT_UNKNOWN 0 72 | #define DT_FIFO 1 73 | #define DT_CHR 2 74 | #define DT_DIR 4 75 | #define DT_BLK 6 76 | #define DT_REG 8 77 | #define DT_LNK 10 78 | #define DT_SOCK 12 79 | #define DT_WHT 14 80 | 81 | struct dirent { 82 | ino_t d_ino; 83 | off_t d_off; 84 | unsigned short d_reclen; 85 | unsigned char d_type; 86 | char d_name[1024]; 87 | }; 88 | 89 | struct fd_handler_t { 90 | int (*close)(int); 91 | int (*fstat)(int, struct stat *); 92 | int (*read)(int, void *, size_t); 93 | int (*write)(int, const void *, size_t); 94 | int (*lseek)(int, off_t, int); 95 | int (*dup)(int); 96 | int (*readdir)(int, struct dirent *); 97 | int (*isatty)(int); 98 | int (*tcgetattr)(int, struct termios *); 99 | int (*tcsetattr)(int, int, struct termios *); 100 | int (*tcflow)(int, int); 101 | int (*getflflags)(int); 102 | int (*setflflags)(int, int); 103 | int (*perfmon_attach)(int); 104 | int (*unlink)(int); 105 | int (*getpath)(int, char *); 106 | ssize_t (*recv)(int fd, void *buf, size_t len, int flags); 107 | }; 108 | 109 | struct file_descriptor_t { 110 | int intern_fd; 111 | int fdflags; 112 | short status; 113 | struct fd_handler_t fd_handler; 114 | }; 115 | 116 | struct pollfd { 117 | int fd; 118 | short events; 119 | short revents; 120 | }; 121 | 122 | #define POLLIN 0x01 123 | #define POLLOUT 0x02 124 | #define POLLPRI 0x04 125 | #define POLLHUP 0x08 126 | #define POLLERR 0x10 127 | #define POLLRDHUP 0x20 128 | #define POLLNVAL 0x40 129 | 130 | int poll(struct pollfd *fds, size_t nfds, int timeout); 131 | 132 | int fd_create(struct file_descriptor_t *); 133 | int close(int); 134 | int fstat(int, struct stat *); 135 | int read(int, void *, size_t); 136 | int write(int, const void *, size_t); 137 | int unlink(int); 138 | int lseek(int, off_t, int); 139 | int dup(int); 140 | int readdir(int, struct dirent *); 141 | int isatty(int); 142 | int tcgetattr(int, struct termios *); 143 | int tcsetattr(int, int, struct termios *); 144 | int tcflow(int, int); 145 | int getflflags(int); 146 | int setflflags(int, int); 147 | int perfmon_attach(int); 148 | 149 | void init_fd(void); 150 | int getfdflags(int); 151 | int setfdflags(int, int); 152 | 153 | int getpath(int, char *); 154 | ssize_t recv(int fd, void *buf, size_t len, int flags); 155 | 156 | __attribute__((unused)) static int bogus_fstat() { 157 | errno = EINVAL; 158 | return -1; 159 | } 160 | 161 | __attribute__((unused)) static int bogus_close() { 162 | errno = EIO; 163 | return -1; 164 | } 165 | 166 | __attribute__((unused)) static int bogus_readdir() { 167 | errno = ENOTDIR; 168 | return -1; 169 | } 170 | 171 | __attribute__((unused)) static int bogus_dup() { 172 | errno = EINVAL; 173 | return -1; 174 | } 175 | 176 | __attribute__((unused)) static int bogus_read() { 177 | errno = EINVAL; 178 | return -1; 179 | } 180 | 181 | __attribute__((unused)) static int bogus_write() { 182 | errno = EINVAL; 183 | return -1; 184 | } 185 | 186 | __attribute__((unused)) static int bogus_lseek() { 187 | errno = EINVAL; 188 | return -1; 189 | } 190 | 191 | __attribute__((unused)) static int bogus_flush() { 192 | return 1; 193 | } 194 | 195 | __attribute__((unused)) static int bogus_tcgetattr() { 196 | errno = ENOTTY; 197 | return -1; 198 | } 199 | 200 | __attribute__((unused)) static int bogus_tcsetattr() { 201 | errno = ENOTTY; 202 | return -1; 203 | } 204 | 205 | __attribute__((unused)) static int bogus_tcflow() { 206 | errno = ENOTTY; 207 | return -1; 208 | } 209 | 210 | __attribute__((unused)) static int bogus_getflflags() { 211 | errno = EINVAL; 212 | return -1; 213 | } 214 | 215 | __attribute__((unused)) static int bogus_setflflags() { 216 | errno = EINVAL; 217 | return -1; 218 | } 219 | 220 | __attribute__((unused)) static int bogus_perfmon_attach() { 221 | errno = EINVAL; 222 | return -1; 223 | } 224 | 225 | __attribute__((unused)) static int bogus_isatty() { 226 | return 0; 227 | } 228 | 229 | __attribute__((unused)) static int bogus_unlink() { 230 | errno = EINVAL; 231 | return -1; 232 | } 233 | 234 | __attribute__((unused)) static int bogus_getpath() { 235 | errno = EINVAL; 236 | return -1; 237 | } 238 | 239 | __attribute__((unused)) static int bogus_recv() { 240 | errno = ENOTSOCK; 241 | return -1; 242 | } 243 | 244 | __attribute__((unused)) static struct fd_handler_t default_fd_handler = { 245 | (void *)bogus_close, 246 | (void *)bogus_fstat, 247 | (void *)bogus_read, 248 | (void *)bogus_write, 249 | (void *)bogus_lseek, 250 | (void *)bogus_dup, 251 | (void *)bogus_readdir, 252 | (void *)bogus_isatty, 253 | (void *)bogus_tcgetattr, 254 | (void *)bogus_tcsetattr, 255 | (void *)bogus_tcflow, 256 | (void *)bogus_getflflags, 257 | (void *)bogus_setflflags, 258 | (void *)bogus_perfmon_attach, 259 | (void *)bogus_unlink, 260 | (void *)bogus_getpath, 261 | (void *)bogus_recv 262 | }; 263 | 264 | #endif 265 | -------------------------------------------------------------------------------- /src/devices/term/tty/tty.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MAX_TTYS 6 13 | #define KBD_BUF_SIZE 2048 14 | #define BIG_BUF_SIZE 65536 15 | #define MAX_ESC_VALUES 256 16 | 17 | static int tty_ready = 0; 18 | 19 | struct tty_t { 20 | lock_t write_lock; 21 | lock_t read_lock; 22 | int cursor_x; 23 | int cursor_y; 24 | int cursor_status; 25 | uint32_t cursor_bg_col; 26 | uint32_t cursor_fg_col; 27 | uint32_t text_bg_col; 28 | uint32_t text_fg_col; 29 | uint32_t default_bg_col; 30 | uint32_t default_fg_col; 31 | char *grid; 32 | uint32_t *gridbg; 33 | uint32_t *gridfg; 34 | int control_sequence; 35 | int saved_cursor_x; 36 | int saved_cursor_y; 37 | int scrolling_region_top; 38 | int scrolling_region_bottom; 39 | int escape; 40 | int esc_values[MAX_ESC_VALUES]; 41 | int esc_values_i; 42 | int rrr; 43 | int tabsize; 44 | event_t kbd_event; 45 | lock_t kbd_lock; 46 | size_t kbd_buf_i; 47 | char kbd_buf[KBD_BUF_SIZE]; 48 | size_t big_buf_i; 49 | char big_buf[BIG_BUF_SIZE]; 50 | struct termios termios; 51 | int tcioff; 52 | int tcooff; 53 | int dec_private_mode; 54 | int decckm; 55 | }; 56 | 57 | /* 58 | static uint32_t ansi_colours[] = { 59 | 0x00000000, // black 60 | 0x00aa0000, // red 61 | 0x0000aa00, // green 62 | 0x00aa5500, // brown 63 | 0x000000aa, // blue 64 | 0x00aa00aa, // magenta 65 | 0x0000aaaa, // cyan 66 | 0x00aaaaaa // grey 67 | }; 68 | */ 69 | 70 | // Solarized-like scheme 71 | static uint32_t ansi_colours[] = { 72 | 0x00073642, // black 73 | 0x00dc322f, // red 74 | 0x00859900, // green 75 | 0x00b58900, // brown 76 | 0x00268bd2, // blue 77 | 0x00d33682, // magenta 78 | 0x002aa198, // cyan 79 | 0x00eee8d5 // grey 80 | }; 81 | 82 | static struct tty_t ttys[MAX_TTYS]; 83 | static int current_tty = 0; 84 | 85 | static const char *tty_names[MAX_TTYS] = { 86 | "tty0", "tty1", "tty2", "tty3", "tty4", "tty5" 87 | }; 88 | 89 | #include "output.inc" 90 | #include "input.inc" 91 | 92 | static int tty_flush(int tty) { 93 | (void)tty; 94 | return 1; 95 | } 96 | 97 | static int tty_tcsetattr(int tty, int optional_actions, struct termios *new_termios) { 98 | spinlock_acquire(&ttys[tty].read_lock); 99 | spinlock_acquire(&ttys[tty].write_lock); 100 | ttys[tty].termios = *new_termios; 101 | spinlock_release(&ttys[tty].write_lock); 102 | spinlock_release(&ttys[tty].read_lock); 103 | return 0; 104 | } 105 | 106 | static int tty_tcgetattr(int tty, struct termios *new_termios) { 107 | spinlock_acquire(&ttys[tty].read_lock); 108 | spinlock_acquire(&ttys[tty].write_lock); 109 | *new_termios = ttys[tty].termios; 110 | spinlock_release(&ttys[tty].write_lock); 111 | spinlock_release(&ttys[tty].read_lock); 112 | return 0; 113 | } 114 | 115 | // manage input/output flow. initially, tcooff = tcioff = 0 116 | static int tty_tcflow(int tty, int action) { 117 | int ret = 0; 118 | 119 | spinlock_acquire(&ttys[tty].read_lock); 120 | spinlock_acquire(&ttys[tty].write_lock); 121 | 122 | switch (action) { 123 | case TCOOFF: 124 | ttys[tty].tcooff = 1; 125 | break; 126 | case TCOON: 127 | ttys[tty].tcooff = 0; 128 | break; 129 | case TCIOFF: 130 | ttys[tty].tcioff = 1; 131 | break; 132 | case TCION: 133 | ttys[tty].tcioff = 0; 134 | break; 135 | default: 136 | errno = EINVAL; 137 | ret = -1; 138 | break; 139 | } 140 | 141 | spinlock_release(&ttys[tty].write_lock); 142 | spinlock_release(&ttys[tty].read_lock); 143 | return ret; 144 | } 145 | 146 | static int tty_isatty(int fd) { 147 | (void)fd; 148 | return 1; 149 | } 150 | 151 | void init_tty_extended(uint32_t *__fb, 152 | int __fb_height, 153 | int __fb_width, 154 | int __fb_pitch, 155 | uint8_t *__font, 156 | int __font_height, 157 | int __font_width) { 158 | kprint(KPRN_INFO, "tty: Initialising..."); 159 | 160 | fb = __fb; 161 | fb_height = __fb_height; 162 | fb_width = __fb_width; 163 | fb_pitch = __fb_pitch; 164 | font = __font; 165 | font_height = __font_height; 166 | font_width = __font_width; 167 | 168 | cols = fb_width / font_width; 169 | rows = fb_height / font_height; 170 | 171 | for (int i = 0; i < MAX_TTYS; i++) { 172 | ttys[i].write_lock = new_lock; 173 | ttys[i].read_lock = new_lock; 174 | ttys[i].cursor_x = 0; 175 | ttys[i].cursor_y = 0; 176 | ttys[i].cursor_status = 1; 177 | ttys[i].cursor_bg_col = 0x00839496; 178 | ttys[i].cursor_fg_col = 0x00002b36; 179 | ttys[i].default_bg_col = 0x00002b36; 180 | ttys[i].default_fg_col = 0x00839496; 181 | ttys[i].text_bg_col = ttys[i].default_bg_col; 182 | ttys[i].text_fg_col = ttys[i].default_fg_col; 183 | ttys[i].control_sequence = 0; 184 | ttys[i].escape = 0; 185 | ttys[i].tabsize = 8; 186 | ttys[i].kbd_event = 0; 187 | ttys[i].kbd_lock = new_lock; 188 | ttys[i].kbd_buf_i = 0; 189 | ttys[i].big_buf_i = 0; 190 | ttys[i].termios.c_lflag = (ISIG | ICANON | ECHO); 191 | ttys[i].termios.c_cc[VINTR] = 0x03; 192 | ttys[i].tcooff = 0; 193 | ttys[i].tcioff = 0; 194 | ttys[i].dec_private_mode = 0; 195 | ttys[i].decckm = 0; 196 | ttys[i].grid = kalloc(rows * cols); 197 | ttys[i].gridbg = kalloc(rows * cols * sizeof(uint32_t)); 198 | ttys[i].gridfg = kalloc(rows * cols * sizeof(uint32_t)); 199 | if (!ttys[i].grid || !ttys[i].gridbg || !ttys[i].gridfg) 200 | panic(NULL, 0, "Out of memory"); 201 | for (size_t j = 0; j < (size_t)(rows * cols); j++) { 202 | ttys[i].grid[j] = ' '; 203 | ttys[i].gridbg[j] = ttys[i].text_bg_col; 204 | ttys[i].gridfg[j] = ttys[i].text_fg_col; 205 | } 206 | refresh(i); 207 | } 208 | 209 | tty_ready = 1; 210 | kprint(KPRN_INFO, "tty: Ready!"); 211 | return; 212 | } 213 | 214 | void init_tty(void) { 215 | init_tty_extended( 216 | vbe_framebuffer, 217 | vbe_height, 218 | vbe_width, 219 | vbe_pitch, 220 | bitmap_font, 221 | bitmap_font_height, 222 | bitmap_font_width); 223 | } 224 | 225 | void init_dev_tty(void) { 226 | for (int i = 0; i < MAX_TTYS; i++) { 227 | struct device_t device = {0}; 228 | device.calls = default_device_calls; 229 | strcpy(device.name, tty_names[i]); 230 | device.intern_fd = i; 231 | device.size = 0; 232 | device.calls.read = tty_read; 233 | device.calls.write = tty_write; 234 | device.calls.flush = tty_flush; 235 | device.calls.tcflow = tty_tcflow; 236 | device.calls.tcgetattr = tty_tcgetattr; 237 | device.calls.tcsetattr = tty_tcsetattr; 238 | device.calls.isatty = tty_isatty; 239 | device_add(&device); 240 | } 241 | 242 | io_apic_set_up_legacy_irq(0, 1, 1); 243 | task_tcreate(0, tcreate_fn_call, tcreate_fn_call_data(0, kbd_handler, 0)); 244 | } 245 | -------------------------------------------------------------------------------- /src/sys/urm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // Macros from mlibc: options/posix/include/sys/wait.h 12 | #define WAITPID_IFCONTINUED 0x00000100 13 | #define WAITPID_IFEXITED 0x00000200 14 | #define WAITPID_IFSIGNALED 0x00000400 15 | #define WAITPID_IFSTOPPED 0x00000800 16 | #define WAITPID_EXITSTATUS(x) ((x) & 0x000000ff) 17 | #define WAITPID_STOPSIG(x) (((x) & 0x000000ff) << 16) 18 | #define WAITPID_TERMSIG(x) (((x) & 0x000000ff) << 24) 19 | 20 | #define USER_REQUEST_EXECVE 1 21 | #define USER_REQUEST_EXIT 2 22 | 23 | struct userspace_request_t { 24 | int type; 25 | void *opaque_data; 26 | }; 27 | 28 | static size_t userspace_request_i = 0; 29 | static struct userspace_request_t *userspace_requests = 0; 30 | static lock_t userspace_request_lock = new_lock; 31 | static event_t userspace_event; 32 | 33 | static void userspace_send_request(int type, void *opaque_data) { 34 | spinlock_acquire(&userspace_request_lock); 35 | 36 | userspace_request_i++; 37 | userspace_requests = krealloc(userspace_requests, 38 | sizeof(struct userspace_request_t) * userspace_request_i); 39 | 40 | struct userspace_request_t *userspace_request = 41 | &userspace_requests[userspace_request_i - 1]; 42 | 43 | userspace_request->type = type; 44 | userspace_request->opaque_data = opaque_data; 45 | 46 | event_trigger(&userspace_event); 47 | 48 | spinlock_release(&userspace_request_lock); 49 | } 50 | 51 | struct execve_request_t { 52 | pid_t pid; 53 | tid_t tid; 54 | char *filename; 55 | char **argv; 56 | char **envp; 57 | event_t *err_event; 58 | int *call_errno; 59 | }; 60 | 61 | void execve_send_request(pid_t pid, tid_t tid, const char *filename, const char **argv, const char **envp, 62 | event_t **err_event, int **call_errno) { 63 | struct execve_request_t *execve_request = kalloc(sizeof(struct execve_request_t)); 64 | 65 | execve_request->pid = pid; 66 | execve_request->tid = tid; 67 | 68 | execve_request->filename = kalloc(strlen(filename) + 1); 69 | strcpy(execve_request->filename, filename); 70 | 71 | size_t argv_i; 72 | for (argv_i = 0; argv[argv_i]; argv_i++); 73 | argv_i++; 74 | execve_request->argv = kalloc(sizeof(char *) * argv_i); 75 | for (size_t i = 0; ; i++) { 76 | if (!argv[i]) { 77 | execve_request->argv[i] = 0; 78 | break; 79 | } 80 | execve_request->argv[i] = kalloc(strlen(argv[i]) + 1); 81 | strcpy(execve_request->argv[i], argv[i]); 82 | } 83 | 84 | size_t envp_i; 85 | for (envp_i = 0; envp[envp_i]; envp_i++); 86 | envp_i++; 87 | execve_request->envp = kalloc(sizeof(char *) * envp_i); 88 | for (size_t i = 0; ; i++) { 89 | if (!envp[i]) { 90 | execve_request->envp[i] = 0; 91 | break; 92 | } 93 | execve_request->envp[i] = kalloc(strlen(envp[i]) + 1); 94 | strcpy(execve_request->envp[i], envp[i]); 95 | } 96 | 97 | execve_request->err_event = kalloc(sizeof(event_t)); 98 | *err_event = execve_request->err_event; 99 | 100 | execve_request->call_errno = kalloc(sizeof(int)); 101 | *call_errno = execve_request->call_errno; 102 | 103 | userspace_send_request(USER_REQUEST_EXECVE, execve_request); 104 | } 105 | 106 | static void execve_receive_request(struct execve_request_t *execve_request) { 107 | int ret = exec( 108 | execve_request->pid, 109 | execve_request->filename, 110 | (const char **)execve_request->argv, 111 | (const char **)execve_request->envp 112 | ); 113 | 114 | *execve_request->call_errno = errno; 115 | 116 | /* free request mem */ 117 | kfree(execve_request->filename); 118 | 119 | for (size_t i = 0; ; i++) { 120 | if (!execve_request->argv[i]) 121 | break; 122 | kfree(execve_request->argv[i]); 123 | } 124 | kfree(execve_request->argv); 125 | 126 | for (size_t i = 0; ; i++) { 127 | if (!execve_request->envp[i]) 128 | break; 129 | kfree(execve_request->envp[i]); 130 | } 131 | kfree(execve_request->envp); 132 | 133 | if (ret) 134 | event_trigger(execve_request->err_event); 135 | else { 136 | kfree(execve_request->call_errno); 137 | kfree(execve_request->err_event); 138 | locked_write(int, &task_table[execve_request->tid]->in_syscall, 0); 139 | } 140 | 141 | kfree(execve_request); 142 | } 143 | 144 | struct exit_request_t { 145 | pid_t pid; 146 | int signal; 147 | int exit_code; 148 | }; 149 | 150 | void exit_send_request(pid_t pid, int exit_code, int signal) { 151 | struct exit_request_t *exit_request = kalloc(sizeof(struct exit_request_t)); 152 | 153 | exit_request->pid = pid; 154 | exit_request->exit_code = exit_code; 155 | exit_request->signal = signal; 156 | 157 | userspace_send_request(USER_REQUEST_EXIT, exit_request); 158 | } 159 | 160 | static void exit_receive_request(struct exit_request_t *exit_request) { 161 | struct process_t *process = process_table[exit_request->pid]; 162 | 163 | if (!process->ppid) 164 | panic(NULL, 0, "Going nowhere without my init!"); 165 | 166 | /* Kill all associated threads */ 167 | for (size_t i = 0; i < MAX_THREADS; i++) 168 | task_tkill(exit_request->pid, i); 169 | 170 | /* Close all file handles */ 171 | for (size_t i = 0; i < MAX_FILE_HANDLES; i++) { 172 | if (process->file_handles[i] == -1) 173 | continue; 174 | close(process->file_handles[i]); 175 | } 176 | kfree(process->file_handles); 177 | 178 | if (process->child_events) 179 | kfree(process->child_events); 180 | 181 | free_address_space(process->pagemap); 182 | 183 | struct child_event_t child_event; 184 | 185 | child_event.pid = exit_request->pid; 186 | child_event.status = 0; 187 | child_event.status |= WAITPID_EXITSTATUS(exit_request->exit_code); 188 | 189 | if (exit_request->signal) { 190 | child_event.status |= WAITPID_IFSIGNALED; 191 | child_event.status |= WAITPID_TERMSIG(exit_request->signal); 192 | } else { 193 | child_event.status |= WAITPID_IFEXITED; 194 | } 195 | 196 | task_send_child_event(process->ppid, &child_event); 197 | 198 | kfree(exit_request); 199 | } 200 | 201 | void userspace_request_monitor(void *arg) { 202 | (void)arg; 203 | 204 | kprint(KPRN_INFO, "urm: Userspace request monitor launched."); 205 | 206 | /* main event loop */ 207 | for (;;) { 208 | spinlock_acquire(&userspace_request_lock); 209 | if (userspace_request_i) { 210 | switch (userspace_requests[0].type) { 211 | case USER_REQUEST_EXECVE: 212 | kprint(KPRN_INFO, "urm: execve request received"); 213 | execve_receive_request(userspace_requests[0].opaque_data); 214 | break; 215 | case USER_REQUEST_EXIT: 216 | kprint(KPRN_INFO, "urm: exit request received"); 217 | exit_receive_request(userspace_requests[0].opaque_data); 218 | break; 219 | default: 220 | kprint(KPRN_ERR, "urm: Invalid request received"); 221 | break; 222 | } 223 | userspace_request_i--; 224 | for (size_t i = 0; i < userspace_request_i; i++) 225 | userspace_requests[i] = userspace_requests[i + 1]; 226 | userspace_requests = krealloc(userspace_requests, 227 | sizeof(struct userspace_request_t) * userspace_request_i); 228 | } 229 | spinlock_release(&userspace_request_lock); 230 | event_await(&userspace_event); 231 | } 232 | } 233 | -------------------------------------------------------------------------------- /src/mm/pmm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MEMORY_BASE 0x1000000 11 | #define BITMAP_BASE (MEMORY_BASE / PAGE_SIZE) 12 | 13 | #define BMREALLOC_STEP 1 14 | 15 | static volatile uint32_t *mem_bitmap; 16 | static volatile uint32_t initial_bitmap[] = { 0xffffff7f }; 17 | static volatile uint32_t *tmp_bitmap; 18 | 19 | /* 32 entries because initial_bitmap is a single dword */ 20 | static size_t bitmap_entries = 32; 21 | 22 | static size_t total_pages = 1; 23 | static size_t free_pages = 1; 24 | 25 | static size_t cur_ptr = BITMAP_BASE; 26 | 27 | /* A core wishing to modify the PMM bitmap must first acquire this lock, 28 | * to ensure other cores cannot simultaneously modify the bitmap */ 29 | static lock_t pmm_lock = new_lock; 30 | 31 | __attribute__((always_inline)) static inline int read_bitmap(size_t i) { 32 | i -= BITMAP_BASE; 33 | 34 | return test_bit(mem_bitmap, i); 35 | } 36 | 37 | __attribute__((always_inline)) static inline void set_bitmap(size_t i, size_t count) { 38 | i -= BITMAP_BASE; 39 | 40 | free_pages -= count; 41 | 42 | size_t f = i + count; 43 | for (size_t j = i; j < f; j++) 44 | set_bit(mem_bitmap, j); 45 | } 46 | 47 | __attribute__((always_inline)) static inline void unset_bitmap(size_t i, size_t count) { 48 | i -= BITMAP_BASE; 49 | 50 | free_pages += count; 51 | 52 | size_t f = i + count; 53 | for (size_t j = i; j < f; j++) 54 | reset_bit(mem_bitmap, j); 55 | } 56 | 57 | /* Populate bitmap using e820 data. */ 58 | void init_pmm(struct stivale_memmap_t *memmap) { 59 | mem_bitmap = initial_bitmap; 60 | if (!(tmp_bitmap = pmm_allocz(BMREALLOC_STEP))) { 61 | panic(NULL, 0, "pmm_alloc failure in init_pmm()"); 62 | } 63 | 64 | tmp_bitmap = (uint32_t *)((size_t)tmp_bitmap + MEM_PHYS_OFFSET); 65 | 66 | for (size_t i = 0; i < (BMREALLOC_STEP * PAGE_SIZE) / sizeof(uint32_t); i++) 67 | tmp_bitmap[i] = 0xffffffff; 68 | 69 | mem_bitmap = tmp_bitmap; 70 | 71 | bitmap_entries = ((PAGE_SIZE / sizeof(uint32_t)) * 32) * BMREALLOC_STEP; 72 | 73 | kprint(KPRN_INFO, "pmm: Mapping memory"); 74 | 75 | /* For each region specified by the memmap, iterate over each page which 76 | fits in that region and if the region type indicates the area itself 77 | is usable, write that page as free in the bitmap. Otherwise, mark the page as used. */ 78 | for (size_t i = 0; i < memmap->entries; i++) { 79 | size_t aligned_base; 80 | struct stivale_memmap_entry_t *entry = &(memmap->address[i]); 81 | 82 | if (entry->base % PAGE_SIZE) 83 | aligned_base = entry->base + (PAGE_SIZE - (entry->base % PAGE_SIZE)); 84 | else 85 | aligned_base = entry->base; 86 | 87 | size_t aligned_length = (entry->size / PAGE_SIZE) * PAGE_SIZE; 88 | 89 | if ((entry->base % PAGE_SIZE) && aligned_length) 90 | aligned_length -= PAGE_SIZE; 91 | 92 | for (size_t j = 0; j * PAGE_SIZE < aligned_length; j++) { 93 | size_t addr = aligned_base + j * PAGE_SIZE; 94 | 95 | size_t page = addr / PAGE_SIZE; 96 | 97 | if (addr < (MEMORY_BASE + PAGE_SIZE /* bitmap */)) 98 | continue; 99 | 100 | if (addr >= (MEMORY_BASE + bitmap_entries * PAGE_SIZE)) { 101 | /* Reallocate bitmap */ 102 | size_t cur_bitmap_size_in_pages = ((bitmap_entries / 32) * sizeof(uint32_t)) / PAGE_SIZE; 103 | size_t new_bitmap_size_in_pages = cur_bitmap_size_in_pages + BMREALLOC_STEP; 104 | if (!(tmp_bitmap = pmm_allocz(new_bitmap_size_in_pages))) { 105 | kprint(KPRN_ERR, "pmm_alloc failure in init_pmm(). Halted."); 106 | for (;;); 107 | } 108 | tmp_bitmap = (uint32_t *)((size_t)tmp_bitmap + MEM_PHYS_OFFSET); 109 | /* Copy over previous bitmap */ 110 | for (size_t i = 0; 111 | i < (cur_bitmap_size_in_pages * PAGE_SIZE) / sizeof(uint32_t); 112 | i++) 113 | tmp_bitmap[i] = mem_bitmap[i]; 114 | /* Fill in the rest */ 115 | for (size_t i = (cur_bitmap_size_in_pages * PAGE_SIZE) / sizeof(uint32_t); 116 | i < (new_bitmap_size_in_pages * PAGE_SIZE) / sizeof(uint32_t); 117 | i++) 118 | tmp_bitmap[i] = 0xffffffff; 119 | bitmap_entries += ((PAGE_SIZE / sizeof(uint32_t)) * 32) * BMREALLOC_STEP; 120 | uint32_t *old_bitmap = (uint32_t *)((size_t)mem_bitmap - MEM_PHYS_OFFSET); 121 | mem_bitmap = tmp_bitmap; 122 | pmm_free(old_bitmap, cur_bitmap_size_in_pages); 123 | } 124 | 125 | if (entry->type == USABLE) { 126 | total_pages++; 127 | unset_bitmap(page, 1); 128 | } 129 | } 130 | } 131 | } 132 | 133 | /* Allocate physical memory without optimisation for early boot */ 134 | static void *pmm_alloc_slow(size_t pg_count) { 135 | spinlock_acquire(&pmm_lock); 136 | 137 | size_t pg_cnt = pg_count; 138 | 139 | size_t i; 140 | for (i = BITMAP_BASE; i < BITMAP_BASE + bitmap_entries; ) { 141 | if (!read_bitmap(i++)) { 142 | if (!--pg_cnt) 143 | goto found; 144 | } else { 145 | pg_cnt = pg_count; 146 | } 147 | } 148 | 149 | spinlock_release(&pmm_lock); 150 | 151 | panic(NULL, 1, "Kernel ran out of memory."); 152 | 153 | found:; 154 | size_t start = i - pg_count; 155 | set_bitmap(start, pg_count); 156 | 157 | spinlock_release(&pmm_lock); 158 | 159 | // Return the physical address that represents the start of this physical page(s). 160 | return (void *)(start * PAGE_SIZE); 161 | } 162 | 163 | /* Allocate physical memory with O(1)-like optimisation */ 164 | static void *pmm_alloc_fast(size_t pg_count) { 165 | spinlock_acquire(&pmm_lock); 166 | 167 | size_t pg_cnt = pg_count; 168 | 169 | for (size_t i = 0; i < bitmap_entries; i++) { 170 | if (cur_ptr == BITMAP_BASE + bitmap_entries) { 171 | cur_ptr = BITMAP_BASE; 172 | pg_cnt = pg_count; 173 | } 174 | if (!read_bitmap(cur_ptr++)) { 175 | if (!--pg_cnt) 176 | goto found; 177 | } else { 178 | pg_cnt = pg_count; 179 | } 180 | } 181 | 182 | spinlock_release(&pmm_lock); 183 | 184 | panic(NULL, 1, "Kernel ran out of memory."); 185 | 186 | found:; 187 | size_t start = cur_ptr - pg_count; 188 | set_bitmap(start, pg_count); 189 | 190 | spinlock_release(&pmm_lock); 191 | 192 | // Return the physical address that represents the start of this physical page(s). 193 | return (void *)(start * PAGE_SIZE); 194 | } 195 | 196 | void *(*pmm_alloc)(size_t) = pmm_alloc_slow; 197 | 198 | void pmm_change_allocation_method(void) { 199 | pmm_alloc = pmm_alloc_fast; 200 | } 201 | 202 | /* Allocate physical memory and zero it out. */ 203 | void *pmm_allocz(size_t pg_count) { 204 | void *ptr = pmm_alloc(pg_count); 205 | if (!ptr) 206 | return NULL; 207 | 208 | uint64_t *pages = (uint64_t *)(ptr + MEM_PHYS_OFFSET); 209 | 210 | for (size_t i = 0; i < (pg_count * PAGE_SIZE) / sizeof(uint64_t); i++) 211 | pages[i] = 0; 212 | 213 | return ptr; 214 | } 215 | 216 | /* Release physical memory. */ 217 | void pmm_free(void *ptr, size_t pg_count) { 218 | spinlock_acquire(&pmm_lock); 219 | 220 | size_t start = (size_t)ptr / PAGE_SIZE; 221 | 222 | unset_bitmap(start, pg_count); 223 | 224 | spinlock_release(&pmm_lock); 225 | } 226 | 227 | int getmemstats(struct memstats *memstats) { 228 | memstats->total = total_pages * PAGE_SIZE; 229 | memstats->used = total_pages * PAGE_SIZE - free_pages * PAGE_SIZE; 230 | 231 | return 0; 232 | } 233 | -------------------------------------------------------------------------------- /src/fd/fd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | void init_fd_vfs(void); 9 | 10 | void init_fd(void) { 11 | init_fd_vfs(); 12 | } 13 | 14 | dynarray_new(struct file_descriptor_t, file_descriptors); 15 | 16 | int poll(struct pollfd *fds, size_t nfds, int timeout) { 17 | if (!timeout) { 18 | return 0; 19 | } 20 | 21 | uint64_t timeout_target; 22 | 23 | if (timeout < 0) { 24 | timeout_target = 0xffffffffffffffff; // effectively disable a timeout 25 | } else { 26 | timeout_target = (uptime_raw + (timeout * (PIT_FREQUENCY_HZ / 1000))) + 1; 27 | } 28 | 29 | int polled_fds = 0; 30 | 31 | while (timeout_target > uptime_raw) { 32 | for (size_t i = 0; i < nfds; i++) { 33 | if (fds[i].fd < 0) { 34 | fds[i].revents = 0; 35 | continue; 36 | } 37 | 38 | struct file_descriptor_t *fd = dynarray_getelem(struct file_descriptor_t, file_descriptors, fds[i].fd); 39 | 40 | if (fd->status & fds[i].events) { 41 | fds[i].revents = fd->status; 42 | polled_fds++; 43 | } else { 44 | fds[i].revents = 0; 45 | } 46 | 47 | dynarray_unref(file_descriptors, fds[i].fd); 48 | } 49 | if (polled_fds) { 50 | break; 51 | } 52 | yield(); 53 | } 54 | 55 | return polled_fds; 56 | } 57 | 58 | int fd_create(struct file_descriptor_t *fd) { 59 | return dynarray_add(struct file_descriptor_t, file_descriptors, fd); 60 | } 61 | 62 | int dup(int fd) { 63 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 64 | int intern_fd = fd_ptr->intern_fd; 65 | int new_intern_fd = fd_ptr->fd_handler.dup(intern_fd); 66 | dynarray_unref(file_descriptors, fd); 67 | 68 | if (new_intern_fd == -1) 69 | return -1; 70 | 71 | struct file_descriptor_t new_fd = {0}; 72 | 73 | new_fd.intern_fd = new_intern_fd; 74 | new_fd.fd_handler = file_descriptors[fd]->data.fd_handler; 75 | 76 | return fd_create(&new_fd); 77 | } 78 | 79 | ssize_t recv(int fd, void *buf, size_t len, int flags) { 80 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 81 | int intern_fd = fd_ptr->intern_fd; 82 | int ret = fd_ptr->fd_handler.recv(intern_fd, buf, len, flags); 83 | dynarray_unref(file_descriptors, fd); 84 | return ret; 85 | } 86 | 87 | int getpath(int fd, char *buf) { 88 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 89 | int intern_fd = fd_ptr->intern_fd; 90 | int ret = fd_ptr->fd_handler.getpath(intern_fd, buf); 91 | dynarray_unref(file_descriptors, fd); 92 | return ret; 93 | } 94 | 95 | int getfdflags(int fd) { 96 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 97 | int ret = fd_ptr->fdflags; 98 | dynarray_unref(file_descriptors, fd); 99 | return ret; 100 | } 101 | 102 | int setfdflags(int fd, int fdflags) { 103 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 104 | fd_ptr->fdflags = fdflags; 105 | dynarray_unref(file_descriptors, fd); 106 | return 0; 107 | } 108 | 109 | int getflflags(int fd) { 110 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 111 | int intern_fd = fd_ptr->intern_fd; 112 | int ret = fd_ptr->fd_handler.getflflags(intern_fd); 113 | dynarray_unref(file_descriptors, fd); 114 | return ret; 115 | } 116 | 117 | int setflflags(int fd, int flflags) { 118 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 119 | int intern_fd = fd_ptr->intern_fd; 120 | int ret = fd_ptr->fd_handler.setflflags(intern_fd, flflags); 121 | dynarray_unref(file_descriptors, fd); 122 | return ret; 123 | } 124 | 125 | int tcsetattr(int fd, int optional_actions, struct termios *buf) { 126 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 127 | int intern_fd = fd_ptr->intern_fd; 128 | int ret = fd_ptr->fd_handler.tcsetattr(intern_fd, optional_actions, buf); 129 | dynarray_unref(file_descriptors, fd); 130 | return ret; 131 | } 132 | 133 | int tcgetattr(int fd, struct termios *buf) { 134 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 135 | int intern_fd = fd_ptr->intern_fd; 136 | int ret = fd_ptr->fd_handler.tcgetattr(intern_fd, buf); 137 | dynarray_unref(file_descriptors, fd); 138 | return ret; 139 | } 140 | 141 | int tcflow(int fd, int action) { 142 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 143 | int intern_fd = fd_ptr->intern_fd; 144 | int ret = fd_ptr->fd_handler.tcflow(intern_fd, action); 145 | dynarray_unref(file_descriptors, fd); 146 | return ret; 147 | } 148 | 149 | int isatty(int fd) { 150 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 151 | int intern_fd = fd_ptr->intern_fd; 152 | int ret = fd_ptr->fd_handler.isatty(intern_fd); 153 | dynarray_unref(file_descriptors, fd); 154 | return ret; 155 | } 156 | 157 | int perfmon_attach(int fd) { 158 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 159 | int intern_fd = fd_ptr->intern_fd; 160 | int ret = fd_ptr->fd_handler.perfmon_attach(intern_fd); 161 | dynarray_unref(file_descriptors, fd); 162 | return ret; 163 | } 164 | 165 | int readdir(int fd, struct dirent *buf) { 166 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 167 | int intern_fd = fd_ptr->intern_fd; 168 | int ret = fd_ptr->fd_handler.readdir(intern_fd, buf); 169 | dynarray_unref(file_descriptors, fd); 170 | return ret; 171 | } 172 | 173 | int read(int fd, void *buf, size_t len) { 174 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 175 | int intern_fd = fd_ptr->intern_fd; 176 | int ret = fd_ptr->fd_handler.read(intern_fd, buf, len); 177 | dynarray_unref(file_descriptors, fd); 178 | return ret; 179 | } 180 | 181 | int write(int fd, const void *buf, size_t len) { 182 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 183 | int intern_fd = fd_ptr->intern_fd; 184 | int ret = fd_ptr->fd_handler.write(intern_fd, buf, len); 185 | dynarray_unref(file_descriptors, fd); 186 | return ret; 187 | } 188 | 189 | int unlink(int fd) { 190 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 191 | int intern_fd = fd_ptr->intern_fd; 192 | int ret = fd_ptr->fd_handler.unlink(intern_fd); 193 | dynarray_unref(file_descriptors, fd); 194 | return ret; 195 | } 196 | 197 | int lseek(int fd, off_t offset, int type) { 198 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 199 | int intern_fd = fd_ptr->intern_fd; 200 | int ret = fd_ptr->fd_handler.lseek(intern_fd, offset, type); 201 | dynarray_unref(file_descriptors, fd); 202 | return ret; 203 | } 204 | 205 | int fstat(int fd, struct stat *st) { 206 | struct file_descriptor_t *fd_ptr = dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 207 | int intern_fd = fd_ptr->intern_fd; 208 | int ret = fd_ptr->fd_handler.fstat(intern_fd, st); 209 | dynarray_unref(file_descriptors, fd); 210 | return ret; 211 | } 212 | 213 | int close(int fd) { 214 | struct file_descriptor_t fd_copy = *dynarray_getelem(struct file_descriptor_t, file_descriptors, fd); 215 | dynarray_unref(file_descriptors, fd); 216 | dynarray_remove(file_descriptors, fd); 217 | int intern_fd = fd_copy.intern_fd; 218 | if (fd_copy.fd_handler.close(intern_fd)) 219 | return -1; 220 | return 0; 221 | } 222 | --------------------------------------------------------------------------------