Added code to setup IRQ's through ioapic but somethings still not working

This commit is contained in:
Conál Paxton 2026-02-15 21:09:19 -05:00
parent d4e1c29f07
commit 07e8015800
14 changed files with 311 additions and 38 deletions

BIN
bin/os

Binary file not shown.

BIN
image.hdd

Binary file not shown.

View File

@ -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:

Binary file not shown.

View File

@ -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:

Binary file not shown.

View File

@ -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;
}

View File

@ -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
@ -85,18 +86,29 @@ 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");
}
}

11
src/apic.h Normal file
View File

@ -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);

View File

@ -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);

View File

@ -1,5 +1,6 @@
#include <stdint.h>
#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;
}

View File

@ -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;
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
u32 apic_get_local_base();
void apic_enable();
void setup_identity_mapping();
// 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,13 +196,60 @@ 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();

View File

@ -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;

View File

@ -3,4 +3,4 @@
#include "common.h"
void* map_mmio(u64, u64);
int test_if_mapped(u64 virt_addr);