diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arch.h | 8 | ||||
-rw-r--r-- | arch/x86_64/cpu.h | 13 | ||||
-rw-r--r-- | arch/x86_64/elf.c | 47 | ||||
-rw-r--r-- | arch/x86_64/elf.d | 2 | ||||
-rw-r--r-- | arch/x86_64/elf.h | 78 | ||||
-rw-r--r-- | arch/x86_64/gdt.c | 125 | ||||
-rw-r--r-- | arch/x86_64/gdt.d | 2 | ||||
-rw-r--r-- | arch/x86_64/idt.c | 70 | ||||
-rw-r--r-- | arch/x86_64/idt.d | 2 | ||||
-rw-r--r-- | arch/x86_64/int.S | 131 | ||||
-rw-r--r-- | arch/x86_64/loadgdt.S | 24 | ||||
-rw-r--r-- | arch/x86_64/paging.c | 202 | ||||
-rw-r--r-- | arch/x86_64/paging.d | 2 | ||||
-rw-r--r-- | arch/x86_64/paging.h | 44 | ||||
-rw-r--r-- | arch/x86_64/savestate.S | 39 | ||||
-rw-r--r-- | arch/x86_64/serial.c | 62 | ||||
-rw-r--r-- | arch/x86_64/serial.d | 2 | ||||
-rw-r--r-- | arch/x86_64/serial.h | 27 | ||||
-rw-r--r-- | arch/x86_64/syscall.c | 1 | ||||
-rw-r--r-- | arch/x86_64/syscall.d | 1 | ||||
-rw-r--r-- | arch/x86_64/syscall_setup.S | 37 | ||||
-rw-r--r-- | arch/x86_64/tables.c | 8 | ||||
-rw-r--r-- | arch/x86_64/tables.d | 1 | ||||
-rw-r--r-- | arch/x86_64/tables.h | 60 | ||||
-rw-r--r-- | arch/x86_64/thread.c | 85 | ||||
-rw-r--r-- | arch/x86_64/thread.d | 3 | ||||
-rw-r--r-- | arch/x86_64/tss.h | 18 | ||||
-rw-r--r-- | arch/x86_64/uart.h | 19 | ||||
-rw-r--r-- | arch/x86_64/umode_enter.S | 8 |
29 files changed, 1121 insertions, 0 deletions
diff --git a/arch/arch.h b/arch/arch.h new file mode 100644 index 0000000..6e569fd --- /dev/null +++ b/arch/arch.h @@ -0,0 +1,8 @@ +#ifndef JOVE_ARCH_H +#define JOVE_ARCH_H 1 + +extern void serial_setup(void); + +extern void arch_tables_setup(void); + +#endif diff --git a/arch/x86_64/cpu.h b/arch/x86_64/cpu.h new file mode 100644 index 0000000..942c8d9 --- /dev/null +++ b/arch/x86_64/cpu.h @@ -0,0 +1,13 @@ +#ifndef ARCH_x86_64_CPU_H +#define ARCH_x86_64_CPU_H 1 + +#include <stdint.h> + +struct Registers +{ + uint64_t r15, r14, r13, r12, r11, r10, r9, r8; + uint64_t bp, di, si, dx, cx, bx, ax; + uint64_t ip, cs, flags, sp, ss; +}; + +#endif diff --git a/arch/x86_64/elf.c b/arch/x86_64/elf.c new file mode 100644 index 0000000..60b8f13 --- /dev/null +++ b/arch/x86_64/elf.c @@ -0,0 +1,47 @@ +#include "elf.h" +#include "lib/string.h" +#include "usr/elf.h" +#include "io/log.h" +#include "mem/memory.h" + +void* +elf_load(const void *data, size_t len) +{ + if(data == NULL) return NULL; + if(len < 4) return NULL; + + struct ELF_header *ehdr = (struct ELF_header*)data; + if(ehdr->e_ident[EI_MAG0] != E_IDENT_MAG0 && + ehdr->e_ident[EI_MAG1] != E_IDENT_MAG1 && + ehdr->e_ident[EI_MAG2] != E_IDENT_MAG2 && + ehdr->e_ident[EI_MAG3] != E_IDENT_MAG3) + return NULL; + + if(ehdr->e_ident[EI_CLASS] != E_IDENT_CLASS64) { + klogf("Jove does not support ELF files of class CLASS32\n"); + return NULL; + } + + if(ehdr->e_type != ET_EXEC) { + klogf("Jove does not support ELF files other than ET_EXEC\n"); + return NULL; + } + + uint64_t entry = ehdr->e_entry; + + size_t phdrc = ehdr->e_phnum; + struct ELF_phdr *phdrs = (struct ELF_phdr*)((uintptr_t)data + ehdr->e_phoff); + + for(size_t phdri = 0; phdri < phdrc; phdri++) + { + struct ELF_phdr *phdr = &phdrs[phdri]; + void *pdata = (void*)phdr->p_vaddr; + + mem_ensure_range(phdr->p_vaddr, phdr->p_vaddr + phdr->p_memsz, true, true); + if(phdr->p_type == PT_LOAD) + { + memcpy(pdata, (void*)((uintptr_t)data + phdr->p_offset), phdr->p_filesz); + } + } + return (void*)entry; +} diff --git a/arch/x86_64/elf.d b/arch/x86_64/elf.d new file mode 100644 index 0000000..f57bbe6 --- /dev/null +++ b/arch/x86_64/elf.d @@ -0,0 +1,2 @@ +arch/x86_64/elf.o: arch/x86_64/elf.c arch/x86_64/elf.h lib/string.h \ + usr/elf.h io/log.h mem/memory.h mem/slab.h diff --git a/arch/x86_64/elf.h b/arch/x86_64/elf.h new file mode 100644 index 0000000..ebcd228 --- /dev/null +++ b/arch/x86_64/elf.h @@ -0,0 +1,78 @@ +#ifndef JOVE_ARCH_x86_64_ELF_H +#define JOVE_ARCH_x86_64_ELF_H 1 + +#include <stdint.h> + +#define EI_MAG0 0 +#define EI_MAG1 1 +#define EI_MAG2 2 +#define EI_MAG3 3 +#define EI_CLASS 4 +#define EI_DATA 5 +#define EI_VERSION 6 +#define EI_OSABI 7 +#define EI_ABIVERSION 8 +#define EI_PAD 9 + +#define E_IDENT_MAG0 0x7F +#define E_IDENT_MAG1 'E' +#define E_IDENT_MAG2 'L' +#define E_IDENT_MAG3 'F' + +#define E_IDENT_CLASS32 1 +#define E_IDENT_CLASS64 2 + +#define ET_EXEC 0x02 + +struct ELF_header +{ + uint8_t e_ident[15]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint64_t e_entry; + uint64_t e_phoff; + uint64_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +#define PT_NULL 0 +#define PT_LOAD 1 + +#define PF_X 1 +#define PF_W 2 +#define PF_R 4 + +struct ELF_phdr +{ + uint32_t p_type; + uint32_t p_flags; + uint64_t p_offset; + uint64_t p_vaddr; + uint64_t p_paddr; + uint64_t p_filesz; + uint64_t p_memsz; + uint64_t p_align; +}; + +struct ELF_shdr +{ + uint32_t sh_name; + uint32_t sh_type; + uint64_t sh_flags; + uint64_t sh_addr; + uint64_t sh_offset; + uint64_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint64_t sh_addralign; + uint64_t sh_entsize; +}; + +#endif diff --git a/arch/x86_64/gdt.c b/arch/x86_64/gdt.c new file mode 100644 index 0000000..d996dcb --- /dev/null +++ b/arch/x86_64/gdt.c @@ -0,0 +1,125 @@ +#include "tables.h" +#include "tss.h" + +enum +{ + GDT_SEGMENT_KERNEL_NULL = 0, + GDT_SEGMENT_KERNEL_CODE, + GDT_SEGMENT_KERNEL_DATA, + + GDT_SEGMENT_USER_NULL, + GDT_SEGMENT_USER_DATA, + GDT_SEGMENT_USER_CODE, + + GDT_SEGMENT_TSS_LOW, + GDT_SEGMENT_TSS_HIGH, + + GDT_SEGMENT_COUNT +}; + +__attribute__((aligned(0x1000))) +static struct SegmentDescriptor s_gdtd[GDT_SEGMENT_COUNT] = +{ + { 0 }, /* Kernel NULL */ + { /* Kernel Code (64-bit RO EX DPL0) */ + .limit_0_15 = 0xFFFF, + .base_0_15 = 0, + .base_16_23 = 0, + .type = CD_SEGMENT_TYPE_CODE | CD_SEGMENT_TYPE_CODE_CONFORMING, + .s = 1, + .dpl = 0, + .p = 1, + .limit_16_19 = 0xF, + .l = 1, + .d_b = 0, + .g = 0, + .base_24_31 = 0 + }, + { /* Kernel Data (64-bit RW DPL0) */ + .limit_0_15 = 0xFFFF, + .base_0_15 = 0, + .base_16_23 = 0, + .type = CD_SEGMENT_TYPE_WRITEABLE, + .s = 1, + .dpl = 0, + .p = 1, + .limit_16_19 = 0xF, + .l = 1, + .d_b = 0, + .g = 0, + .base_24_31 = 0 + }, + { 0 }, /* User NULL */ + { /* User Data (64-bit RO EX DPL3)*/ + .limit_0_15 = 0xFFFF, + .base_0_15 = 0, + .base_16_23 = 0, + .type = CD_SEGMENT_TYPE_WRITEABLE, + .s = 1, + .dpl = 3, + .p = 1, + .limit_16_19 = 0xF, + .l = 1, + .d_b = 0, + .g = 0, + .base_24_31 = 0, + }, + { /* User Code (64-bit RO EX DPL3)*/ + .limit_0_15 = 0xFFFF, + .base_0_15 = 0, + .base_16_23 = 0, + .type = CD_SEGMENT_TYPE_CODE | CD_SEGMENT_TYPE_CODE_CONFORMING, + .s = 1, + .dpl = 3, + .p = 1, + .limit_16_19 = 0xF, + .l = 1, + .d_b = 0, + .g = 0, + .base_24_31 = 0, + }, + { /* TSS Low */ + .limit_0_15 = sizeof(struct TSS), + .base_0_15 = 0, + .base_16_23 = 0, + .type = S_SEGMENT_TYPE_TSS_AVAIL, + .avl = 1, + .s = 0, + .dpl = 0, + .p = 1, + .limit_16_19 = 0, + .l = 1, + .d_b = 0, + .g = 0, + .base_24_31 = 0, + }, + { 0 } +}; +static struct XDTR s_gdtr = { + .length = sizeof(s_gdtd) - 1, + .address = (uintptr_t)&s_gdtd +}; + +static struct TSS s_tss = { + +}; + +extern void x86_64_lgdt(struct XDTR *gdtr); +extern void x86_64_flush_tss(void); +void +x86_64_load_gdt(void) +{ + { + struct SegmentDescriptor *tss_lo = &s_gdtd[GDT_SEGMENT_TSS_LOW]; + struct SegmentDescriptor *tss_hi = &s_gdtd[GDT_SEGMENT_TSS_HIGH]; + uintptr_t tssb = (uintptr_t)&s_tss; + tss_lo->base_0_15 = tssb & 0xFFFF; + tss_lo->base_16_23 = (tssb >> 16) & 0xFF; + tss_lo->base_24_31 = (tssb >> 24) & 0xFF; + tss_hi->limit_0_15 = (tssb >> 32) & 0xFFFF; + tss_hi->base_0_15 = (tssb >> 48) & 0xFFFF; + } + + x86_64_lgdt(&s_gdtr); + x86_64_flush_tss(); +} diff --git a/arch/x86_64/gdt.d b/arch/x86_64/gdt.d new file mode 100644 index 0000000..7b43bdb --- /dev/null +++ b/arch/x86_64/gdt.d @@ -0,0 +1,2 @@ +arch/x86_64/gdt.o: arch/x86_64/gdt.c arch/x86_64/tables.h \ + arch/x86_64/tss.h diff --git a/arch/x86_64/idt.c b/arch/x86_64/idt.c new file mode 100644 index 0000000..567dead --- /dev/null +++ b/arch/x86_64/idt.c @@ -0,0 +1,70 @@ +#include "tables.h" +#include "cpu.h" +#include "lib/jove.h" +#include "io/log.h" + +PAGEALIGN +static struct InterruptTrapGate s_idtd[48]; +static struct InterruptState *(*s_int_handlers[48])(struct Registers*); +static struct XDTR s_idtr = { + .length = sizeof(s_idtd) - 1, + .address = (uintptr_t)&s_idtd +}; + +uint64_t __isr_err; +uint64_t __isr_num; + +struct Registers* +irq_handle(struct Registers *state) +{ + if(__isr_num < 48) { + if(s_int_handlers[__isr_num] != NULL) { + s_int_handlers[__isr_num](state); + return state; + } + } + klogf("Interrupt %i\nerror code %#016X\n", __isr_num, __isr_err); + klogf("IP: %#016X\n", state->ip); + klogf("AX: %#016X\n", state->ax); + klogf("BX: %#016X\n", state->bx); + klogf("CX: %#016X\n", state->cx); + klogf("DX: %#016X\n", state->dx); + klogf("SI: %#016X\n", state->si); + klogf("DI: %#016X\n", state->di); + klogf("BP: %#016X\n", state->bp); + klogf("R8: %#016X\n", state->r8); + klogf("R9: %#016X\n", state->r9); + klogf("R10: %#016X\n", state->r10); + klogf("R11: %#016X\n", state->r11); + klogf("R12: %#016X\n", state->r12); + klogf("R13: %#016X\n", state->r13); + klogf("R14: %#016X\n", state->r14); + klogf("R15: %#016X\n", state->r15); + kpanic("Unhandled exception\n"); + return state; +} + +extern void x86_64_lidt(struct XDTR *idtr); +void +x86_64_load_idt(void) +{ + extern uintptr_t __isr_stubs[22]; + for(int i = 0; i < 22; i++) + { + uintptr_t base = __isr_stubs[i]; + klogf("INT %2i : %#016X\n", i, base); + s_idtd[i] = (struct InterruptTrapGate){ + .base_0_15 = (base & 0xFFFF), + .segment_selector = 0x10, + .ist = 0, + .zero_0 = 0, + .type = 0xE, + .zero_1 = 0, + .dpl = 0, + .p = 1, + .base_16_31 = (base >> 16) & 0xFFFF, + .base_32_63 = (base >> 32) & 0xFFFFFFFF + }; + } + x86_64_lidt(&s_idtr); +} diff --git a/arch/x86_64/idt.d b/arch/x86_64/idt.d new file mode 100644 index 0000000..7e976e7 --- /dev/null +++ b/arch/x86_64/idt.d @@ -0,0 +1,2 @@ +arch/x86_64/idt.o: arch/x86_64/idt.c arch/x86_64/tables.h \ + arch/x86_64/cpu.h lib/jove.h io/log.h diff --git a/arch/x86_64/int.S b/arch/x86_64/int.S new file mode 100644 index 0000000..96c62d9 --- /dev/null +++ b/arch/x86_64/int.S @@ -0,0 +1,131 @@ +.section .text +.global x86_64_lidt +.type x86_64_lidt @function +x86_64_lidt: + lidt (%rdi) + retq + +.macro irq_preserve + 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 irq_restore + 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 + +.global irq_stub +.type irq_stub @function +irq_stub: + irq_preserve + + movq %rsp, %rdi + cld + + .extern irq_handle + call irq_handle + movq %rax, %rsp + + irq_restore + addq $128, %rsp + iretq + +.extern __isr_err +.extern __isr_num + +.macro isr_error num:req +.type __isr\num @function +isr\num: + subq $128, %rsp + pushq %rbx + movq 8(%rsp), %rbx + movq %rbx, __isr_err + popq %rbx + addq $8, %rsp + movq $\num, __isr_num + jmp irq_stub +.endm + +.macro isr_noerr num:req +.type __isr\num @function +isr\num: + movq $\num, __isr_num + jmp irq_stub +.endm + +isr_noerr 0 +isr_noerr 1 +isr_noerr 2 +isr_noerr 3 +isr_noerr 4 +isr_noerr 5 +isr_noerr 6 +isr_noerr 7 +isr_error 8 +isr_noerr 9 +isr_error 10 +isr_error 11 +isr_error 12 +isr_error 13 +isr_error 14 +isr_noerr 15 +isr_noerr 16 +isr_error 17 +isr_noerr 18 +isr_noerr 19 +isr_noerr 20 +isr_error 21 + +.section .data +.global __isr_stubs +.type __isr_stubs @object +__isr_stubs: + .quad isr0 + .quad isr1 + .quad isr2 + .quad isr3 + .quad isr4 + .quad isr5 + .quad isr6 + .quad isr7 + .quad isr8 + .quad isr9 + .quad isr10 + .quad isr11 + .quad isr12 + .quad isr13 + .quad isr14 + .quad isr15 + .quad isr16 + .quad isr17 + .quad isr18 + .quad isr19 + .quad isr20 + .quad isr21 diff --git a/arch/x86_64/loadgdt.S b/arch/x86_64/loadgdt.S new file mode 100644 index 0000000..e183850 --- /dev/null +++ b/arch/x86_64/loadgdt.S @@ -0,0 +1,24 @@ +.global x86_64_lgdt +.type x86_64_lgdt @function +x86_64_lgdt: + lgdt (%rdi) +.reload_segments: + pushq $0x8 + leaq .reload_cs, %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 + +.global x86_64_flush_tss +.type x86_64_flush_tss @function +x86_64_flush_tss: + movw $0x30, %ax + ltr %ax + retq diff --git a/arch/x86_64/paging.c b/arch/x86_64/paging.c new file mode 100644 index 0000000..76b5735 --- /dev/null +++ b/arch/x86_64/paging.c @@ -0,0 +1,202 @@ +#include "paging.h" +#include <stddef.h> +#include "lib/jove.h" +#include "io/log.h" +#include "lib/string.h" +#include "boot/boot.h" + +extern void *_kernel_end; + +PAGEALIGN static uint64_t s_kernel_initial_pml4[512]; +PAGEALIGN static uint64_t s_kernel_initial_pml3[2][512]; +PAGEALIGN static uint64_t s_kernel_initial_pml2[2][512]; +PAGEALIGN static uint64_t s_kernel_initial_pml1[2][512]; +static struct PageDirectory s_kernel_initial_pd; + +struct PageDirectory *mem_current_pd; + +physptr_t +mem_linear_tophys_koffset(uintptr_t virt) +{ + return (virt - boot_kernel_virtual_base) + boot_kernel_physical_address; +} + +uintptr_t +mem_phys_tolinear(physptr_t phys) +{ + return (uintptr_t)(phys + 0xFFFF800000000000ULL); +} + +static size_t +s_paging_pmle(size_t l, uintptr_t addr) +{ + size_t shift = (12 + (9 * l)); + return (addr & (0x1FFULL << shift)) >> shift; +} + +static union PageEntry* +s_paging_fetch_table(union PageEntry *pt, size_t l, uintptr_t virt) +{ + size_t pmle = s_paging_pmle(l, virt); + union PageEntry entry = pt[pmle]; + bool entry_new = false; + if(!entry.p) { + entry_new = true; + entry.value = mem_phys_take4k(); + entry.p = 1; + entry.rw = 1; + entry.us = 1; + pt[pmle] = entry; + } + union PageEntry *table = (union PageEntry*)(mem_phys_tolinear(entry.paddr << 12)); + if(entry_new) memset(table, 0, PAGESIZE); + return table; +} + +static union PageEntry* +s_paging_get_table(union PageEntry *pt, size_t l, uintptr_t virt) +{ + if(pt == NULL) return NULL; + size_t pmle = s_paging_pmle(l, virt); + union PageEntry entry = pt[pmle]; + if(!entry.p) return NULL; + return (union PageEntry*)(mem_phys_tolinear(entry.paddr << 12)); +} + +physptr_t +mem_linear_tophys(uintptr_t virt) +{ + struct PageDirectory *pd = mem_current_pd; + union PageEntry *pml3 = s_paging_get_table(pd->pml4_vaddr, 3, virt); + union PageEntry *pml2 = s_paging_get_table(pd->pml4_vaddr, 3, virt); + union PageEntry *pml1 = s_paging_get_table(pd->pml4_vaddr, 3, virt); + if(pml1 == NULL) return 0; + + size_t pml1i = s_paging_pmle(0, virt); + + if(!pml1[pml1i].p) return 0; + return pml1[pml1i].paddr << 12; +} + +bool +mem_check_ptr(const void *ptr) +{ + if(ptr == NULL) return false; + return mem_linear_tophys((uintptr_t)ptr) != 0; +} + +void +mem_paging_map4k(struct PageDirectory *pd, physptr_t phys, uintptr_t virt, uint8_t flg) +{ + union PageEntry *pml3 = s_paging_fetch_table(pd->pml4_vaddr, 3, virt); + union PageEntry *pml2 = s_paging_fetch_table(pml3, 2, virt); + union PageEntry *pml1 = s_paging_fetch_table(pml2, 1, virt); + size_t pml1e = s_paging_pmle(0, virt); + + pml1[pml1e] = (union PageEntry) { + .p = (flg & 1) > 0, + .rw = (flg & 2) > 0, + .us = (flg & 4) > 0, + .paddr = phys >> 12 + }; +} + +union PageEntry +mem_paging_fetch4k(struct PageDirectory *pd, uintptr_t virt) +{ + union PageEntry *pml3 = s_paging_fetch_table(pd->pml4_vaddr, 3, virt); + union PageEntry *pml2 = s_paging_fetch_table(pml3, 2, virt); + union PageEntry *pml1 = s_paging_fetch_table(pml2, 1, virt); + return pml1[s_paging_pmle(0, virt)]; +} + +void +mem_pd_ensure_4k(struct PageDirectory *pd, uintptr_t virt, uint8_t flg) +{ + union PageEntry pml1e = mem_paging_fetch4k(pd, virt); + if(!pml1e.p) { + uintptr_t phys = mem_phys_take4k(); + mem_paging_map4k(pd, phys, virt, flg); + } +} + +void +mem_pd_ensure_range(struct PageDirectory *pd, uintptr_t from, uintptr_t to, uint8_t flg) +{ + from &= ~0xFFF; + for(; from < to; from += PAGESIZE) + mem_pd_ensure_4k(pd, from, flg); +} + +void +mem_ensure_range(uintptr_t from, uintptr_t to, bool rw, bool user) +{ + mem_pd_ensure_range(mem_current_pd, from, to, 1 | (rw << 1) | (user << 2)); +} + +void mem_pd_new(struct PageDirectory *pd) +{ + physptr_t pml4p = mem_phys_take4k(); + union PageEntry *pml4 = (union PageEntry*)mem_phys_tolinear(pml4p); + memset(pml4, 0, PAGESIZE); + memcpy(&pml4[256], &pd->pml4_vaddr[256], PAGESIZE / 2); + + *pd = (struct PageDirectory){ + .pml4_vaddr = pml4, + .pml4_paddr = pml4p, + .references = 1 + }; +} + +void mem_pd_clone(struct PageDirectory *pd, struct PageDirectory *parent) +{ + mem_pd_new(pd); + for(size_t i = 0; i < 256; i++) { + + } +} + +void +mem_paging_setup(void) +{ + memset(s_kernel_initial_pml4, 0, PAGESIZE); + memset(s_kernel_initial_pml3, 0, 2 * PAGESIZE); + memset(s_kernel_initial_pml2, 0, 2 * PAGESIZE); + memset(s_kernel_initial_pml1, 0, PAGESIZE); + s_kernel_initial_pd = (struct PageDirectory){ + .pml4_vaddr = (union PageEntry*)&s_kernel_initial_pml4, + .pml4_paddr = mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml4), + .references = 1 + }; + mem_current_pd = &s_kernel_initial_pd; + + /* Map first few GiBs */ + s_kernel_initial_pml4[256] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[0]) + | 3; + s_kernel_initial_pml3[0][0] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[0]) + | 3; + for(int i = 0; i < 512; i++) { + s_kernel_initial_pml2[0][i] = (i * (PAGESIZE * 512)) | 0x80 | 3; + } + + size_t kernel_pml4e = (boot_kernel_virtual_base >> (39)); + size_t kernel_pml3e = (boot_kernel_virtual_base >> (30)) % 512; + size_t kernel_pml2e = (boot_kernel_virtual_base >> (21)) % 512; + size_t kernel_npages = ((((uintptr_t)&_kernel_end) - boot_kernel_virtual_base) >> 12) + 1; + klogf("Kernel has %i pages\n", kernel_npages); + + /* Map kernel pages */ + s_kernel_initial_pml4[511] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml3[1]) | 3; + s_kernel_initial_pml3[1][kernel_pml3e] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml2[1]) | 3; + s_kernel_initial_pml2[1][kernel_pml2e] = + mem_linear_tophys_koffset((uintptr_t)&s_kernel_initial_pml1[0]) | 3; + for(int i = 0; i < kernel_npages; i++) { + s_kernel_initial_pml1[0][i] = (i * PAGESIZE) + boot_kernel_physical_address | 3; + } + + __asm__ volatile("mov %0, %%cr3":: "r"(s_kernel_initial_pd.pml4_paddr)); +} diff --git a/arch/x86_64/paging.d b/arch/x86_64/paging.d new file mode 100644 index 0000000..bb3ea83 --- /dev/null +++ b/arch/x86_64/paging.d @@ -0,0 +1,2 @@ +arch/x86_64/paging.o: arch/x86_64/paging.c arch/x86_64/paging.h \ + mem/memory.h mem/slab.h lib/jove.h io/log.h lib/string.h boot/boot.h diff --git a/arch/x86_64/paging.h b/arch/x86_64/paging.h new file mode 100644 index 0000000..1e88a0b --- /dev/null +++ b/arch/x86_64/paging.h @@ -0,0 +1,44 @@ +#ifndef JOVE_ARCH_x86_64_PAGING_H +#define JOVE_ARCH_x86_64_PAGING_H 1 + +#include <stdint.h> +#include "mem/memory.h" + +union PageEntry +{ + 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)); + +struct PageDirectory +{ + union PageEntry *pml4_vaddr; + physptr_t pml4_paddr; + size_t references; +}; + +extern struct PageDirectory *mem_current_pd; + +void mem_pd_new(struct PageDirectory *pd); +void mem_pd_clone(struct PageDirectory *pd, struct PageDirectory *parent); + +void mem_pd_ensure_4k(struct PageDirectory *pd, uintptr_t virt, uint8_t flg); +void mem_pd_ensure_range(struct PageDirectory *pd, uintptr_t from, uintptr_t to, uint8_t flg); + +#endif diff --git a/arch/x86_64/savestate.S b/arch/x86_64/savestate.S new file mode 100644 index 0000000..c89933b --- /dev/null +++ b/arch/x86_64/savestate.S @@ -0,0 +1,39 @@ +.global saveregs +.type saveregs @function +saveregs: + 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 + retq + +.global loadregs +.type loadregs @function +loadregs: + 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 + diff --git a/arch/x86_64/serial.c b/arch/x86_64/serial.c new file mode 100644 index 0000000..1b49e3f --- /dev/null +++ b/arch/x86_64/serial.c @@ -0,0 +1,62 @@ +#include "serial.h" +#include "uart.h" +#include "io/log.h" + +static struct LogDevice s_serial_logdev = + { .out = serial_out, .chain = NULL }; + +bool serial_supported = true; + +void +serial_setup(void) +{ + /* Disable interrupts. */ + poutb(SERIAL_UART_COM_IER(SERIAL_UART_COM1), 0x0); + /* Enable DLAB. */ + poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 0x80); + /* Set divisor to 3 (38400 baud)*/ + poutb(SERIAL_UART_COM_DLAB_DLL(SERIAL_UART_COM1), 3); + poutb(SERIAL_UART_COM_DLAB_DLH(SERIAL_UART_COM1), 0); + /* Set flags for LCR (8 bits, no parity, one stop)*/ + poutb(SERIAL_UART_COM_LCR(SERIAL_UART_COM1), 1 | 2); + /* Enable & clear FIFO, 14-byte threshold */ + poutb(SERIAL_UART_COM_FCR(SERIAL_UART_COM1), 1 | 2 | 4 | 0xC0); + /* Enable interrupts, set RTS/DSR. */ + poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 8); + /* Set loopback mode for testing. */ + poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 2 | 4 | 8 | 0x10); + /* Test serial output. */ + poutb(SERIAL_UART_COM1, 0xAE); + if(pinb(SERIAL_UART_COM1) != 0xAE) { + serial_supported = false; + return; + } + + /* Serial is not faulty. + * No loopback, enable output 1 & 2.*/ + poutb(SERIAL_UART_COM_MCR(SERIAL_UART_COM1), 1 | 2 | 4 | 8); + + klog_newdev(&s_serial_logdev); +} + +static ALWAYS_INLINE bool +serial_transmit_empty(uint16_t com) +{ + return pinb(SERIAL_UART_COM_LSR(com) & 0x20); +} + +static inline void +serial_outb(uint16_t com, uint8_t b) +{ + if(b == '\n') serial_outb(com, '\r'); + while(!serial_transmit_empty(SERIAL_UART_COM1)); + poutb(com, b); +} + +void +serial_out(const char *s, size_t len) +{ + if(!serial_supported) return; + for(; len > 0; len--) + serial_outb(SERIAL_UART_COM1, *(s++)); +} diff --git a/arch/x86_64/serial.d b/arch/x86_64/serial.d new file mode 100644 index 0000000..a0b0756 --- /dev/null +++ b/arch/x86_64/serial.d @@ -0,0 +1,2 @@ +arch/x86_64/serial.o: arch/x86_64/serial.c arch/x86_64/serial.h \ + arch/x86_64/uart.h lib/jove.h io/log.h diff --git a/arch/x86_64/serial.h b/arch/x86_64/serial.h new file mode 100644 index 0000000..ecb896d --- /dev/null +++ b/arch/x86_64/serial.h @@ -0,0 +1,27 @@ +#ifndef JOVE_KERNEL_ARCH_x86_64_SERIAL_H +#define JOVE_KERNEL_ARCH_x86_64_SERIAL_H 1 + +#include <stdbool.h> +#include <stddef.h> + +#define SERIAL_UART_COM1 0x3F8 +#define SERIAL_UART_COM2 0x2F8 + +#define SERIAL_UART_COM_THR(COM) COM +#define SERIAL_UART_COM_RBR(COM) COM +#define SERIAL_UART_COM_DLAB_DLL(COM) COM +#define SERIAL_UART_COM_IER(COM) (COM + 1) +#define SERIAL_UART_COM_DLAB_DLH(COM) (COM + 1) +#define SERIAL_UART_COM_IIR(COM) (COM + 2) +#define SERIAL_UART_COM_FCR(COM) (COM + 2) +#define SERIAL_UART_COM_LCR(COM) (COM + 3) +#define SERIAL_UART_COM_MCR(COM) (COM + 4) +#define SERIAL_UART_COM_LSR(COM) (COM + 5) +#define SERIAL_UART_COM_MSR(COM) (COM + 6) +#define SERIAL_UART_COM_SR(COM) (COM + 7) + +extern bool serial_supported; + +void serial_out(const char *s, size_t len); + +#endif diff --git a/arch/x86_64/syscall.c b/arch/x86_64/syscall.c new file mode 100644 index 0000000..0398f11 --- /dev/null +++ b/arch/x86_64/syscall.c @@ -0,0 +1 @@ +#include "usr/umode.h" diff --git a/arch/x86_64/syscall.d b/arch/x86_64/syscall.d new file mode 100644 index 0000000..bb8f166 --- /dev/null +++ b/arch/x86_64/syscall.d @@ -0,0 +1 @@ +arch/x86_64/syscall.o: arch/x86_64/syscall.c usr/umode.h diff --git a/arch/x86_64/syscall_setup.S b/arch/x86_64/syscall_setup.S new file mode 100644 index 0000000..cbd3220 --- /dev/null +++ b/arch/x86_64/syscall_setup.S @@ -0,0 +1,37 @@ +.extern _kernel_thread_sp +.extern syscall_handler + +.global syscall_entry +.type syscall_entry @function +syscall_entry: + movq %rsp, %rax + movq (_kernel_thread_bp), %rsp + pushq %rax + pushq %rbp + pushq %rcx + pushq %r11 + movq %rsp, %rbp + call syscall_handler + popq %r11 + popq %rcx + popq %rbp + popq %rsp + sysretq + +.global syscall_setup_syscall +.type syscall_setup_syscall @function +syscall_setup_syscall: + movq $0xc0000082, %rcx + leaq syscall_entry, %rdx + mov %edx, %eax + shr $32, %rdx + wrmsr + movq $0xc0000080, %rcx + rdmsr + or $1, %eax + wrmsr + movq $0xc0000081, %rcx + rdmsr + mov $0x00180008, %edx + wrmsr + retq diff --git a/arch/x86_64/tables.c b/arch/x86_64/tables.c new file mode 100644 index 0000000..f530089 --- /dev/null +++ b/arch/x86_64/tables.c @@ -0,0 +1,8 @@ +#include "tables.h" + +void +arch_tables_setup(void) +{ + x86_64_load_gdt(); + x86_64_load_idt(); +} diff --git a/arch/x86_64/tables.d b/arch/x86_64/tables.d new file mode 100644 index 0000000..6b10ebe --- /dev/null +++ b/arch/x86_64/tables.d @@ -0,0 +1 @@ +arch/x86_64/tables.o: arch/x86_64/tables.c arch/x86_64/tables.h diff --git a/arch/x86_64/tables.h b/arch/x86_64/tables.h new file mode 100644 index 0000000..8e43bec --- /dev/null +++ b/arch/x86_64/tables.h @@ -0,0 +1,60 @@ +#ifndef JOVE_ARCH_X86_64_TABLES_H +#define JOVE_ARCH_X86_64_TABLES_H 1 + +#include <stdint.h> + +#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 + +struct 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)); + +struct InterruptTrapGate +{ + 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; + +}__attribute__((packed)); + +struct XDTR /* Generic table descriptor struct */ +{ + uint16_t length; + uint64_t address; +}__attribute__((packed)); + +void x86_64_load_gdt(void); +void x86_64_load_idt(void); + +#endif diff --git a/arch/x86_64/thread.c b/arch/x86_64/thread.c new file mode 100644 index 0000000..da20067 --- /dev/null +++ b/arch/x86_64/thread.c @@ -0,0 +1,85 @@ +#include "tsk/tasking.h" +#include "mem/memory.h" +#include "io/log.h" +#include "lib/hashtable.h" +#include "lib/string.h" +#include "paging.h" +#include "cpu.h" + +struct ThreadBody { + struct Thread base; + struct PageDirectory pd; + struct Registers state; +}; + +struct Thread *thread_current; +uintptr_t _kernel_thread_bp = 0; + +//static struct SLinkedList s_threads; +static struct HashTable s_threads; + +static struct SlabCache s_thread_cache; +static struct SlabCache s_kbp_cache; + +static tid_t s_thread_id_next = 1; + +static size_t +s_thread_hash_func(const void* tid, size_t _) +{ + return (tid_t)tid; +} + +void +tasking_setup(void) +{ + hashtable_new(&s_threads, struct ThreadBody*, tid_t); + s_threads.hash_function = s_thread_hash_func; + + mem_slabcache_new(&s_thread_cache, "threads", sizeof(struct ThreadBody)); + mem_slabcache_new(&s_kbp_cache, "kernel stacks", 4096); + + struct ThreadBody *kthread = mem_slab_alloc(&s_thread_cache); + *kthread = (struct ThreadBody){ + .base.id = s_thread_id_next++, + .base.kbp = ((uintptr_t)mem_slab_alloc(&s_kbp_cache)) + 0xFFF, + .base.perm = (size_t)-1, + .pd = *mem_current_pd + }; + hashtable_insert(&s_threads, 0, kthread); + + thread_current = (struct Thread*)kthread; + _kernel_thread_bp = thread_current->kbp; +} + +struct Thread* +thread_new(struct Thread *parent) +{ + struct ThreadBody *new = mem_slab_alloc(&s_thread_cache); + memcpy(new, parent, sizeof(struct ThreadBody)); + new->base.id = s_thread_id_next++; + + uintptr_t ksp_base = (uintptr_t)mem_slab_alloc(&s_kbp_cache); + new->base.kbp = ksp_base + 0xFFF; + new->base.perm = parent->perm; + + hashtable_insert(&s_threads, (void*)new->base.id, new); + return (struct Thread*)new; +} + +struct Thread* +thread_get(tid_t id) +{ + struct Thread **thread = hashtable_get(&s_threads, (void*)id, struct Thread*); + if(thread == NULL) return NULL; + return *thread; +} + +void +thread_free(struct Thread *thread) +{ + struct ThreadBody *body = (struct ThreadBody*)thread; + body->pd.references--; + thread->kbp -= 0xFFF; + mem_slab_free(&s_kbp_cache, (void*)(thread->kbp)); + klogf("Need impl for thread_free\n"); +} diff --git a/arch/x86_64/thread.d b/arch/x86_64/thread.d new file mode 100644 index 0000000..c78e4a9 --- /dev/null +++ b/arch/x86_64/thread.d @@ -0,0 +1,3 @@ +arch/x86_64/thread.o: arch/x86_64/thread.c tsk/tasking.h mem/memory.h \ + mem/slab.h io/log.h lib/hashtable.h lib/linkedlist.h lib/string.h \ + arch/x86_64/paging.h arch/x86_64/cpu.h diff --git a/arch/x86_64/tss.h b/arch/x86_64/tss.h new file mode 100644 index 0000000..34ec444 --- /dev/null +++ b/arch/x86_64/tss.h @@ -0,0 +1,18 @@ +#ifndef JOVE_ARCH_x86_64_TSS_H +#define JOVE_ARCH_x86_64_TSS_H 1 + +#include <stddef.h> +#include <stdint.h> + +struct TSS +{ + uint32_t resv0; + uint64_t rsp[3]; + uint64_t resv1; + uint64_t ist[8]; + uint64_t resv2; + uint16_t resv3; + uint16_t iobp; +}; + +#endif diff --git a/arch/x86_64/uart.h b/arch/x86_64/uart.h new file mode 100644 index 0000000..8386eb7 --- /dev/null +++ b/arch/x86_64/uart.h @@ -0,0 +1,19 @@ +#ifndef JOVE_KERNEL_ARCH_x86_64_UART_H +#define JOVE_KERNEL_ARCH_x86_64_UART_H 1 + +#include "lib/jove.h" +#include <stdint.h> + +ALWAYS_INLINE uint8_t pinb(uint16_t port) +{ + uint8_t v; + __asm__ volatile("inb %1, %0": "=a"(v): "Nd"(port)); + return v; +} + +ALWAYS_INLINE void poutb(uint16_t port, uint8_t b) +{ + __asm__ volatile("outb %0, %1":: "a"(b), "Nd"(port)); +} + +#endif diff --git a/arch/x86_64/umode_enter.S b/arch/x86_64/umode_enter.S new file mode 100644 index 0000000..29aa4e3 --- /dev/null +++ b/arch/x86_64/umode_enter.S @@ -0,0 +1,8 @@ +.global umode_enter +.type umode_enter @function +umode_enter: + movq %rdi, %rcx + movq %rsi, %rsp + movq $0x0202, %r11 + cli + sysretq |