diff options
| author | Jon Santmyer <jon@jonsantmyer.com> | 2026-09-04 11:31:40 -0400 |
|---|---|---|
| committer | Jon Santmyer <jon@jonsantmyer.com> | 2026-09-04 11:31:40 -0400 |
| commit | 8251da342161767fe203627223ccd4a7026701c6 (patch) | |
| tree | af2db0f11b0ea8ad35f88663a855bab39a80f679 | |
| download | jove-kernel-8251da342161767fe203627223ccd4a7026701c6.tar.gz jove-kernel-8251da342161767fe203627223ccd4a7026701c6.tar.bz2 jove-kernel-8251da342161767fe203627223ccd4a7026701c6.zip | |
initial commit. working on tasking
58 files changed, 3025 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71d7146 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.elf +*.o +*.d diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c53a551 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +include $(CONFIG) +include config.mk + +CDIRS := boot lib hal sys +CDIRS += boot/$(TARGET_BOOTLOADER) + +CFILES := $(wildcard *.c) +CFILES += $(wildcard arch/$(TARGET_MACHINE)/*.c) +CFILES += $(foreach dir, $(CDIRS), $(wildcard $(dir)/*.c)) +CFILES += $(foreach dir, $(CDIRS), $(wildcard arch/$(TARGET_MACHINE)/$(dir)/*.c)) + +SFILES := $(wildcard *.s) +SFILES += $(wildcard arch/$(TARGET_MACHINE)/*.s) +SFILES += $(foreach dir, $(CDIRS), $(wildcard $(dir)/*.s)) +SFILES += $(foreach dir, $(CDIRS), $(wildcard arch/$(TARGET_MACHINE)/$(dir)/*.s)) + +OBJFILES := $(patsubst %.c,%.o,$(CFILES)) +OBJFILES += $(patsubst %.s,%.o,$(SFILES)) + +DEPFILES := $(patsubst %.c,%.d,$(CFILES)) + +BIN := jove.elf + +all: $(BIN) + +.PHONY: clean +clean: + -rm $(OBJFILES) + -rm $(DEPFILES) + -rm $(BIN) + +$(BIN): ${OBJFILES} + $(LD) $(LDFLAGS) ${OBJFILES} -o $(BIN) + +-include ${DEPFILES} + +%.o:%.c + $(CC) $(CFLAGS) -c $< -o $@ + +%.o:%.S + $(AS) -g -c $< -o $@ diff --git a/arch/x86_64/boot/limine/framebuffer.c b/arch/x86_64/boot/limine/framebuffer.c new file mode 100644 index 0000000..aa93496 --- /dev/null +++ b/arch/x86_64/boot/limine/framebuffer.c @@ -0,0 +1,48 @@ +#include "arch/x86_64/hal/paging.h" +#include "jove.h" +#include "config.h" +#include "hal/framebuffer.h" +#include "lib/printf.h" + +/*We don't know the size of the framebuffer until runtime, but at the same + * time we don't want to dynamically allocate from physical memory. In this + * case we allocate memory for the maximum supported framebuffer at compile + * time and only use what we need at runtime.*/ +#define FRAMEBUFFER_MAX_BYTES (FRAMEBUFFER_MAX_WIDTH * FRAMEBUFFER_MAX_WIDTH * 4) +#define FRAMEBUFFER_MAX_PAGES ((FRAMEBUFFER_MAX_BYTES + 4095) / 0x1000) +#define FRAMEBUFFER_MAX_HUGEPAGES ((FRAMEBUFFER_MAX_PAGES + 511) / 512) +#define FRAMEBUFFER_MAX_GIANTPAGES ((FRAMEBUFFER_MAX_HUGEPAGES + 511) / 512) + +PAGEALIGN static page_t fb_pml2[FRAMEBUFFER_MAX_GIANTPAGES][512]; + +extern page_t _kernel_pml3[512]; + +void* +fb_remap(uintptr_t fb_address, + size_t fb_bytes) +{ + fb_address &= ~IDENT_VIRT_BASE; + size_t fb_pages = (fb_bytes + 4095) >> 12; + size_t fb_hugepages = (fb_pages + 511) >> 9; + size_t fb_giantpages = (fb_hugepages + 511) >> 9; + + if(fb_pages > FRAMEBUFFER_MAX_PAGES) { + kprintf("Framebuffer is too big! Please recompile the kernel with a bigger framebuffer allowance!"); + return NULL; + } + + for(size_t pml2 = 0; pml2 < fb_giantpages; pml2++) { + uintptr_t fb_pml2_pptr = KPTR_TOPHYS((uintptr_t)fb_pml2[pml2]); + _kernel_pml3[pml2].value = fb_pml2_pptr | PAGE_PRESENT | PAGE_GLOBAL | PAGE_WRITEABLE; + } + + for(size_t pml1 = 0; pml1 < fb_hugepages; pml1++) { + size_t pml2 = pml1 >> 9; + size_t pml1_mod = pml1 % 512; + uintptr_t fb_off = fb_address + (pml1 << 21); + fb_pml2[pml2][pml1_mod].value = fb_off | PAGE_PRESENT | PAGE_GLOBAL | PAGE_WRITEABLE | PAGE_PS; + } + + uintptr_t fb_virt = IDENT_VIRT_BASE | (511ULL << PMLI_SHL(3)); + return (void*)fb_virt; +} diff --git a/arch/x86_64/hal/gdt.c b/arch/x86_64/hal/gdt.c new file mode 100644 index 0000000..a64bdc1 --- /dev/null +++ b/arch/x86_64/hal/gdt.c @@ -0,0 +1,81 @@ +#include "gdt.h" +#include "smp.h" +#include "lib/string.h" + +static struct gdt_entry _gdt[GDT_TSS_HI+1] = +{ + [GDT_KERNEL_NULL] = { 0 }, + [GDT_KERNEL_CODE] = (struct gdt_entry) { + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0b10011010, + .limit_flg = 0b10101111, + .base_24_31 = 0x0 + }, + [GDT_KERNEL_DATA] = (struct gdt_entry) { + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0b10010010, + .limit_flg = 0b10101111, + .base_24_31 = 0x0 + }, + [GDT_USER_NULL] = { 0 }, + [GDT_USER_DATA] = (struct gdt_entry) { + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0b11110010, + .limit_flg = 0b10101111, + .base_24_31 = 0x0 + }, + [GDT_USER_CODE] = (struct gdt_entry) { + .limit_0_15 = 0xFFFF, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0b11111010, + .limit_flg = 0b10101111, + .base_24_31 = 0x0 + }, + [GDT_TSS_LO] = (struct gdt_entry) { + .limit_0_15 = 0x0, + .base_0_15 = 0x0, + .base_16_23 = 0x0, + .type_flg = 0x89, + .limit_flg = 0x0, + .base_24_31 = 0x0 + }, + [GDT_TSS_HI] = { 0 } +}; + +void +gdt_setup(processor_t *processor) +{ + memcpy(processor->gdt, _gdt, sizeof(struct gdt_entry) * (GDT_TSS_HI+1)); + + struct gdt_descriptor gdtr; + gdtr.base = (uintptr_t)&processor->gdt; + gdtr.limit = sizeof(struct gdt_entry) * (GDT_TSS_HI+1) - 1; + + extern void load_gdt(struct gdt_descriptor *gdtr); + load_gdt(&gdtr); + + uintptr_t tss_base = (uintptr_t)&processor->tss; + size_t tss_limit = sizeof(struct tss); + + struct gdt_entry *tss_lo = &processor->gdt[GDT_TSS_LO]; + struct gdt_entry *tss_hi = &processor->gdt[GDT_TSS_HI]; + + tss_lo->base_0_15 = (uint16_t)(tss_base & 0xFFFF); + tss_lo->base_16_23 = (uint8_t)((tss_base >> 16) & 0xFF); + tss_lo->base_24_31 = (uint8_t)((tss_base >> 24) & 0xFF); + tss_hi->limit_0_15 = (uint16_t)((tss_base >> 32) & 0xFFFF); + tss_hi->base_0_15 = (uint16_t)((tss_base >> 48) & 0xFFFF); + + tss_lo->limit_0_15 = (uint16_t)(tss_limit & 0xFFFF); + tss_lo->limit_flg |= (uint8_t)((tss_limit >> 16) & 0xF); + + extern void load_tss(void); + load_tss(); +} diff --git a/arch/x86_64/hal/gdt.h b/arch/x86_64/hal/gdt.h new file mode 100644 index 0000000..7fb7dfc --- /dev/null +++ b/arch/x86_64/hal/gdt.h @@ -0,0 +1,48 @@ +#ifndef _JOVE_x86_64_HAL_GDT_H +#define _JOVE_x86_64_HAL_GDT_H 1 + +#include <stddef.h> +#include <stdint.h> +#include "jove.h" + +enum { + GDT_KERNEL_NULL = 0, + GDT_KERNEL_CODE, + GDT_KERNEL_DATA, + GDT_USER_NULL, + GDT_USER_DATA, + GDT_USER_CODE, + GDT_TSS_LO, + GDT_TSS_HI +}; + +#define GDT_OFFSET(i) (i << 3) + +struct gdt_entry +{ + uint16_t limit_0_15; + uint16_t base_0_15; + uint8_t base_16_23; + uint8_t type_flg; + uint8_t limit_flg; + uint8_t base_24_31; +}; + +struct tss +{ + uint32_t rsv0; + uint64_t rsp[3]; + uint64_t rsv1; + uint64_t ist[7]; + uint64_t rsv2; + uint16_t rsv3; + uint16_t iopb; +} PACKED; + +struct gdt_descriptor +{ + uint16_t limit; + uint64_t base; +} PACKED; + +#endif diff --git a/arch/x86_64/hal/idt.c b/arch/x86_64/hal/idt.c new file mode 100644 index 0000000..b2251bd --- /dev/null +++ b/arch/x86_64/hal/idt.c @@ -0,0 +1,53 @@ +#include "idt.h" +#include "smp.h" +#include "gdt.h" +#include "jove.h" +#include "lib/printf.h" + +ALIGN(8) +static struct idt_entry s_idt[IDT_ENTRIES]; + +typedef void (*isr_t)(void); +extern isr_t __isrs[IDT_ENTRIES]; + +typedef struct int_stackframe *(*int_handler_t)(struct int_stackframe*); +int_handler_t __int_handles[IDT_ENTRIES]; + +static struct int_stackframe* +s_int_handle_stub(struct int_stackframe* frame) +{ + kprintf("Unhandled interrupt %i at %p\n", frame->int_num, frame->int_rip); + hcf(); +} + +void +idt_init(void) +{ + for(size_t i = 0; i < IDT_ENTRIES; i++) { + uintptr_t isr = (uintptr_t)(__isrs[i]); + + s_idt[i] = (struct idt_entry) { + .offset_0_15 = (uint16_t)(isr & 0xFFFF), + .segment_selector = GDT_KERNEL_CODE * 8, + .ist = 0, + .type = IDT_INTERRUPT_GATE, + .dpl = 0, + .p = 1, + .offset_16_31 = (uint16_t)((isr >> 16) & 0xFFFF), + .offset_32_63 = (uint32_t)(isr >> 32) + }; + + __int_handles[i] = s_int_handle_stub; + } +} + +void +idt_setup(processor_t *processor) +{ + struct idt_descriptor idtr = (struct idt_descriptor) { + .limit = sizeof(struct idt_entry) * IDT_ENTRIES - 1, + .base = (uint64_t)&s_idt + }; + + __asm__ volatile("lidt %0":: "m"(idtr)); +} diff --git a/arch/x86_64/hal/idt.h b/arch/x86_64/hal/idt.h new file mode 100644 index 0000000..961e720 --- /dev/null +++ b/arch/x86_64/hal/idt.h @@ -0,0 +1,66 @@ +#ifndef _JOVE_x86_64_HAL_IDT_H +#define _JOVE_x86_64_HAL_IDT_H 1 + +#include <stdint.h> +#include "jove.h" +#include "../x86_64.h" + +struct idt_entry +{ + uint16_t offset_0_15; + uint16_t segment_selector; + union { + struct { + uint8_t ist : 3; + uint8_t zero_1 : 5; + uint8_t type : 4; + uint8_t zero_2 : 1; + uint8_t dpl : 2; + uint8_t p : 1; + }; + uint16_t flags; + }; + uint16_t offset_16_31; + uint32_t offset_32_63; + uint32_t resv; +}; + +#define IDT_INTERRUPT_GATE 0xE + +struct idt_descriptor +{ + uint16_t limit; + uint64_t base; +} PACKED; + +struct int_stackframe +{ + struct cpu_state state; + uint64_t int_num, int_err; + uint64_t int_rip, int_cs, int_flags, int_rsp, int_rss; +}; + +#define IDT_ENTRIES 48 + +#define IDT_EXCEPT_DE 0 +#define IDT_EXCEPT_DB 1 +#define IDT_EXCEPT_NMI 2 +#define IDT_EXCEPT_BP 3 +#define IDT_EXCEPT_OF 4 +#define IDT_EXCEPT_BR 5 +#define IDT_EXCEPT_UD 6 +#define IDT_EXCEPT_NM 7 +#define IDT_EXCEPT_DF 8 +#define IDT_EXCEPT_TS 10 +#define IDT_EXCEPT_NP 11 +#define IDT_EXCEPT_SS 12 +#define IDT_EXCEPT_GP 13 +#define IDT_EXCEPT_PF 14 +#define IDT_EXCEPT_MF 16 +#define IDT_EXCEPT_AC 17 +#define IDT_EXCEPT_MC 18 +#define IDT_EXCEPT_XM 19 +#define IDT_EXCEPT_VE 20 +#define IDT_EXCEPT_CP 21 + +#endif diff --git a/arch/x86_64/hal/idt_entries.s b/arch/x86_64/hal/idt_entries.s new file mode 100644 index 0000000..204fa93 --- /dev/null +++ b/arch/x86_64/hal/idt_entries.s @@ -0,0 +1,127 @@ +.section .text +.macro push_state + pushq %rax + pushq %rbx + pushq %rcx + pushq %rdx + pushq %rsi + pushq %rdi + pushq %rbp + pushq %r8 + pushq %r9 + pushq %r10 + pushq %r11 + pushq %r12 + pushq %r13 + pushq %r14 + pushq %r15 +.endm + +.macro pop_state + popq %r15 + popq %r14 + popq %r13 + popq %r12 + popq %r11 + popq %r10 + popq %r9 + popq %r8 + popq %rbp + popq %rdi + popq %rsi + popq %rdx + popq %rcx + popq %rbx + popq %rax +.endm + +.macro swapgs_if_necessary + cmpq $0x08, 0x8(%rsp) + je 1f + swapgs +1: +.endm + +.extern __int_handles +.type __isr_header @function +__isr_header: + push_state + cld + + movq %rsp, %rdi + +isr_break: + movq 0x78(%rdi), %rax + movq __int_handles(,%rax,8), %rbx + call %rbx + + pop_state + addq $16, %rsp + swapgs_if_necessary + iretq +.size __isr_header, . - __isr_header + +.macro defn_isr_err num:req +.type __isr\num @function +__isr\num: + swapgs_if_necessary + pushq $\num + jmp __isr_header +.size __isr\num, . - __isr\num +.endm + +.macro defn_isr num:req +.type __isr\num @function +__isr\num: + swapgs_if_necessary + pushq $0 + pushq $\num + jmp __isr_header +.size __isr\num, . - __isr\num +.endm + +.macro decl_isr num:req +.quad __isr\num +.endm + +defn_isr 0 +defn_isr 1 +defn_isr 2 +defn_isr 3 +defn_isr 4 +defn_isr 5 +defn_isr 6 +defn_isr 7 +defn_isr_err 8 +defn_isr 9 +defn_isr_err 10 +defn_isr_err 11 +defn_isr_err 12 +defn_isr_err 13 +defn_isr_err 14 +defn_isr 15 +defn_isr 16 +defn_isr_err 17 +defn_isr 18 +defn_isr 19 +defn_isr 20 +defn_isr_err 21 + +.altmacro +.set i, 22 +.rept 48-22 + defn_isr %i + .set i, i+1 +.endr + +.section .data + +.global __isrs +.type __isrs @object +__isrs: + .set i, 0 + .rept 48 + decl_isr %i + .set i, i+1 + .endr +.size __isrs, . - __isrs diff --git a/arch/x86_64/hal/lxdt.s b/arch/x86_64/hal/lxdt.s new file mode 100644 index 0000000..1591599 --- /dev/null +++ b/arch/x86_64/hal/lxdt.s @@ -0,0 +1,26 @@ +.global load_gdt +.type load_gdt @function +load_gdt: + lgdt (%rdi) +.reload_segments: + pushq $0x8 + leaq .reload_cs(%rip), %rax + pushq %rax + retfq +.reload_cs: + movw $0x10, %ax + movw %ax, %ds + movw %ax, %es + movw %ax, %fs + movw %ax, %gs + movw %ax, %ss + retq +.size load_gdt, . - load_gdt + +.global load_tss +.type load_tss @function +load_tss: + movw $0x30, %ax + ltr %ax + retq +.size load_tss, . - load_tss diff --git a/arch/x86_64/hal/msr.c b/arch/x86_64/hal/msr.c new file mode 100644 index 0000000..f27e303 --- /dev/null +++ b/arch/x86_64/hal/msr.c @@ -0,0 +1,52 @@ +#include "msr.h" +#include "gdt.h" + +void +msr_read(uint32_t msr, uint32_t *lo, uint32_t *hi) +{ + __asm__ volatile("rdmsr": "=a"(*lo), "=d"(*hi): "c"(msr)); +} + +void +msr_write(uint32_t msr, uint32_t lo, uint32_t hi) +{ + __asm__ volatile("wrmsr":: "a"(lo), "c"(msr), "d"(hi)); +} + +void +msr_set_gs_base(uintptr_t gs) +{ + union msr_gs_base gs_base = { .gs = gs }; + msr_write(MSR_GS_BASE, gs_base.v[0], gs_base.v[1]); +} + +uintptr_t +msr_get_gs_base(void) +{ + union msr_gs_base gs_base; + msr_read(MSR_GS_BASE, &gs_base.v[0], &gs_base.v[1]); + return gs_base.gs; +} + +void +msr_enable_sce(void) +{ + uint32_t efer[2]; + msr_read(MSR_EFER, &efer[0], &efer[1]); + + efer[0] |= MSR_EFER_SCE; + msr_write(MSR_EFER, efer[0], efer[1]); + + union msr_star star; + star.kcs = GDT_OFFSET(GDT_KERNEL_CODE); + star.ucs = GDT_OFFSET(GDT_USER_CODE); + msr_write(MSR_STAR, star.v[0], star.v[1]); +} + +void +msr_set_lstar(void *lstar_value) +{ + union msr_lstar lstar; + lstar.rip = lstar_value; + msr_write(MSR_LSTAR, lstar.v[0], lstar.v[1]); +} diff --git a/arch/x86_64/hal/msr.h b/arch/x86_64/hal/msr.h new file mode 100644 index 0000000..69d96be --- /dev/null +++ b/arch/x86_64/hal/msr.h @@ -0,0 +1,48 @@ +#ifndef _JOVE_x86_64_HAL_MSR_H +#define _JOVE_x86_64_HAL_MSR_H 1 + +#include <stdint.h> + +#define MSR_FS_BASE 0xC0000100 +#define MSR_GS_BASE 0xC0000101 +#define MSR_KGS_BASE 0xC0000102 + +#define MSR_EFER 0xC0000080 +#define MSR_EFER_SCE 0b1 + +#define MSR_STAR 0xC0000081 +#define MSR_LSTAR 0xC0000082 +#define MSR_SFMASK 0xC0000084 + +union msr_gs_base +{ + uintptr_t gs; + uint32_t v[2]; +}; + +union msr_star +{ + struct { + uint32_t eip; + uint16_t kcs; + uint16_t ucs; + }; + uint16_t v[2]; +}; + +union msr_lstar +{ + void *rip; + uint32_t v[2]; +}; + +void msr_set_gs_base(uintptr_t gs_base); +uintptr_t msr_get_gs_base(void); + +void msr_enable_sce(void); +void msr_set_lstar(void *syscall_entry); + +void msr_read(uint32_t msr, uint32_t *lo, uint32_t *hi); +void msr_write(uint32_t msr, uint32_t lo, uint32_t hi); + +#endif diff --git a/arch/x86_64/hal/obj.c b/arch/x86_64/hal/obj.c new file mode 100644 index 0000000..783d2f4 --- /dev/null +++ b/arch/x86_64/hal/obj.c @@ -0,0 +1,87 @@ +#include "obj.h" +#include "arch/x86_64/lock.h" +#include "hal/obj.h" +#include "jove.h" + +jove_owned_obj_t* +obj_take(jove_obj_t *obj) +{ + take_mutex(&obj->lock); + return (jove_owned_obj_t*)obj; +} + +jove_obj_t* +obj_release(jove_owned_obj_t *obj) +{ + release_mutex((atomic_flag*)&obj->lock); + return (jove_obj_t*)obj; +} + +void* +obj_deref(jove_owned_obj_t *obj) +{ + return (void*)(((uintptr_t)obj_getvalue(obj)) | 0xFFFF800000000000ULL); +} + +uint8_t +obj_gettype(jove_owned_obj_t *obj) +{ + return obj->type; +} + +void +obj_settype(jove_owned_obj_t *obj, uint8_t type) +{ + obj->type = type; +} + +uintmax_t +obj_getvalue(jove_owned_obj_t *obj) +{ + return obj->value; +} + +void +obj_setvalue(jove_owned_obj_t *obj, uintmax_t value) +{ + obj->value = value & 0x00007FFFFFFFFFFFULL; +} + +jove_obj_t* +objdir_getlocal( + jove_owned_obj_t *objdir_obj, + uint16_t entry) +{ + if(objdir_obj->type != JOVE_OBJ_OBJDIR) { + reterr(EBADOBJ); + } + if(entry >= JOVE_OBJDIR_ENTRIES) { + reterr(EOOB); + } + + jove_objdir_t *objtab = obj_deref(objdir_obj); + return &objtab->entries[entry]; +} + +jove_owned_obj_t* +objdir_getobj( + jove_owned_obj_t *objdir_obj, + const uint16_t *path, + size_t path_len) +{ + if(path_len == 0) { + return objdir_obj; + } + { + jove_obj_t *child_locked_objdir = objdir_getlocal(objdir_obj, path[0]); + if(child_locked_objdir == NULL) { + return 0; + } + + jove_owned_obj_t *child_objdir = obj_take(child_locked_objdir); + jove_owned_obj_t *target_obj = objdir_getobj(child_objdir, path + 1, path_len - 1); + obj_release(child_objdir); + return target_obj; + } +} + diff --git a/arch/x86_64/hal/obj.h b/arch/x86_64/hal/obj.h new file mode 100644 index 0000000..645727d --- /dev/null +++ b/arch/x86_64/hal/obj.h @@ -0,0 +1,79 @@ +#ifndef _JOVE_ARCH_HAL_OBJ_H +#define _JOVE_ARCH_HAL_OBJ_H 1 + +#include <stdatomic.h> +#include <stdint.h> +#include <stddef.h> + +enum +{ + JOVE_OBJ_SERIAL_COM = 0x81, + JOVE_OBJ_PAGE_FRAME, + JOVE_OBJ_PAGE_MAPPING, +}; + +/*Represents a locked kernel object pointer inside of a object directory.*/ +typedef union jove_obj +{ + struct { + uint8_t type; + atomic_flag lock; + /*Raw value or pointer to a data-structure located in kernel memory.*/ + uint64_t value : 48; + }; + uintmax_t data; +} jove_obj_t; + +/*Represents an unlocked kernel object pointer. + *This object should only exist temporarily while accessing the underlying + *structure this object points to.*/ +typedef union jove_obj_locked +{ + struct { + uint8_t type; + uint8_t lock; + uint64_t value : 48; + }; + uintmax_t data; +} jove_owned_obj_t; + +/*Object directories are always 1 page wide. Since an object inside the directory + * is a pointer width, on x86_64 that is 512 entries per directory.*/ +#define JOVE_OBJDIR_SIZE 0x1000 +#define JOVE_OBJDIR_ENTRIES (JOVE_OBJDIR_SIZE / sizeof(jove_obj_t)) + +typedef struct jove_objdir +{ + jove_obj_t entries[JOVE_OBJDIR_ENTRIES]; +} jove_objdir_t; +/*Locks the mutex of the kernel object provided. Returns the locked version. */ +jove_owned_obj_t *obj_take(jove_obj_t *obj); +/*Unlocks the mutex of the kernel object provided. Returns the unlocked version. */ +jove_obj_t *obj_release(jove_owned_obj_t *obj); + +/*Converts the value pointer of the object into a pointer to kernel memory.*/ +void *obj_deref(jove_owned_obj_t *obj); + +/*Getters and setters for accessing the type field of the kernel object. */ +uint8_t obj_gettype(jove_owned_obj_t *obj); +void obj_settype(jove_owned_obj_t *obj, uint8_t type); + +/*Getters and setters for accessing the value field of the kernel object. */ +uintmax_t obj_getvalue(jove_owned_obj_t *obj); +void obj_setvalue(jove_owned_obj_t *obj, uintmax_t value); + +/*Returns the n'th entry of the object directory passed. + * If the passed object is not an objdir, returns NULL and sets errno to EBADOBJ. + * If the passed entry index is out of bounds, returns NULL and sets errno to EOOB.*/ +jove_obj_t *objdir_getlocal(jove_owned_obj_t *objdir_obj, uint16_t entry); + +/*Recursively seeks through an object directory for an object following the passed + * path variable. + * If the path length is zero, returns the passed object. + * If the passed object is not an objdir, returns NULL and sets errno to EBADOBJ. + * If any object excluding the object at the end of the path is not an objdir, + * returns NULL and sets errno to EBADOBJ. + * If any entry in the path is out of bounds, returns NULL and sets errno to EBADOBJ.*/ +jove_owned_obj_t *objdir_getobj(jove_owned_obj_t *objdir_obj, const uint16_t *path, size_t path_len); + +#endif diff --git a/arch/x86_64/hal/paging.c b/arch/x86_64/hal/paging.c new file mode 100644 index 0000000..c1a22a2 --- /dev/null +++ b/arch/x86_64/hal/paging.c @@ -0,0 +1,174 @@ +#include "paging.h" +#include "arch/x86_64/x86_64.h" +#include "jove.h" +#include "config.h" +#include "smp.h" +#include "lib/string.h" +#include "lib/printf.h" +#include "lib/panic.h" +#include "idt.h" + +PAGEALIGN page_t _kernel_pml4[512]; +PAGEALIGN page_t _kernel_pml3[512]; +PAGEALIGN page_t _kernel_pml2[512]; +PAGEALIGN page_t _kernel_pml1[512]; + +#define IDENT_HUGEPAGES ((PHYS_BIGPAGES_MAX + 511) / 512) +#define IDENT_GIANTPAGES ((IDENT_HUGEPAGES + 511) / 512) + +PAGEALIGN static page_t ident_pml3[IDENT_GIANTPAGES][512]; +PAGEALIGN static page_t ident_pml2[IDENT_HUGEPAGES][512]; + +void* +phys_tovirt(uintptr_t phys) +{ + return (void*)(phys | IDENT_VIRT_BASE); +} + +uintptr_t +paging_get_pml4(void) +{ + uintptr_t ret = 0; + __asm__ volatile("movq %%cr3, %0": "=r"(ret)); + return ret; +} + +void +paging_pml4_switch(uintptr_t pml4) +{ + __asm__ volatile("movq %0, %%cr3":: "r"(pml4)); +} + +static struct int_stackframe* +s_int_handle_pf_early(struct int_stackframe *frame) +{ + extern int _kernel_panic_unlock; + _kernel_panic_unlock = 1; + + union { + struct { + uint8_t p : 1; + uint8_t wr : 1; + uint8_t us : 1; + uint8_t rsvd : 1; + uint8_t id : 1; + uint8_t pk : 1; + }; + uint64_t value; + } pf_error = { .value = frame->int_err }; + + kprintf("Kernel has encountered a page fault exception early in initializaiton\n"); + kprintf("%s %s during %s\n", + pf_error.wr ? "Wrote to" : "Read from", + pf_error.p ? "Present" : "Non-present", + pf_error.id ? "Instruction fetch" : "Data access"); + uintptr_t cr2 = 0; + __asm__ volatile("movq %%cr2, %0": "=r"(cr2)); + kprintf("Faulting address: %p\n", cr2); + kprintf("RIP: %p | RSP: %p\n", frame->int_rip, frame->int_rsp); + print_state(&frame->state); + + hcf(); +} + +void +paging_pml4_init(void) +{ + //Setup kernel pages + memset(_kernel_pml4, 0, 0x1000); + memset(_kernel_pml3, 0, 0x1000); + memset(_kernel_pml2, 0, 0x1000); + memset(_kernel_pml1, 0, 0x1000); + + /*Paging entries depend on physical addresses to properly map. + * Since the virtual kernel address differs from the physical memory address, + * we need to convert the pointers using the physical memory pointer passed + * to us by the bootloader.*/ + uintptr_t kernel_pml4_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml4); + uintptr_t kernel_pml3_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml3); + uintptr_t kernel_pml2_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml2); + uintptr_t kernel_pml1_pptr = KPTR_TOPHYS((uintptr_t)_kernel_pml1); + + /*Maps pml4-2 as global writeable pages.*/ + _kernel_pml4[511].value = kernel_pml3_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + _kernel_pml3[510].value = kernel_pml2_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + _kernel_pml2[0].value = kernel_pml1_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + + /*text*/ + extern void *_kernel_text_start; + extern void *_kernel_text_end; + uintptr_t kernel_text_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_text_start); + uintptr_t kernel_text_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_text_end); + size_t kernel_text_pages = ((kernel_text_end_pptr - kernel_text_start_pptr) / 0x1000) + 1; + + uintptr_t kernel_text_off = (((uintptr_t)&_kernel_text_start) - KERNEL_VIRT_BASE) >> 12; + + for(size_t i = 0; i < kernel_text_pages; i++) { + size_t off = i + kernel_text_off; + uintptr_t page_off = kernel_text_start_pptr + (i << 12); + _kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_GLOBAL; + } + + /*rodata*/ + extern void *_kernel_rodata_start; + extern void *_kernel_rodata_end; + uintptr_t kernel_rodata_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_rodata_start); + uintptr_t kernel_rodata_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_rodata_end); + size_t kernel_rodata_pages = ((kernel_rodata_end_pptr - kernel_rodata_start_pptr) / 0x1000) + 1; + + uintptr_t kernel_rodata_off = kernel_text_off + kernel_text_pages; + for(size_t i = 0; i < kernel_rodata_pages; i++) { + size_t off = i + kernel_rodata_off; + uintptr_t page_off = kernel_text_start_pptr + (off << 12); + _kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_GLOBAL | PAGE_XD; + } + + /*data/bss*/ + extern void *_kernel_data_start; + extern void *_kernel_bss_end; + uintptr_t kernel_data_start_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_data_start); + uintptr_t kernel_data_end_pptr = KPTR_TOPHYS((uintptr_t)&_kernel_bss_end); + size_t kernel_data_pages = ((kernel_data_end_pptr - kernel_data_start_pptr) / 0x1000) + 1; + + uintptr_t kernel_data_off = kernel_rodata_off + kernel_rodata_pages; + for(size_t i = 0; i < kernel_data_pages; i++) { + size_t off = i + kernel_data_off; + uintptr_t page_off = kernel_text_start_pptr + (off << 12); + _kernel_pml1[off].value = page_off | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL | PAGE_XD; + } + + /*Identity pages are mapped as huge pages starting at the 256'th PML3 entry. + *We want to support any range of physical memory up to several TiB, so + *the mapper has to consider multiple heirarchies of huge pages.*/ + for(size_t l3 = 0; l3 < IDENT_GIANTPAGES; l3++) { + memset(ident_pml3[l3], 0, 0x1000); + uintptr_t ident_pml3_pptr = KPTR_TOPHYS((uintptr_t)ident_pml3[l3]); + + _kernel_pml4[256 + l3].value = ident_pml3_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + } + + for(size_t l2 = 0; l2 < IDENT_HUGEPAGES; l2++) { + size_t l3 = l2 / 512; + size_t l2_mod = l2 % 512; + + memset(ident_pml2[l2], 0, 0x1000); + uintptr_t ident_pml2_pptr = KPTR_TOPHYS((uintptr_t)ident_pml2[l2]); + + ident_pml3[l3][l2_mod].value = ident_pml2_pptr | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_GLOBAL; + } + + for(size_t l1 = 0; l1 < PHYS_BIGPAGES_MAX; l1++) { + size_t l2 = l1 / 512; + size_t l1_mod = l1 % 512; + + ident_pml2[l2][l1_mod].value = (l1 << 21) | PAGE_PRESENT | PAGE_WRITEABLE | PAGE_PS | PAGE_GLOBAL; + ident_pml2[l2][l1_mod].xd = 1; + } + + paging_pml4_switch(kernel_pml4_pptr); + + /*Before tasking, if the kernel has a bug and crashes we need some + * information about what happened.*/ + extern struct int_stackframe *(*__int_handles[])(struct int_stackframe*); + __int_handles[IDT_EXCEPT_PF] = s_int_handle_pf_early; +} diff --git a/arch/x86_64/hal/paging.h b/arch/x86_64/hal/paging.h new file mode 100644 index 0000000..54df1eb --- /dev/null +++ b/arch/x86_64/hal/paging.h @@ -0,0 +1,52 @@ +#ifndef _JOVE_x86_64_HAL_PAGING_H +#define _JOVE_x86_64_HAL_PAGING_H 1 + +#include "jove.h" +#include <stdint.h> + +typedef union page_table_entry +{ + struct { + uint8_t p : 1; + uint8_t rw : 1; + uint8_t u : 1; + uint8_t pwt : 1; + uint8_t pcd : 1; + uint8_t a : 1; + uint8_t d : 1; + uint8_t ps : 1; + uint8_t g : 1; + uint8_t ign_0 : 2; + uint8_t r : 1; + uint64_t paddr : 35; + uint8_t ign_1 : 4; + uint8_t pkey : 4; + uint8_t xd : 1; + }; + uint64_t value; +} PACKED page_t; + +#define PAGE_PRESENT 0b1 +#define PAGE_WRITEABLE 0b10 +#define PAGE_USER 0b100 +#define PAGE_WRITETHROUGH 0b1000 +#define PAGE_CACHEDISABLE 0b10000 +#define PAGE_ACCESSED 0b100000 +#define PAGE_DIRTY 0b1000000 +#define PAGE_PS 0b10000000 +#define PAGE_GLOBAL 0b100000000 +#define PAGE_XD (1ULL << 63) + +extern void *_kernel_physptr; + +#define PMLI_SHL(l) (12 + (l * 9)) +#define PMLI_MASK(l) (~0xFFFF << PMLI_SHL(l)) + +#define IDENT_VIRT_BASE 0xFFFF800000000000ULL +#define KERNEL_VIRT_BASE 0xFFFFFFFF80000000ULL +#define KPTR_TOPHYS(v) (v - KERNEL_VIRT_BASE + (uintptr_t)_kernel_physptr) + +uintptr_t paging_get_pml4(void); +void paging_pml4_init(void); + +#endif diff --git a/arch/x86_64/hal/port.h b/arch/x86_64/hal/port.h new file mode 100644 index 0000000..6dbc27c --- /dev/null +++ b/arch/x86_64/hal/port.h @@ -0,0 +1,12 @@ +#ifndef _JOVE_PORT_H +#define _JOVE_PORT_H 1 + +#include <stdint.h> + +static inline uint8_t inb(uint16_t port) +{ uint8_t r; __asm__ volatile("inb %w1, %b0": "=a"(r): "Nd"(port): "memory"); return r; } + +static inline void outb(uint16_t port, uint8_t v) +{ __asm__ volatile("outb %b0, %w1":: "a"(v), "Nd"(port): "memory"); } + +#endif diff --git a/arch/x86_64/hal/process.c b/arch/x86_64/hal/process.c new file mode 100644 index 0000000..dd49456 --- /dev/null +++ b/arch/x86_64/hal/process.c @@ -0,0 +1,35 @@ +#include "process.h" +#include "arch/x86_64/hal/obj.h" +#include "hal/obj.h" +#include "init.h" +#include "smp.h" +#include "paging.h" +#include "jove.h" + +PAGEALIGN char s_init_pcb_bytes[0x1000] = { 0 }; +static pcb_t *s_init_pcb = (pcb_t*)&s_init_pcb_bytes; + +void +processing_setup(void (*process_main)) +{ + uintptr_t ksp = (uintptr_t)&s_init_pcb_bytes + 8; + s_init_pcb->ksp = (void*)ksp; + s_init_pcb->pml4 = paging_get_pml4(); + + processor_t *proc = processor_current(); + proc->pcb = s_init_pcb; + proc->tss.rsp[0] = (uintptr_t)s_init_pcb->ksp; + + { + jove_owned_obj_t *process_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_PCB_I)); + obj_settype(process_obj, JOVE_OBJ_PROCESS); + obj_setvalue(process_obj, (uintptr_t)s_init_pcb); + obj_release(process_obj); + } + + __asm__ volatile("\ + movq %0, %%rsp; \ + movq $0, %%rbp; \ + jmpq %1":: + "r"(s_init_pcb->ksp), "r"(process_main)); +} diff --git a/arch/x86_64/hal/process.h b/arch/x86_64/hal/process.h new file mode 100644 index 0000000..0c0fb5b --- /dev/null +++ b/arch/x86_64/hal/process.h @@ -0,0 +1,34 @@ +#ifndef _JOVE_x86_64_HAL_PROCESS_H +#define _JOVE_x86_64_HAL_PROCESS_H 1 + +#include "hal/obj.h" +#include "arch/x86_64/x86_64.h" + +enum pcb_state +{ + PCB_DEAD, PCB_READY, PCB_RUNNING, PCB_BLOCKED +}; + +struct pcb_mailbox +{ + jove_obj_t *obj; + uintmax_t pcbid; +}; + +typedef struct process_control_block +{ + jove_obj_t *rootdir; + uintptr_t pml4; + + enum pcb_state state; + int killed; + struct pcb_mailbox send, recv; + + struct cpu_context context; + void *ksp; + char kstack[]; +} pcb_t; + +#define PCB_KSTACK_SIZE (0x1000 - sizeof(pcb_t)) + +#endif diff --git a/arch/x86_64/hal/serial_com.c b/arch/x86_64/hal/serial_com.c new file mode 100644 index 0000000..3967cd7 --- /dev/null +++ b/arch/x86_64/hal/serial_com.c @@ -0,0 +1,92 @@ +#include "serial_com.h" +#include "port.h" +#include "jove.h" +#include "hal/obj.h" +#include "init.h" +#include "lib/printf.h" + +static int +serial_com_recv(uint16_t port) +{ + return inb(SERIAL_COM_LSR(port)) & 1; +} + +static char +serial_com_getc(uint16_t port) +{ + while(serial_com_recv(port) == 0); + return inb(port); +} + +static int +serial_com_put_ready(uint16_t port) +{ + return inb(SERIAL_COM_LSR(port)) & 0x20; +} + +static void +serial_com_putc(uint16_t port, char c) +{ + while(serial_com_put_ready(port) == 0); + outb(port, c); +} + +int +serial_com_init_port( + uint16_t port, + uint16_t baud_divisor) +{ + uint8_t div_low = (uint8_t)baud_divisor; + uint8_t div_high = (uint8_t)(baud_divisor >> 8); + + outb(SERIAL_COM_IER(port), 0x00); // Disable all interrupts + outb(SERIAL_COM_LCR(port), 0x80); // Enable DLAB mode. + outb(SERIAL_COM_DLAB_BAUD_LO(port), div_low); + outb(SERIAL_COM_DLAB_BAUD_HI(port), div_high); + outb(SERIAL_COM_LCR(port), 0x03); // 8 bits, no parity, one stop bit. + outb(SERIAL_COM_FIFO(port), 0xC7); // Enable FIFO, clear them, 14 byte threshold. + outb(SERIAL_COM_MCR(port), 0x0B); // Enable IRQs, set RTS/DSR. + + //Test to check if the serial port actually works. + outb(SERIAL_COM_MCR(port), 0x1E); // Set loopback mode. + outb(port, 0xAE); // Send test byte. + if(inb(port) != 0xAE) { + return 1; + } + + //Set the port to normal operation mode. + //(no loopback, IRQs enabled, OUT#1 and OUT#2 enabled.) + outb(SERIAL_COM_MCR(port), 0x0F); + return 0; +} + +void +serial_com_init(void) +{ + if(serial_com_init_port(SERIAL_COM1, 3)) { + hcf(); + } + + { + jove_owned_obj_t *com_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_SERIAL_COM_I)); + obj_settype(com_obj, JOVE_OBJ_SERIAL_COM); + obj_setvalue(com_obj, SERIAL_COM1); + obj_release(com_obj); + } + + kprintf("Initialized COM1 on port %X for obj %X\n", SERIAL_COM1, ROOTDIR_SERIAL_COM_I); +} + +int +serial_com_write( + jove_owned_obj_t *obj, + const char *s, size_t len) +{ + if(obj->type != JOVE_OBJ_SERIAL_COM) { + reterr(EBADOBJ); + } + for(size_t i = 0; i < len; i++) { + serial_com_putc((uint16_t)obj->value, s[i]); + } + return len; +} diff --git a/arch/x86_64/hal/serial_com.h b/arch/x86_64/hal/serial_com.h new file mode 100644 index 0000000..2dbb0cd --- /dev/null +++ b/arch/x86_64/hal/serial_com.h @@ -0,0 +1,26 @@ +#ifndef _JOVE_SERIAL_COM_H +#define _JOVE_SERIAL_COM_H 1 + +#include <stdint.h> +#include "obj.h" + +#define SERIAL_COM1 0x3F8 + +#define SERIAL_COM_TR(com) (com) +#define SERIAL_COM_IER(com) (com + 1) +#define SERIAL_COM_II(com) (com + 2) +#define SERIAL_COM_FIFO(com) (com + 2) +#define SERIAL_COM_LCR(com) (com + 3) +#define SERIAL_COM_MCR(com) (com + 4) +#define SERIAL_COM_LSR(com) (com + 5) +#define SERIAL_COM_MSR(com) (com + 6) +#define SERIAL_COM_SR(com) (com + 7) + +#define SERIAL_COM_DLAB_BAUD_LO(com) (com) +#define SERIAL_COM_DLAB_BAUD_HI(com) (com + 1) + +void serial_com_init(void); + +int serial_com_write(jove_owned_obj_t *obj, const char *s, size_t len); + +#endif diff --git a/arch/x86_64/hal/smp.c b/arch/x86_64/hal/smp.c new file mode 100644 index 0000000..a28fdc1 --- /dev/null +++ b/arch/x86_64/hal/smp.c @@ -0,0 +1,65 @@ +#include "smp.h" +#include "init.h" +#include "hal/obj.h" +#include "config.h" +#include "jove.h" +#include "lib/printf.h" +#include "paging.h" +#include "msr.h" + +processor_t s_processors[SMP_PROCESSORS_MAX] = { 0 }; + +PAGEALIGN +jove_objdir_t s_processor_objdir = { 0 }; + +extern void +gdt_setup(processor_t *processor); + +extern void +idt_init(void); + +extern void +idt_setup(processor_t *processor); + +static void +init_processor(processor_t *processor, jove_owned_obj_t *obj) +{ + gdt_setup(processor); + idt_setup(processor); + + msr_set_gs_base((uintptr_t)processor); + + obj_settype(obj, JOVE_OBJ_PROCESSOR); + obj_setvalue(obj, (uintptr_t)processor); +} + +void +smp_init_bsp(void) +{ + idt_init(); + paging_pml4_init(); + + kprintf("%p\n", _rootdir_obj); + processor_t *bsp = &s_processors[0]; + { + jove_owned_obj_t *processor_objdir_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_PROCESSORS_I)); + obj_settype(processor_objdir_obj, JOVE_OBJ_OBJDIR); + obj_setvalue(processor_objdir_obj, (uintptr_t)&s_processor_objdir); + + jove_owned_obj_t *bsp_obj = obj_take(objdir_getlocal(processor_objdir_obj, 0)); + init_processor(bsp, bsp_obj); + + obj_release(bsp_obj); + obj_release(processor_objdir_obj); + } +} + +void *processor_current(void) +{ + return (processor_t*)msr_get_gs_base(); +} + +jove_obj_t *processor_objdir(void *processor) +{ + return ((processor_t*)processor)->pcb->rootdir; +} diff --git a/arch/x86_64/hal/smp.h b/arch/x86_64/hal/smp.h new file mode 100644 index 0000000..68e420f --- /dev/null +++ b/arch/x86_64/hal/smp.h @@ -0,0 +1,18 @@ +#ifndef _JOVE_x86_64_HAL_SMP_H +#define _JOVE_x86_64_HAL_SMP_H 1 + +#include "gdt.h" +#include "process.h" +#include "hal/smp.h" + +typedef struct processor +{ + struct gdt_entry gdt[GDT_TSS_HI+1]; + struct tss tss; + + pcb_t *pcb; +} processor_t; + +void smp_init_bsp(void); + +#endif diff --git a/arch/x86_64/lib/printf.c b/arch/x86_64/lib/printf.c new file mode 100644 index 0000000..42ee568 --- /dev/null +++ b/arch/x86_64/lib/printf.c @@ -0,0 +1,25 @@ +#include "../hal/serial_com.h" +#include "lib/printf.h" +#include "lib/virtterm.h" +#include "init.h" + +int +kvprintf(const char *fmt, va_list ap) +{ + char buffer[256] = { 0 }; + int r = vsnprintf(buffer, 256, fmt, ap); + int wlen = (r > 256 ? 256 : r); + + { + jove_owned_obj_t *serial_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_SERIAL_COM_I)); + serial_com_write(serial_obj, buffer, wlen); + obj_release(serial_obj); + + jove_owned_obj_t *vt_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_VIRTTERM_I)); + vt_write(vt_obj, buffer, wlen); + + obj_release(vt_obj); + } + + return r; +} diff --git a/arch/x86_64/lock.c b/arch/x86_64/lock.c new file mode 100644 index 0000000..b010ee6 --- /dev/null +++ b/arch/x86_64/lock.c @@ -0,0 +1,18 @@ +#include "lock.h" + +extern int _kernel_panic_unlock; + +void +take_mutex(atomic_flag *lock) +{ + if(_kernel_panic_unlock) return; + while(atomic_flag_test_and_set(lock)) { + __builtin_ia32_pause(); + } +} + +void +release_mutex(atomic_flag *lock) +{ + atomic_flag_clear(lock); +} diff --git a/arch/x86_64/lock.h b/arch/x86_64/lock.h new file mode 100644 index 0000000..609ea39 --- /dev/null +++ b/arch/x86_64/lock.h @@ -0,0 +1,9 @@ +#ifndef _JOVE_x86_64_LOCK_H +#define _JOVE_x86_64_LOCK_H 1 + +#include <stdatomic.h> + +void take_mutex(atomic_flag *lock); +void release_mutex(atomic_flag *lock); + +#endif diff --git a/arch/x86_64/main.c b/arch/x86_64/main.c new file mode 100644 index 0000000..44591a5 --- /dev/null +++ b/arch/x86_64/main.c @@ -0,0 +1,48 @@ +#include "jove.h" +#include "lib/printf.h" +#include "lib/virtterm.h" +#include "lib/panic.h" +#include "../../hal/obj.h" +#include "hal/serial_com.h" +#include "hal/smp.h" +#include "hal/memory.h" +#include "hal/framebuffer.h" +#include "hal/process.h" +#include "boot/initrd.h" +#include "boot/cmdline.h" + +int errno = 0; + +PAGEALIGN jove_objdir_t _rootdir = { 0 }; + +void *_rootdir_obj = &_rootdir; + +static void kernel_process_entry(void); + +void +kernel_entry(void) +{ + obj_settype(_rootdir_obj, JOVE_OBJ_OBJDIR); + serial_com_init(); + + smp_init_bsp(); + + initrd_setup(); + + fb_init(); + vt_init(); + + cmdline_print(); + + mem_setup_untyped(); + + extern void processing_setup(void*); + processing_setup(kernel_process_entry); + hcf(); +} + +static void +kernel_process_entry(void) +{ + kpanic("Reached the end of kernel main!\n"); +} diff --git a/arch/x86_64/x86_64.c b/arch/x86_64/x86_64.c new file mode 100644 index 0000000..a478ce1 --- /dev/null +++ b/arch/x86_64/x86_64.c @@ -0,0 +1,13 @@ +#include "x86_64.h" +#include "lib/printf.h" + +void +print_state(struct cpu_state *state) +{ + kprintf("RAX: %p | RBX: %p | RCX: %p\n", state->rax, state->rbx, state->rcx); + kprintf("RDX: %p | RSI: %p | RDI: %p\n", state->rdx, state->rsi, state->rdi); + kprintf("RBP: %p\n", state->rbp); + kprintf("R8 : %p | R9 : %p | R10: %p\n", state->r8, state->r9, state->r10); + kprintf("R11: %p | R12: %p | R13: %p\n", state->r11, state->r12, state->r13); + kprintf("R14: %p | R15: %p\n", state->r14, state->r15); +} diff --git a/arch/x86_64/x86_64.h b/arch/x86_64/x86_64.h new file mode 100644 index 0000000..9a0311b --- /dev/null +++ b/arch/x86_64/x86_64.h @@ -0,0 +1,20 @@ +#ifndef _JOVE_x86_64_H +#define _JOVE_x86_64_H 1 + +#include <stdint.h> + +struct cpu_state +{ + uint64_t r15, r14, r13, r12, r11, r10, r9, r8; + uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax; +}; + +struct cpu_context +{ + struct cpu_state state; + uint64_t rsp, rip; +}; + +void print_state(struct cpu_state *state); + +#endif diff --git a/boot/cmdline.c b/boot/cmdline.c new file mode 100644 index 0000000..06a6169 --- /dev/null +++ b/boot/cmdline.c @@ -0,0 +1,65 @@ +#include "config.h" +#include "cmdline.h" +#include <stddef.h> +#include "lib/string.h" +#include "lib/printf.h" + +const char *s_cmdline = NULL; + +struct kvpair +{ + const char *key, *value; +} s_arguments[CMDLINE_MAX_ARGUMENTS] = { 0 }; +size_t s_numargs = 0; + +void +cmdline_init(char *cmdline) +{ + s_cmdline = cmdline; + size_t last_arg = 0; + const char *arg = cmdline; + + for(char *s = cmdline; *s; s++) { + if(*s == '=') { + *(s++) = 0; + s_arguments[last_arg].key = arg; + arg = s; + for(; *s && (*s != ' '); s++) { + if(*s == '"') { + s++; + for(; *s && (*s != '"'); s++); + s++; + } + } + *(s++) = 0; + s_arguments[last_arg++].value = arg; + arg = s; + } + } + s_numargs = last_arg; +} + +void +cmdline_print() +{ + for(size_t i = 0; i < s_numargs; i++) { + const char *arg_key = s_arguments[i].key; + const char *arg_value = s_arguments[i].value; + + kprintf("cmdline: %s=%s\n", arg_key, arg_value); + } +} + +const char* +cmdline_getarg(const char *key) +{ + for(size_t i = 0; i < s_numargs; i++) { + const char *arg_key = s_arguments[i].key; + const char *arg_value = s_arguments[i].value; + + if(strncmp(arg_key, key, strlen(arg_key)) == 0) { + return arg_value; + } + } + return NULL; +} diff --git a/boot/cmdline.h b/boot/cmdline.h new file mode 100644 index 0000000..aa5da43 --- /dev/null +++ b/boot/cmdline.h @@ -0,0 +1,9 @@ +#ifndef _JOVE_BOOT_CMDLINE_H +#define _JOVE_BOOT_CMDLINE_H 1 + +void cmdline_init(char *cmdline); + +void cmdline_print(void); +const char *cmdline_getarg(const char *key); + +#endif diff --git a/boot/initrd.c b/boot/initrd.c new file mode 100644 index 0000000..dc16d98 --- /dev/null +++ b/boot/initrd.c @@ -0,0 +1,72 @@ +#include "initrd.h" +#include "init.h" +#include "jove.h" +#include "lib/printf.h" +#include "lib/tar.h" +#include "hal/obj.h" +#include "hal/memory.h" + +extern uintptr_t _initrd_module; + +PAGEALIGN jove_objdir_t s_initrd_objdir = { 0 }; + +#define CHECK_IF_INITRD(obj) \ + if(obj_gettype(obj) != JOVE_OBJ_INITRD_FILE) { \ + reterr(EBADOBJ); \ + } + +int +initrd_file_name(jove_owned_obj_t *obj, const char **nameptr) +{ + CHECK_IF_INITRD(obj); + struct tar_header *file = obj_deref(obj); + *nameptr = tar_filename(file); + return 0; +} + +int +initrd_file_size(jove_owned_obj_t *obj, size_t *sizeptr) +{ + CHECK_IF_INITRD(obj); + struct tar_header *file = obj_deref(obj); + *sizeptr = tar_filesize(file); + return 0; +} + +int +initrd_file_data(jove_owned_obj_t *obj, uintptr_t *dataptr) +{ + CHECK_IF_INITRD(obj); + union tar_block *file = obj_deref(obj); + *dataptr = (uintptr_t)&file[1]; + return 0; +} + +void initrd_setup(void) +{ + kprintf("Loading initrd from bootloader:\n"); + { + jove_owned_obj_t *initrd_objdir_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_INITRD_I)); + obj_settype(initrd_objdir_obj, JOVE_OBJ_OBJDIR); + obj_setvalue(initrd_objdir_obj, (uintmax_t)&s_initrd_objdir); + + size_t initrd_files = 0; + union tar_block *block = phys_tovirt(_initrd_module); + for(;;) { + struct tar_header *header = &block->header; + if(*header->filename == 0) break; + + size_t file_size = tar_filesize(header); + kprintf("File: %s, Size: %i\n", tar_filename(header), file_size); + { + jove_owned_obj_t *initrd_file_obj = obj_take(objdir_getlocal(initrd_objdir_obj, initrd_files++)); + obj_settype(initrd_file_obj, JOVE_OBJ_INITRD_FILE); + obj_setvalue(initrd_file_obj, (uintmax_t)block); + obj_release(initrd_file_obj); + } + + block = &block[((file_size + 511) / 512) + 1]; + } + obj_release(initrd_objdir_obj); + } +} diff --git a/boot/initrd.h b/boot/initrd.h new file mode 100644 index 0000000..9b3bba9 --- /dev/null +++ b/boot/initrd.h @@ -0,0 +1,12 @@ +#ifndef _JOVE_BOOT_INITRD_H +#define _JOVE_BOOT_INITRD_H 1 + +#include "hal/obj.h" + +int initrd_file_name(jove_owned_obj_t *obj, const char **nameptr); +int initrd_file_size(jove_owned_obj_t *obj, size_t *sizeptr); +int initrd_file_data(jove_owned_obj_t *obj, uintptr_t *dataptr); + +void initrd_setup(void); + +#endif diff --git a/boot/limine/framebuffer.c b/boot/limine/framebuffer.c new file mode 100644 index 0000000..b4330bb --- /dev/null +++ b/boot/limine/framebuffer.c @@ -0,0 +1,79 @@ +#include "arch/x86_64/hal/obj.h" +#include "jove.h" +#include "lib/printf.h" +#include "limine.h" +#include "init.h" +#include "hal/framebuffer.h" + +extern struct limine_framebuffer_response *_limine_framebuffers; + +#define CHECK_IF_FB(obj) \ + if(obj_gettype(obj) != JOVE_OBJ_FRAMEBUFFER) { \ + reterr(EBADOBJ); \ + } + +size_t +fb_width(jove_owned_obj_t *obj) +{ + CHECK_IF_FB(obj); + struct limine_framebuffer *fb = obj_deref(obj); + return fb->width; +} + +size_t +fb_height(jove_owned_obj_t *obj) +{ + CHECK_IF_FB(obj); + struct limine_framebuffer *fb = obj_deref(obj); + return fb->height; +} + +int +fb_blit(jove_owned_obj_t *obj, + uint32_t *data, + size_t x, size_t y, + size_t width, size_t height) +{ + CHECK_IF_FB(obj); + struct limine_framebuffer *fb = obj_deref(obj); + + uint32_t *fb_address = fb->address; + for(size_t oline = 0; oline < height; oline++) { + size_t line = oline + y; + uint32_t *line_data = &data[oline * width]; + for(size_t ocol = 0; ocol < width; ocol++) { + size_t col = ocol + x; + fb_address[line * (fb->pitch >> 2) + col] = line_data[ocol]; + } + } + return 0; +} + +void +fb_init() +{ + if(_limine_framebuffers->framebuffer_count == 0) { + return; + } + struct limine_framebuffer *fb = _limine_framebuffers->framebuffers[0]; + size_t fb_bytes = fb->width * fb->height * (fb->bpp / 8); + void *fb_virt = fb_remap((uintptr_t)fb->address, fb_bytes); + if(fb_virt == NULL) { + kprintf("Unable to remap framebuffer.\n"); + return; + } + + kprintf("framebuffer: phys address %p\n", (uintptr_t)fb->address); + kprintf("framebuffer: virt address %p\n", fb_virt); + kprintf("framebuffer: width %ipx\n", fb->width); + kprintf("framebuffer: height %ipx\n", fb->height); + kprintf("framebuffer: %i bpp\n", fb->bpp); + + fb->address = fb_virt; + { + jove_owned_obj_t *fb_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_FRAMEBUFFER_I)); + obj_settype(fb_obj, JOVE_OBJ_FRAMEBUFFER); + obj_setvalue(fb_obj, (uintptr_t)fb); + obj_release(fb_obj); + } +} diff --git a/boot/limine/limine.h b/boot/limine/limine.h new file mode 100644 index 0000000..785d89a --- /dev/null +++ b/boot/limine/limine.h @@ -0,0 +1,575 @@ +/* BSD Zero Clause License */ + +/* Copyright (C) 2022-2025 Mintsuki and contributors. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef LIMINE_H +#define LIMINE_H 1 + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* Misc */ + +#ifdef LIMINE_NO_POINTERS +# define LIMINE_PTR(TYPE) uint64_t +#else +# define LIMINE_PTR(TYPE) TYPE +#endif + +#define LIMINE_REQUESTS_START_MARKER { 0xf6b8f4b39de7d1ae, 0xfab91a6940fcb9cf, \ + 0x785c6ed015d3e316, 0x181e920a7852b9d9 } +#define LIMINE_REQUESTS_END_MARKER { 0xadc0e0531bb10d03, 0x9572709f31764c62 } + +#define LIMINE_BASE_REVISION(N) { 0xf9562b2d5c95a6c8, 0x6a7b384944536bdc, (N) } + +#define LIMINE_BASE_REVISION_SUPPORTED(VAR) ((VAR)[2] == 0) + +#define LIMINE_LOADED_BASE_REVISION_VALID(VAR) ((VAR)[1] != 0x6a7b384944536bdc) +#define LIMINE_LOADED_BASE_REVISION(VAR) ((VAR)[1]) + +#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b + +struct limine_uuid { + uint32_t a; + uint16_t b; + uint16_t c; + uint8_t d[8]; +}; + +#define LIMINE_MEDIA_TYPE_GENERIC 0 +#define LIMINE_MEDIA_TYPE_OPTICAL 1 +#define LIMINE_MEDIA_TYPE_TFTP 2 + +struct limine_file { + uint64_t revision; + LIMINE_PTR(void *) address; + uint64_t size; + LIMINE_PTR(char *) path; + LIMINE_PTR(char *) string; + uint32_t media_type; + uint32_t unused; + uint32_t tftp_ip; + uint32_t tftp_port; + uint32_t partition_index; + uint32_t mbr_disk_id; + struct limine_uuid gpt_disk_uuid; + struct limine_uuid gpt_part_uuid; + struct limine_uuid part_uuid; +}; + +/* Boot info */ + +#define LIMINE_BOOTLOADER_INFO_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 } + +struct limine_bootloader_info_response { + uint64_t revision; + LIMINE_PTR(char *) name; + LIMINE_PTR(char *) version; +}; + +struct limine_bootloader_info_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_bootloader_info_response *) response; +}; + +/* Executable command line */ + +#define LIMINE_EXECUTABLE_CMDLINE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x4b161536e598651e, 0xb390ad4a2f1f303a } + +struct limine_executable_cmdline_response { + uint64_t revision; + LIMINE_PTR(char *) cmdline; +}; + +struct limine_executable_cmdline_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_executable_cmdline_response *) response; +}; + +/* Firmware type */ + +#define LIMINE_FIRMWARE_TYPE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x8c2f75d90bef28a8, 0x7045a4688eac00c3 } + +#define LIMINE_FIRMWARE_TYPE_X86BIOS 0 +#define LIMINE_FIRMWARE_TYPE_EFI32 1 +#define LIMINE_FIRMWARE_TYPE_EFI64 2 +#define LIMINE_FIRMWARE_TYPE_SBI 3 + +struct limine_firmware_type_response { + uint64_t revision; + uint64_t firmware_type; +}; + +struct limine_firmware_type_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_firmware_type_response *) response; +}; + +/* Stack size */ + +#define LIMINE_STACK_SIZE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d } + +struct limine_stack_size_response { + uint64_t revision; +}; + +struct limine_stack_size_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_stack_size_response *) response; + uint64_t stack_size; +}; + +/* HHDM */ + +#define LIMINE_HHDM_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b } + +struct limine_hhdm_response { + uint64_t revision; + uint64_t offset; +}; + +struct limine_hhdm_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_hhdm_response *) response; +}; + +/* Framebuffer */ + +#define LIMINE_FRAMEBUFFER_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b } + +#define LIMINE_FRAMEBUFFER_RGB 1 + +struct limine_video_mode { + uint64_t pitch; + uint64_t width; + uint64_t height; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; +}; + +struct limine_framebuffer { + LIMINE_PTR(void *) address; + uint64_t width; + uint64_t height; + uint64_t pitch; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; + uint8_t unused[7]; + uint64_t edid_size; + LIMINE_PTR(void *) edid; + /* Response revision 1 */ + uint64_t mode_count; + LIMINE_PTR(struct limine_video_mode **) modes; +}; + +struct limine_framebuffer_response { + uint64_t revision; + uint64_t framebuffer_count; + LIMINE_PTR(struct limine_framebuffer **) framebuffers; +}; + +struct limine_framebuffer_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_framebuffer_response *) response; +}; + +/* Paging mode */ + +#define LIMINE_PAGING_MODE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x95c1a0edab0944cb, 0xa4e5cb3842f7488a } + +#define LIMINE_PAGING_MODE_X86_64_4LVL 0 +#define LIMINE_PAGING_MODE_X86_64_5LVL 1 +#define LIMINE_PAGING_MODE_X86_64_MIN LIMINE_PAGING_MODE_X86_64_4LVL +#define LIMINE_PAGING_MODE_X86_64_DEFAULT LIMINE_PAGING_MODE_X86_64_4LVL + +#define LIMINE_PAGING_MODE_AARCH64_4LVL 0 +#define LIMINE_PAGING_MODE_AARCH64_5LVL 1 +#define LIMINE_PAGING_MODE_AARCH64_MIN LIMINE_PAGING_MODE_AARCH64_4LVL +#define LIMINE_PAGING_MODE_AARCH64_DEFAULT LIMINE_PAGING_MODE_AARCH64_4LVL + +#define LIMINE_PAGING_MODE_RISCV_SV39 0 +#define LIMINE_PAGING_MODE_RISCV_SV48 1 +#define LIMINE_PAGING_MODE_RISCV_SV57 2 +#define LIMINE_PAGING_MODE_RISCV_MIN LIMINE_PAGING_MODE_RISCV_SV39 +#define LIMINE_PAGING_MODE_RISCV_DEFAULT LIMINE_PAGING_MODE_RISCV_SV48 + +#define LIMINE_PAGING_MODE_LOONGARCH_4LVL 0 +#define LIMINE_PAGING_MODE_LOONGARCH_MIN LIMINE_PAGING_MODE_LOONGARCH_4LVL +#define LIMINE_PAGING_MODE_LOONGARCH_DEFAULT LIMINE_PAGING_MODE_LOONGARCH_4LVL + +struct limine_paging_mode_response { + uint64_t revision; + uint64_t mode; +}; + +struct limine_paging_mode_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_paging_mode_response *) response; + uint64_t mode; + uint64_t max_mode; + uint64_t min_mode; +}; + +/* MP */ + +#define LIMINE_MP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 } + +struct limine_mp_info; + +typedef void (*limine_goto_address)(struct limine_mp_info *); + +#if defined (__x86_64__) || defined (__i386__) + +#define LIMINE_MP_RESPONSE_X86_64_X2APIC (1 << 0) + +struct limine_mp_info { + uint32_t processor_id; + uint32_t lapic_id; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_mp_response { + uint64_t revision; + uint32_t flags; + uint32_t bsp_lapic_id; + uint64_t cpu_count; + LIMINE_PTR(struct limine_mp_info **) cpus; +}; + +#elif defined (__aarch64__) + +struct limine_mp_info { + uint32_t processor_id; + uint32_t reserved1; + uint64_t mpidr; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_mp_response { + uint64_t revision; + uint64_t flags; + uint64_t bsp_mpidr; + uint64_t cpu_count; + LIMINE_PTR(struct limine_mp_info **) cpus; +}; + +#elif defined (__riscv) && (__riscv_xlen == 64) + +struct limine_mp_info { + uint64_t processor_id; + uint64_t hartid; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_mp_response { + uint64_t revision; + uint64_t flags; + uint64_t bsp_hartid; + uint64_t cpu_count; + LIMINE_PTR(struct limine_mp_info **) cpus; +}; + +#elif defined (__loongarch__) && (__loongarch_grlen == 64) + +struct limine_mp_info { + uint64_t reserved; +}; + +struct limine_mp_response { + uint64_t cpu_count; + LIMINE_PTR(struct limine_mp_info **) cpus; +}; + +#else +#error Unknown architecture +#endif + +#define LIMINE_MP_REQUEST_X86_64_X2APIC (1 << 0) + +struct limine_mp_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_mp_response *) response; + uint64_t flags; +}; + +/* Memory map */ + +#define LIMINE_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 } + +#define LIMINE_MEMMAP_USABLE 0 +#define LIMINE_MEMMAP_RESERVED 1 +#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2 +#define LIMINE_MEMMAP_ACPI_NVS 3 +#define LIMINE_MEMMAP_BAD_MEMORY 4 +#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5 +#define LIMINE_MEMMAP_EXECUTABLE_AND_MODULES 6 +#define LIMINE_MEMMAP_FRAMEBUFFER 7 +#define LIMINE_MEMMAP_ACPI_TABLES 8 + +struct limine_memmap_entry { + uint64_t base; + uint64_t length; + uint64_t type; +}; + +struct limine_memmap_response { + uint64_t revision; + uint64_t entry_count; + LIMINE_PTR(struct limine_memmap_entry **) entries; +}; + +struct limine_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_memmap_response *) response; +}; + +/* Entry point */ + +#define LIMINE_ENTRY_POINT_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a } + +typedef void (*limine_entry_point)(void); + +struct limine_entry_point_response { + uint64_t revision; +}; + +struct limine_entry_point_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_entry_point_response *) response; + LIMINE_PTR(limine_entry_point) entry; +}; + +/* Executable File */ + +#define LIMINE_EXECUTABLE_FILE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 } + +struct limine_executable_file_response { + uint64_t revision; + LIMINE_PTR(struct limine_file *) executable_file; +}; + +struct limine_executable_file_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_executable_file_response *) response; +}; + +/* Module */ + +#define LIMINE_MODULE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee } + +#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0) +#define LIMINE_INTERNAL_MODULE_COMPRESSED (1 << 1) + +struct limine_internal_module { + LIMINE_PTR(const char *) path; + LIMINE_PTR(const char *) string; + uint64_t flags; +}; + +struct limine_module_response { + uint64_t revision; + uint64_t module_count; + LIMINE_PTR(struct limine_file **) modules; +}; + +struct limine_module_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_module_response *) response; + + /* Request revision 1 */ + uint64_t internal_module_count; + LIMINE_PTR(struct limine_internal_module **) internal_modules; +}; + +/* RSDP */ + +#define LIMINE_RSDP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c } + +struct limine_rsdp_response { + uint64_t revision; + LIMINE_PTR(void *) address; +}; + +struct limine_rsdp_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_rsdp_response *) response; +}; + +/* SMBIOS */ + +#define LIMINE_SMBIOS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee } + +struct limine_smbios_response { + uint64_t revision; + uint64_t entry_32; + uint64_t entry_64; +}; + +struct limine_smbios_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_smbios_response *) response; +}; + +/* EFI system table */ + +#define LIMINE_EFI_SYSTEM_TABLE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc } + +struct limine_efi_system_table_response { + uint64_t revision; + uint64_t address; +}; + +struct limine_efi_system_table_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_system_table_response *) response; +}; + +/* EFI memory map */ + +#define LIMINE_EFI_MEMMAP_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x7df62a431d6872d5, 0xa4fcdfb3e57306c8 } + +struct limine_efi_memmap_response { + uint64_t revision; + LIMINE_PTR(void *) memmap; + uint64_t memmap_size; + uint64_t desc_size; + uint64_t desc_version; +}; + +struct limine_efi_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_memmap_response *) response; +}; + +/* Date at boot */ + +#define LIMINE_DATE_AT_BOOT_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 } + +struct limine_date_at_boot_response { + uint64_t revision; + int64_t timestamp; +}; + +struct limine_date_at_boot_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_date_at_boot_response *) response; +}; + +/* Executable address */ + +#define LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 } + +struct limine_executable_address_response { + uint64_t revision; + uint64_t physical_base; + uint64_t virtual_base; +}; + +struct limine_executable_address_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_executable_address_response *) response; +}; + +/* Device Tree Blob */ + +#define LIMINE_DTB_REQUEST_ID { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 } + +struct limine_dtb_response { + uint64_t revision; + LIMINE_PTR(void *) dtb_ptr; +}; + +struct limine_dtb_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_dtb_response *) response; +}; + +/* RISC-V Boot Hart ID */ + +#define LIMINE_RISCV_BSP_HARTID_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x1369359f025525f9, 0x2ff2a56178391bb6 } + +struct limine_riscv_bsp_hartid_response { + uint64_t revision; + uint64_t bsp_hartid; +}; + +struct limine_riscv_bsp_hartid_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_riscv_bsp_hartid_response *) response; +}; + +/* Bootloader Performance */ + +#define LIMINE_BOOTLOADER_PERFORMANCE_REQUEST_ID { LIMINE_COMMON_MAGIC, 0x6b50ad9bf36d13ad, 0xdc4c7e88fc759e17 } + +struct limine_bootloader_performance_response { + uint64_t revision; + uint64_t reset_usec; + uint64_t init_usec; + uint64_t exec_usec; +}; + +struct limine_bootloader_performance_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_bootloader_performance_response *) response; +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/boot/limine/memorymap.c b/boot/limine/memorymap.c new file mode 100644 index 0000000..905ff3a --- /dev/null +++ b/boot/limine/memorymap.c @@ -0,0 +1,73 @@ +#include "hal/obj.h" +#include "limine.h" +#include "hal/memory.h" +#include "hal/obj.h" +#include "lib/panic.h" +#include "init.h" +#include "lib/printf.h" + +extern struct limine_memmap_response *_limine_memmap_resp; +static jove_objdir_t s_untyped_objdir; + +#define MEMMAP_MAX_ENTRIES 255 + +static const char *limine_mmap_entry_type_str[9] = { + "USABLE", + "RESERVED", + "ACPI RECLAIMABLE", + "ACPI NVS", + "BAD", + "LIMINE RECLAIMABLE", + "KERNEL", + "FRAMEBUFFER", + "ACPI TABLES" +}; + +void +mem_setup_untyped(void) +{ + { + jove_owned_obj_t *untyped_objdir_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_UNTYPED_I)); + obj_settype(untyped_objdir_obj, JOVE_OBJ_OBJDIR); + obj_setvalue(untyped_objdir_obj, (uintptr_t)&s_untyped_objdir); + obj_release(untyped_objdir_obj); + } + + if(_limine_memmap_resp == NULL) { + kpanic("Limine failed to provide memory map.\n"); + } + + kprintf("Memory map provided by Limine:\n"); + + size_t untyped_i = 0; + uintptr_t highest_phys = 0; + for(size_t i = 0; i < _limine_memmap_resp->entry_count; i++) { + struct limine_memmap_entry *entry = _limine_memmap_resp->entries[i]; + kprintf("Limine: %p : %p %s\n", entry->base, entry->length, limine_mmap_entry_type_str[entry->type]); + + if(entry->type == LIMINE_MEMMAP_USABLE || + entry->type == LIMINE_MEMMAP_ACPI_RECLAIMABLE || + entry->type == LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE) + { + + if(entry->base == 0) continue; + if(entry->base + entry->length > highest_phys) highest_phys = entry->base + entry->length; + + { + jove_owned_obj_t *untyped_obj = obj_take(&s_untyped_objdir.entries[untyped_i++]); + obj_settype(untyped_obj, JOVE_OBJ_UNTYPED); + obj_setvalue(untyped_obj, entry->base); + + jove_untyped_t *untyped_data = obj_deref(untyped_obj); + untyped_data->limit = entry->length; + obj_release(untyped_obj); + } + + if(untyped_i > MEMMAP_MAX_ENTRIES){ + kprintf("!!!Provided memory map exceeds kernel limits. Some memory may not be accessable!!!"); + break; + } + } + } + kprintf("Highest physical address: %p\n", highest_phys); +} diff --git a/boot/limine/start.c b/boot/limine/start.c new file mode 100644 index 0000000..b371f92 --- /dev/null +++ b/boot/limine/start.c @@ -0,0 +1,81 @@ +#include <stdint.h> +#include <stddef.h> + +#include "boot/cmdline.h" +#include "hal/framebuffer.h" +#include "limine.h" + +void _start(void); + +#define LIMINE_REQUEST_SECTION __attribute__((section(".limine_requests"))) + +LIMINE_REQUEST_SECTION +static volatile uint64_t limine_base_revision[] = LIMINE_BASE_REVISION(4); + +LIMINE_REQUEST_SECTION +static volatile uint64_t limine_requests_start_marker[] = LIMINE_REQUESTS_START_MARKER; + +LIMINE_REQUEST_SECTION +static volatile struct limine_executable_cmdline_request cmdline_req = { + .id = LIMINE_EXECUTABLE_CMDLINE_REQUEST_ID, + .revision = 0, .response = NULL +}; + +LIMINE_REQUEST_SECTION +static volatile struct limine_entry_point_request entry_point_req = { + .id = LIMINE_ENTRY_POINT_REQUEST_ID, + .revision = 0, .response = NULL, + .entry = _start +}; + +LIMINE_REQUEST_SECTION +static volatile struct limine_executable_address_request executable_address_req = { + .id = LIMINE_EXECUTABLE_ADDRESS_REQUEST_ID, + .revision = 0, .response = NULL +}; + +LIMINE_REQUEST_SECTION +static volatile struct limine_memmap_request memmap_req = { + .id = LIMINE_MEMMAP_REQUEST_ID, + .revision = 0, .response = NULL +}; + +LIMINE_REQUEST_SECTION +static volatile struct limine_module_request module_req = { + .id = LIMINE_MODULE_REQUEST_ID, + .revision = 0, .response = NULL +}; + +LIMINE_REQUEST_SECTION +static volatile struct limine_framebuffer_request framebuffer_request = { + .id = LIMINE_FRAMEBUFFER_REQUEST_ID, + .revision = 0, .response = NULL +}; + +LIMINE_REQUEST_SECTION +static volatile uint64_t limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER; + +void *_kernel_physptr = NULL; +void *_initrd_module = NULL; +struct limine_framebuffer_response *_limine_framebuffers; +struct limine_memmap_response *_limine_memmap_resp = NULL; + +__attribute__((noreturn)) +void +_start(void) +{ + _kernel_physptr = (void*)executable_address_req.response->physical_base; + _limine_memmap_resp = memmap_req.response; + _limine_framebuffers = framebuffer_request.response; + + if(module_req.response->module_count > 0) { + _initrd_module = module_req.response->modules[0]->address; + } + + cmdline_init(cmdline_req.response->cmdline); + + __attribute__((noreturn)) + extern void kernel_entry(void); + + kernel_entry(); +} diff --git a/config.h b/config.h new file mode 100644 index 0000000..35f4896 --- /dev/null +++ b/config.h @@ -0,0 +1,12 @@ +#ifndef _JOVE_CONFIG_H +#define _JOVE_CONFIG_H 1 + +#define CMDLINE_MAX_ARGUMENTS 128 + +#define SMP_PROCESSORS_MAX 8 +#define PHYS_BIGPAGES_MAX 512 + +#define FRAMEBUFFER_MAX_WIDTH 1920 +#define FRAMEBUFFER_MAX_HEIGHT 1080 + +#endif diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..16e3859 --- /dev/null +++ b/config.mk @@ -0,0 +1,21 @@ +CFLAGS = \ + -ffreestanding \ + -nostdlib \ + -fno-pie \ + -fno-pic \ + -g \ + -MD \ + -D__$(TARGET_MACHINE)__ \ + -D__$(TARGET_BOOTLOADER)__ \ + -Iinclude \ + -I. + +LDFLAGS = -nostdlib \ + -T link/$(TARGET_TRIPLET).ld + +ifeq "$(TARGET_MACHINE)" "x86_64" + CFLAGS += -m64 \ + -mno-red-zone \ + -mcmodel=kernel \ + -mfsgsbase +endif diff --git a/hal/framebuffer.h b/hal/framebuffer.h new file mode 100644 index 0000000..e070889 --- /dev/null +++ b/hal/framebuffer.h @@ -0,0 +1,14 @@ +#ifndef _JOVE_HAL_FRAMEBUFFER_H +#define _JOVE_HAL_FRAMEBUFFER_H 1 + +#include <stddef.h> +#include "hal/obj.h" + +size_t fb_width(jove_owned_obj_t *fb); +size_t fb_height(jove_owned_obj_t *fb); +int fb_blit(jove_owned_obj_t *obj, uint32_t *data, size_t x, size_t y, size_t width, size_t height); + +void *fb_remap(uintptr_t fb_address, size_t fb_size); +void fb_init(void); + +#endif diff --git a/hal/memory.h b/hal/memory.h new file mode 100644 index 0000000..4d866d0 --- /dev/null +++ b/hal/memory.h @@ -0,0 +1,16 @@ +#ifndef _JOVE_HAL_MEMORY_H +#define _JOVE_HAL_MEMORY_H 1 + +#include <stddef.h> +#include <stdint.h> + +typedef struct jove_obj_untyped +{ + size_t limit; +} jove_untyped_t; + +void mem_setup_untyped(void); + +void *phys_tovirt(uintptr_t phys); + +#endif diff --git a/hal/obj.h b/hal/obj.h new file mode 100644 index 0000000..c0b2a4d --- /dev/null +++ b/hal/obj.h @@ -0,0 +1,22 @@ +#ifndef _JOVE_HAL_OBJ_H +#define _JOVE_HAL_OBJ_H 1 + +#include <stddef.h> + +enum +{ + JOVE_OBJ_NONE = 0, + JOVE_OBJ_UNTYPED, + JOVE_OBJ_OBJDIR, + JOVE_OBJ_PROCESSOR, + JOVE_OBJ_PROCESS, + JOVE_OBJ_INITRD_FILE, + JOVE_OBJ_FRAMEBUFFER, + JOVE_OBJ_VIRTTERM +}; + +#ifdef __x86_64__ +#include "arch/x86_64/hal/obj.h" +#endif + +#endif diff --git a/hal/smp.h b/hal/smp.h new file mode 100644 index 0000000..3718f46 --- /dev/null +++ b/hal/smp.h @@ -0,0 +1,10 @@ +#ifndef _JOVE_HAL_SMP_H +#define _JOVE_HAL_SMP_H 1 + +#include "obj.h" + +void *processor_current(void); + +jove_obj_t *processor_objdir(void *processor); + +#endif @@ -0,0 +1,15 @@ +#ifndef _JOVE_INIT_H +#define _JOVE_INIT_H 1 + +extern void *_rootdir_obj; + +#define ROOTDIR_PROCESSORS_I 0x0 +#define ROOTDIR_UNTYPED_I 0x01 +#define ROOTDIR_PCB_I 0x02 +#define ROOTDIR_INITRD_I 0x03 + +#define ROOTDIR_SERIAL_COM_I 0x80 +#define ROOTDIR_FRAMEBUFFER_I 0x81 +#define ROOTDIR_VIRTTERM_I 0x82 + +#endif @@ -0,0 +1,20 @@ +#ifndef _JOVE_H +#define _JOVE_H 1 + +#define NORETURN __attribute__((noreturn)) +#define PACKED __attribute__((packed)) + +#define ALIGN(n) __attribute__((aligned(n))) +#define PAGEALIGN __attribute__((aligned(0x1000))) + +NORETURN void hcf(void); + +extern int errno; +#define reterr(e) \ + errno = e; \ + return 0 + +#define EBADOBJ -1 +#define EOOB -2 + +#endif diff --git a/lib/panic.c b/lib/panic.c new file mode 100644 index 0000000..3b39fbf --- /dev/null +++ b/lib/panic.c @@ -0,0 +1,18 @@ +#include "panic.h" +#include "lib/printf.h" + +int _kernel_panic_unlock = 0; + +void +kpanic(const char *fmt, ...) +{ + _kernel_panic_unlock = 1; + + va_list ap; + va_start(ap, fmt); + + kvprintf(fmt, ap); + + va_end(ap); + hcf(); +} diff --git a/lib/panic.h b/lib/panic.h new file mode 100644 index 0000000..8f3b409 --- /dev/null +++ b/lib/panic.h @@ -0,0 +1,8 @@ +#ifndef _JOVE_LIB_PANIC_H +#define _JOVE_LIB_PANIC_H 1 + +#include "jove.h" + +NORETURN void kpanic(const char *fmt, ...); + +#endif diff --git a/lib/printf.c b/lib/printf.c new file mode 100644 index 0000000..4c26fe4 --- /dev/null +++ b/lib/printf.c @@ -0,0 +1,138 @@ +#include "printf.h" +#include "string.h" +#include "init.h" +#include "hal/obj.h" +#include <stdint.h> + +int kprintf(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + int r = kvprintf(fmt, ap); + va_end(ap); + return r; +} + +#define SPRINTF_PUTC(str, size, i, c) \ + if(str && i < size) str[i] = (c); \ + i++ + +static int +convert_as_int( + char *str, + size_t size, + int stri, + int field_width, + uintmax_t value, + int radix, + int unsign) +{ + unsigned digits = 0; + int ostri = stri; + if((intmax_t)value < 0 && !unsign) { + SPRINTF_PUTC(str, size, stri, '-'); + value = 0 - (intmax_t)value; + } + + for(uintmax_t i = value; i != 0; i /= radix) digits++; + if(value == 0) digits++; + + if(field_width < digits) field_width = digits; + for(uintmax_t i = value, digiti = 0; digiti < digits; i /= radix) { + char i_mod = (char)(i % radix); + int stri_digiti = stri + (field_width - digiti) - 1; + + SPRINTF_PUTC(str, size, stri_digiti, + (i_mod > 9 ? (i_mod + 'a' - 10) : (i_mod + '0'))); + digiti++; + } + + return field_width + (stri - ostri) + 1; +} + +int +vsnprintf( + char *str, size_t size, + const char *fmt, va_list ap) +{ + int stri = 0; + for(const char *fmtc = fmt; *fmtc; fmtc++) { + if(*fmtc != '%') { + SPRINTF_PUTC(str, size, stri, *fmtc); + continue; + } + fmtc++; + + //TODO: other format specifiers. + int field_width = 0; + char field_pad = ' '; + + int lenspec = 4; + + int radix = 10; + int unsign = 0; + int caps = 0; + switch(*fmtc) { + case 's': + goto string_conversion; + case 'b': + radix = 2; + goto int_conversion; + break; + case 'o': + radix = 8; + goto int_conversion; + break; + case 'p': + lenspec = sizeof(uintptr_t); + field_width = lenspec * 2; + field_pad = '0'; + case 'X': + caps = 1; + case 'x': + unsign = 1; + radix = 16; + goto int_conversion; + break; + case 'u': + unsign = 1; + case 'd': + case 'i': + goto int_conversion; + break; + } +string_conversion: + { + const char *strarg = va_arg(ap, const char*); + for(const char *strargc = strarg; *strargc; strargc++) { + SPRINTF_PUTC(str, size, stri, *strargc); + } + } continue; +int_conversion: + { + uintmax_t value = 0; + switch(lenspec) { + case 1: value = (uintmax_t)(int8_t)va_arg(ap, int); break; + case 2: value = (uintmax_t)(int16_t)va_arg(ap, int); break; + default: + case 4: value = (uintmax_t)va_arg(ap, unsigned int); break; + case 8: value = (uintmax_t)va_arg(ap, uintmax_t); break; + } + size_t pad_stri = stri; + for(size_t i = 0; i < field_width; i++) { + SPRINTF_PUTC(str, size, pad_stri, field_pad); + } + + int advance = convert_as_int(str, size, stri, field_width, value, radix, unsign); + if(caps && str) { + for(int i = 0; i < advance; i++) { + int stra = stri + i; + if(stra < size) str[stra] = c_toupper(str[stra]); + } + } + stri += advance; + } continue; + } + if(str && stri < size) str[stri] = 0; + return stri; +} diff --git a/lib/printf.h b/lib/printf.h new file mode 100644 index 0000000..a132b39 --- /dev/null +++ b/lib/printf.h @@ -0,0 +1,12 @@ +#ifndef _JOVE_LIB_PRINTF_H +#define _JOVE_LIB_PRINTF_H 1 + +#include <stdarg.h> +#include <stddef.h> + +int kprintf(const char *fmt, ...); +int kvprintf(const char *fmt, va_list ap); + +int vsnprintf(char *str, size_t size, const char *fmt, va_list ap); + +#endif diff --git a/lib/psf.c b/lib/psf.c new file mode 100644 index 0000000..407420e --- /dev/null +++ b/lib/psf.c @@ -0,0 +1,8 @@ +#include "psf.h" + +uint8_t* +psf_glyph(struct psf1_header *header, uint8_t glyph) +{ + uint8_t *glyph_bitmap = header->bitmap; + return &glyph_bitmap[(size_t)glyph * header->char_height]; +} diff --git a/lib/psf.h b/lib/psf.h new file mode 100644 index 0000000..b6b8cec --- /dev/null +++ b/lib/psf.h @@ -0,0 +1,19 @@ +#ifndef _JOVE_LIB_PSF_H +#define _JOVE_LIB_PSF_H 1 + +#include <stddef.h> +#include <stdint.h> + +#define PSF1_FONT_MAGIC 0x0436 + +struct psf1_header +{ + uint16_t magic; + uint8_t mode; + uint8_t char_height; + uint8_t bitmap[]; +}; + +uint8_t *psf_glyph(struct psf1_header *header, uint8_t glyph); + +#endif diff --git a/lib/string.c b/lib/string.c new file mode 100644 index 0000000..28436d5 --- /dev/null +++ b/lib/string.c @@ -0,0 +1,50 @@ +#include "string.h" + +void *memset(void *s, int c, size_t n) +{ + for(size_t i = 0; i < n; i++) { + ((char*)s)[i] = c; + } + return s; +} +void *memcpy(void *a, const void *b, size_t n) +{ + for(size_t i = 0; i < n; i++) { + ((char*)a)[i] = ((const char*)b)[i]; + } + return a; +} + +int memcmp(const void *a, const void *b, size_t n) +{ + const char *ca = a; + const char *cb = b; + for(size_t i = 0; i < n; i++) { + if(ca[i] != cb[i]) return ca[i] - cb[i]; + } + return 0; +} + +size_t strlen(const char *s) +{ + size_t i = 0; + for(; s[i]; i++); + return i; +} + +char c_toupper(char c) { + return (c > 0x60 && c < 0x7B) ? (c - 0x20) : c; +} + +char *str_toupper(char *s, size_t n) +{ + for(size_t i = 0; i < n; i++) { + s[i] = c_toupper(s[i]); + } + return s; +} + +int strncmp(const char *s1, const char *s2, size_t n) +{ + return memcmp(s1, s2, n); +} diff --git a/lib/string.h b/lib/string.h new file mode 100644 index 0000000..bdcb0dd --- /dev/null +++ b/lib/string.h @@ -0,0 +1,16 @@ +#ifndef _JOVE_STRING_H +#define _JOVE_STRING_H 1 + +#include <stddef.h> + +void *memset(void *s, int c, size_t n); +void *memcpy(void *a, const void *b, size_t n); +int memcmp(const void *a, const void *b, size_t n); + +size_t strlen(const char *s); +char c_toupper(char c); +char *str_toupper(char *s, size_t n); + +int strncmp(const char *s1, const char *s2, size_t n); + +#endif diff --git a/lib/tar.c b/lib/tar.c new file mode 100644 index 0000000..58b94b4 --- /dev/null +++ b/lib/tar.c @@ -0,0 +1,16 @@ +#include "tar.h" + +const char* +tar_filename(struct tar_header *file) +{ + return file->filename; +} + +int +tar_filesize(struct tar_header *file) +{ + int r = 0; + const char *oct = file->size; + for(; *oct; oct++) r = (r * 8) + (*oct - '0'); + return r; +} diff --git a/lib/tar.h b/lib/tar.h new file mode 100644 index 0000000..d2435ac --- /dev/null +++ b/lib/tar.h @@ -0,0 +1,25 @@ +#ifndef _JOVE_HAL_TAR_H +#define _JOVE_HAL_TAR_H 1 + +struct tar_header +{ + char filename[100]; + char mode[8]; + char uid[8]; + char gid[8]; + char size[12]; + char modtime[12]; + char checksum[8]; + char type; +}; + +union tar_block +{ + struct tar_header header; + char data[512]; +}; + +const char *tar_filename(struct tar_header *header); +int tar_filesize(struct tar_header *header); + +#endif diff --git a/lib/virtterm.c b/lib/virtterm.c new file mode 100644 index 0000000..de43c51 --- /dev/null +++ b/lib/virtterm.c @@ -0,0 +1,131 @@ +#include "virtterm.h" +#include "boot/cmdline.h" +#include "boot/initrd.h" +#include "hal/obj.h" +#include "init.h" +#include "jove.h" +#include "hal/framebuffer.h" +#include "lib/printf.h" +#include "lib/psf.h" +#include "lib/string.h" + +struct psf1_header *s_font = NULL; + +struct virtterm s_init_vtty = { 0 }; + +static void +vt_blit(struct virtterm *vtty, jove_owned_obj_t *fb, const uint8_t *glyph) +{ + uint32_t buffer[s_font->char_height << 3]; + size_t cursor_x = vtty->cursor_col * 9; + size_t cursor_y = vtty->cursor_row * s_font->char_height; + + for(size_t y = 0; y < s_font->char_height; y++) { + uint8_t mask = 1 << 7; + for(size_t x = 0; x < 8; x++) { + buffer[x + (y << 3)] = glyph[y] & mask ? vtty->cursor_fg : vtty->cursor_bg; + mask >>=1; + } + } + fb_blit(fb, buffer, cursor_x, cursor_y, 8, s_font->char_height); + vtty->cursor_col++; +} + +static void +vt_putc(struct virtterm *vtty, jove_owned_obj_t *fb, char c) +{ + const uint8_t *glyph = &s_font->bitmap[(size_t)c * s_font->char_height]; + + switch(c) { + case '\n': + vtty->cursor_col = 0; + vtty->cursor_row++; + break; + default: + vt_blit(vtty, fb, glyph); + break; + } + + if(vtty->cursor_col >= vtty->width) { + vtty->cursor_col = 0; + vtty->cursor_row++; + } + if(vtty->cursor_row >= vtty->height) { + vtty->cursor_row = 0; + } +} + +int +vt_write(jove_owned_obj_t *obj, const char *s, size_t n) +{ + if(obj_gettype(obj) != JOVE_OBJ_VIRTTERM) { + reterr(EBADOBJ); + } + + struct virtterm *vtty = obj_deref(obj); + jove_owned_obj_t *fb_obj = obj_take(objdir_getlocal(_rootdir_obj, vtty->fb_obj)); + if(obj_gettype(fb_obj) != JOVE_OBJ_FRAMEBUFFER) { + obj_release(fb_obj); + reterr(EBADOBJ); + } + + for(size_t i = 0; i < n; i++) { + vt_putc(vtty, fb_obj, s[i]); + } + + obj_release(fb_obj); + return 0; +} + +void +vt_init() +{ + const char *font_path = cmdline_getarg("font"); + if(font_path == NULL) { + kprintf("Kernel commandline is missing 'font' argument. VTT is disabled."); + return; + } + + jove_owned_obj_t *initrd_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_INITRD_I)); + if(obj_gettype(initrd_obj) != JOVE_OBJ_OBJDIR) { + kprintf("Initrd is not present. VTT is disabled.\n"); + obj_release(initrd_obj); + return; + } + + jove_owned_obj_t *file_obj; + size_t file_i = 0; + while((file_obj = obj_take(objdir_getlocal(initrd_obj, file_i++)))) { + const char *filename = NULL; + if(initrd_file_name(file_obj, &filename) != 0) { + break; + } + if(strncmp(font_path, filename, strlen(font_path)) == 0) { + initrd_file_data(file_obj, (uintptr_t*)&s_font); + break; + } + obj_release(file_obj); + } + obj_release(file_obj); + obj_release(initrd_obj); + + if(s_font == NULL) { + kprintf("Could not find file %s in initrd. VTT is disabled.\n", font_path); + return; + } + s_init_vtty.fb_obj = ROOTDIR_FRAMEBUFFER_I; + s_init_vtty.cursor_fg = 0x00FFFFFF; + + + { + jove_owned_obj_t *fb_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_FRAMEBUFFER_I)); + s_init_vtty.width = fb_width(fb_obj) / 9; + s_init_vtty.height = fb_height(fb_obj) / s_font->char_height; + obj_release(fb_obj); + + jove_owned_obj_t *vt_obj = obj_take(objdir_getlocal(_rootdir_obj, ROOTDIR_VIRTTERM_I)); + obj_settype(vt_obj, JOVE_OBJ_VIRTTERM); + obj_setvalue(vt_obj, (uintmax_t)&s_init_vtty); + obj_release(vt_obj); + } +} diff --git a/lib/virtterm.h b/lib/virtterm.h new file mode 100644 index 0000000..08e22e9 --- /dev/null +++ b/lib/virtterm.h @@ -0,0 +1,19 @@ +#ifndef _JOVE_LIB_VIRTTERM_H +#define _JOVE_LIB_VIRTTERM_H 1 + +#include <stddef.h> +#include "hal/obj.h" + +struct virtterm +{ + size_t fb_obj; + size_t cursor_col, cursor_row; + size_t width, height; + uint32_t cursor_fg, cursor_bg; +}; + +int vt_write(jove_owned_obj_t *obj, const char *s, size_t n); + +void vt_init(void); + +#endif diff --git a/link/x86_64-elf.ld b/link/x86_64-elf.ld new file mode 100644 index 0000000..6c38b47 --- /dev/null +++ b/link/x86_64-elf.ld @@ -0,0 +1,60 @@ +OUTPUT_FORMAT(elf64-x86-64) +OUTPUT_ARCH(i386:x86-64) + +ENTRY(_start) + +PAGESIZE = CONSTANT(MAXPAGESIZE); + +PHDRS +{ + limine_requests PT_LOAD; + text PT_LOAD; + rodata PT_LOAD; + data PT_LOAD; + bss PT_LOAD; +} + +SECTIONS +{ + . = 0xFFFFFFFF80000000; + _kernel_start = .; + + _kernel_text_start = .; + .text : { + *(.init) + *(.text .text.*) + *(.fini) + } :text + _kernel_text_end = .; + . = ALIGN(PAGESIZE); + + _kernel_rodata_start = .; + .rodata : { + *(.rodata .rodata.*) + } :rodata + _kernel_rodata_end = .; + . = ALIGN(PAGESIZE); + + _kernel_data_start = .; + .data : { + *(.data .data.*) + *(.limine_requests) + } :data + _kernel_data_end = .; + . = ALIGN(PAGESIZE); + + _kernel_bss_start = .; + .bss : { + *(COMMON) + *(.bss .bss.*) + } :bss + _kernel_bss_end = .; + + /DISCARD/ : { + *(.eh_frame*) + *(.note .note.*) + } + + _kernel_end = .; +} + @@ -0,0 +1,9 @@ +#include "jove.h" + +void +hcf(void) +{ + for(;;) { + __asm__("hlt"); + } +} |
