From b905869a35f062a4e5072f10bec3a2ba3db0e365 Mon Sep 17 00:00:00 2001 From: Jon Santmyer Date: Wed, 30 Jul 2025 14:32:01 -0400 Subject: working userland with some invoke syscalls --- include/arch/x86_64/idt.h | 18 +++++++++++ include/arch/x86_64/object.h | 26 ++++++++++++++++ include/arch/x86_64/page.h | 41 +++++++++++++++++++++++++ include/arch/x86_64/processor.h | 66 +++++++++++++++++++++++++++++++++++++++++ include/arch/x86_64/tables.h | 51 +++++++++++++++++++++++++++++++ include/boot.h | 7 +++++ include/bootargs.h | 13 ++++++++ include/device/initrd.h | 29 ++++++++++++++++++ include/device/portio.h | 26 ++++++++++++++++ include/device/portio_uart.h | 27 +++++++++++++++++ include/device/processor.h | 22 ++++++++++++++ include/device/uart.h | 11 +++++++ include/error.h | 8 +++++ include/init.h | 10 +++++++ include/jove.h | 15 ++++++++++ include/memory.h | 17 +++++++++++ include/object.h | 61 +++++++++++++++++++++++++++++++++++++ include/panic.h | 9 ++++++ include/print.h | 17 +++++++++++ include/string.h | 25 ++++++++++++++++ include/syscall.h | 46 ++++++++++++++++++++++++++++ include/tcb.h | 18 +++++++++++ 22 files changed, 563 insertions(+) create mode 100644 include/arch/x86_64/idt.h create mode 100644 include/arch/x86_64/object.h create mode 100644 include/arch/x86_64/page.h create mode 100644 include/arch/x86_64/processor.h create mode 100644 include/arch/x86_64/tables.h create mode 100644 include/boot.h create mode 100644 include/bootargs.h create mode 100644 include/device/initrd.h create mode 100644 include/device/portio.h create mode 100644 include/device/portio_uart.h create mode 100644 include/device/processor.h create mode 100644 include/device/uart.h create mode 100644 include/error.h create mode 100644 include/init.h create mode 100644 include/jove.h create mode 100644 include/memory.h create mode 100644 include/object.h create mode 100644 include/panic.h create mode 100644 include/print.h create mode 100644 include/string.h create mode 100644 include/syscall.h create mode 100644 include/tcb.h (limited to 'include') diff --git a/include/arch/x86_64/idt.h b/include/arch/x86_64/idt.h new file mode 100644 index 0000000..90ce48b --- /dev/null +++ b/include/arch/x86_64/idt.h @@ -0,0 +1,18 @@ +#ifndef _JOVE_x86_64_IDT_H +#define _JOVE_x86_64_IDT_H 1 + +#include "processor.h" + +typedef struct jove_IVTState +{ + uint64_t r15, r14, r13, r12, r11, r10, r9, r8; + uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax; + uint64_t rip, cs, rflags, rsp, ss; +} ivt_state_t; + +void kpanic_state(ivt_state_t *state, const char *fmt, ...); + +void ivt_setup(void); +void idt_setup(processor_t *processor); + +#endif diff --git a/include/arch/x86_64/object.h b/include/arch/x86_64/object.h new file mode 100644 index 0000000..8d5af33 --- /dev/null +++ b/include/arch/x86_64/object.h @@ -0,0 +1,26 @@ +#ifndef _JOVE_x86_64_OBJECT_H +#define _JOVE_x86_64_OBJECT_H 1 + +#include + +typedef struct jove_InitData +{ + uint8_t log_object; + uint8_t untyped_data_dir; + uint8_t processor_dir; + uint8_t pm_object; //Page mapping object. + uint8_t initrd_dir; //Init ramdisk files directory. + uint8_t tcb_object; + uint8_t kernel_stack_object; + uint8_t message_object; + uintptr_t message_object_address; +} init_data_t; + +typedef struct jove_ThreadControlBlock +{ + void *stack; + uintptr_t sp, ksp; + void *pml4; +} tcb_t; + +#endif diff --git a/include/arch/x86_64/page.h b/include/arch/x86_64/page.h new file mode 100644 index 0000000..99bc691 --- /dev/null +++ b/include/arch/x86_64/page.h @@ -0,0 +1,41 @@ +#ifndef _JOVE_ARCH_x86_64_PAGE_H +#define _JOVE_ARCH_x86_64_PAGE_H 1 + +#include +#include "include/object.h" + +typedef union jove_PageMapLevelEntry +{ + struct { + uint8_t p : 1; /* Present */ + uint8_t rw : 1; /* Read/write. 0 for RO.*/ + uint8_t us : 1; /* User/supervisor. 0 for DPL3 forbid */ + uint8_t pwt : 1; + uint8_t pcd : 1; + uint8_t a : 1; /* Accessed */ + uint8_t d : 1; /* Dirty */ + uint8_t ps_pat : 1; + uint8_t g : 1; /* Global */ + uint8_t _r0 : 2; + uint8_t r : 1; + uint64_t paddr : 35; + uint8_t _r1; + uint8_t pk : 4; + uint8_t xd : 1; + }__attribute__((packed)); + uint64_t value; +} __attribute__((packed)) pmle_t; + +typedef uint16_t pmli_t; + +#define PML_SHL(l) ((l * 9) + 3) +#define PML_I_FOR_LAYER(v, l) ((v >> PML_SHL(l)) % 512) + +uintptr_t vmem_ident_tophys(void *vptr); +void *vmem_phys_tovirt(uintptr_t pptr); + +void *pmle_get_page(pmle_t entry); + +int untyped_retype_page(objdir_entry_t *untyped_entry, void **dest_ptr); + +#endif diff --git a/include/arch/x86_64/processor.h b/include/arch/x86_64/processor.h new file mode 100644 index 0000000..f8a93ce --- /dev/null +++ b/include/arch/x86_64/processor.h @@ -0,0 +1,66 @@ +#ifndef _JOVE_ARCH_x86_64_PROCESSOR_H +#define _JOVE_ARCH_x86_64_PROCESSOR_H 1 + +#include "memory.h" +#include "tables.h" +#include "object.h" +#include + +#define MSR_FS_BASE 0xC0000100 +#define MSR_GS_BASE 0xC0000101 +#define MSR_KGS_BASE 0xC0000102 + +#define MSR_EFER 0xC0000080 +#define MSR_STAR 0xC0000081 +#define MSR_LSTAR 0xC0000082 +#define MSR_SFMASK 0xC0000084 + +typedef struct jove_TSS +{ + uint32_t resv0; + uint64_t rsp[3]; + uint32_t resv1; + uint64_t ist[8]; + uint32_t resv2[2]; + uint16_t resv3; + uint16_t iopb; +} tss_t; + +enum +{ + GDT_ENTRY_KERNEL_NULL = 0, + GDT_ENTRY_KERNEL_CODE, + GDT_ENTRY_KERNEL_DATA, + GDT_ENTRY_USER_NULL, + GDT_ENTRY_USER_DATA, + GDT_ENTRY_USER_CODE, + GDT_ENTRY_TSS_LOW, + GDT_ENTRY_TSS_HIGH, + GDT_ENTRY_COUNT +}; + +typedef struct jove_Processor +{ + physptr_t pdir; + struct jove_ObjectDirectory *odir; + + segment_descriptor_t gdt[GDT_ENTRY_COUNT]; + struct { + uint16_t length; + uint64_t base; + } __attribute__((packed)) gdtr; + struct { + uint16_t length; + uint64_t base; + } __attribute__((packed)) idtr; + + tss_t tss; + tcb_t *tcb; +} processor_t; + +void gdt_setup(processor_t *processor); + +void rdmsr(uint32_t msr, uint32_t *lo, uint32_t *hi); +void wrmsr(uint32_t msr, uint32_t lo, uint32_t hi); + +#endif diff --git a/include/arch/x86_64/tables.h b/include/arch/x86_64/tables.h new file mode 100644 index 0000000..42651a1 --- /dev/null +++ b/include/arch/x86_64/tables.h @@ -0,0 +1,51 @@ +#ifndef _JOVE_ARCH_x86_64_TABLES_H +#define _JOVE_ARCH_x86_64_TABLES_H 1 + +#include + +#define CD_SEGMENT_TYPE_ACCESSED 1 +#define CD_SEGMENT_TYPE_WRITEABLE 2 +#define CD_SEGMENT_TYPE_DATA_EXPAND_DOWN 4 +#define CD_SEGMENT_TYPE_CODE_CONFORMING 4 +#define CD_SEGMENT_TYPE_CODE 8 + +#define S_SEGMENT_TYPE_LDT 2 +#define S_SEGMENT_TYPE_TSS_AVAIL 9 +#define S_SEGMENT_TYPE_TSS_BUSY 11 +#define S_SEGMENT_TYPE_CALLGATE 12 +#define S_SEGMENT_TYPE_INT_GATE 14 +#define S_SEGMENT_TYPE_TRAP_GATE 15 + +typedef struct jove_SegmentDescriptor +{ + uint16_t limit_0_15; /* Segment limit. */ + uint16_t base_0_15; /* Segment base. */ + uint8_t base_16_23; + uint8_t type : 4; /* Segment type. */ + uint8_t s : 1; /* Descriptor type (0 = system, 1 = code/data)*/ + uint8_t dpl : 2; /* Descriptor privilege level. */ + uint8_t p : 1; /* Present. */ + uint8_t limit_16_19 : 4; + uint8_t avl : 1; /* Available for use by system software. */ + uint8_t l : 1; /* 64-bit segment (Ext). */ + uint8_t d_b : 1; /* Default operation size (0 = 16-bit, 1 = 32-bit)*/ + uint8_t g : 1; /* Granularity. */ + uint8_t base_24_31; +}__attribute__((packed)) segment_descriptor_t; + +typedef struct jove_InterruptGate +{ + uint16_t base_0_15; + uint16_t segment_selector; + uint8_t ist : 3; + uint8_t zero_0 : 5; + uint8_t type : 4; + uint8_t zero_1 : 1; + uint8_t dpl : 2; + uint8_t p : 1; + uint16_t base_16_31; + uint32_t base_32_63; + uint32_t resv; +}__attribute__((packed)) interrupt_gate_t; + +#endif diff --git a/include/boot.h b/include/boot.h new file mode 100644 index 0000000..989b4b9 --- /dev/null +++ b/include/boot.h @@ -0,0 +1,7 @@ +#ifndef _JOVE_BOOT_H +#define _JOVE_BOOT_H 1 + +extern char *jove_bootargs; +extern int jove_bootargs_len; + +#endif diff --git a/include/bootargs.h b/include/bootargs.h new file mode 100644 index 0000000..94910f4 --- /dev/null +++ b/include/bootargs.h @@ -0,0 +1,13 @@ +#ifndef _JOVE_BOOTARGS_H +#define _JOVE_BOOTARGS_H 1 + +/*Layout: + * [KEY]=[VALUE] + * All values are seperated by spaces.*/ + +/**@FUNC Get the value associated with the given key. + * @PARAM key string to search for. + * @RETURN value associated with key. */ +char *bootargs_getarg(const char *key); + +#endif diff --git a/include/device/initrd.h b/include/device/initrd.h new file mode 100644 index 0000000..eaf3157 --- /dev/null +++ b/include/device/initrd.h @@ -0,0 +1,29 @@ +#ifndef _JOVE_DEV_INITRD_H +#define _JOVE_DEV_INITRD_H 1 + +#include + +typedef struct tarHeader +{ + char name[100]; + char mode[8]; + char owner[8]; + char group[8]; + char size[12]; + char modified[12]; + char checksum[8]; + char link; + char linkname[100]; +} tar_header_t; + +typedef union tarBlock { + tar_header_t header; + char data[512]; +} tar_block_t; + +void initrd_setup(void); + +tar_header_t *initrd_find_file(const char *filename); +int initrd_file_size(tar_header_t *header); + +#endif diff --git a/include/device/portio.h b/include/device/portio.h new file mode 100644 index 0000000..76b28c4 --- /dev/null +++ b/include/device/portio.h @@ -0,0 +1,26 @@ +#ifndef _JOVE_PORTIO_H +#define _JOVE_PORTIO_H 1 + +#include + +typedef uint16_t ioport_t; + +static inline uint8_t port_inb(ioport_t port) +{ uint8_t r; __asm__ volatile("inb %w1, %b0": "=a"(r): "Nd"(port): "memory"); return r; } + +static inline uint16_t port_inw(ioport_t port) +{ uint16_t r; __asm__ volatile("inw %w1, %w0": "=a"(r): "Nd"(port): "memory"); return r; } + +static inline uint32_t port_inl(ioport_t port) +{ uint32_t r; __asm__ volatile("inl %d1, %l0": "=a"(r): "Nd"(port): "memory"); return r; } + +static inline void port_outb(ioport_t port, uint8_t v) +{ __asm__ volatile("outb %b0, %w1":: "a"(v), "Nd"(port): "memory"); } + +static inline void port_outw(ioport_t port, uint16_t v) +{ __asm__ volatile("outb %w0, %w1":: "a"(v), "Nd"(port): "memory"); } + +static inline void port_outl(ioport_t port, uint32_t v) +{ __asm__ volatile("outb %d0, %w1":: "a"(v), "Nd"(port): "memory"); } + +#endif diff --git a/include/device/portio_uart.h b/include/device/portio_uart.h new file mode 100644 index 0000000..1b521a1 --- /dev/null +++ b/include/device/portio_uart.h @@ -0,0 +1,27 @@ +#ifndef _JOVE_DEVICE_PORTIO_UART +#define _JOVE_DEVICE_PORTIO_UART 1 + +#include + +#define PORTIO_UART_COM1 0x3F8 + +#define PORTIO_UART_COM_THR(COM) COM +#define PORTIO_UART_COM_RBR(COM) COM +#define PORTIO_UART_COM_DLAB_DLL(COM) COM +#define PORTIO_UART_COM_IER(COM) (COM + 1) +#define PORTIO_UART_COM_DLAB_DLH(COM) (COM + 1) +#define PORTIO_UART_COM_IIR(COM) (COM + 2) +#define PORTIO_UART_COM_FCR(COM) (COM + 2) +#define PORTIO_UART_COM_LCR(COM) (COM + 3) +#define PORTIO_UART_COM_MCR(COM) (COM + 4) +#define PORTIO_UART_COM_LSR(COM) (COM + 5) +#define PORTIO_UART_COM_MSR(COM) (COM + 6) +#define PORTIO_UART_COM_SR(COM) (COM + 7) + +void +portio_uart_setup(void); + +void +portio_uart_write(uint64_t dev, const char *s, int n); + +#endif diff --git a/include/device/processor.h b/include/device/processor.h new file mode 100644 index 0000000..33deed4 --- /dev/null +++ b/include/device/processor.h @@ -0,0 +1,22 @@ +#ifndef _JOVE_DEVICE_PROCESSOR_H +#define _JOVE_DEVICE_PROCESSOR_H 1 + +#if defined(__x86_64__) +#include "arch/x86_64/processor.h" +#endif + +/**@FUNC Initialize the bootstrap processor.*/ +void bsp_setup(void); +/**@FUNC Initialize the given processor with kernel-specific values. + * Generically: + * Instantiates a new kernel object representing the passed processor. + * For x86_64: + * Loads and uses the generic GDT and IDT. + * @PARAM processor processor to initialize.*/ +void processor_setup(void* processor); + +/**@FUNC Returns the processor struct this function is called by. + * @RET pointer to current processor.*/ +void *processor_current(void); + +#endif diff --git a/include/device/uart.h b/include/device/uart.h new file mode 100644 index 0000000..3d481a2 --- /dev/null +++ b/include/device/uart.h @@ -0,0 +1,11 @@ +#ifndef _JOVE_DEVICE_UART_H +#define _JOVE_DEVICE_UART_H 1 + +#include +#include + +#include "object.h" + +void uart_write(objdir_t *dir, uint64_t entryi, const char *s, size_t w); + +#endif diff --git a/include/error.h b/include/error.h new file mode 100644 index 0000000..8aa087c --- /dev/null +++ b/include/error.h @@ -0,0 +1,8 @@ +#ifndef _JOVE_ERROR_H +#define _JOVE_ERROR_H 1 + +#define E_OK 0 +#define E_BADOBJ 1 +#define E_ARGUMENT 2 + +#endif diff --git a/include/init.h b/include/init.h new file mode 100644 index 0000000..aa722b1 --- /dev/null +++ b/include/init.h @@ -0,0 +1,10 @@ +#ifndef _JOVE_INIT_H +#define _JOVE_INIT_H 1 + +#ifdef __x86_64__ + +#endif + +void init_load(void); + +#endif diff --git a/include/jove.h b/include/jove.h new file mode 100644 index 0000000..cbe1a77 --- /dev/null +++ b/include/jove.h @@ -0,0 +1,15 @@ +#ifndef _JOVE_H +#define _JOVE_H 1 + +#define NORETURN __attribute__((noreturn)) + +extern void (*_kernel_start)(void); +extern void (*_kernel_end)(void); + +#include "object.h" +extern objdir_t _initDirectory; +extern init_data_t _initData; + +NORETURN void hcf(void); + +#endif diff --git a/include/memory.h b/include/memory.h new file mode 100644 index 0000000..e29c41b --- /dev/null +++ b/include/memory.h @@ -0,0 +1,17 @@ +#ifndef _JOVE_MEMORY_H +#define _JOVE_MEMORY_H 1 + +#include +#include "object.h" + +typedef uintptr_t physptr_t; +typedef uintptr_t virtptr_t; + +#define KERNEL_STACK_SIZE 0x1000 + +void pmem_setup(void); +void vmem_setup(void); + +int untyped_retype_kernel_stack(objdir_entry_t *untyped_entry, objdir_entry_t *dest_entry); + +#endif diff --git a/include/object.h b/include/object.h new file mode 100644 index 0000000..0a71b5f --- /dev/null +++ b/include/object.h @@ -0,0 +1,61 @@ +#ifndef _JOVE_OBJECT_H +#define _JOVE_OBJECT_H + +#include + +#if defined(__x86_64__) +#include "arch/x86_64/object.h" +#endif + +enum +{ + /* Generic objects */ + KO_NONE = 0, + KO_OBJECT_DIRECTORY, + KO_INIT_DATA, + KO_MEMORY_UNTYPED, + KO_MEMORY_MAPPED_PAGE, //4KiB Fixed Width + KO_MEMORY_MAPPING_PAGE, //4Kib Fixed Width + KO_INITRD_FILE, + KO_TCB, + KO_KERNEL_STACK, + KO_MESSAGE, + /* Device objects*/ + KO_DEV_INVALID = 0x100, + KO_DEV_PROCESSOR, + KO_DEV_UART +}; + +typedef uintmax_t obj_path_t; +typedef uint16_t obj_type_t; + +typedef struct jove_ObjectDirectoryEntry +{ + obj_type_t type; + union { + struct { + char lock : 1; + char u0 : 7; + char u1; +}; + unsigned short flg; + }; + uintmax_t data; +} objdir_entry_t; + +#define OBJECT_DIRECTORY_MAX_ENTRIES 256 + +//The first entry always represents itself, which allows the kernel to ignore +//some checks. +//The data variable also contains the next free index for this directory. +typedef struct jove_ObjectDirectory +{ + union { + objdir_entry_t self; + objdir_entry_t entries[OBJECT_DIRECTORY_MAX_ENTRIES]; + }; +} objdir_t; + +objdir_entry_t *objdir_seek(objdir_t *dir, uintmax_t index); + +#endif diff --git a/include/panic.h b/include/panic.h new file mode 100644 index 0000000..076a425 --- /dev/null +++ b/include/panic.h @@ -0,0 +1,9 @@ +#ifndef _JOVE_PANIC_H +#define _JOVE_PANIC_H 1 + +#include "jove.h" + +#define kpanic(...) _kpanic(__FILE__, __LINE__, __VA_ARGS__) +NORETURN void _kpanic(const char *file, int line, const char *fmt, ...); + +#endif diff --git a/include/print.h b/include/print.h new file mode 100644 index 0000000..f4c942c --- /dev/null +++ b/include/print.h @@ -0,0 +1,17 @@ +#ifndef _JOVE_LIB_PRINT_H +#define _JOVE_LIB_PRINT_H 1 + +#include + +void _klogf(const char *file, const char *func, int line, const char *fmt, ...); +#define klogf(...) _klogf(__FILE__, __FUNCTION__, __LINE__, __VA_ARGS__) + +int kprintf(const char *fmt, ...); +int ksprintf(char *s, const char *fmt, ...); +int ksnprintf(char *s, int size, const char *fmt, ...); + +int kvprintf(const char *fmt, va_list ap); +int kvsprintf(char *s, const char *fmt, va_list ap); +int kvsnprintf(char *s, int size, const char *fmt, va_list ap); + +#endif diff --git a/include/string.h b/include/string.h new file mode 100644 index 0000000..a821f1c --- /dev/null +++ b/include/string.h @@ -0,0 +1,25 @@ +#ifndef _JOVE_STRING_H +#define _JOVE_STRING_H 1 + +#include +#include + +/**@FUNC Writes the given integer to the string using a custom base. + * If the integer is larger than size, s will stop being written to at s[size-1]. + * Returns the number of characters written, or would have been written. + * @PARAM s buffer to write to. + * @PARAM size size of buffer to write to. + * @PARAM l integer to write. + * @PARAM sign whether the integer is signed or unsigned. + * @PARAM radix base to write at. + * @RETURN number of characters in number.*/ +int ltostr(char *s, int size, unsigned long l, bool sign, int radix); + +size_t strlen(const char *s); +int strcmp(const char *s1, const char *s2); + +void *memset(void *dest, char c, size_t n); +void *memcpy(void *dest, const void *src, size_t n); +void *memmove(void *dest, const void *src, size_t n); + +#endif diff --git a/include/syscall.h b/include/syscall.h new file mode 100644 index 0000000..c9c26d8 --- /dev/null +++ b/include/syscall.h @@ -0,0 +1,46 @@ +#ifndef _JOVE_SYSCALL_H +#define _JOVE_SYSCALL_H 1 + +#include +#include +#include "object.h" + +enum +{ + SYSCALL_NONE = 0, + SYSCALL_INVOKE, + SYSCALL_SEND, + SYSCALL_RECV, + + SYSCALL_DEBUG_PUTC, + SYSCALL_DEBUG_IDENTIFY +}; + +typedef uint16_t invokeid_t; + +struct syscallInvokeHeader +{ + obj_path_t target_path; + invokeid_t func_id; +}; + +enum +{ + INVOKE_OBJDIR_NMEMB = 0, + INVOKE_OBJDIR_GETMEMB +}; + +struct syscallInvoke_objdir_nmemb +{ + struct syscallInvokeHeader header; + size_t value; +}; + +struct syscallInvoke_objdir_getmemb +{ + struct syscallInvokeHeader header; + uint8_t member; + obj_type_t value; +}; + +#endif diff --git a/include/tcb.h b/include/tcb.h new file mode 100644 index 0000000..6545083 --- /dev/null +++ b/include/tcb.h @@ -0,0 +1,18 @@ +#ifndef _JOVE_TCB_H +#define _JOVE_TCB_H 1 + +#include +#include + +typedef struct jove_ThreadControlBlock +{ + uintmax_t id; + struct jove_ThreadControlBlock *children; + struct jove_ThreadControlBlock *next; + + void *stack; + uintptr_t sp, ksp; + void *pml4; +} tcb_t; + +#endif -- cgit v1.2.1