diff --git a/bin/os b/bin/os index 52b90eb..2d0b0cf 100755 Binary files a/bin/os and b/bin/os differ diff --git a/image.hdd b/image.hdd index 1ace025..e9406da 100644 Binary files a/image.hdd and b/image.hdd differ diff --git a/obj/src/int.c.d b/obj/src/int.c.d index 21bcf73..efb2f36 100644 --- a/obj/src/int.c.d +++ b/obj/src/int.c.d @@ -1,3 +1,4 @@ -obj/src/int.c.o: src/int.c src/print.h src/common.h -src/print.h: +obj/src/int.c.o: src/int.c src/apic.h src/common.h src/print.h +src/apic.h: src/common.h: +src/print.h: diff --git a/obj/src/int.c.o b/obj/src/int.c.o index b317f52..0784825 100644 Binary files a/obj/src/int.c.o and b/obj/src/int.c.o differ diff --git a/obj/src/main.c.d b/obj/src/main.c.d index 9650bd8..927ac6e 100644 --- a/obj/src/main.c.d +++ b/obj/src/main.c.d @@ -1,7 +1,9 @@ obj/src/main.c.o: src/main.c src/../include/limine.h src/acpi.h \ - src/common.h src/alloc.h src/print.h + src/common.h src/apic.h src/alloc.h src/map.h src/print.h src/../include/limine.h: src/acpi.h: src/common.h: +src/apic.h: src/alloc.h: +src/map.h: src/print.h: diff --git a/obj/src/main.c.o b/obj/src/main.c.o index 1f3405b..c6a62a6 100644 Binary files a/obj/src/main.c.o and b/obj/src/main.c.o differ diff --git a/src/alloc.c b/src/alloc.c index 19fa70c..9a05ddd 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -151,12 +151,18 @@ void* alloc(size_t size) { size_t page = 0; if(pages == 0 || pages >= total_pages) { + print("Too many or too few pages: "); + print8(pages); + print("\n"); return NULL; } + print("Attempting to find "); + print64(pages); + print(" consecutive pages\n"); size_t consecutive = 0; - for(size_t i = 0; i < pages; i++) { + for(size_t i = 0; i < total_pages/64; i++) { u64 word = alloc_bitmap[i]; if(word == 0) { if(!consecutive) @@ -181,7 +187,7 @@ void* alloc(size_t size) { if(++consecutive >= pages) { usepagerange(page, pages); - return addr(pages); + return addr(page); } } else { consecutive = 0; @@ -190,7 +196,6 @@ void* alloc(size_t size) { } } - return NULL; } diff --git a/src/apic.c b/src/apic.c index 84562aa..0e9e38c 100644 --- a/src/apic.c +++ b/src/apic.c @@ -11,7 +11,7 @@ enum { PIC_DATA_SLAVE = 0xA1, }; -#define IOAPIC_REG_REDIR(n) (0x10 + 2(n)) +#define IOAPIC_REG_REDIR(n) (0x10 + 2*(n)) enum { IOAPIC_REG_SELECT = 0x00, @@ -27,6 +27,7 @@ enum { #define IOAPIC_ACTIVE_LOW (1 << 13) #define IOAPIC_ACTIVE_HIGH (0 << 13) + static void pic_init() { // Start initialization sequence outb(PIC_COMM_MASTER, 0x11); // ICW1: Initialize in cascading mode @@ -84,19 +85,30 @@ u64 apic_get_local_base() { static u64 apic_set_local_base(u64 base) { const u8 APIC_BASE_MSR = 0x1B; - - wrmsr(APIC_BASE_MSR, base & 0xfffff000); + + u64 msr = rdmsr(APIC_BASE_MSR); + msr &= 0xFFF; // keep flags + msr |= (base & 0xFFFFF000); + msr |= (1 << 11); // to ensure APIC is enabled + + wrmsr(APIC_BASE_MSR, msr); return base & 0xfffff000; } -static u32* apic_reg(u32 reg) { - return (u32*) (apic_base + reg); +u32* apic_reg(u32 reg) { + return (u32*) (hhdm_offset + apic_base + reg); +} + +void send_eoi() { + volatile u32* reg= apic_reg(0xB0); + *reg = 0; } void apic_enable() { pic_disable(); print("\nPIC Disabled\n"); + apic_set_local_base(apic_get_local_base()); if(!map_mmio((u64)apic_base, 1<<12)) { @@ -104,15 +116,35 @@ void apic_enable() { hang(); } - volatile u32* reg = apic_reg(0xF0); + volatile u32* spurious = apic_reg(0xF0); print("Reg 0xF0 at 0x"); - print64((u64) reg); + print64((u64) spurious); + print("\nSpurious: "); + print32(*spurious); // set enable flag - *reg = (*reg | 0x100); - print("\nReg written\n"); + *spurious |= 0x100; + print(" after flag: "); + print32(*spurious); + print("\n"); + + // TPR = 0 (accept all interrupts) + volatile u32* tpr = apic_reg(0x80); + *tpr = 0; + + // Mask all LVT antries except LINT0 (0x21) + + volatile u32* timer = apic_reg(0x320); + *timer = (1 << 16); + volatile u32* LINT0 = apic_reg(0x350); + *LINT0 = (7 << 8); +// *LINT0 = (1 << 16); + volatile u32* LINT1 = apic_reg(0x360); + *LINT1 = (1 << 16); + volatile u32* Error = apic_reg(0x370); + *Error = (1 << 16); } -static u32* ioapic_base; +static volatile u32* ioapic_base; void ioapic_write(u8 reg, u32 value) { ioapic_base[IOAPIC_REG_SELECT / 4] = reg; @@ -124,8 +156,63 @@ u32 ioapic_read(u8 reg) { return ioapic_base[IOAPIC_REG_WINDOW / 4]; } - - void ioapic_init() { - + // simply assume it is at the default address + ioapic_base = map_mmio(0xFEC00000, 4096); + print("IOAPIC BASE: "); + print64((u64)ioapic_base); + print("\nIOAPIC Version:"); + ioapic_base[0] = 0x01; + print32(ioapic_base[4]); + print("\n"); + + // mask all IRQs + for(size_t i = 0; i < 24; i++) { + u8 vect = 0x20 + i; + u32 low = vect | IOAPIC_MASKED | IOAPIC_DST_PHYS | IOAPIC_EDGE_TRIGG | IOAPIC_ACTIVE_HIGH; + u32 high = 0; + + ioapic_write(0x10 + i*2, low); + ioapic_write(0x10 + i*2 + 1, high); + } + + // setup keyboard by selecting IRQ1 + u8 irq = 1; + u8 vect = 0x21; + u8 cpu = 0; + + u32 low = ioapic_read(IOAPIC_REG_REDIR(irq)); + u32 high = ioapic_read(IOAPIC_REG_REDIR(irq)+1); + + + print("Current redirection for IRQ"); + print8(irq); + print(": "); + print32(low); + print(" "); + print32(high); + print("\n"); + + // Configure keyboard - UNMASKED (no IOAPIC_MASKED bit!) + low = vect | IOAPIC_DST_PHYS | IOAPIC_EDGE_TRIGG | IOAPIC_ACTIVE_HIGH; + high = (cpu << 24); + + ioapic_write(IOAPIC_REG_REDIR(irq), low); + ioapic_write(IOAPIC_REG_REDIR(irq)+1, high); + + low = ioapic_read(IOAPIC_REG_REDIR(irq)); + high = ioapic_read(IOAPIC_REG_REDIR(irq)+1); + // Verify it worked + print("Current redirection for IRQ"); + print8(irq); + print(": "); + print32(low); + print(" "); + print32(high); + print("\n"); + if (low & IOAPIC_MASKED) { + print(" [STILL MASKED (BAD)]\n"); + } else { + print(" [UNMASKED (GOOD)]\n"); + } } diff --git a/src/apic.h b/src/apic.h new file mode 100644 index 0000000..d9efe8c --- /dev/null +++ b/src/apic.h @@ -0,0 +1,11 @@ +#pragma once + +#include "common.h" + +u32 apic_get_local_base(); +void apic_enable(); +void send_eoi(); +void ioapic_write(u8 reg, u32 value); +u32 ioapic_read(u8 reg); +void ioapic_init(); +u32* apic_reg(u32 reg); diff --git a/src/common.h b/src/common.h index 5c8e7d2..83977ab 100644 --- a/src/common.h +++ b/src/common.h @@ -33,6 +33,23 @@ static inline void outd(u16 port, u32 value) { asm volatile ("outl %0, %1" : : "a"(value), "Nd"(port)); } +static inline u8 inb(u16 port) { + u8 value; + asm volatile ("inb %w1, %b0" : "=a"(value) : "Nd"(port) : "memory"); + return value; +} +static inline u16 inw(u16 port) { + u16 value; + asm volatile ("inw %w1, %b0" : "=a"(value) : "Nd"(port) : "memory"); + return value; +} +static inline u32 ind(u16 port) { + u32 value; + asm volatile ("ind %w1, %b0" : "=a"(value) : "Nd"(port) : "memory"); + return value; +} + + void* memcpy(void* dst, const void* src, size_t n); void* memset(void* s, int c, size_t n); diff --git a/src/int.c b/src/int.c index ec7f739..efee74f 100644 --- a/src/int.c +++ b/src/int.c @@ -1,5 +1,6 @@ #include +#include "apic.h" // for debugging #include "print.h" @@ -80,7 +81,8 @@ struct cpu_ctx* interrupt_dispatch(struct cpu_ctx* ctx) { print("] with message: "); print64(dbg_var); print("\n"); - while(1); + + send_eoi(); return ctx; } diff --git a/src/main.c b/src/main.c index 1d5fb09..4955666 100644 --- a/src/main.c +++ b/src/main.c @@ -5,8 +5,10 @@ #include "../include/limine.h" #include "acpi.h" +#include "apic.h" #include "alloc.h" #include "common.h" +#include "map.h" #include "print.h" // credit owed to https://wiki.osdev.org/Limine_Bare_Bones for the limine setup code @@ -106,9 +108,7 @@ void draw(u8 vect) { for(size_t x = 0; x < fb->width; x++) { volatile u32* fb_ptr = fb->address; fb_ptr[y * fb->width + x] = ( - (x + y) * 0x00010000 | - (x ^ y) * 0x00000100 | - (x - y) * 0x00000001 + ((x ^ y) & 0xff) * 0x0F0003 )*vect; } } @@ -119,11 +119,23 @@ extern void init_idt(void); extern u32 fg; extern u32 bg; - - -u32 apic_get_local_base(); -void apic_enable(); -void setup_identity_mapping(); +void enable_ps2_keyboard_interrupts(void) { + // Read PS/2 configuration byte + outb(0x64, 0x20); + while (!(inb(0x64) & 0x01)); // Wait for data + u8 config = inb(0x60); + + // Enable keyboard interrupt (bit 0) and clock (clear bit 4) + config |= 0x01; // Enable first port interrupt + config &= ~0x10; // Enable first port clock + + // Write config back + outb(0x64, 0x60); + outb(0x60, config); + + // Enable keyboard port + outb(0x64, 0xAE); +} void kmain() { if(LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) { @@ -136,10 +148,11 @@ void kmain() { fb = fb_req.response->framebuffers[0]; + draw(1); print_init(fb); init_idt(); - - + bg = 0xFFFFFF; + fg = 0x000000; if(!hhdm_req.response) { print("Failed to get higher half direct mapping\n."); @@ -155,6 +168,7 @@ void kmain() { alloc_init(); + rsdp = (struct acpi_rsdp_header*)(rsdp_req.response->address); @@ -182,14 +196,61 @@ void kmain() { /* I should check cpuid to ensure its supported but it will * be for my machines ;^) */ /* APIC stuff */ - u32 r = 0xDEADBEEF; - r = apic_get_local_base(); - print32(r); - apic_enable(); + print("APIC Enabled\n"); + ioapic_init(); - print("\nAPIC Enabled"); + if(!test_if_mapped((u64) apic_reg(0))) { + print("Mapping APIC registers failed :(\n"); + hang(); + } + + u32 id = *apic_reg(0x20); + print("LAPIC ID: "); + print32(id); + print("\n"); + + print("Enabling keyboard\n"); + enable_ps2_keyboard_interrupts(); + + outb(0x64, 0x20); // Read config + while (!(inb(0x64) & 0x01)); + u8 config = inb(0x60); + + asm volatile("sti"); + print("Press a key NOW...\n"); + volatile u32* tpr = apic_reg(0x80); + print("TPR: 0x"); + print32(*tpr); + print("\n"); + + print("PS/2 config: 0x"); + print8(config); + if (!(config & 0x01)) { + print("\nProblem: Bit 0 is 0 (interrupt disabled)\n"); + } else { + print("\nOK: Bit 0 is 1 (interrupt enabled)\n"); + } + print("Press keys (polling test)...\n"); + while (1) { + if (inb(0x64) & 0x01) { // Data available + u8 code = inb(0x60); + print("Scan code: 0x"); + print8(code); + print("\n"); + volatile u32* irr = apic_reg(0x210); + print32(*irr); + irr = apic_reg(0x200); // IRR bits 31:0 + u32* isr = apic_reg(0x100); // ISR bits 31:0 + + print("IRR: "); print32(*irr); + print(" ISR: "); print32(*isr); + print("\n"); + if (code == 0x01) break; // ESC + } + } + hang(); } diff --git a/src/map.c b/src/map.c index b8a28de..5c89772 100644 --- a/src/map.c +++ b/src/map.c @@ -39,6 +39,9 @@ static u64 get_cr3() { static u64 alloc_page_table() { void* a = alloc((1<<12) / PAGE_SIZE); + if(!a) { + print("Failed to allocate page table\n"); + } return a? virt_to_phys(a) : 0; } @@ -47,6 +50,7 @@ static struct page_entry* get_or_create_table(struct page_entry *table, u64 inde if (!table[index].present) { u64 new_table_phys = alloc_page_table(); if (new_table_phys == 0) { + print("failed to alloc\n"); return NULL; } @@ -71,8 +75,8 @@ void* map_mmio(u64 physical_addr, u64 size) { print("\n Size: 0x"); print64(size); print(" ("); - print64(size); - print(" bytes)\n"); + print64(size >> 20); + print(" MiB)\n"); // Align physical address down to page boundary u64 phys_base = physical_addr & ~(PAGE_SIZE-1); @@ -154,6 +158,89 @@ void* map_mmio(u64 physical_addr, u64 size) { return (void*)(virt_base + offset_in_page); } +// Test correct mapping +int test_if_mapped(u64 virt_addr) { + // Try to read - if we get page fault, it's not mapped + // For now, just check the page tables manually + + u64 pml4_idx = (virt_addr >> 39) & 0x1FF; + u64 pdpt_idx = (virt_addr >> 30) & 0x1FF; + u64 pd_idx = (virt_addr >> 21) & 0x1FF; + u64 pt_idx = (virt_addr >> 12) & 0x1FF; + + // Get CR3 + u64 cr3; + asm volatile("mov %%cr3, %0" : "=r"(cr3)); + u64 pml4_phys = cr3 & ~0xFFF; + + struct page_entry { + u64 present : 1; + u64 writable : 1; + u64 user : 1; + u64 write_through : 1; + u64 cache_disabled : 1; + u64 accessed : 1; + u64 dirty : 1; + u64 huge_page : 1; + u64 global : 1; + u64 unused : 3; + u64 frame : 40; + u64 reserved : 11; + u64 no_execute : 1; + }; + + // Access PML4 + struct page_entry *pml4 = (struct page_entry*)(pml4_phys + hhdm_offset); + + if (!pml4[pml4_idx].present) { + print(" PML4["); + print64(pml4_idx); + print("] NOT PRESENT\n"); + return 0; + } + + // Access PDPT + struct page_entry *pdpt = (struct page_entry*)(((u64)pml4[pml4_idx].frame << 12) + hhdm_offset); + + if (!pdpt[pdpt_idx].present) { + print(" PDPT["); + print64(pdpt_idx); + print("] NOT PRESENT\n"); + return 0; + } + + // Access PD + struct page_entry *pd = (struct page_entry*)(((u64)pdpt[pdpt_idx].frame << 12) + hhdm_offset); + + if (!pd[pd_idx].present) { + print(" PD["); + print64(pd_idx); + print("] NOT PRESENT\n"); + return 0; + } + + // Access PT + struct page_entry *pt = (struct page_entry*)(((u64)pd[pd_idx].frame << 12) + hhdm_offset); + + if (!pt[pt_idx].present) { + print(" PT["); + print64(pt_idx); + print("] NOT PRESENT\n"); + return 0; + } + + print(" All levels present\n"); + print(" Physical page: 0x"); + print64((u64)pt[pt_idx].frame << 12); + print("\n"); + print(" Cache disabled: "); + print8(pt[pt_idx].cache_disabled); + print("\n"); + + return 1; +} + + // Unmap MMIO region void unmap_mmio(void *virtual_addr, u64 size) { u64 virt_base = (u64)virtual_addr & ~0xFFF; diff --git a/src/map.h b/src/map.h index 4ce0ccd..b3e50cf 100644 --- a/src/map.h +++ b/src/map.h @@ -3,4 +3,4 @@ #include "common.h" void* map_mmio(u64, u64); - +int test_if_mapped(u64 virt_addr);