From 90a6065691beee52bf5309916fba98f7580d27be Mon Sep 17 00:00:00 2001 From: Freya Murphy Date: Sat, 3 Feb 2024 00:50:07 -0500 Subject: refactor, new arch dirs, (wip) page alloc on write, hsv screen (convert to userspace later), other fixes --- src/arch/amd64/acpi.c | 36 +++- src/arch/amd64/backtrace.c | 45 ----- src/arch/amd64/cpu/backtrace.c | 45 +++++ src/arch/amd64/cpu/debugger.c | 414 ++++++++++++++++++++++++++++++++++++++++ src/arch/amd64/cpu/debugger.h | 9 + src/arch/amd64/cpu/idt.S | 207 ++++++++++++++++++++ src/arch/amd64/cpu/idt.c | 160 ++++++++++++++++ src/arch/amd64/cpu/idt.h | 29 +++ src/arch/amd64/debugger.c | 413 --------------------------------------- src/arch/amd64/debugger.h | 9 - src/arch/amd64/drivers/bochs.c | 73 +++++++ src/arch/amd64/drivers/pci.c | 166 ++++++++++++++++ src/arch/amd64/drivers/pic.c | 89 +++++++++ src/arch/amd64/drivers/pic.h | 31 +++ src/arch/amd64/drivers/serial.c | 48 +++++ src/arch/amd64/fb.c | 89 --------- src/arch/amd64/fpu.c | 1 + src/arch/amd64/idt.S | 207 -------------------- src/arch/amd64/idt.c | 161 ---------------- src/arch/amd64/idt.h | 29 --- src/arch/amd64/linker.ld | 38 ---- src/arch/amd64/mboot.c | 30 +++ src/arch/amd64/paging.c | 82 +++++++- src/arch/amd64/paging.h | 1 + src/arch/amd64/pci.c | 166 ---------------- src/arch/amd64/pic.c | 89 --------- src/arch/amd64/pic.h | 31 --- src/arch/amd64/serial.c | 47 ----- src/arch/amd64/shim.c | 4 +- 29 files changed, 1405 insertions(+), 1344 deletions(-) delete mode 100644 src/arch/amd64/backtrace.c create mode 100644 src/arch/amd64/cpu/backtrace.c create mode 100644 src/arch/amd64/cpu/debugger.c create mode 100644 src/arch/amd64/cpu/debugger.h create mode 100644 src/arch/amd64/cpu/idt.S create mode 100644 src/arch/amd64/cpu/idt.c create mode 100644 src/arch/amd64/cpu/idt.h delete mode 100644 src/arch/amd64/debugger.c delete mode 100644 src/arch/amd64/debugger.h create mode 100644 src/arch/amd64/drivers/bochs.c create mode 100644 src/arch/amd64/drivers/pci.c create mode 100644 src/arch/amd64/drivers/pic.c create mode 100644 src/arch/amd64/drivers/pic.h create mode 100644 src/arch/amd64/drivers/serial.c delete mode 100644 src/arch/amd64/fb.c delete mode 100644 src/arch/amd64/idt.S delete mode 100644 src/arch/amd64/idt.c delete mode 100644 src/arch/amd64/idt.h delete mode 100644 src/arch/amd64/linker.ld delete mode 100644 src/arch/amd64/pci.c delete mode 100644 src/arch/amd64/pic.c delete mode 100644 src/arch/amd64/pic.h delete mode 100644 src/arch/amd64/serial.c (limited to 'src/arch/amd64') diff --git a/src/arch/amd64/acpi.c b/src/arch/amd64/acpi.c index e262a99..eb38f73 100644 --- a/src/arch/amd64/acpi.c +++ b/src/arch/amd64/acpi.c @@ -1,14 +1,12 @@ #include #include - +#include #include #include +#include +#include #include "bindings.h" -#include "memory.h" - -/* global state, idk a better way rn */ -struct acpi_state state; struct acpi_header { char signature[4]; @@ -20,7 +18,7 @@ struct acpi_header { uint32_t oem_revision; uint32_t creator_id; uint32_t creator_revision; -}; +} __attribute__((packed)); // root system descriptor pointer // ACPI 1.0 @@ -30,7 +28,7 @@ struct rsdp { char oemid[6]; uint8_t revision; uint32_t rsdt_addr; -}; +} __attribute__((packed)); // eXtended system descriptor pointer // ACPI 2.0 @@ -45,7 +43,7 @@ struct xsdp { uint64_t xsdt_addr; uint8_t extendeid_checksum; uint8_t reserved[3]; -}; +} __attribute__((packed)); // root system descriptor table // ACPI 1.0 @@ -152,6 +150,9 @@ struct acpi_state { uint16_t SCI_EN; }; +/* global state, idk a better way rn */ +static struct acpi_state state; + static bool checksum(uint8_t *data, size_t len) { unsigned char sum = 0; for (size_t i = 0; i < len; i++) @@ -230,6 +231,9 @@ static void *acpi_find_table_xsdt(struct xsdt *xsdt, const char *identifier, int } int acpi_init_rsdt(struct rsdt *rsdt) { + + kprintf("RSDT: %#016lx\n", (size_t)rsdt); + rsdt = mmap(rsdt, sizeof(struct rsdt)); state.dst.rsdt = rsdt; @@ -278,23 +282,35 @@ int acpi_init(void *rootsdp) { if (!checksum((uint8_t *)rsdp, sizeof(struct rsdp))) return -1; + if (strncmp(rsdp->signature, "RSD PTR ", 8) != 0) { + panic("invalid acpi rsdp signature: %.*s\n", 8, rsdp->signature); + } + int res; if (rsdp->revision == 0) { + kprintf("ACPI 1.0\n"); + kprintf("RSDP: %#016lx\n", (size_t)rsdp); res = acpi_init_rsdt( (struct rsdt *) (uintptr_t) rsdp->rsdt_addr ); } else if (rsdp->revision == 2) { struct xsdp *xsdp = (struct xsdp *) rsdp; + kprintf("ACPI 2.0\n"); + kprintf("XSDP: %#016lx\n", (size_t)xsdp); res = acpi_init_xsdt( (struct xsdt *) (uintptr_t) xsdp->xsdt_addr ); } else { - return -1; + panic("invalid acpi rev: %d\n", rsdp->revision); } - if (res) + if (res) { + kprintf("...acpi failed to load\n\n"); return res; + } + + kprintf("\n\n"); int ret = read_s5_addr(&state); if (!ret) diff --git a/src/arch/amd64/backtrace.c b/src/arch/amd64/backtrace.c deleted file mode 100644 index 9e1c9d7..0000000 --- a/src/arch/amd64/backtrace.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include - -struct stackframe { - struct stackframe *rbp; - void *rip; -}; - -size_t backtrace(void **dst, size_t len) { - struct stackframe *rbp; - __asm__ volatile ("mov %%rbp, %0" : "=r"(rbp)); - return backtrace_ex(dst, len, rbp->rip, rbp->rbp); -} - -size_t backtrace_ex(void **dst, size_t len, void *ip, void *bp) { - struct stackframe *frame = bp; - __asm__ volatile ("mov %%rbp, %0" : "=r"(frame)); - if (len > 0) { - dst[0] = ip; - } - size_t i; - for (i = 1; frame && i < len; i++) { - dst[i] = frame->rip; - frame = frame->rbp; - } - return i; -} - -void log_backtrace() { - struct stackframe *rbp; - __asm__ volatile ("mov %%rbp, %0" : "=r"(rbp)); - log_backtrace_ex(rbp->rip, rbp->rbp); -} - - -void log_backtrace_ex(void *ip, void *bp) { - struct stackframe *frame = bp; - kputs("Stack trace:\n"); - kprintf(" %#lx\n", (size_t)ip); - while (frame) { - kprintf(" %#lx\n", (size_t)frame->rip); - frame = frame->rbp; - } - -} diff --git a/src/arch/amd64/cpu/backtrace.c b/src/arch/amd64/cpu/backtrace.c new file mode 100644 index 0000000..9e1c9d7 --- /dev/null +++ b/src/arch/amd64/cpu/backtrace.c @@ -0,0 +1,45 @@ +#include +#include + +struct stackframe { + struct stackframe *rbp; + void *rip; +}; + +size_t backtrace(void **dst, size_t len) { + struct stackframe *rbp; + __asm__ volatile ("mov %%rbp, %0" : "=r"(rbp)); + return backtrace_ex(dst, len, rbp->rip, rbp->rbp); +} + +size_t backtrace_ex(void **dst, size_t len, void *ip, void *bp) { + struct stackframe *frame = bp; + __asm__ volatile ("mov %%rbp, %0" : "=r"(frame)); + if (len > 0) { + dst[0] = ip; + } + size_t i; + for (i = 1; frame && i < len; i++) { + dst[i] = frame->rip; + frame = frame->rbp; + } + return i; +} + +void log_backtrace() { + struct stackframe *rbp; + __asm__ volatile ("mov %%rbp, %0" : "=r"(rbp)); + log_backtrace_ex(rbp->rip, rbp->rbp); +} + + +void log_backtrace_ex(void *ip, void *bp) { + struct stackframe *frame = bp; + kputs("Stack trace:\n"); + kprintf(" %#lx\n", (size_t)ip); + while (frame) { + kprintf(" %#lx\n", (size_t)frame->rip); + frame = frame->rbp; + } + +} diff --git a/src/arch/amd64/cpu/debugger.c b/src/arch/amd64/cpu/debugger.c new file mode 100644 index 0000000..4d9d3c3 --- /dev/null +++ b/src/arch/amd64/cpu/debugger.c @@ -0,0 +1,414 @@ +#include +#include +#include +#include + +#include "debugger.h" + +struct dr6 { + uint64_t b0 : 1, + b1 : 1, + b2 : 1, + b3 : 1, + : 7, + bld : 1, + : 1, + bd : 1, + bs : 1, + bt : 1, + rtm : 1, + : 47; +}; + +struct dr7 { + uint64_t l0 : 1, + g0 : 1, + l1 : 1, + g1 : 1, + l2 : 1, + g2 : 1, + l3 : 1, + g3 : 1, + : 8, + rw0 : 2, + len0 : 2, + rw1 : 2, + len1 : 2, + rw2 : 2, + len2 : 2, + rw3 : 2, + len3 : 2, + : 32; +}; + +struct rflags { + uint64_t cf : 1, + : 1, + pf : 1, + : 1, + af : 1, + : 1, + zf : 1, + sf : 1, + + tf : 1, + if_ : 1, + df : 1, + of : 1, + iopl : 2, + nt : 1, + md : 1, + + rf : 1, + vm : 1, + ac : 1, + vif : 1, + vip : 1, + id : 1, + : 42; +}; + +struct breakpoint { + uint64_t addr; + uint8_t len; + uint8_t rw; + uint8_t used; + uint8_t enable; + uint8_t instr_len; +}; + +static int dbg_steps = 0; +static int dbg_continue = 0; +static struct breakpoint bkps[4] = {{0}, {0}, {0}, {0}}; + +static size_t debugger_read(char *buf, size_t len) { + char *p = buf; + size_t result; + while (p < buf + len - 1) { + char ch = serial_in(); + switch (ch) { + case '\r': + goto end; + case '\x7f': + if (p > buf) { + p--; + kputs("\x08 \x08"); + } + break; + default: + kputc(ch); + *p++ = ch; + } + } +end: + result = p - buf; + kputc('\n'); + for(; p < buf + len; p++) { + *p = 0; + } + return result; +} + +static void debugger_msg(int cause, struct dr6 dr6) { + switch (cause) { + case DEBUG_INT3: + kputs("dbg: reached int3"); + break; + case DEBUG_FAULT: + kputs("dbg: a fault occured"); + break; + case DEBUG_DBG: + if (dr6.bs) + kputs("dbg: finished steps"); + if (dr6.b0) + kputs("dbg: reached breakpoint 0"); + else if (dr6.b1) + kputs("dbg: reached breakpoint 1"); + else if (dr6.b2) + kputs("dbg: reached breakpoint 2"); + else if (dr6.b3) + kputs("dbg: reached breakpoint 3"); + } + if (dbg_steps > 0) { + kprintf(" (%d steps left)", dbg_steps); + } + if (dbg_continue > 0) { + kputs(" (paused continue)"); + } + kputs("\n"); +} + +static void debugger_print_regs(struct isr_regs *state) { + kprintf("rax: %#016lx (%lu)\n", state->rax, state->rax); + kprintf("rbx: %#016lx (%lu)\n", state->rbx, state->rbx); + kprintf("rcx: %#016lx (%lu)\n", state->rcx, state->rcx); + kprintf("rdx: %#016lx (%lu)\n", state->rdx, state->rdx); + kprintf("rsi: %#016lx (%lu)\n", state->rsi, state->rsi); + kprintf("rdi: %#016lx (%lu)\n", state->rdi, state->rdi); + kprintf("rsp: %#016lx (%lu)\n", state->rsp, state->rsp); + kprintf("rbp: %#016lx (%lu)\n", state->rbp, state->rbp); + kprintf("r8 : %#016lx (%lu)\n", state->r8 , state->r8 ); + kprintf("r9 : %#016lx (%lu)\n", state->r9 , state->r9 ); + kprintf("r10: %#016lx (%lu)\n", state->r10, state->r10); + kprintf("r11: %#016lx (%lu)\n", state->r11, state->r11); + kprintf("r12: %#016lx (%lu)\n", state->r12, state->r12); + kprintf("r13: %#016lx (%lu)\n", state->r13, state->r13); + kprintf("r14: %#016lx (%lu)\n", state->r14, state->r14); + kprintf("r15: %#016lx (%lu)\n", state->r15, state->r15); + kputs("---\n"); + kprintf("rip: %#016lx (%lu)\n", state->rip, state->rip); + kputs("---\n"); + kprintf("rflags: %#016lx (%lu)\n", state->rflags, state->rflags); + struct rflags *rflags = (struct rflags *)state->rflags; + kputs("rflags: "); + if(rflags->cf) kputs("CF "); + if(rflags->pf) kputs("PF "); + if(rflags->af) kputs("AF "); + if(rflags->zf) kputs("ZF "); + if(rflags->sf) kputs("SF "); + if(rflags->tf) kputs("TF "); + if(rflags->if_) kputs("IF "); + if(rflags->df) kputs("DF "); + if(rflags->of) kputs("OF "); + if(rflags->iopl) kputs("IOPL "); + if(rflags->nt) kputs("NT "); + if(rflags->md) kputs("MD "); + if(rflags->rf) kputs("RF "); + if(rflags->vm) kputs("VM "); + if(rflags->ac) kputs("AC "); + if(rflags->vif) kputs("VIF "); + if(rflags->vip) kputs("VIP "); + if(rflags->id) kputs("ID "); + kputs("\n"); +} + +#define PROMPT_LEN 60 + +static int debugger_handle_bkp_cmd(char *msg) { + if (msg[0] == 'l') { + // list breakpoints + for (int i = 0; i < 4; i++) { + struct breakpoint bkp = bkps[i]; + if(!bkp.used) { + kprintf("breakpoint %d: unset\n", i); + continue; + } + const char *lenstrs[] = {"1", "2", "8", "4"}; + const char *rwstrs[] = {"x ", "w ", "io", "rw"}; + kprintf( + "breakpoint %d: %#016lx len=%s trigger=%s instrlen=%01d %s\n", + i, + bkp.addr, + lenstrs[bkp.len], + rwstrs[bkp.rw], + bkp.instr_len, + bkp.enable ? " enabled" : " disabled" + ); + } + return 1; + } else if (msg[0] == 'd') { + // disable breakpoints + bkps[0].enable = 0; + bkps[1].enable = 0; + bkps[2].enable = 0; + bkps[3].enable = 0; + kputs("disabled breakpoints\n"); + return 1; + } else if (msg[0] == 'c') { + // clear breakpoints + bkps[0].used = 0; + bkps[1].used = 0; + bkps[2].used = 0; + bkps[3].used = 0; + kputs("cleared breakpoints\n"); + return 1; + } else if (msg[0] <= '0' && msg[0] >= '3') { + kputs("invalid breakpoint command\n"); + return 1; + } + char buf[64]; + int id = msg[0] - '0'; + switch (msg[1]) { + case 'e': + bkps[id].enable = bkps[id].used; + kprintf("enabled breakpoint %d\n", id); + return 1; + case 'd': + bkps[id].enable = 0; + kprintf("disabled breakpoint %d\n", id); + return 1; + case 'c': + bkps[id].used = 0; + kprintf("cleared breakpoint %d\n", id); + return 1; + case 'a': + kputs("addr> 0x"); + debugger_read(buf, 64); + bkps[id].addr = strtoll(buf, NULL, 16); + kputs("len (1/2/4/8)> "); + debugger_read(buf, 64); + switch (buf[0]) { + case '1': bkps[id].len = 0x0; break; + case '2': bkps[id].len = 0x1; break; + case '8': bkps[id].len = 0x2; break; + case '4': bkps[id].len = 0x3; break; + default: bkps[id].len = 0x0; break; + } + kputs("cond (x/w/io/rw)> "); + debugger_read(buf, 64); + switch ((int)buf[0] * 256 + (int)buf[1]) { + case (int)'x'*256 + (int)0: bkps[id].rw = 0x0; break; + case (int)'w'*256 + (int)0: bkps[id].rw = 0x1; break; + case (int)'i'*256 + (int)'o': bkps[id].rw = 0x2; break; + case (int)'r'*256 + (int)'w': bkps[id].rw = 0x3; break; + default: bkps[id].len = 0x0; break; + } + kputs("instr len (1..15)> "); + debugger_read(buf, 64); + bkps[id].instr_len = strtoi(buf, NULL, 10); + kputs("enable (y/n)> "); + debugger_read(buf, 64); + bkps[id].used = 1; + bkps[id].enable = !(buf[0] == 'n' || buf[0] == 'N'); + kprintf("added breakpoint %d\n", id); + return 1; + default: + kputs("invalid breakpoint command\n"); + return 1; + } +} + +static void debugger_load_bkps() { + struct dr7 dr7; + __asm__ volatile ("mov %%dr7, %0" : "=r"(dr7)); + dr7.g0 = bkps[0].enable & bkps[0].used; + dr7.g1 = bkps[1].enable & bkps[1].used; + dr7.g2 = bkps[2].enable & bkps[2].used; + dr7.g3 = bkps[3].enable & bkps[3].used; + dr7.l0 = 0; + dr7.l1 = 0; + dr7.l2 = 0; + dr7.l3 = 0; + dr7.rw0 = bkps[0].rw; + dr7.rw1 = bkps[1].rw; + dr7.rw2 = bkps[2].rw; + dr7.rw3 = bkps[3].rw; + dr7.len0 = bkps[0].len; + dr7.len1 = bkps[1].len; + dr7.len2 = bkps[2].len; + dr7.len3 = bkps[3].len; + __asm__ volatile ("mov %0, %%dr7" : : "r"(dr7)); + __asm__ volatile ("mov %0, %%dr0" : : "r"(bkps[0].addr)); + __asm__ volatile ("mov %0, %%dr1" : : "r"(bkps[1].addr)); + __asm__ volatile ("mov %0, %%dr2" : : "r"(bkps[2].addr)); + __asm__ volatile ("mov %0, %%dr3" : : "r"(bkps[3].addr)); +} + +static int debugger_prompt(struct isr_regs *state) { + kputs("dbg> "); + char buf[64]; + debugger_read(buf, 64); + + struct rflags *rflags = (struct rflags *)&state->rflags; + + switch (buf[0]) { + case '\0': // nothing entered + return 1; + case 'h': // help + kputs("see debugger.c for help information\n"); + return 1; + case 'q': // quit + return 0; + case 'c': // continue + rflags->tf = 1; + dbg_continue = 1; + return 0; + case 'r': // print registers + debugger_print_regs(state); + return 1; + case 'k': // backtrace + log_backtrace_ex((void *)state->rip, (void *)state->rbp); + return 1; + case 's': // step (n) + rflags->tf = 1; + dbg_steps = atol(buf + 1) - 1; + //if (dbg_steps < 0) dbg_steps = 0; + return 0; + case 'm': // memory + { + kputs("addr> 0x"); + debugger_read(buf, 64); + uint64_t start = (~0xF) & strtoll(buf, NULL, 16); + + kputs("len> 0x"); + debugger_read(buf, 64); + uint64_t len = (~0xF) & strtoll(buf, NULL, 16); + + for (uint64_t a = start; a <= start + len; a += 0x10) { + kprintf("%08lx: ", a); + for (uint64_t b = 0; b < 0x10; b++) { + kprintf("%02x ", *(uint8_t *)(a + b)); + if (b % 0x08 == 7) { + kputc(' '); + } + } + kputs("|"); + for (uint64_t b = 0; b < 0x10; b++) { + uint8_t ch = *(uint8_t *)(a + b); + if (ch < 0x20 || ch >= 0x7f) { + ch = '.'; + } + kputc(ch); + } + kputs("|\n"); + } + return 1; + } + case 'b': // breakpoints + { + int res = debugger_handle_bkp_cmd(buf+1); + debugger_load_bkps(); + return res; + } + default: + kputs("unknown command\n"); + return 1; + } +} + +void debugger(struct isr_regs *state, int cause) { + struct dr6 dr6; + __asm__ volatile ("mov %%dr6, %0" : "=r"(dr6)); + + if (!(dr6.b0 || dr6.b1 || dr6.b2 || dr6.b3)) { + if (dr6.bs && dbg_steps > 0) { + dbg_steps--; + return; + } + + if (dr6.bs && dbg_continue) { + return; + } + } + + debugger_msg(cause, dr6); + + kputs("hi\n"); + + dbg_steps = 0; + dbg_continue = 0; + + ((struct rflags *)&state->rflags)->tf = 0; + + if (dr6.b0) { + state->rip += bkps[0].instr_len; + } else if (dr6.b1) { + state->rip += bkps[1].instr_len; + } else if (dr6.b2) { + state->rip += bkps[2].instr_len; + } else if (dr6.b3) { + state->rip += bkps[3].instr_len; + } + + while (debugger_prompt(state)); +} diff --git a/src/arch/amd64/cpu/debugger.h b/src/arch/amd64/cpu/debugger.h new file mode 100644 index 0000000..14f73bf --- /dev/null +++ b/src/arch/amd64/cpu/debugger.h @@ -0,0 +1,9 @@ +#pragma once + +#include "idt.h" + +#define DEBUG_INT3 0x00 +#define DEBUG_DBG 0x01 +#define DEBUG_FAULT 0x02 + +void debugger(struct isr_regs *state, int cause); diff --git a/src/arch/amd64/cpu/idt.S b/src/arch/amd64/cpu/idt.S new file mode 100644 index 0000000..cd8783e --- /dev/null +++ b/src/arch/amd64/cpu/idt.S @@ -0,0 +1,207 @@ +extern idt_exception_handler +global isr_stub_table + +extern idt_pic_timer +extern idt_pic_keyboard +extern idt_pic_mouse +extern idt_pic_eoi + +%macro PUSHALL 0 + push rax + push rbx + push rcx + push rdx + push rsi + push rdi + push rbp + push r8 + push r9 + push r10 + push r11 + push r12 + push r13 + push r14 + push r15 +%endmacro + +%macro POPALL 0 + pop r15 + pop r14 + pop r13 + pop r12 + pop r11 + pop r10 + pop r9 + pop r8 + pop rbp + pop rdi + pop rsi + pop rdx + pop rcx + pop rbx + pop rax +%endmacro + +; call the exception handler with the interrupt number +; args: interrupt number +%macro ISRException 1 +align 8 +isr_stub_%+%1: + PUSHALL + cld + mov rdi, %1 ; exception number + mov rsi, 0 ; placeholder error code + mov rdx, rsp ; top of stack + call idt_exception_handler + POPALL + iretq +%endmacro + +; call the exception handler with the interrupt number +; these exceptions also put an error code on the stack +; args: interrupt number +%macro ISRExceptionCode 1 +align 8 +isr_stub_%+%1: + ; retrieve the error code without corrupting registers + mov [isr_tmp], rax + pop rax + mov [isr_err_code], rax + mov rax, [isr_tmp] + PUSHALL + cld + mov rdi, %1 ; exception number + mov rsi, [isr_err_code] ; error code + mov rdx, rsp ; top of stack + call idt_exception_handler + POPALL + iretq +%endmacro + +%macro PICGeneric 1 +isr_stub_%+%1: + PUSHALL + cld + mov rdi, %1 + call idt_pic_eoi + POPALL + iretq +%endmacro + +%macro PICTimer 1 +isr_stub_%+%1: + PUSHALL + cld + call idt_pic_timer + mov rdi, %1 + call idt_pic_eoi + POPALL + iretq +%endmacro + +%macro PICKeyboard 1 +isr_stub_%+%1: + PUSHALL + cld + call idt_pic_keyboard + mov rdi, %1 + call idt_pic_eoi + POPALL + iretq +%endmacro + +%macro PICMouse 1 +isr_stub_%+%1: + PUSHALL + cld + call idt_pic_mouse + mov rdi, %1 + call idt_pic_eoi + POPALL + iretq +%endmacro + +; do nothing +; args: interrupt number +%macro ISRIgnore 1 +align 8 +isr_stub_%+%1: + iretq +%endmacro + +; isr stubs +section .text +bits 64 + +ISRException 0 +ISRException 1 +ISRException 2 +ISRException 3 +ISRException 4 +ISRException 5 +ISRException 6 +ISRException 7 +ISRExceptionCode 8 +ISRException 9 +ISRExceptionCode 10 +ISRExceptionCode 11 +ISRExceptionCode 12 +ISRExceptionCode 13 +ISRExceptionCode 14 +ISRException 15 +ISRException 16 +ISRExceptionCode 17 +ISRException 18 +ISRException 19 +ISRException 20 +ISRExceptionCode 21 +ISRException 22 +ISRException 23 +ISRException 24 +ISRException 25 +ISRException 26 +ISRException 27 +ISRException 28 +ISRExceptionCode 29 +ISRExceptionCode 30 +ISRException 31 + +PICTimer 32 ; 0 +PICKeyboard 33 ; 1 +PICGeneric 34 ; 2 +PICGeneric 35 ; 3 +PICGeneric 36 ; 4 +PICGeneric 37 ; 5 +PICGeneric 38 ; 6 +PICGeneric 39 ; 7 +PICGeneric 40 ; 8 +PICGeneric 41 ; 9 +PICGeneric 42 ; 10 +PICGeneric 43 ; 11 +PICMouse 44 ; 12 +PICGeneric 45 ; 13 +PICGeneric 46 ; 14 +PICGeneric 47 ; 15 + +; ignore other interrupts +%assign i 48 +%rep 256 - i + ISRIgnore i + %assign i i+1 +%endrep + +section .data +isr_tmp: dq 0 +isr_err_code: dq 0 + +; isr stub table +section .rodata +bits 64 +align 16 + +isr_stub_table: +%assign i 0 +%rep 256 + dq isr_stub_%+i +%assign i i+1 +%endrep diff --git a/src/arch/amd64/cpu/idt.c b/src/arch/amd64/cpu/idt.c new file mode 100644 index 0000000..053f614 --- /dev/null +++ b/src/arch/amd64/cpu/idt.c @@ -0,0 +1,160 @@ +#include +#include +#include +#include +#include "idt.h" +#include "debugger.h" +#include "../paging.h" +#include "../drivers/pic.h" + +#define IDT_SIZE 256 + +struct idt_entry { + uint16_t isr_low; // low 16 bits of isr + uint16_t kernel_cs; // kernel segment selector + uint8_t ist; // interrupt stack table + uint8_t flags; // gate type, privilege level, present bit + uint16_t isr_mid; // middle 16 bits of isr + uint32_t isr_high; // high 32 bits of isr + uint32_t reserved; +} __attribute__((packed)); + +struct idtr { + uint16_t size; + uint64_t address; +} __attribute__((packed)); + +// interrupt gate +#define GATE_64BIT_INT 0x0E +// trap gate +#define GATE_64BIT_TRAP 0x0F + +// privilege ring allowed to call interrupt +#define RING0 0x00 +#define RING1 0x20 +#define RING2 0x40 +#define RING3 0x60 + +// interrupt is present in IDT +#define PRESENT 0x80 + +__attribute__((aligned(0x10))) +static struct idt_entry idt[256]; + +static struct idtr idtr; +// from idt.S +extern void *isr_stub_table[]; + +// initialize and load the IDT +void idt_init(void) { + // initialize idtr + idtr.address = (uint64_t)&idt; + idtr.size = (uint16_t)sizeof(struct idt_entry) * IDT_SIZE - 1; + + // initialize idt + for (size_t vector = 0; vector < IDT_SIZE; vector++) { + struct idt_entry *entry = &idt[vector]; + + uint64_t isr = (uint64_t)isr_stub_table[vector]; + // interrupts before 0x20 are for cpu exceptions + uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT; + + entry->kernel_cs = 0x08; // offset of 1 into GDT + entry->ist = 0; + entry->flags = PRESENT | RING0 | gate_type; + entry->isr_low = isr & 0xffff; + entry->isr_mid = (isr >> 16) & 0xffff; + entry->isr_high = (isr >> 32) & 0xffffffff; + entry->reserved = 0; + } + + __asm__ volatile ("lidt %0" : : "m"(idtr)); +} + +// Intel manual vol 3 ch 6.3.1 +char *EXCEPTIONS[] = { + "Division Error", + "Debug", + "NMI", + "Breakpoint", + "Overflow", + "BOUND Range Exceeded", + "Invalid Opcode", + "Device Not Available", + "Double Fault", + "Coprocessor Segment Overrun", + "Invalid TSS", + "Segment Not Present", + "Stack-Segment Fault", + "General Protection Fault", + "Page Fault", + "Reserved", + "x87 Floating-Point Error", + "Alignment Check", + "Machine Check", + "SIMD Floaing-Point Exception", + "Virtualization Exception", + "Control Protection Exception", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Reserved", + "Hypervisor Injection Exception", + "VMM Communication Exception", + "Security Exception", + "Reserved", +}; + +void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *state) { + switch (exception) { + case 0x01: // debug + debugger(state, DEBUG_DBG); + return; + case 0x03: // breakpoint + debugger(state, DEBUG_INT3); + return; + } + + char custom[64]; + *custom = '\0'; + + // page faults store the offending address in cr2 + if (exception == 0x0E) { + strcat(custom, "\nPage fault address: 0x"); + uint64_t cr2; + __asm__ volatile ("mov %%cr2, %0" : "=r"(cr2)); + ultoa((size_t)cr2, custom + 23, 16); + } + + panic_interrupt( + (void *)state->rip, + (void *)state->rbp, + "Exception %s\nError code 0x%lu%s", + EXCEPTIONS[exception], + code, + custom + ); +} + +void idt_pic_eoi(uint8_t exception) { + pic_eoi(exception - PIC_REMAP_OFFSET); +} + +int counter = 0; + +void idt_pic_timer(void) { + // print a message once we know the timer works + // but avoid spamming the logs + if (counter == 3) { + //kputs("pic timer!\n"); + } + if (counter <= 3) { + counter++; + } +} + +void idt_pic_keyboard(void) {} + +void idt_pic_mouse(void) {} diff --git a/src/arch/amd64/cpu/idt.h b/src/arch/amd64/cpu/idt.h new file mode 100644 index 0000000..89a9dab --- /dev/null +++ b/src/arch/amd64/cpu/idt.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +struct isr_regs { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rbp; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}; + +void idt_init(); diff --git a/src/arch/amd64/debugger.c b/src/arch/amd64/debugger.c deleted file mode 100644 index a1fa968..0000000 --- a/src/arch/amd64/debugger.c +++ /dev/null @@ -1,413 +0,0 @@ -#include -#include -#include -#include -#include "debugger.h" - -struct dr6 { - uint64_t b0 : 1, - b1 : 1, - b2 : 1, - b3 : 1, - : 7, - bld : 1, - : 1, - bd : 1, - bs : 1, - bt : 1, - rtm : 1, - : 47; -}; - -struct dr7 { - uint64_t l0 : 1, - g0 : 1, - l1 : 1, - g1 : 1, - l2 : 1, - g2 : 1, - l3 : 1, - g3 : 1, - : 8, - rw0 : 2, - len0 : 2, - rw1 : 2, - len1 : 2, - rw2 : 2, - len2 : 2, - rw3 : 2, - len3 : 2, - : 32; -}; - -struct rflags { - uint64_t cf : 1, - : 1, - pf : 1, - : 1, - af : 1, - : 1, - zf : 1, - sf : 1, - - tf : 1, - if_ : 1, - df : 1, - of : 1, - iopl : 2, - nt : 1, - md : 1, - - rf : 1, - vm : 1, - ac : 1, - vif : 1, - vip : 1, - id : 1, - : 42; -}; - -struct breakpoint { - uint64_t addr; - uint8_t len; - uint8_t rw; - uint8_t used; - uint8_t enable; - uint8_t instr_len; -}; - -static int dbg_steps = 0; -static int dbg_continue = 0; -static struct breakpoint bkps[4] = {{0}, {0}, {0}, {0}}; - -static size_t debugger_read(char *buf, size_t len) { - char *p = buf; - size_t result; - while (p < buf + len - 1) { - char ch = serial_in(); - switch (ch) { - case '\r': - goto end; - case '\x7f': - if (p > buf) { - p--; - kputs("\x08 \x08"); - } - break; - default: - kputc(ch); - *p++ = ch; - } - } -end: - result = p - buf; - kputc('\n'); - for(; p < buf + len; p++) { - *p = 0; - } - return result; -} - -static void debugger_msg(int cause, struct dr6 dr6) { - switch (cause) { - case DEBUG_INT3: - kputs("dbg: reached int3"); - break; - case DEBUG_FAULT: - kputs("dbg: a fault occured"); - break; - case DEBUG_DBG: - if (dr6.bs) - kputs("dbg: finished steps"); - if (dr6.b0) - kputs("dbg: reached breakpoint 0"); - else if (dr6.b1) - kputs("dbg: reached breakpoint 1"); - else if (dr6.b2) - kputs("dbg: reached breakpoint 2"); - else if (dr6.b3) - kputs("dbg: reached breakpoint 3"); - } - if (dbg_steps > 0) { - kprintf(" (%d steps left)", dbg_steps); - } - if (dbg_continue > 0) { - kputs(" (paused continue)"); - } - kputs("\n"); -} - -static void debugger_print_regs(struct isr_regs *state) { - kprintf("rax: %#016lx (%lu)\n", state->rax, state->rax); - kprintf("rbx: %#016lx (%lu)\n", state->rbx, state->rbx); - kprintf("rcx: %#016lx (%lu)\n", state->rcx, state->rcx); - kprintf("rdx: %#016lx (%lu)\n", state->rdx, state->rdx); - kprintf("rsi: %#016lx (%lu)\n", state->rsi, state->rsi); - kprintf("rdi: %#016lx (%lu)\n", state->rdi, state->rdi); - kprintf("rsp: %#016lx (%lu)\n", state->rsp, state->rsp); - kprintf("rbp: %#016lx (%lu)\n", state->rbp, state->rbp); - kprintf("r8 : %#016lx (%lu)\n", state->r8 , state->r8 ); - kprintf("r9 : %#016lx (%lu)\n", state->r9 , state->r9 ); - kprintf("r10: %#016lx (%lu)\n", state->r10, state->r10); - kprintf("r11: %#016lx (%lu)\n", state->r11, state->r11); - kprintf("r12: %#016lx (%lu)\n", state->r12, state->r12); - kprintf("r13: %#016lx (%lu)\n", state->r13, state->r13); - kprintf("r14: %#016lx (%lu)\n", state->r14, state->r14); - kprintf("r15: %#016lx (%lu)\n", state->r15, state->r15); - kputs("---\n"); - kprintf("rip: %#016lx (%lu)\n", state->rip, state->rip); - kputs("---\n"); - kprintf("rflags: %#016lx (%lu)\n", state->rflags, state->rflags); - struct rflags *rflags = (struct rflags *)state->rflags; - kputs("rflags: "); - if(rflags->cf) kputs("CF "); - if(rflags->pf) kputs("PF "); - if(rflags->af) kputs("AF "); - if(rflags->zf) kputs("ZF "); - if(rflags->sf) kputs("SF "); - if(rflags->tf) kputs("TF "); - if(rflags->if_) kputs("IF "); - if(rflags->df) kputs("DF "); - if(rflags->of) kputs("OF "); - if(rflags->iopl) kputs("IOPL "); - if(rflags->nt) kputs("NT "); - if(rflags->md) kputs("MD "); - if(rflags->rf) kputs("RF "); - if(rflags->vm) kputs("VM "); - if(rflags->ac) kputs("AC "); - if(rflags->vif) kputs("VIF "); - if(rflags->vip) kputs("VIP "); - if(rflags->id) kputs("ID "); - kputs("\n"); -} - -#define PROMPT_LEN 60 - -static int debugger_handle_bkp_cmd(char *msg) { - if (msg[0] == 'l') { - // list breakpoints - for (int i = 0; i < 4; i++) { - struct breakpoint bkp = bkps[i]; - if(!bkp.used) { - kprintf("breakpoint %d: unset\n", i); - continue; - } - const char *lenstrs[] = {"1", "2", "8", "4"}; - const char *rwstrs[] = {"x ", "w ", "io", "rw"}; - kprintf( - "breakpoint %d: %#016lx len=%s trigger=%s instrlen=%01d %s\n", - i, - bkp.addr, - lenstrs[bkp.len], - rwstrs[bkp.rw], - bkp.instr_len, - bkp.enable ? " enabled" : " disabled" - ); - } - return 1; - } else if (msg[0] == 'd') { - // disable breakpoints - bkps[0].enable = 0; - bkps[1].enable = 0; - bkps[2].enable = 0; - bkps[3].enable = 0; - kputs("disabled breakpoints\n"); - return 1; - } else if (msg[0] == 'c') { - // clear breakpoints - bkps[0].used = 0; - bkps[1].used = 0; - bkps[2].used = 0; - bkps[3].used = 0; - kputs("cleared breakpoints\n"); - return 1; - } else if (msg[0] <= '0' && msg[0] >= '3') { - kputs("invalid breakpoint command\n"); - return 1; - } - char buf[64]; - int id = msg[0] - '0'; - switch (msg[1]) { - case 'e': - bkps[id].enable = bkps[id].used; - kprintf("enabled breakpoint %d\n", id); - return 1; - case 'd': - bkps[id].enable = 0; - kprintf("disabled breakpoint %d\n", id); - return 1; - case 'c': - bkps[id].used = 0; - kprintf("cleared breakpoint %d\n", id); - return 1; - case 'a': - kputs("addr> 0x"); - debugger_read(buf, 64); - bkps[id].addr = strtoll(buf, NULL, 16); - kputs("len (1/2/4/8)> "); - debugger_read(buf, 64); - switch (buf[0]) { - case '1': bkps[id].len = 0x0; break; - case '2': bkps[id].len = 0x1; break; - case '8': bkps[id].len = 0x2; break; - case '4': bkps[id].len = 0x3; break; - default: bkps[id].len = 0x0; break; - } - kputs("cond (x/w/io/rw)> "); - debugger_read(buf, 64); - switch ((int)buf[0] * 256 + (int)buf[1]) { - case (int)'x'*256 + (int)0: bkps[id].rw = 0x0; break; - case (int)'w'*256 + (int)0: bkps[id].rw = 0x1; break; - case (int)'i'*256 + (int)'o': bkps[id].rw = 0x2; break; - case (int)'r'*256 + (int)'w': bkps[id].rw = 0x3; break; - default: bkps[id].len = 0x0; break; - } - kputs("instr len (1..15)> "); - debugger_read(buf, 64); - bkps[id].instr_len = strtoi(buf, NULL, 10); - kputs("enable (y/n)> "); - debugger_read(buf, 64); - bkps[id].used = 1; - bkps[id].enable = !(buf[0] == 'n' || buf[0] == 'N'); - kprintf("added breakpoint %d\n", id); - return 1; - default: - kputs("invalid breakpoint command\n"); - return 1; - } -} - -static void debugger_load_bkps() { - struct dr7 dr7; - __asm__ volatile ("mov %%dr7, %0" : "=r"(dr7)); - dr7.g0 = bkps[0].enable & bkps[0].used; - dr7.g1 = bkps[1].enable & bkps[1].used; - dr7.g2 = bkps[2].enable & bkps[2].used; - dr7.g3 = bkps[3].enable & bkps[3].used; - dr7.l0 = 0; - dr7.l1 = 0; - dr7.l2 = 0; - dr7.l3 = 0; - dr7.rw0 = bkps[0].rw; - dr7.rw1 = bkps[1].rw; - dr7.rw2 = bkps[2].rw; - dr7.rw3 = bkps[3].rw; - dr7.len0 = bkps[0].len; - dr7.len1 = bkps[1].len; - dr7.len2 = bkps[2].len; - dr7.len3 = bkps[3].len; - __asm__ volatile ("mov %0, %%dr7" : : "r"(dr7)); - __asm__ volatile ("mov %0, %%dr0" : : "r"(bkps[0].addr)); - __asm__ volatile ("mov %0, %%dr1" : : "r"(bkps[1].addr)); - __asm__ volatile ("mov %0, %%dr2" : : "r"(bkps[2].addr)); - __asm__ volatile ("mov %0, %%dr3" : : "r"(bkps[3].addr)); -} - -static int debugger_prompt(struct isr_regs *state) { - kputs("dbg> "); - char buf[64]; - debugger_read(buf, 64); - - struct rflags *rflags = (struct rflags *)&state->rflags; - - switch (buf[0]) { - case '\0': // nothing entered - return 1; - case 'h': // help - kputs("see debugger.c for help information\n"); - return 1; - case 'q': // quit - return 0; - case 'c': // continue - rflags->tf = 1; - dbg_continue = 1; - return 0; - case 'r': // print registers - debugger_print_regs(state); - return 1; - case 'k': // backtrace - log_backtrace_ex((void *)state->rip, (void *)state->rbp); - return 1; - case 's': // step (n) - rflags->tf = 1; - dbg_steps = atol(buf + 1) - 1; - //if (dbg_steps < 0) dbg_steps = 0; - return 0; - case 'm': // memory - { - kputs("addr> 0x"); - debugger_read(buf, 64); - uint64_t start = (~0xF) & strtoll(buf, NULL, 16); - - kputs("len> 0x"); - debugger_read(buf, 64); - uint64_t len = (~0xF) & strtoll(buf, NULL, 16); - - for (uint64_t a = start; a <= start + len; a += 0x10) { - kprintf("%08lx: ", a); - for (uint64_t b = 0; b < 0x10; b++) { - kprintf("%02x ", *(uint8_t *)(a + b)); - if (b % 0x08 == 7) { - kputc(' '); - } - } - kputs("|"); - for (uint64_t b = 0; b < 0x10; b++) { - uint8_t ch = *(uint8_t *)(a + b); - if (ch < 0x20 || ch >= 0x7f) { - ch = '.'; - } - kputc(ch); - } - kputs("|\n"); - } - return 1; - } - case 'b': // breakpoints - { - int res = debugger_handle_bkp_cmd(buf+1); - debugger_load_bkps(); - return res; - } - default: - kputs("unknown command\n"); - return 1; - } -} - -void debugger(struct isr_regs *state, int cause) { - struct dr6 dr6; - __asm__ volatile ("mov %%dr6, %0" : "=r"(dr6)); - - if (!(dr6.b0 || dr6.b1 || dr6.b2 || dr6.b3)) { - if (dr6.bs && dbg_steps > 0) { - dbg_steps--; - return; - } - - if (dr6.bs && dbg_continue) { - return; - } - } - - debugger_msg(cause, dr6); - - kputs("hi\n"); - - dbg_steps = 0; - dbg_continue = 0; - - ((struct rflags *)&state->rflags)->tf = 0; - - if (dr6.b0) { - state->rip += bkps[0].instr_len; - } else if (dr6.b1) { - state->rip += bkps[1].instr_len; - } else if (dr6.b2) { - state->rip += bkps[2].instr_len; - } else if (dr6.b3) { - state->rip += bkps[3].instr_len; - } - - while (debugger_prompt(state)); -} diff --git a/src/arch/amd64/debugger.h b/src/arch/amd64/debugger.h deleted file mode 100644 index e679c07..0000000 --- a/src/arch/amd64/debugger.h +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once - -#include "idt.h" - -#define DEBUG_INT3 0x00 -#define DEBUG_DBG 0x01 -#define DEBUG_FAULT 0x02 - -void debugger(struct isr_regs *state, int cause); diff --git a/src/arch/amd64/drivers/bochs.c b/src/arch/amd64/drivers/bochs.c new file mode 100644 index 0000000..5383213 --- /dev/null +++ b/src/arch/amd64/drivers/bochs.c @@ -0,0 +1,73 @@ +#include +#include +#include +#include +#include +#include + +#include "../bindings.h" + +#define INDEX 0x1CE +#define DATA 0x1CF + +#define INDEX_ID 0 +#define INDEX_XRES 1 +#define INDEX_YRES 2 +#define INDEX_BPP 3 +#define INDEX_ENABLE 4 +#define INDEX_BANK 5 +#define INDEX_VIRT_WIDTH 6 +#define INDEX_VIRT_HEIGHT 7 +#define INDEX_X_OFFSET 8 +#define INDEX_Y_OFFSET 9 + +#define DATA_DISP_DISABLE 0x00 +#define DATA_DISP_ENABLE 0x01 +#define DATA_LFB_ENABLE 0x40 +#define DATA_NO_CLEAR_MEM 0x80 + +#define BOCHS_PCI_VENDOR 0x1234 +#define BOCHS_PCI_DEVICE 0x1111 + +static void write(uint16_t index, uint16_t data) { + outw(INDEX, index); + outw(DATA, data); +} + +static uint16_t read(uint16_t value) { + outw(INDEX, value); + return inw(DATA); +} + +static int is_available(void) { + return (read(INDEX_ID) == 0xB0C5); +} + +static void set_mode(uint16_t width, uint16_t height, uint16_t bit_depth, int lfb, int clear) { + write(INDEX_ENABLE, DATA_DISP_DISABLE); + write(INDEX_XRES, width); + write(INDEX_YRES, height); + write(INDEX_BPP, bit_depth); + write(INDEX_ENABLE, DATA_DISP_ENABLE | + (lfb ? DATA_LFB_ENABLE : 0) | + (clear ? 0 : DATA_NO_CLEAR_MEM)); +} + +uint32_t* bochs_init(uint16_t width, uint16_t height, uint8_t bit_depth) { + + set_mode(width, height, bit_depth, true, true); + + if (!is_available()) + return NULL; + + struct pci_device bochs = {0}; + bool found = pci_findby_id(&bochs, BOCHS_PCI_DEVICE, BOCHS_PCI_VENDOR, NULL); + if (!found) + return NULL; + + uint32_t bar0 = pci_rcfg_d(bochs, PCI_BAR0_D); + uint32_t *addr = (uint32_t*) (uintptr_t) bar0; + addr = mmap(addr, width * height * bit_depth); + + return addr; +} diff --git a/src/arch/amd64/drivers/pci.c b/src/arch/amd64/drivers/pci.c new file mode 100644 index 0000000..410eb7e --- /dev/null +++ b/src/arch/amd64/drivers/pci.c @@ -0,0 +1,166 @@ +#include +#include +#include +#include + +#include "../bindings.h" + +#define CONF_ADDR 0xCF8 +#define CONF_DATA 0xCFC + +#define TABLE_LEN 16 + +struct pci_table_entry { + struct pci_device device; + uint16_t device_id; + uint16_t vendor_id; + uint8_t class; + uint8_t subclass; + uint8_t prog_if; + uint8_t revision; +}; + +static struct pci_table_entry pci_table[TABLE_LEN]; +static size_t pci_table_next = 0; + +uint32_t pci_rcfg_d(struct pci_device dev, uint8_t offset) { + uint32_t addr = 0x80000000; + addr |= ((uint32_t)dev.bus) << 16; + addr |= ((uint32_t)dev.device) << 11; + addr |= ((uint32_t)dev.function) << 8; + addr |= offset & 0xFC; + + outl(CONF_ADDR, addr); + uint32_t in = inl(CONF_DATA); + return in; +} + +uint16_t pci_rcfg_w(struct pci_device dev, uint8_t offset) { + uint32_t dword = pci_rcfg_d(dev, offset); + return (uint16_t)((dword >> ((offset & 2) * 8)) & 0xFFFF); +} + +uint8_t pci_rcfg_b(struct pci_device dev, uint8_t offset) { + uint32_t dword = pci_rcfg_d(dev, offset); + return (uint8_t)((dword >> ((offset & 3) * 8)) & 0xFF); +} + +void pci_wcfg_d(struct pci_device dev, uint8_t offset, uint32_t dword) { + uint32_t addr = 0x80000000; + addr |= ((uint32_t)dev.bus) << 16; + addr |= ((uint32_t)dev.device) << 11; + addr |= ((uint32_t)dev.function) << 8; + addr |= offset & 0xFC; + + outl(CONF_ADDR, addr); + outl(CONF_DATA, dword); +} + +void pci_wcfg_w(struct pci_device dev, uint8_t offset, uint16_t word) { + size_t shift = (offset & 2) * 8; + uint32_t dword = pci_rcfg_d(dev, offset); + dword &= ~(0xFFFF << shift); + dword |= word << shift; + pci_wcfg_d(dev, offset, dword); +} + +void pci_wcfg_b(struct pci_device dev, uint8_t offset, uint8_t byte) { + size_t shift = (offset & 3) * 8; + uint32_t dword = pci_rcfg_d(dev, offset); + dword &= ~(0xFF << shift); + dword |= byte << shift; + pci_wcfg_d(dev, offset, dword); +} + +static void print_device(struct pci_table_entry *entry) { + kprintf( + "BUS: %#-4x DEV: %#-4x FUNC: %#-4x ID: %04x:%04x CLASS: %02x:%02x:%02x REV: %#02x\n", + entry->device.bus, + entry->device.device, + entry->device.function, + entry->vendor_id, + entry->device_id, + entry->class, + entry->subclass, + entry->prog_if, + entry->revision + ); +} + +static struct pci_table_entry *load_device(struct pci_device dev) { + if(pci_table_next >= TABLE_LEN) panic("Too many PCI devices: limit is %d", TABLE_LEN); + struct pci_table_entry *entry = &pci_table[pci_table_next++]; + entry->device = dev; + uint32_t dword0 = pci_rcfg_d(dev, 0); + uint32_t dword2 = pci_rcfg_d(dev, 8); + + entry->device_id = (dword0 >> 16) & 0xFFFF; + entry->vendor_id = dword0 & 0xFFFF; + + entry->class = (dword2 >> 24) & 0xFF; + entry->subclass = (dword2 >> 16) & 0xFF; + entry->prog_if = (dword2 >> 8) & 0xFF; + entry->revision = dword2 & 0xFF; + + return entry; +} + +void pci_init(void) { + pci_table_next = 0; + struct pci_device pcidev; + for(int bus = 0; bus < 256; bus++) { + pcidev.bus = bus; + for(int dev = 0; dev < 32; dev++) { + pcidev.device = dev; + pcidev.function = 0; + + uint16_t vendor = pci_rcfg_w(pcidev, 0); + if(vendor == 0xFFFF) continue; + + load_device(pcidev); + + uint8_t header_type = pci_rcfg_b(pcidev, 14); + + if(!(header_type & 0x80)) continue; + for(int func = 1; func < 8; func++) { + pcidev.function = func; + + uint16_t vendor = pci_rcfg_w(pcidev, 0); + if(vendor == 0xFFFF) continue; + + load_device(pcidev); + } + } + } + kprintf("PCI DEVICES\n"); + for (size_t i = 0; i < pci_table_next; i++) { + print_device(&pci_table[i]); + } + kprintf("\n"); +} + +bool pci_findby_class(struct pci_device *dest, uint8_t class, uint8_t subclass, size_t *offset) { + size_t o = 0; + if(offset == NULL) offset = &o; + for(; *offset < pci_table_next; (*offset)++) { + struct pci_table_entry *entry = &pci_table[*offset]; + if(entry->class == class && entry->subclass == subclass) { + *dest = entry->device; + return true; + } + } + return false; +} + +bool pci_findby_id(struct pci_device *dest, uint16_t device, uint16_t vendor, size_t *offset) { + size_t o = 0; + if(offset == NULL) offset = &o; + for(; *offset < pci_table_next; (*offset)++) { + struct pci_table_entry *entry = &pci_table[*offset]; + if(entry->device_id == device && entry->vendor_id == vendor) { + *dest = entry->device; + return true; + } + } + return false; +} diff --git a/src/arch/amd64/drivers/pic.c b/src/arch/amd64/drivers/pic.c new file mode 100644 index 0000000..be7716f --- /dev/null +++ b/src/arch/amd64/drivers/pic.c @@ -0,0 +1,89 @@ +#include "../bindings.h" +#include "pic.h" + +#define PIC1 0x20 /* IO base address for master PIC */ +#define PIC2 0xA0 /* IO base address for slave PIC */ +#define PIC1_COMMAND PIC1 +#define PIC1_DATA (PIC1+1) +#define PIC2_COMMAND PIC2 +#define PIC2_DATA (PIC2+1) + +#define PIC_EOI 0x20 /* End-of-interrupt command code */ + +#define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */ +#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ +#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ +#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ +#define ICW1_INIT 0x10 /* Initialization - required! */ + +#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ +#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ +#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ +#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ +#define ICW4_SFNM 0x10 /* Special fully nested (not) */ + +void pic_remap(void) { + uint8_t a1, a2; + + a1 = inb(PIC1_DATA); // save masks + a2 = inb(PIC2_DATA); + + outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode) + io_wait(); + outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); + io_wait(); + outb(PIC1_DATA, PIC_REMAP_OFFSET); // ICW2: Master PIC vector offset + io_wait(); + outb(PIC2_DATA, PIC_REMAP_OFFSET + 8); // ICW2: Slave PIC vector offset + io_wait(); + outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100) + io_wait(); + outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010) + io_wait(); + + outb(PIC1_DATA, ICW4_8086); // ICW4: have the PICs use 8086 mode (and not 8080 mode) + io_wait(); + outb(PIC2_DATA, ICW4_8086); + io_wait(); + + outb(PIC1_DATA, a1); // restore saved masks. + outb(PIC2_DATA, a2); +} + +void pic_mask(int irq) { + uint16_t port; + uint8_t mask; + if (irq < 8) { + port = PIC1_DATA; + } else { + port = PIC2_DATA; + irq -= 8; + } + mask = inb(port) | (1 << irq); + outb(port, mask); +} + +void pic_unmask(int irq) { + uint16_t port; + uint8_t mask; + if (irq < 8) { + port = PIC1_DATA; + } else { + irq -= 8; + port = PIC2_DATA; + } + mask = inb(port) & ~(1 << irq); + outb(port, mask); +} + +void pic_disable(void) { + outb(PIC1_DATA, 0xff); + outb(PIC2_DATA, 0xff); +} + +void pic_eoi(int irq) { + if (irq >= 8) { + outb(PIC2_COMMAND, PIC_EOI); + } + outb(PIC1_COMMAND, PIC_EOI); +} diff --git a/src/arch/amd64/drivers/pic.h b/src/arch/amd64/drivers/pic.h new file mode 100644 index 0000000..2a4670e --- /dev/null +++ b/src/arch/amd64/drivers/pic.h @@ -0,0 +1,31 @@ +#pragma once + +#define PIC_REMAP_OFFSET 0x20 + +/** + * Remaps the pie, i.e. initializes it + */ +void pic_remap(void); + +/** + * Masks an external irq to stop firing until un masked + * @param irq - the irq to mask + */ +void pic_mask(int irq); + +/** + * Unmasks an external irq to allow interrupts to continue for that irq + * @param irq - the irq to unmask + */ +void pic_unmask(int irq); + +/** + * Disabled the pick + */ +void pic_disable(void); + +/** + * Tells the pick that the interrupt has ended + * @param irq - the irq that has ended + */ +void pic_eoi(int irq); diff --git a/src/arch/amd64/drivers/serial.c b/src/arch/amd64/drivers/serial.c new file mode 100644 index 0000000..b9e351e --- /dev/null +++ b/src/arch/amd64/drivers/serial.c @@ -0,0 +1,48 @@ +#include + +#include "../bindings.h" + +#define PORT 0x3F8 + +// initialize the specified COM port for serial +// see https://wiki.osdev.org/Serial_Ports +// and https://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming +int serial_init(void) { + outb(PORT + 1, 0x00); // disable interrupts + outb(PORT + 3, 0x80); // enable DLAB (divisor latch access bit) + outb(PORT + 0, 0x03); // (lo) Set baud divisor to 3 38400 baud + outb(PORT + 1, 0x00); // (hi) + outb(PORT + 3, 0x03); // disable DLAB, set 8 bits per word, one stop bit, no parity + outb(PORT + 2, 0xC7); // enable and clear FIFOs, set to maximum threshold + // outb(port + 4, 0x0B); // TODO copied this from osdev wiki but i don't think you need it here + outb(PORT + 4, 0x1E); // set in loopback mode for test + outb(PORT + 0, 0xAE); // test by sending 0xAE + + uint8_t response = inb(PORT + 0); + if (response != 0xAE) { + // TODO panic here? + return -1; + } + + // disable loopback, enable IRQs + outb(PORT + 4, 0x0F); + return 0; +} + +uint8_t serial_in(void) { + // wait for data to be available + while ((inb(PORT + 5) & 0x01) == 0); + return inb(PORT); +} + +void serial_out(uint8_t ch) { + // wait for output to be free + while ((inb(PORT + 5) & 0x20) == 0); + outb(PORT, ch); +} + +void serial_out_str(const char *str) { + for (; *str != '\0'; str++) { + serial_out(*str); + } +} diff --git a/src/arch/amd64/fb.c b/src/arch/amd64/fb.c deleted file mode 100644 index 8560166..0000000 --- a/src/arch/amd64/fb.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include -#include -#include - -#include "bindings.h" - -#define INDEX 0x1CE -#define DATA 0x1CF - -#define INDEX_ID 0 -#define INDEX_XRES 1 -#define INDEX_YRES 2 -#define INDEX_BPP 3 -#define INDEX_ENABLE 4 -#define INDEX_BANK 5 -#define INDEX_VIRT_WIDTH 6 -#define INDEX_VIRT_HEIGHT 7 -#define INDEX_X_OFFSET 8 -#define INDEX_Y_OFFSET 9 - -#define DATA_DISP_DISABLE 0x00 -#define DATA_DISP_ENABLE 0x01 -#define DATA_LFB_ENABLE 0x40 -#define DATA_NO_CLEAR_MEM 0x80 - -#define BOCHS_PCI_VENDOR 0x1234 -#define BOCHS_PCI_DEVICE 0x1111 - -static void write(uint16_t index, uint16_t data) { - outw(INDEX, index); - outw(DATA, data); -} - -static uint16_t read(uint16_t value) { - outw(INDEX, value); - return inw(DATA); -} - -static int is_available(void) { - return (read(INDEX_ID) == 0xB0C5); -} - -static void set_mode(uint16_t width, uint16_t height, uint16_t bit_depth, int lfb, int clear) { - write(INDEX_ENABLE, DATA_DISP_DISABLE); - write(INDEX_XRES, width); - write(INDEX_YRES, height); - write(INDEX_BPP, bit_depth); - write(INDEX_ENABLE, DATA_DISP_ENABLE | - (lfb ? DATA_LFB_ENABLE : 0) | - (clear ? 0 : DATA_NO_CLEAR_MEM)); -} - -//static void set_bank(uint16_t bank) { -// write(INDEX_BANK, bank); -//} - -int fb_init(uint16_t width, uint16_t height) { - - set_mode(width, height, 32, true, true); - - if (!is_available()) - panic("bochs framebuffer not avaliable"); - - struct pci_device bochs = {0}; - bool found = pci_findby_id(&bochs, BOCHS_PCI_DEVICE, BOCHS_PCI_VENDOR, NULL); - if (!found) - panic("bochs pci device not avaliable"); - - uint32_t bar0 = pci_rcfg_d(bochs, PCI_BAR0_D); - uint32_t *fb = (uint32_t*) (uintptr_t) bar0; - fb = mmap(fb, width * height * 4); - - for (uint16_t y = 0; y < height; y++) { - for (uint16_t x = 0; x < width; x++) { - double dx = x / (double) width, - dy = y / (double) height, - dz = (2 - dx - dy) / 2; - uint32_t r = (uint32_t)(dx * 255), - g = (uint32_t)(dy * 255), - b = (uint32_t)(dz * 255); - fb[x + y * width] = (b << 0) | (g << 8) | (r << 16); - } - } - - - return 0; -} diff --git a/src/arch/amd64/fpu.c b/src/arch/amd64/fpu.c index 551485e..43fc653 100644 --- a/src/arch/amd64/fpu.c +++ b/src/arch/amd64/fpu.c @@ -1,6 +1,7 @@ #include #include #include +#include void enable_fpu() { size_t cr4; diff --git a/src/arch/amd64/idt.S b/src/arch/amd64/idt.S deleted file mode 100644 index cd8783e..0000000 --- a/src/arch/amd64/idt.S +++ /dev/null @@ -1,207 +0,0 @@ -extern idt_exception_handler -global isr_stub_table - -extern idt_pic_timer -extern idt_pic_keyboard -extern idt_pic_mouse -extern idt_pic_eoi - -%macro PUSHALL 0 - push rax - push rbx - push rcx - push rdx - push rsi - push rdi - push rbp - push r8 - push r9 - push r10 - push r11 - push r12 - push r13 - push r14 - push r15 -%endmacro - -%macro POPALL 0 - pop r15 - pop r14 - pop r13 - pop r12 - pop r11 - pop r10 - pop r9 - pop r8 - pop rbp - pop rdi - pop rsi - pop rdx - pop rcx - pop rbx - pop rax -%endmacro - -; call the exception handler with the interrupt number -; args: interrupt number -%macro ISRException 1 -align 8 -isr_stub_%+%1: - PUSHALL - cld - mov rdi, %1 ; exception number - mov rsi, 0 ; placeholder error code - mov rdx, rsp ; top of stack - call idt_exception_handler - POPALL - iretq -%endmacro - -; call the exception handler with the interrupt number -; these exceptions also put an error code on the stack -; args: interrupt number -%macro ISRExceptionCode 1 -align 8 -isr_stub_%+%1: - ; retrieve the error code without corrupting registers - mov [isr_tmp], rax - pop rax - mov [isr_err_code], rax - mov rax, [isr_tmp] - PUSHALL - cld - mov rdi, %1 ; exception number - mov rsi, [isr_err_code] ; error code - mov rdx, rsp ; top of stack - call idt_exception_handler - POPALL - iretq -%endmacro - -%macro PICGeneric 1 -isr_stub_%+%1: - PUSHALL - cld - mov rdi, %1 - call idt_pic_eoi - POPALL - iretq -%endmacro - -%macro PICTimer 1 -isr_stub_%+%1: - PUSHALL - cld - call idt_pic_timer - mov rdi, %1 - call idt_pic_eoi - POPALL - iretq -%endmacro - -%macro PICKeyboard 1 -isr_stub_%+%1: - PUSHALL - cld - call idt_pic_keyboard - mov rdi, %1 - call idt_pic_eoi - POPALL - iretq -%endmacro - -%macro PICMouse 1 -isr_stub_%+%1: - PUSHALL - cld - call idt_pic_mouse - mov rdi, %1 - call idt_pic_eoi - POPALL - iretq -%endmacro - -; do nothing -; args: interrupt number -%macro ISRIgnore 1 -align 8 -isr_stub_%+%1: - iretq -%endmacro - -; isr stubs -section .text -bits 64 - -ISRException 0 -ISRException 1 -ISRException 2 -ISRException 3 -ISRException 4 -ISRException 5 -ISRException 6 -ISRException 7 -ISRExceptionCode 8 -ISRException 9 -ISRExceptionCode 10 -ISRExceptionCode 11 -ISRExceptionCode 12 -ISRExceptionCode 13 -ISRExceptionCode 14 -ISRException 15 -ISRException 16 -ISRExceptionCode 17 -ISRException 18 -ISRException 19 -ISRException 20 -ISRExceptionCode 21 -ISRException 22 -ISRException 23 -ISRException 24 -ISRException 25 -ISRException 26 -ISRException 27 -ISRException 28 -ISRExceptionCode 29 -ISRExceptionCode 30 -ISRException 31 - -PICTimer 32 ; 0 -PICKeyboard 33 ; 1 -PICGeneric 34 ; 2 -PICGeneric 35 ; 3 -PICGeneric 36 ; 4 -PICGeneric 37 ; 5 -PICGeneric 38 ; 6 -PICGeneric 39 ; 7 -PICGeneric 40 ; 8 -PICGeneric 41 ; 9 -PICGeneric 42 ; 10 -PICGeneric 43 ; 11 -PICMouse 44 ; 12 -PICGeneric 45 ; 13 -PICGeneric 46 ; 14 -PICGeneric 47 ; 15 - -; ignore other interrupts -%assign i 48 -%rep 256 - i - ISRIgnore i - %assign i i+1 -%endrep - -section .data -isr_tmp: dq 0 -isr_err_code: dq 0 - -; isr stub table -section .rodata -bits 64 -align 16 - -isr_stub_table: -%assign i 0 -%rep 256 - dq isr_stub_%+i -%assign i i+1 -%endrep diff --git a/src/arch/amd64/idt.c b/src/arch/amd64/idt.c deleted file mode 100644 index d33c795..0000000 --- a/src/arch/amd64/idt.c +++ /dev/null @@ -1,161 +0,0 @@ -#include -#include -#include -#include - -#include "debugger.h" -#include "idt.h" -#include "pic.h" - -#define IDT_SIZE 256 - -struct idt_entry { - uint16_t isr_low; // low 16 bits of isr - uint16_t kernel_cs; // kernel segment selector - uint8_t ist; // interrupt stack table - uint8_t flags; // gate type, privilege level, present bit - uint16_t isr_mid; // middle 16 bits of isr - uint32_t isr_high; // high 32 bits of isr - uint32_t reserved; -} __attribute__((packed)); - -struct idtr { - uint16_t size; - uint64_t address; -} __attribute__((packed)); - -// interrupt gate -#define GATE_64BIT_INT 0x0E -// trap gate -#define GATE_64BIT_TRAP 0x0F - -// privilege ring allowed to call interrupt -#define RING0 0x00 -#define RING1 0x20 -#define RING2 0x40 -#define RING3 0x60 - -// interrupt is present in IDT -#define PRESENT 0x80 - -__attribute__((aligned(0x10))) -static struct idt_entry idt[256]; - -static struct idtr idtr; -// from idt.S -extern void *isr_stub_table[]; - -// initialize and load the IDT -void idt_init(void) { - // initialize idtr - idtr.address = (uint64_t)&idt; - idtr.size = (uint16_t)sizeof(struct idt_entry) * IDT_SIZE - 1; - - // initialize idt - for (size_t vector = 0; vector < IDT_SIZE; vector++) { - struct idt_entry *entry = &idt[vector]; - - uint64_t isr = (uint64_t)isr_stub_table[vector]; - // interrupts before 0x20 are for cpu exceptions - uint8_t gate_type = (vector < 0x20) ? GATE_64BIT_TRAP : GATE_64BIT_INT; - - entry->kernel_cs = 0x08; // offset of 1 into GDT - entry->ist = 0; - entry->flags = PRESENT | RING0 | gate_type; - entry->isr_low = isr & 0xffff; - entry->isr_mid = (isr >> 16) & 0xffff; - entry->isr_high = (isr >> 32) & 0xffffffff; - entry->reserved = 0; - } - - __asm__ volatile ("lidt %0" : : "m"(idtr)); -} - -// Intel manual vol 3 ch 6.3.1 -char *EXCEPTIONS[] = { - "Division Error", - "Debug", - "NMI", - "Breakpoint", - "Overflow", - "BOUND Range Exceeded", - "Invalid Opcode", - "Device Not Available", - "Double Fault", - "Coprocessor Segment Overrun", - "Invalid TSS", - "Segment Not Present", - "Stack-Segment Fault", - "General Protection Fault", - "Page Fault", - "Reserved", - "x87 Floating-Point Error", - "Alignment Check", - "Machine Check", - "SIMD Floaing-Point Exception", - "Virtualization Exception", - "Control Protection Exception", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Reserved", - "Hypervisor Injection Exception", - "VMM Communication Exception", - "Security Exception", - "Reserved", -}; - -void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *state) { - switch (exception) { - case 0x01: // debug - debugger(state, DEBUG_DBG); - return; - case 0x03: // breakpoint - debugger(state, DEBUG_INT3); - return; - } - - char custom[64]; - *custom = '\0'; - - // page faults store the offending address in cr2 - if (exception == 0x0E) { - strcat(custom, "\nPage fault address: 0x"); - uint64_t cr2; - __asm__ volatile ("mov %%cr2, %0" : "=r"(cr2)); - ultoa((size_t)cr2, custom + 23, 16); - } - - panic_interrupt( - (void *)state->rip, - (void *)state->rbp, - "Exception %s\nError code 0x%lu%s", - EXCEPTIONS[exception], - code, - custom - ); -} - -void idt_pic_eoi(uint8_t exception) { - pic_eoi(exception - PIC_REMAP_OFFSET); -} - -int counter = 0; - -void idt_pic_timer(void) { - // print a message once we know the timer works - // but avoid spamming the logs - if (counter == 3) { - kputs("pic timer!\n"); - } - if (counter <= 3) { - counter++; - } -} - -void idt_pic_keyboard(void) {} - -void idt_pic_mouse(void) {} - diff --git a/src/arch/amd64/idt.h b/src/arch/amd64/idt.h deleted file mode 100644 index 89a9dab..0000000 --- a/src/arch/amd64/idt.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include - -struct isr_regs { - uint64_t r15; - uint64_t r14; - uint64_t r13; - uint64_t r12; - uint64_t r11; - uint64_t r10; - uint64_t r9; - uint64_t r8; - uint64_t rbp; - uint64_t rdi; - uint64_t rsi; - uint64_t rdx; - uint64_t rcx; - uint64_t rbx; - uint64_t rax; - - uint64_t rip; - uint64_t cs; - uint64_t rflags; - uint64_t rsp; - uint64_t ss; -}; - -void idt_init(); diff --git a/src/arch/amd64/linker.ld b/src/arch/amd64/linker.ld deleted file mode 100644 index 0032765..0000000 --- a/src/arch/amd64/linker.ld +++ /dev/null @@ -1,38 +0,0 @@ -ENTRY(start) - -SECTIONS { - . = 1M; - - kernel_start = .; - - .boot BLOCK(4K) : ALIGN(4K) - { - *(.multiboot) - } - - .rodata BLOCK(4K) : ALIGN(4K) - { - *(.rodata) - } - - .data BLOCK(4K) : ALIGN(4K) - { - *(.data) - } - - text_start = .; - - .text BLOCK(4K) : ALIGN(4K) - { - *(.text) - } - - text_end = .; - - .bss BLOCK(4K) : ALIGN(4K) - { - *(.bss) - } - - kernel_end = .; -} diff --git a/src/arch/amd64/mboot.c b/src/arch/amd64/mboot.c index 315747e..34424a0 100644 --- a/src/arch/amd64/mboot.c +++ b/src/arch/amd64/mboot.c @@ -9,6 +9,7 @@ #define MBOOT_CMDLINE 1 #define MBOOT_MEMORY_MAP 6 +#define MBOOT_FRAMEBUFFER 8 #define MBOOT_ELF_SYMBOLS 9 #define MBOOT_OLD_RSDP 14 #define MBOOT_NEW_RSDP 15 @@ -82,6 +83,18 @@ struct mboot_tag_cmdline { uint8_t cmdline[]; }; +struct mboot_tag_framebuffer { + uint32_t type; + uint32_t size; + uint64_t framebuffer_addr; + uint32_t framebuffer_pitch; + uint32_t framebuffer_width; + uint32_t framebuffer_height; + uint8_t framebuffer_bpp; + uint8_t framebuffer_type; + uint16_t reserved; +}; + static void read_symbols( struct boot_info *shim_info, struct mboot_tag_elf_sections *sections @@ -133,6 +146,17 @@ static void read_cmdline( shim_info->cmdline[size] = '\0'; } +static void read_framebuffer( + struct boot_info *shim_info, + struct mboot_tag_framebuffer *framebuffer +) { + shim_info->fb.addr = framebuffer->framebuffer_addr; + shim_info->fb.width = framebuffer->framebuffer_width; + shim_info->fb.height = framebuffer->framebuffer_height; + shim_info->fb.pitch = framebuffer->framebuffer_pitch; + shim_info->fb.bit_depth = framebuffer->framebuffer_bpp; +} + static const char *segment_type[] = { "Reserved", "Free", @@ -217,6 +241,12 @@ void mboot_load_info( (struct mboot_tag_cmdline *) tag ); break; + case MBOOT_FRAMEBUFFER: + read_framebuffer( + shim_info, + (struct mboot_tag_framebuffer *) tag + ); + break; case MBOOT_MEMORY_MAP: read_memory_map( shim_info, diff --git a/src/arch/amd64/paging.c b/src/arch/amd64/paging.c index 604e0a0..1c1c56c 100644 --- a/src/arch/amd64/paging.c +++ b/src/arch/amd64/paging.c @@ -45,7 +45,8 @@ struct pde { // PAGE TABLE ENTRY struct pte { uint64_t flags : 9; - uint64_t : 3; + uint64_t loaded : 1; + uint64_t : 2; uint64_t address : 40; uint64_t : 7; uint64_t protection_key : 4; @@ -69,7 +70,7 @@ static struct pde *pd_mapped = (void *) (uintptr_t) 0x202000; static struct pte *pt_mapped = (void *) (uintptr_t) 0x203000; static inline void invlpg(void *addr) { - __asm volatile("invlpg (%0)" ::"r" (addr) : "memory"); + __asm__ volatile("invlpg (%0)" ::"r" (addr) : "memory"); } static void load_addr(void *phys_addr) { @@ -297,6 +298,7 @@ static void unmap_page( page->address = 0; page->flags = 0; + page->loaded = 0; try_unmap_pt(); @@ -360,6 +362,7 @@ static void unmap_pages( page->address = 0; page->flags = 0; + page->loaded = 0; } @@ -369,6 +372,31 @@ static void unmap_pages( return; } +static struct pte *get_page( + struct pml4e *root, + void *virt +) { + struct pdpte *pdpt; + struct pde *pd; + struct pte *pt; + struct pte *page; + + unsigned int df = 0; + + if (select_pdpt(virt, df, root, &pdpt, false)) + return NULL; + + if (select_pd(virt, df, pdpt, &pd, false)) + return NULL; + + if (select_pt(virt, df, pd, &pt, false)) + return NULL; + + select_page(virt, pt, &page); + + return page; +} + static int map_page( struct pml4e *root, void *virt, @@ -382,6 +410,9 @@ static int map_page( unsigned int df = F_WRITEABLE; + if (phys == NULL) + df = 0; // alloc page on fault + if (select_pdpt(virt, df, root, &pdpt, true)) return 1; @@ -393,9 +424,16 @@ static int map_page( select_page(virt, pt, &page); - page->address = (uint64_t)phys >> 12; - page->flags = F_PRESENT | flags; - invlpg(virt); + if (phys) { + page->flags = F_PRESENT | flags; + page->address = (uint64_t)phys >> 12; + page->loaded = 1; + invlpg(virt); + } else { + page->flags = flags; + page->address = 0; + page->loaded = 0; + } return 0; } @@ -424,6 +462,9 @@ static int map_pages( unsigned int df = F_WRITEABLE; + if (phys_start == NULL) + df = 0; // alloc page on fault + long i; for (i = 0; i < page_count; i++) { @@ -454,15 +495,22 @@ static int map_pages( select_page(virt, pt, &page); - page->address = (uint64_t)phys >> 12; - page->flags = F_PRESENT | flags; + if (phys_start) { + page->flags = F_PRESENT | flags; + page->address = (uint64_t)phys >> 12; + page->loaded = 1; + } else { + page->flags = flags; + page->address = 0; + page->loaded = 0; + } if (flags & F_GLOBAL) invlpg(virt); } - __asm volatile("mov %cr3, %rax; mov %rax, %cr3;"); + __asm__ volatile("mov %cr3, %rax; mov %rax, %cr3;"); return 0; @@ -575,3 +623,21 @@ int kunmap_page(void *virt_addr) { unmap_page(kernel_pml4, virt_addr); return 0; } + +int kload_page(void *virt_addr) { + struct pte *page = get_page(kernel_pml4, virt_addr); + if (page == NULL) + return -1; + if (page->loaded) + return -1; + void *phys = alloc_phys_page(); + kprintf("0x%p\n", phys); + if (phys == NULL) + return -2; + page->loaded = 1; + page->address = (uint64_t)phys >> 12; + page->flags |= F_PRESENT | F_WRITEABLE; + invlpg(virt_addr); + __asm__ volatile ("movq %cr3, %rax; movq %rax, %cr3;"); + return 0; +} diff --git a/src/arch/amd64/paging.h b/src/arch/amd64/paging.h index a76a172..9e1352c 100644 --- a/src/arch/amd64/paging.h +++ b/src/arch/amd64/paging.h @@ -13,3 +13,4 @@ void paging_init(void); int kmap_page(void *virt_addr, void *phys_addr, unsigned int flags); int kunmap_page(void *virt_addr); +int kload_page(void *virt_addr); diff --git a/src/arch/amd64/pci.c b/src/arch/amd64/pci.c deleted file mode 100644 index 7b30f0e..0000000 --- a/src/arch/amd64/pci.c +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include -#include -#include - -#include "bindings.h" - -#define CONF_ADDR 0xCF8 -#define CONF_DATA 0xCFC - -#define TABLE_LEN 16 - -struct pci_table_entry { - struct pci_device device; - uint16_t device_id; - uint16_t vendor_id; - uint8_t class; - uint8_t subclass; - uint8_t prog_if; - uint8_t revision; -}; - -static struct pci_table_entry pci_table[TABLE_LEN]; -static size_t pci_table_next = 0; - -uint32_t pci_rcfg_d(struct pci_device dev, uint8_t offset) { - uint32_t addr = 0x80000000; - addr |= ((uint32_t)dev.bus) << 16; - addr |= ((uint32_t)dev.device) << 11; - addr |= ((uint32_t)dev.function) << 8; - addr |= offset & 0xFC; - - outl(CONF_ADDR, addr); - uint32_t in = inl(CONF_DATA); - return in; -} - -uint16_t pci_rcfg_w(struct pci_device dev, uint8_t offset) { - uint32_t dword = pci_rcfg_d(dev, offset); - return (uint16_t)((dword >> ((offset & 2) * 8)) & 0xFFFF); -} - -uint8_t pci_rcfg_b(struct pci_device dev, uint8_t offset) { - uint32_t dword = pci_rcfg_d(dev, offset); - return (uint8_t)((dword >> ((offset & 3) * 8)) & 0xFF); -} - -void pci_wcfg_d(struct pci_device dev, uint8_t offset, uint32_t dword) { - uint32_t addr = 0x80000000; - addr |= ((uint32_t)dev.bus) << 16; - addr |= ((uint32_t)dev.device) << 11; - addr |= ((uint32_t)dev.function) << 8; - addr |= offset & 0xFC; - - outl(CONF_ADDR, addr); - outl(CONF_DATA, dword); -} - -void pci_wcfg_w(struct pci_device dev, uint8_t offset, uint16_t word) { - size_t shift = (offset & 2) * 8; - uint32_t dword = pci_rcfg_d(dev, offset); - dword &= ~(0xFFFF << shift); - dword |= word << shift; - pci_wcfg_d(dev, offset, dword); -} - -void pci_wcfg_b(struct pci_device dev, uint8_t offset, uint8_t byte) { - size_t shift = (offset & 3) * 8; - uint32_t dword = pci_rcfg_d(dev, offset); - dword &= ~(0xFF << shift); - dword |= byte << shift; - pci_wcfg_d(dev, offset, dword); -} - -static void print_device(struct pci_table_entry *entry) { - kprintf( - "BUS: %#-4x DEV: %#-4x FUNC: %#-4x ID: %04x:%04x CLASS: %02x:%02x:%02x REV: %#02x\n", - entry->device.bus, - entry->device.device, - entry->device.function, - entry->vendor_id, - entry->device_id, - entry->class, - entry->subclass, - entry->prog_if, - entry->revision - ); -} - -static struct pci_table_entry *load_device(struct pci_device dev) { - if(pci_table_next >= TABLE_LEN) panic("Too many PCI devices: limit is %d", TABLE_LEN); - struct pci_table_entry *entry = &pci_table[pci_table_next++]; - entry->device = dev; - uint32_t dword0 = pci_rcfg_d(dev, 0); - uint32_t dword2 = pci_rcfg_d(dev, 8); - - entry->device_id = (dword0 >> 16) & 0xFFFF; - entry->vendor_id = dword0 & 0xFFFF; - - entry->class = (dword2 >> 24) & 0xFF; - entry->subclass = (dword2 >> 16) & 0xFF; - entry->prog_if = (dword2 >> 8) & 0xFF; - entry->revision = dword2 & 0xFF; - - return entry; -} - -void pci_init(void) { - pci_table_next = 0; - struct pci_device pcidev; - for(int bus = 0; bus < 256; bus++) { - pcidev.bus = bus; - for(int dev = 0; dev < 32; dev++) { - pcidev.device = dev; - pcidev.function = 0; - - uint16_t vendor = pci_rcfg_w(pcidev, 0); - if(vendor == 0xFFFF) continue; - - load_device(pcidev); - - uint8_t header_type = pci_rcfg_b(pcidev, 14); - - if(!(header_type & 0x80)) continue; - for(int func = 1; func < 8; func++) { - pcidev.function = func; - - uint16_t vendor = pci_rcfg_w(pcidev, 0); - if(vendor == 0xFFFF) continue; - - load_device(pcidev); - } - } - } - kprintf("PCI DEVICES\n"); - for (size_t i = 0; i < pci_table_next; i++) { - print_device(&pci_table[i]); - } - kprintf("\n"); -} - -bool pci_findby_class(struct pci_device *dest, uint8_t class, uint8_t subclass, size_t *offset) { - size_t o = 0; - if(offset == NULL) offset = &o; - for(; *offset < pci_table_next; (*offset)++) { - struct pci_table_entry *entry = &pci_table[*offset]; - if(entry->class == class && entry->subclass == subclass) { - *dest = entry->device; - return true; - } - } - return false; -} - -bool pci_findby_id(struct pci_device *dest, uint16_t device, uint16_t vendor, size_t *offset) { - size_t o = 0; - if(offset == NULL) offset = &o; - for(; *offset < pci_table_next; (*offset)++) { - struct pci_table_entry *entry = &pci_table[*offset]; - if(entry->device_id == device && entry->vendor_id == vendor) { - *dest = entry->device; - return true; - } - } - return false; -} diff --git a/src/arch/amd64/pic.c b/src/arch/amd64/pic.c deleted file mode 100644 index c25856b..0000000 --- a/src/arch/amd64/pic.c +++ /dev/null @@ -1,89 +0,0 @@ -#include "bindings.h" -#include "pic.h" - -#define PIC1 0x20 /* IO base address for master PIC */ -#define PIC2 0xA0 /* IO base address for slave PIC */ -#define PIC1_COMMAND PIC1 -#define PIC1_DATA (PIC1+1) -#define PIC2_COMMAND PIC2 -#define PIC2_DATA (PIC2+1) - -#define PIC_EOI 0x20 /* End-of-interrupt command code */ - -#define ICW1_ICW4 0x01 /* Indicates that ICW4 will be present */ -#define ICW1_SINGLE 0x02 /* Single (cascade) mode */ -#define ICW1_INTERVAL4 0x04 /* Call address interval 4 (8) */ -#define ICW1_LEVEL 0x08 /* Level triggered (edge) mode */ -#define ICW1_INIT 0x10 /* Initialization - required! */ - -#define ICW4_8086 0x01 /* 8086/88 (MCS-80/85) mode */ -#define ICW4_AUTO 0x02 /* Auto (normal) EOI */ -#define ICW4_BUF_SLAVE 0x08 /* Buffered mode/slave */ -#define ICW4_BUF_MASTER 0x0C /* Buffered mode/master */ -#define ICW4_SFNM 0x10 /* Special fully nested (not) */ - -void pic_remap(void) { - uint8_t a1, a2; - - a1 = inb(PIC1_DATA); // save masks - a2 = inb(PIC2_DATA); - - outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4); // starts the initialization sequence (in cascade mode) - io_wait(); - outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4); - io_wait(); - outb(PIC1_DATA, PIC_REMAP_OFFSET); // ICW2: Master PIC vector offset - io_wait(); - outb(PIC2_DATA, PIC_REMAP_OFFSET + 8); // ICW2: Slave PIC vector offset - io_wait(); - outb(PIC1_DATA, 4); // ICW3: tell Master PIC that there is a slave PIC at IRQ2 (0000 0100) - io_wait(); - outb(PIC2_DATA, 2); // ICW3: tell Slave PIC its cascade identity (0000 0010) - io_wait(); - - outb(PIC1_DATA, ICW4_8086); // ICW4: have the PICs use 8086 mode (and not 8080 mode) - io_wait(); - outb(PIC2_DATA, ICW4_8086); - io_wait(); - - outb(PIC1_DATA, a1); // restore saved masks. - outb(PIC2_DATA, a2); -} - -void pic_mask(int irq) { - uint16_t port; - uint8_t mask; - if (irq < 8) { - port = PIC1_DATA; - } else { - port = PIC2_DATA; - irq -= 8; - } - mask = inb(port) | (1 << irq); - outb(port, mask); -} - -void pic_unmask(int irq) { - uint16_t port; - uint8_t mask; - if (irq < 8) { - port = PIC1_DATA; - } else { - irq -= 8; - port = PIC2_DATA; - } - mask = inb(port) & ~(1 << irq); - outb(port, mask); -} - -void pic_disable(void) { - outb(PIC1_DATA, 0xff); - outb(PIC2_DATA, 0xff); -} - -void pic_eoi(int irq) { - if (irq >= 8) { - outb(PIC2_COMMAND, PIC_EOI); - } - outb(PIC1_COMMAND, PIC_EOI); -} diff --git a/src/arch/amd64/pic.h b/src/arch/amd64/pic.h deleted file mode 100644 index 2a4670e..0000000 --- a/src/arch/amd64/pic.h +++ /dev/null @@ -1,31 +0,0 @@ -#pragma once - -#define PIC_REMAP_OFFSET 0x20 - -/** - * Remaps the pie, i.e. initializes it - */ -void pic_remap(void); - -/** - * Masks an external irq to stop firing until un masked - * @param irq - the irq to mask - */ -void pic_mask(int irq); - -/** - * Unmasks an external irq to allow interrupts to continue for that irq - * @param irq - the irq to unmask - */ -void pic_unmask(int irq); - -/** - * Disabled the pick - */ -void pic_disable(void); - -/** - * Tells the pick that the interrupt has ended - * @param irq - the irq that has ended - */ -void pic_eoi(int irq); diff --git a/src/arch/amd64/serial.c b/src/arch/amd64/serial.c deleted file mode 100644 index fe21629..0000000 --- a/src/arch/amd64/serial.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include "bindings.h" - -#define PORT 0x3F8 - -// initialize the specified COM port for serial -// see https://wiki.osdev.org/Serial_Ports -// and https://en.wikibooks.org/wiki/Serial_Programming/8250_UART_Programming -int serial_init(void) { - outb(PORT + 1, 0x00); // disable interrupts - outb(PORT + 3, 0x80); // enable DLAB (divisor latch access bit) - outb(PORT + 0, 0x03); // (lo) Set baud divisor to 3 38400 baud - outb(PORT + 1, 0x00); // (hi) - outb(PORT + 3, 0x03); // disable DLAB, set 8 bits per word, one stop bit, no parity - outb(PORT + 2, 0xC7); // enable and clear FIFOs, set to maximum threshold - // outb(port + 4, 0x0B); // TODO copied this from osdev wiki but i don't think you need it here - outb(PORT + 4, 0x1E); // set in loopback mode for test - outb(PORT + 0, 0xAE); // test by sending 0xAE - - uint8_t response = inb(PORT + 0); - if (response != 0xAE) { - // TODO panic here? - return -1; - } - - // disable loopback, enable IRQs - outb(PORT + 4, 0x0F); - return 0; -} - -uint8_t serial_in(void) { - // wait for data to be available - while ((inb(PORT + 5) & 0x01) == 0); - return inb(PORT); -} - -void serial_out(uint8_t ch) { - // wait for output to be free - while ((inb(PORT + 5) & 0x20) == 0); - outb(PORT, ch); -} - -void serial_out_str(const char *str) { - for (; *str != '\0'; str++) { - serial_out(*str); - } -} diff --git a/src/arch/amd64/shim.c b/src/arch/amd64/shim.c index c161c88..b84167c 100644 --- a/src/arch/amd64/shim.c +++ b/src/arch/amd64/shim.c @@ -6,8 +6,8 @@ #include "paging.h" #include "mboot.h" -#include "idt.h" -#include "pic.h" +#include "cpu/idt.h" +#include "drivers/pic.h" static struct boot_info boot_info; -- cgit v1.2.3-freya