Fixed small errors in PIC signalling, added code for allocation and MMIO mapping

This commit is contained in:
Conál Paxton 2026-02-15 05:55:36 -05:00
parent 4ca9447efa
commit d4e1c29f07
19 changed files with 1324 additions and 734 deletions

BIN
bin/os

Binary file not shown.

4
bochs.bxrc Normal file
View File

@ -0,0 +1,4 @@
vga: extension=vgahw
ata0-master: type=disk, path="image.hdd", mode=flat
boot: disk
memory: guest=1024, host=1024

View File

@ -1,3 +0,0 @@
vga: extension=vgahw
display_library: x, options="gui_debug"

26
flake.lock generated
View File

@ -1,26 +0,0 @@
{
"nodes": {
"nixpkgs": {
"locked": {
"lastModified": 1770057536,
"narHash": "sha256-Y/Dqu+7StqRVlzQEbow5l2Ws02P9IrHO3eVnpVWbLTE=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "79faf5ae0424fe8cd1d07064a513667e6b6ae65a",
"type": "github"
},
"original": {
"owner": "NixOS",
"repo": "nixpkgs",
"type": "github"
}
},
"root": {
"inputs": {
"nixpkgs": "nixpkgs"
}
}
},
"root": "root",
"version": 7
}

BIN
image.hdd

Binary file not shown.

0
image.hdd.lock Normal file
View File

Binary file not shown.

View File

@ -1,6 +1,7 @@
obj/src/main.c.o: src/main.c src/../include/limine.h src/acpi.h \
src/common.h src/print.h
src/common.h src/alloc.h src/print.h
src/../include/limine.h:
src/acpi.h:
src/common.h:
src/alloc.h:
src/print.h:

Binary file not shown.

View File

@ -1,17 +1,17 @@
#include "common.h"
#include "print.h"
#include "../include/limine.h"
// credit to dreamportdev's OSDev-Notes and the OSDev Wiki for table layouts
//
#include "acpi.h"
#define RSDT_SIGNATURE "RSDT"
#define XSDT_SIGNATURE "XSDT"
static struct acpi_rsdt* rsdt;
struct acpi_rsdp_header* rsdp;
#include "common.h"
#include "print.h"
#include "../include/limine.h"
// credit to dreamportdev's OSDev-Notes and the OSDev Wiki for table layouts
//
#include "acpi.h"
#define RSDT_SIGNATURE "RSDT"
#define XSDT_SIGNATURE "XSDT"
static struct acpi_rsdt* rsdt;
struct acpi_rsdp_header* rsdp;

View File

@ -1,44 +1,44 @@
#pragma once
#include "common.h"
#define RSDP_SIGNATURE "RSDT PTR "
pstruct acpi_rsdp_header {
u8 signature[8];
u8 checksum;
u8 OEMID[6];
u8 revision;
/*
union {
struct acpi_rsdt* rsdt :32;
struct acpi_xsdt* xsdt :32;
} ptr;
*/
u32 ptr32;
// v2
u32 len;
u64 ptr64;
u8 extended_checksum;
u8 resv[3];
};
struct acpi_rsdt {
u8 signature[4];
u32 len;
u8 revision;
u8 checksum;
u8 OEMID[6];
u8 OEM_table_id[8];
u32 OEM_revision;
u32 creator_id;
u32 creator_revision;
union {
u32 addrs32[];
u64 addrs64[];
};
};
extern struct acpi_rsdp_header* rsdp;
#pragma once
#include "common.h"
#define RSDP_SIGNATURE "RSDT PTR "
pstruct acpi_rsdp_header {
u8 signature[8];
u8 checksum;
u8 OEMID[6];
u8 revision;
/*
union {
struct acpi_rsdt* rsdt :32;
struct acpi_xsdt* xsdt :32;
} ptr;
*/
u32 ptr32;
// v2
u32 len;
u64 ptr64;
u8 extended_checksum;
u8 resv[3];
};
struct acpi_rsdt {
u8 signature[4];
u32 len;
u8 revision;
u8 checksum;
u8 OEMID[6];
u8 OEM_table_id[8];
u32 OEM_revision;
u32 creator_id;
u32 creator_revision;
union {
u32 addrs32[];
u64 addrs64[];
};
};
extern struct acpi_rsdp_header* rsdp;

196
src/alloc.c Normal file
View File

@ -0,0 +1,196 @@
#include "alloc.h"
#include "common.h"
#include "print.h"
#include "../include/limine.h"
__attribute__((used, section(".limine_requests")))
static volatile struct limine_memmap_request mem_req = {
.id = LIMINE_MEMMAP_REQUEST_ID,
.revision = 0,
};
extern u32 fg, bg;
static void print_memmap_entry(struct limine_memmap_entry* entry) {
u32 savefg = fg;
u32 savebg = bg;
static const char* type_strs[] = {
"Usable",
"Reserved",
"ACPI Reclaimable",
"ACPI NVS",
"BAD!!!",
"Bootloader Reclaimable",
"Executable and Modules",
"Framebuffer",
"ACPI Tables",
};
static u32 type_colors[] = {
0x00AF00,
0xAF1F00,
0x7f7f00,
0x7f7f00,
0xFF0000,
0x007f7f,
0x408000,
0x0000FF,
0x00FF00
};
bg = type_colors[entry->type];
fg = ~bg;
u64 addr = entry->base;
u64 end = addr + entry->length;
print("[");
print(type_strs[entry->type]);
print("]");
print64(addr);
print(" - ");
print64(end);
print("\n");
fg = savefg;
bg = savebg;
}
static size_t total_pages;
static u8* alloc_start;
static u8* alloc_end;
static u8* alloc_next;
static u64* alloc_bitmap;
void alloc_init() {
print("Initializing Page Allocator\n");
if(!mem_req.response) {
print("Failed to get memory map :(\n)");
hang();
}
u64 largest_base = 0;
size_t largest_size = 0;
for(size_t i = 0; i < mem_req.response->entry_count; i++) {
struct limine_memmap_entry* entry = mem_req.response->entries[i];
print_memmap_entry(entry);
if(entry->type == LIMINE_MEMMAP_USABLE) {
if(entry->length > largest_size) {
largest_base = entry->base;
largest_size = entry->length;
print("\t\\LARGEST USABLE: ");
print64(entry->length >> 20);
print("MiB\n");
}
}
}
if(!largest_size) {
print("Couldn't find a free page!!!\n");
hang();
}
total_pages = largest_size / PAGE_SIZE;
size_t usage_bitmap_size = (total_pages + 7) / 8;
total_pages -= (usage_bitmap_size + PAGE_SIZE-1) / PAGE_SIZE;
alloc_bitmap = (u64*)(phys_to_virt(largest_base));
alloc_start = (u8*)(phys_to_virt(largest_base + usage_bitmap_size));
alloc_next = alloc_start;
alloc_end = (u8*)(phys_to_virt(largest_base + largest_size));
}
static size_t page(void* addr) {
return ((u8*)addr - alloc_start) / PAGE_SIZE;
}
static void* addr(size_t page) {
return alloc_start + page*PAGE_SIZE;
}
static void usepage(size_t page) {
size_t idx = page / 64;
size_t bit = page & 63;
alloc_bitmap[idx] |= (1 << bit);
}
static void usepagerange(size_t page, size_t len) {
for(size_t i = 0; i < len; len++) {
usepage(i + page);
}
}
static void unusepage(size_t page) {
size_t idx = page / 64;
size_t bit = page & 63;
alloc_bitmap[idx] &= ~(1 << bit);
}
static void unusepagerange(size_t page, size_t len) {
for(size_t i = 0; i < len; len++) {
unusepage(i+page);
}
}
static u8 getpageusage(size_t page) {
return (alloc_bitmap[page / 8] >> (page & 7)) & 1;
}
void dealloc(void* addr, size_t size) {
// adjust to page size
size_t pages = (size+PAGE_SIZE-1) / PAGE_SIZE;
unusepagerange(page(addr), pages);
}
void* alloc(size_t size) {
size_t pages = (size + PAGE_SIZE - 1) / PAGE_SIZE;
size_t page = 0;
if(pages == 0 || pages >= total_pages) {
return NULL;
}
size_t consecutive = 0;
for(size_t i = 0; i < pages; i++) {
u64 word = alloc_bitmap[i];
if(word == 0) {
if(!consecutive)
page = i * 64;
consecutive += 64;
if(consecutive >= pages) {
usepagerange(page, pages);
return addr(page);
}
continue;
}
if(word == ~0ULL) {
consecutive = 0;
page = -1;
}
for(size_t bit = 0; bit < 64; bit++) {
if((word & (1ULL << bit)) == 0) {
if(!consecutive)
page = i * 64 + bit;
if(++consecutive >= pages) {
usepagerange(page, pages);
return addr(pages);
}
} else {
consecutive = 0;
page = -1;
}
}
}
return NULL;
}

16
src/alloc.h Normal file
View File

@ -0,0 +1,16 @@
#pragma once
#include "common.h"
static const size_t PAGE_SIZE = (1 << 12);
void alloc_init();
void* alloc(size_t size);
void dealloc(void* arg, size_t size);
static inline u64 virt_to_phys(void* virt) {
return (u64)virt - hhdm_offset;
}
static inline void* phys_to_virt(u64 phys) {
return (void*)(phys + hhdm_offset);
}

View File

@ -1,73 +1,131 @@
#include "common.h"
#include "print.h"
// stub of a PIC layout, we don't need the whole thing
// as we only care about initializing it to disable it
enum {
PIC_COMM_MASTER = 0x20,
PIC_COMM_SLAVE = 0x21,
PIC_DATA_MASTER = 0xA0,
PIC_DATA_SLAVE = 0xA1,
};
static void pic_disable() {
outb(PIC_DATA_MASTER, ~0);
outb(PIC_DATA_SLAVE, ~0);
}
static inline u64 rdmsr(u32 msr) {
u32 hi, lo;
asm volatile (
"rdmsr"
: "=a"(lo), "=d"(hi)
: "c"(msr)
);
return (((u64)hi) << 32) | (u64)lo;
}
static inline void wrmsr(u32 msr, u64 val) {
u32 eax = (u32) val;
u32 edx = (u32) (val >> 32);
asm volatile (
"wrmsr"
:
: "c"(msr), "a" (eax), "d" (edx)
);
}
static u64 apic_base;
u64 apic_get_local_base() {
const u8 APIC_BASE_MSR = 0x1B;
u64 msr = rdmsr(APIC_BASE_MSR);
return (apic_base = (msr & 0xfffff000));
}
static u64 apic_set_local_base(u64 base) {
const u8 APIC_BASE_MSR = 0x1B;
wrmsr(APIC_BASE_MSR, base & 0xfffff000);
return base & 0xfffff000;
}
static u32* apic_reg(u32 reg) {
return (u32*) (apic_base + reg);
}
void apic_enable() {
pic_disable();
print("\nPIC Disabled\n");
apic_set_local_base(apic_get_local_base());
volatile u32* reg = apic_reg(0xF0);
print("Local Base Set\nReg 0xF0 at 0x");
print64((u64) reg);
// set enable flag
*reg = (*reg | 0x100);
print("\nReg written\n");
}
#include "common.h"
#include "print.h"
#include "map.h"
// stub of a PIC layout, we don't need the whole thing
// as we only care about initializing it to disable it
enum {
PIC_COMM_MASTER = 0x20,
PIC_COMM_SLAVE = 0xA0,
PIC_DATA_MASTER = 0x21,
PIC_DATA_SLAVE = 0xA1,
};
#define IOAPIC_REG_REDIR(n) (0x10 + 2(n))
enum {
IOAPIC_REG_SELECT = 0x00,
IOAPIC_REG_WINDOW = 0x10,
};
// I/O APIC redirection entry bits
#define IOAPIC_DST_PHYS (0 << 11)
#define IOAPIC_DST_LOGICAL (1 << 11)
#define IOAPIC_MASKED (1 << 16)
#define IOAPIC_LVL_TRIGG (1 << 15)
#define IOAPIC_EDGE_TRIGG (0 << 15)
#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
outb(PIC_DATA_MASTER, 0x20); // ICW2: Master PIC vector offset
outb(PIC_DATA_MASTER, 0x04); // ICW3: Slave PIC at IRQ2
outb(PIC_DATA_MASTER, 0x01); // ICW4: 8086/88 (MCS-80 compatible)
outb(PIC_COMM_SLAVE, 0x11); // ICW1: Initialize slave PIC
outb(PIC_DATA_SLAVE, 0x28); // ICW2: Slave PIC vector offset
outb(PIC_DATA_SLAVE, 0x02); // ICW3: It's connected to master PIC
outb(PIC_DATA_SLAVE, 0x01); // ICW4: 8086/88 mode
// Mask all interrupts
outb(PIC_DATA_MASTER, 0xFF);
outb(PIC_DATA_SLAVE, 0xFF);
}
static void pic_disable() {
pic_init();
outb(PIC_DATA_MASTER, ~0);
outb(PIC_DATA_SLAVE, ~0);
}
static inline u64 rdmsr(u32 msr) {
u32 hi, lo;
asm volatile (
"rdmsr"
: "=a"(lo), "=d"(hi)
: "c"(msr)
);
return (((u64)hi) << 32) | (u64)lo;
}
static inline void wrmsr(u32 msr, u64 val) {
u32 eax = (u32) val;
u32 edx = (u32) (val >> 32);
asm volatile (
"wrmsr"
:
: "c"(msr), "a" (eax), "d" (edx)
);
}
static u64 apic_base;
u64 apic_get_local_base() {
const u8 APIC_BASE_MSR = 0x1B;
u64 msr = rdmsr(APIC_BASE_MSR);
return (apic_base = (msr & 0xfffff000));
}
static u64 apic_set_local_base(u64 base) {
const u8 APIC_BASE_MSR = 0x1B;
wrmsr(APIC_BASE_MSR, base & 0xfffff000);
return base & 0xfffff000;
}
static u32* apic_reg(u32 reg) {
return (u32*) (apic_base + reg);
}
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)) {
print("Failed to map APIC registers!\n");
hang();
}
volatile u32* reg = apic_reg(0xF0);
print("Reg 0xF0 at 0x");
print64((u64) reg);
// set enable flag
*reg = (*reg | 0x100);
print("\nReg written\n");
}
static u32* ioapic_base;
void ioapic_write(u8 reg, u32 value) {
ioapic_base[IOAPIC_REG_SELECT / 4] = reg;
ioapic_base[IOAPIC_REG_WINDOW / 4] = value;
}
u32 ioapic_read(u8 reg) {
ioapic_base[IOAPIC_REG_SELECT / 4] = reg;
return ioapic_base[IOAPIC_REG_WINDOW / 4];
}
void ioapic_init() {
}

View File

@ -1,42 +1,42 @@
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define pstruct struct __attribute__((packed))
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
static inline void INT(int n) {
asm volatile (
"int %0"
:
: "i"(n)
);
}
static inline void outb(u16 port, u8 value) {
asm volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static inline void outw(u16 port, u16 value) {
asm volatile ("outw %0, %1" : : "a"(value), "Nd"(port));
}
static inline void outd(u16 port, u32 value) {
asm volatile ("outl %0, %1" : : "a"(value), "Nd"(port));
}
void* memcpy(void* restrict dst, const void* src, size_t n);
void* memset(void* s, int c, size_t n);
void* memmove(void* dst, const void* src, size_t n);
int memcmp(const void* s1, const void* s2, size_t n);
extern u64 hhdm_offset;
#pragma once
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#define pstruct struct __attribute__((packed))
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
static inline void INT(int n) {
asm volatile (
"int %0"
:
: "i"(n)
);
}
static inline void outb(u16 port, u8 value) {
asm volatile ("outb %0, %1" : : "a"(value), "Nd"(port));
}
static inline void outw(u16 port, u16 value) {
asm volatile ("outw %0, %1" : : "a"(value), "Nd"(port));
}
static inline void outd(u16 port, u32 value) {
asm volatile ("outl %0, %1" : : "a"(value), "Nd"(port));
}
void* memcpy(void* dst, const void* src, size_t n);
void* memset(void* s, int c, size_t n);
void* memmove(void* dst, const void* src, size_t n);
int memcmp(const void* s1, const void* s2, size_t n);
void hang();
extern u64 hhdm_offset;

564
src/int.c
View File

@ -1,282 +1,282 @@
#include <stdint.h>
// for debugging
#include "print.h"
#include "common.h"
// for trap debugging
u64 dbg_var = 0;
pstruct int_desc {
u16 addr_low;
u16 selector;
u8 ist;
u8 flags;
u16 addr_mid;
u32 addr_high;
u32 resv;
};
enum INT_DESC_FLAGS {
ID_GATE_INT = 0b00001110,
ID_GATE_TRAP = 0b00001111,
ID_DPL = 0b00100000,
ID_PRESENT = 0b10000000,
};
#define CODE64_SELECTOR 0x28
struct int_desc idt[256];
void set_idt(u8 vect, void* handler, u8 dpl) {
struct int_desc* ent = &idt[vect];
u64 addr = (u64) handler;
ent->addr_low = addr & 0xFFFF;
ent->addr_mid = (addr >> 16) & 0xFFFF;
ent->addr_high = addr >> 32;
ent->selector = CODE64_SELECTOR;
ent->flags = ID_GATE_INT | dpl*ID_DPL | ID_PRESENT;
ent->ist = 0;
}
pstruct idtr {
u16 limit;
u64 base;
};
#define IDTR_LIMIT (sizeof(struct int_desc)*256 - 1)
void load_idt(void* addr) {
struct idtr ir = (struct idtr) {
.limit = IDTR_LIMIT,
.base = (u64) addr,
};
asm volatile("lidt %0" :: "m"(ir));
}
extern void draw(u8 vect);
struct cpu_ctx {
u64 r15, r14, r13, r12, r11, r10, r9, r8, rdi, rsi, rdx, rcx, rbx, rax;
u64 vect;
u64 err;
u64 iret_rip;
u64 iret_cs;
u64 iret_flags;
u64 iret_rsp;
u64 iret_ss;
};
struct cpu_ctx* interrupt_dispatch(struct cpu_ctx* ctx) {
print("\n[IRQ ");
print8(ctx->vect);
print("] with message: ");
print64(dbg_var);
print("\n");
while(1);
return ctx;
}
__attribute__((naked))
void int_stub(void) {
__asm__ volatile (
"push %%rax\n"
"push %%rbx\n"
"push %%rcx\n"
"push %%rdx\n"
"push %%rsi\n"
"push %%rdi\n"
"push %%r8\n"
"push %%r9\n"
"push %%r10\n"
"push %%r11\n"
"push %%r12\n"
"push %%r13\n"
"push %%r14\n"
"push %%r15\n"
"mov %%rsp, %%rdi\n"
"call interrupt_dispatch\n"
"mov %%rax, %%rsp\n"
"pop %%r15\n"
"pop %%r14\n"
"pop %%r13\n"
"pop %%r12\n"
"pop %%r11\n"
"pop %%r10\n"
"pop %%r9\n"
"pop %%r8\n"
"pop %%rdi\n"
"pop %%rsi\n"
"pop %%rdx\n"
"pop %%rcx\n"
"pop %%rbx\n"
"pop %%rax\n"
"add $16, %%rsp\n"
"iretq\n"
:
:
: "memory"
);
}
// Macro to generate interrupt stubs without error codes (push dummy 0)
#define ISR_NO_ERR(num) \
__attribute__((naked)) void isr##num(void) { \
asm volatile( \
"push $0\n" \
"push %0\n" \
"jmp int_stub\n" \
: : "i"(num)); \
}
// Macro to generate interrupt stubs with error codes
#define ISR_ERR(num) \
__attribute__((naked)) void isr##num(void) { \
asm volatile( \
"push %0\n" \
"jmp int_stub\n" \
: : "i"(num)); \
}
// CPU exceptions (0-31)
ISR_NO_ERR(0) // Divide by zero
ISR_NO_ERR(1) // Debug
ISR_NO_ERR(2) // NMI
ISR_NO_ERR(3) // Breakpoint
ISR_NO_ERR(4) // Overflow
ISR_NO_ERR(5) // Bound range exceeded
ISR_NO_ERR(6) // Invalid opcode
ISR_NO_ERR(7) // Device not available
ISR_ERR(8) // Double fault (pushes error code)
ISR_NO_ERR(9) // Coprocessor segment overrun
ISR_ERR(10) // Invalid TSS (pushes error code)
ISR_ERR(11) // Segment not present (pushes error code)
ISR_ERR(12) // Stack-segment fault (pushes error code)
ISR_ERR(13) // General protection fault (pushes error code)
ISR_ERR(14) // Page fault (pushes error code)
ISR_NO_ERR(15) // Reserved
ISR_NO_ERR(16) // x87 FPU error
ISR_ERR(17) // Alignment check (pushes error code)
ISR_NO_ERR(18) // Machine check
ISR_NO_ERR(19) // SIMD floating-point exception
ISR_NO_ERR(20) // Virtualization exception
ISR_ERR(21) // Control protection exception (pushes error code)
ISR_NO_ERR(22) // Reserved
ISR_NO_ERR(23) // Reserved
ISR_NO_ERR(24) // Reserved
ISR_NO_ERR(25) // Reserved
ISR_NO_ERR(26) // Reserved
ISR_NO_ERR(27) // Reserved
ISR_NO_ERR(28) // Reserved
ISR_NO_ERR(29) // Reserved
ISR_ERR(30) // Security exception (pushes error code)
ISR_NO_ERR(31) // Reserved
// IRQs and user-defined interrupts (32-255)
ISR_NO_ERR(32) ISR_NO_ERR(33) ISR_NO_ERR(34) ISR_NO_ERR(35)
ISR_NO_ERR(36) ISR_NO_ERR(37) ISR_NO_ERR(38) ISR_NO_ERR(39)
ISR_NO_ERR(40) ISR_NO_ERR(41) ISR_NO_ERR(42) ISR_NO_ERR(43)
ISR_NO_ERR(44) ISR_NO_ERR(45) ISR_NO_ERR(46) ISR_NO_ERR(47)
ISR_NO_ERR(48) ISR_NO_ERR(49) ISR_NO_ERR(50) ISR_NO_ERR(51)
ISR_NO_ERR(52) ISR_NO_ERR(53) ISR_NO_ERR(54) ISR_NO_ERR(55)
ISR_NO_ERR(56) ISR_NO_ERR(57) ISR_NO_ERR(58) ISR_NO_ERR(59)
ISR_NO_ERR(60) ISR_NO_ERR(61) ISR_NO_ERR(62) ISR_NO_ERR(63)
ISR_NO_ERR(64) ISR_NO_ERR(65) ISR_NO_ERR(66) ISR_NO_ERR(67)
ISR_NO_ERR(68) ISR_NO_ERR(69) ISR_NO_ERR(70) ISR_NO_ERR(71)
ISR_NO_ERR(72) ISR_NO_ERR(73) ISR_NO_ERR(74) ISR_NO_ERR(75)
ISR_NO_ERR(76) ISR_NO_ERR(77) ISR_NO_ERR(78) ISR_NO_ERR(79)
ISR_NO_ERR(80) ISR_NO_ERR(81) ISR_NO_ERR(82) ISR_NO_ERR(83)
ISR_NO_ERR(84) ISR_NO_ERR(85) ISR_NO_ERR(86) ISR_NO_ERR(87)
ISR_NO_ERR(88) ISR_NO_ERR(89) ISR_NO_ERR(90) ISR_NO_ERR(91)
ISR_NO_ERR(92) ISR_NO_ERR(93) ISR_NO_ERR(94) ISR_NO_ERR(95)
ISR_NO_ERR(96) ISR_NO_ERR(97) ISR_NO_ERR(98) ISR_NO_ERR(99)
ISR_NO_ERR(100) ISR_NO_ERR(101) ISR_NO_ERR(102) ISR_NO_ERR(103)
ISR_NO_ERR(104) ISR_NO_ERR(105) ISR_NO_ERR(106) ISR_NO_ERR(107)
ISR_NO_ERR(108) ISR_NO_ERR(109) ISR_NO_ERR(110) ISR_NO_ERR(111)
ISR_NO_ERR(112) ISR_NO_ERR(113) ISR_NO_ERR(114) ISR_NO_ERR(115)
ISR_NO_ERR(116) ISR_NO_ERR(117) ISR_NO_ERR(118) ISR_NO_ERR(119)
ISR_NO_ERR(120) ISR_NO_ERR(121) ISR_NO_ERR(122) ISR_NO_ERR(123)
ISR_NO_ERR(124) ISR_NO_ERR(125) ISR_NO_ERR(126) ISR_NO_ERR(127)
ISR_NO_ERR(128) ISR_NO_ERR(129) ISR_NO_ERR(130) ISR_NO_ERR(131)
ISR_NO_ERR(132) ISR_NO_ERR(133) ISR_NO_ERR(134) ISR_NO_ERR(135)
ISR_NO_ERR(136) ISR_NO_ERR(137) ISR_NO_ERR(138) ISR_NO_ERR(139)
ISR_NO_ERR(140) ISR_NO_ERR(141) ISR_NO_ERR(142) ISR_NO_ERR(143)
ISR_NO_ERR(144) ISR_NO_ERR(145) ISR_NO_ERR(146) ISR_NO_ERR(147)
ISR_NO_ERR(148) ISR_NO_ERR(149) ISR_NO_ERR(150) ISR_NO_ERR(151)
ISR_NO_ERR(152) ISR_NO_ERR(153) ISR_NO_ERR(154) ISR_NO_ERR(155)
ISR_NO_ERR(156) ISR_NO_ERR(157) ISR_NO_ERR(158) ISR_NO_ERR(159)
ISR_NO_ERR(160) ISR_NO_ERR(161) ISR_NO_ERR(162) ISR_NO_ERR(163)
ISR_NO_ERR(164) ISR_NO_ERR(165) ISR_NO_ERR(166) ISR_NO_ERR(167)
ISR_NO_ERR(168) ISR_NO_ERR(169) ISR_NO_ERR(170) ISR_NO_ERR(171)
ISR_NO_ERR(172) ISR_NO_ERR(173) ISR_NO_ERR(174) ISR_NO_ERR(175)
ISR_NO_ERR(176) ISR_NO_ERR(177) ISR_NO_ERR(178) ISR_NO_ERR(179)
ISR_NO_ERR(180) ISR_NO_ERR(181) ISR_NO_ERR(182) ISR_NO_ERR(183)
ISR_NO_ERR(184) ISR_NO_ERR(185) ISR_NO_ERR(186) ISR_NO_ERR(187)
ISR_NO_ERR(188) ISR_NO_ERR(189) ISR_NO_ERR(190) ISR_NO_ERR(191)
ISR_NO_ERR(192) ISR_NO_ERR(193) ISR_NO_ERR(194) ISR_NO_ERR(195)
ISR_NO_ERR(196) ISR_NO_ERR(197) ISR_NO_ERR(198) ISR_NO_ERR(199)
ISR_NO_ERR(200) ISR_NO_ERR(201) ISR_NO_ERR(202) ISR_NO_ERR(203)
ISR_NO_ERR(204) ISR_NO_ERR(205) ISR_NO_ERR(206) ISR_NO_ERR(207)
ISR_NO_ERR(208) ISR_NO_ERR(209) ISR_NO_ERR(210) ISR_NO_ERR(211)
ISR_NO_ERR(212) ISR_NO_ERR(213) ISR_NO_ERR(214) ISR_NO_ERR(215)
ISR_NO_ERR(216) ISR_NO_ERR(217) ISR_NO_ERR(218) ISR_NO_ERR(219)
ISR_NO_ERR(220) ISR_NO_ERR(221) ISR_NO_ERR(222) ISR_NO_ERR(223)
ISR_NO_ERR(224) ISR_NO_ERR(225) ISR_NO_ERR(226) ISR_NO_ERR(227)
ISR_NO_ERR(228) ISR_NO_ERR(229) ISR_NO_ERR(230) ISR_NO_ERR(231)
ISR_NO_ERR(232) ISR_NO_ERR(233) ISR_NO_ERR(234) ISR_NO_ERR(235)
ISR_NO_ERR(236) ISR_NO_ERR(237) ISR_NO_ERR(238) ISR_NO_ERR(239)
ISR_NO_ERR(240) ISR_NO_ERR(241) ISR_NO_ERR(242) ISR_NO_ERR(243)
ISR_NO_ERR(244) ISR_NO_ERR(245) ISR_NO_ERR(246) ISR_NO_ERR(247)
ISR_NO_ERR(248) ISR_NO_ERR(249) ISR_NO_ERR(250) ISR_NO_ERR(251)
ISR_NO_ERR(252) ISR_NO_ERR(253) ISR_NO_ERR(254) ISR_NO_ERR(255)
// Array of all ISR handlers for easy initialization
void* isr_table[256] = {
isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7,
isr8, isr9, isr10, isr11, isr12, isr13, isr14, isr15,
isr16, isr17, isr18, isr19, isr20, isr21, isr22, isr23,
isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31,
isr32, isr33, isr34, isr35, isr36, isr37, isr38, isr39,
isr40, isr41, isr42, isr43, isr44, isr45, isr46, isr47,
isr48, isr49, isr50, isr51, isr52, isr53, isr54, isr55,
isr56, isr57, isr58, isr59, isr60, isr61, isr62, isr63,
isr64, isr65, isr66, isr67, isr68, isr69, isr70, isr71,
isr72, isr73, isr74, isr75, isr76, isr77, isr78, isr79,
isr80, isr81, isr82, isr83, isr84, isr85, isr86, isr87,
isr88, isr89, isr90, isr91, isr92, isr93, isr94, isr95,
isr96, isr97, isr98, isr99, isr100, isr101, isr102, isr103,
isr104, isr105, isr106, isr107, isr108, isr109, isr110, isr111,
isr112, isr113, isr114, isr115, isr116, isr117, isr118, isr119,
isr120, isr121, isr122, isr123, isr124, isr125, isr126, isr127,
isr128, isr129, isr130, isr131, isr132, isr133, isr134, isr135,
isr136, isr137, isr138, isr139, isr140, isr141, isr142, isr143,
isr144, isr145, isr146, isr147, isr148, isr149, isr150, isr151,
isr152, isr153, isr154, isr155, isr156, isr157, isr158, isr159,
isr160, isr161, isr162, isr163, isr164, isr165, isr166, isr167,
isr168, isr169, isr170, isr171, isr172, isr173, isr174, isr175,
isr176, isr177, isr178, isr179, isr180, isr181, isr182, isr183,
isr184, isr185, isr186, isr187, isr188, isr189, isr190, isr191,
isr192, isr193, isr194, isr195, isr196, isr197, isr198, isr199,
isr200, isr201, isr202, isr203, isr204, isr205, isr206, isr207,
isr208, isr209, isr210, isr211, isr212, isr213, isr214, isr215,
isr216, isr217, isr218, isr219, isr220, isr221, isr222, isr223,
isr224, isr225, isr226, isr227, isr228, isr229, isr230, isr231,
isr232, isr233, isr234, isr235, isr236, isr237, isr238, isr239,
isr240, isr241, isr242, isr243, isr244, isr245, isr246, isr247,
isr248, isr249, isr250, isr251, isr252, isr253, isr254, isr255,
};
// Initialize all IDT entries
void init_idt(void) {
for (int i = 0; i < 256; i++) {
set_idt(i, isr_table[i], 0);
}
load_idt(idt);
}
#include <stdint.h>
// for debugging
#include "print.h"
#include "common.h"
// for trap debugging
u64 dbg_var = 0;
pstruct int_desc {
u16 addr_low;
u16 selector;
u8 ist;
u8 flags;
u16 addr_mid;
u32 addr_high;
u32 resv;
};
enum INT_DESC_FLAGS {
ID_GATE_INT = 0b00001110,
ID_GATE_TRAP = 0b00001111,
ID_DPL = 0b00100000,
ID_PRESENT = 0b10000000,
};
#define CODE64_SELECTOR 0x28
struct int_desc idt[256];
void set_idt(u8 vect, void* handler, u8 dpl) {
struct int_desc* ent = &idt[vect];
u64 addr = (u64) handler;
ent->addr_low = addr & 0xFFFF;
ent->addr_mid = (addr >> 16) & 0xFFFF;
ent->addr_high = addr >> 32;
ent->selector = CODE64_SELECTOR;
ent->flags = ID_GATE_INT | dpl*ID_DPL | ID_PRESENT;
ent->ist = 0;
}
pstruct idtr {
u16 limit;
u64 base;
};
#define IDTR_LIMIT (sizeof(struct int_desc)*256 - 1)
void load_idt(void* addr) {
struct idtr ir = (struct idtr) {
.limit = IDTR_LIMIT,
.base = (u64) addr,
};
asm volatile("lidt %0" :: "m"(ir));
}
extern void draw(u8 vect);
struct cpu_ctx {
u64 r15, r14, r13, r12, r11, r10, r9, r8, rdi, rsi, rdx, rcx, rbx, rax;
u64 vect;
u64 err;
u64 iret_rip;
u64 iret_cs;
u64 iret_flags;
u64 iret_rsp;
u64 iret_ss;
};
struct cpu_ctx* interrupt_dispatch(struct cpu_ctx* ctx) {
print("\n[IRQ ");
print8(ctx->vect);
print("] with message: ");
print64(dbg_var);
print("\n");
while(1);
return ctx;
}
__attribute__((naked))
void int_stub(void) {
__asm__ volatile (
"push %%rax\n"
"push %%rbx\n"
"push %%rcx\n"
"push %%rdx\n"
"push %%rsi\n"
"push %%rdi\n"
"push %%r8\n"
"push %%r9\n"
"push %%r10\n"
"push %%r11\n"
"push %%r12\n"
"push %%r13\n"
"push %%r14\n"
"push %%r15\n"
"mov %%rsp, %%rdi\n"
"call interrupt_dispatch\n"
"mov %%rax, %%rsp\n"
"pop %%r15\n"
"pop %%r14\n"
"pop %%r13\n"
"pop %%r12\n"
"pop %%r11\n"
"pop %%r10\n"
"pop %%r9\n"
"pop %%r8\n"
"pop %%rdi\n"
"pop %%rsi\n"
"pop %%rdx\n"
"pop %%rcx\n"
"pop %%rbx\n"
"pop %%rax\n"
"add $16, %%rsp\n"
"iretq\n"
:
:
: "memory"
);
}
// Macro to generate interrupt stubs without error codes (push dummy 0)
#define ISR_NO_ERR(num) \
__attribute__((naked)) void isr##num(void) { \
asm volatile( \
"push $0\n" \
"push %0\n" \
"jmp int_stub\n" \
: : "i"(num)); \
}
// Macro to generate interrupt stubs with error codes
#define ISR_ERR(num) \
__attribute__((naked)) void isr##num(void) { \
asm volatile( \
"push %0\n" \
"jmp int_stub\n" \
: : "i"(num)); \
}
// CPU exceptions (0-31)
ISR_NO_ERR(0) // Divide by zero
ISR_NO_ERR(1) // Debug
ISR_NO_ERR(2) // NMI
ISR_NO_ERR(3) // Breakpoint
ISR_NO_ERR(4) // Overflow
ISR_NO_ERR(5) // Bound range exceeded
ISR_NO_ERR(6) // Invalid opcode
ISR_NO_ERR(7) // Device not available
ISR_ERR(8) // Double fault (pushes error code)
ISR_NO_ERR(9) // Coprocessor segment overrun
ISR_ERR(10) // Invalid TSS (pushes error code)
ISR_ERR(11) // Segment not present (pushes error code)
ISR_ERR(12) // Stack-segment fault (pushes error code)
ISR_ERR(13) // General protection fault (pushes error code)
ISR_ERR(14) // Page fault (pushes error code)
ISR_NO_ERR(15) // Reserved
ISR_NO_ERR(16) // x87 FPU error
ISR_ERR(17) // Alignment check (pushes error code)
ISR_NO_ERR(18) // Machine check
ISR_NO_ERR(19) // SIMD floating-point exception
ISR_NO_ERR(20) // Virtualization exception
ISR_ERR(21) // Control protection exception (pushes error code)
ISR_NO_ERR(22) // Reserved
ISR_NO_ERR(23) // Reserved
ISR_NO_ERR(24) // Reserved
ISR_NO_ERR(25) // Reserved
ISR_NO_ERR(26) // Reserved
ISR_NO_ERR(27) // Reserved
ISR_NO_ERR(28) // Reserved
ISR_NO_ERR(29) // Reserved
ISR_ERR(30) // Security exception (pushes error code)
ISR_NO_ERR(31) // Reserved
// IRQs and user-defined interrupts (32-255)
ISR_NO_ERR(32) ISR_NO_ERR(33) ISR_NO_ERR(34) ISR_NO_ERR(35)
ISR_NO_ERR(36) ISR_NO_ERR(37) ISR_NO_ERR(38) ISR_NO_ERR(39)
ISR_NO_ERR(40) ISR_NO_ERR(41) ISR_NO_ERR(42) ISR_NO_ERR(43)
ISR_NO_ERR(44) ISR_NO_ERR(45) ISR_NO_ERR(46) ISR_NO_ERR(47)
ISR_NO_ERR(48) ISR_NO_ERR(49) ISR_NO_ERR(50) ISR_NO_ERR(51)
ISR_NO_ERR(52) ISR_NO_ERR(53) ISR_NO_ERR(54) ISR_NO_ERR(55)
ISR_NO_ERR(56) ISR_NO_ERR(57) ISR_NO_ERR(58) ISR_NO_ERR(59)
ISR_NO_ERR(60) ISR_NO_ERR(61) ISR_NO_ERR(62) ISR_NO_ERR(63)
ISR_NO_ERR(64) ISR_NO_ERR(65) ISR_NO_ERR(66) ISR_NO_ERR(67)
ISR_NO_ERR(68) ISR_NO_ERR(69) ISR_NO_ERR(70) ISR_NO_ERR(71)
ISR_NO_ERR(72) ISR_NO_ERR(73) ISR_NO_ERR(74) ISR_NO_ERR(75)
ISR_NO_ERR(76) ISR_NO_ERR(77) ISR_NO_ERR(78) ISR_NO_ERR(79)
ISR_NO_ERR(80) ISR_NO_ERR(81) ISR_NO_ERR(82) ISR_NO_ERR(83)
ISR_NO_ERR(84) ISR_NO_ERR(85) ISR_NO_ERR(86) ISR_NO_ERR(87)
ISR_NO_ERR(88) ISR_NO_ERR(89) ISR_NO_ERR(90) ISR_NO_ERR(91)
ISR_NO_ERR(92) ISR_NO_ERR(93) ISR_NO_ERR(94) ISR_NO_ERR(95)
ISR_NO_ERR(96) ISR_NO_ERR(97) ISR_NO_ERR(98) ISR_NO_ERR(99)
ISR_NO_ERR(100) ISR_NO_ERR(101) ISR_NO_ERR(102) ISR_NO_ERR(103)
ISR_NO_ERR(104) ISR_NO_ERR(105) ISR_NO_ERR(106) ISR_NO_ERR(107)
ISR_NO_ERR(108) ISR_NO_ERR(109) ISR_NO_ERR(110) ISR_NO_ERR(111)
ISR_NO_ERR(112) ISR_NO_ERR(113) ISR_NO_ERR(114) ISR_NO_ERR(115)
ISR_NO_ERR(116) ISR_NO_ERR(117) ISR_NO_ERR(118) ISR_NO_ERR(119)
ISR_NO_ERR(120) ISR_NO_ERR(121) ISR_NO_ERR(122) ISR_NO_ERR(123)
ISR_NO_ERR(124) ISR_NO_ERR(125) ISR_NO_ERR(126) ISR_NO_ERR(127)
ISR_NO_ERR(128) ISR_NO_ERR(129) ISR_NO_ERR(130) ISR_NO_ERR(131)
ISR_NO_ERR(132) ISR_NO_ERR(133) ISR_NO_ERR(134) ISR_NO_ERR(135)
ISR_NO_ERR(136) ISR_NO_ERR(137) ISR_NO_ERR(138) ISR_NO_ERR(139)
ISR_NO_ERR(140) ISR_NO_ERR(141) ISR_NO_ERR(142) ISR_NO_ERR(143)
ISR_NO_ERR(144) ISR_NO_ERR(145) ISR_NO_ERR(146) ISR_NO_ERR(147)
ISR_NO_ERR(148) ISR_NO_ERR(149) ISR_NO_ERR(150) ISR_NO_ERR(151)
ISR_NO_ERR(152) ISR_NO_ERR(153) ISR_NO_ERR(154) ISR_NO_ERR(155)
ISR_NO_ERR(156) ISR_NO_ERR(157) ISR_NO_ERR(158) ISR_NO_ERR(159)
ISR_NO_ERR(160) ISR_NO_ERR(161) ISR_NO_ERR(162) ISR_NO_ERR(163)
ISR_NO_ERR(164) ISR_NO_ERR(165) ISR_NO_ERR(166) ISR_NO_ERR(167)
ISR_NO_ERR(168) ISR_NO_ERR(169) ISR_NO_ERR(170) ISR_NO_ERR(171)
ISR_NO_ERR(172) ISR_NO_ERR(173) ISR_NO_ERR(174) ISR_NO_ERR(175)
ISR_NO_ERR(176) ISR_NO_ERR(177) ISR_NO_ERR(178) ISR_NO_ERR(179)
ISR_NO_ERR(180) ISR_NO_ERR(181) ISR_NO_ERR(182) ISR_NO_ERR(183)
ISR_NO_ERR(184) ISR_NO_ERR(185) ISR_NO_ERR(186) ISR_NO_ERR(187)
ISR_NO_ERR(188) ISR_NO_ERR(189) ISR_NO_ERR(190) ISR_NO_ERR(191)
ISR_NO_ERR(192) ISR_NO_ERR(193) ISR_NO_ERR(194) ISR_NO_ERR(195)
ISR_NO_ERR(196) ISR_NO_ERR(197) ISR_NO_ERR(198) ISR_NO_ERR(199)
ISR_NO_ERR(200) ISR_NO_ERR(201) ISR_NO_ERR(202) ISR_NO_ERR(203)
ISR_NO_ERR(204) ISR_NO_ERR(205) ISR_NO_ERR(206) ISR_NO_ERR(207)
ISR_NO_ERR(208) ISR_NO_ERR(209) ISR_NO_ERR(210) ISR_NO_ERR(211)
ISR_NO_ERR(212) ISR_NO_ERR(213) ISR_NO_ERR(214) ISR_NO_ERR(215)
ISR_NO_ERR(216) ISR_NO_ERR(217) ISR_NO_ERR(218) ISR_NO_ERR(219)
ISR_NO_ERR(220) ISR_NO_ERR(221) ISR_NO_ERR(222) ISR_NO_ERR(223)
ISR_NO_ERR(224) ISR_NO_ERR(225) ISR_NO_ERR(226) ISR_NO_ERR(227)
ISR_NO_ERR(228) ISR_NO_ERR(229) ISR_NO_ERR(230) ISR_NO_ERR(231)
ISR_NO_ERR(232) ISR_NO_ERR(233) ISR_NO_ERR(234) ISR_NO_ERR(235)
ISR_NO_ERR(236) ISR_NO_ERR(237) ISR_NO_ERR(238) ISR_NO_ERR(239)
ISR_NO_ERR(240) ISR_NO_ERR(241) ISR_NO_ERR(242) ISR_NO_ERR(243)
ISR_NO_ERR(244) ISR_NO_ERR(245) ISR_NO_ERR(246) ISR_NO_ERR(247)
ISR_NO_ERR(248) ISR_NO_ERR(249) ISR_NO_ERR(250) ISR_NO_ERR(251)
ISR_NO_ERR(252) ISR_NO_ERR(253) ISR_NO_ERR(254) ISR_NO_ERR(255)
// Array of all ISR handlers for easy initialization
void* isr_table[256] = {
isr0, isr1, isr2, isr3, isr4, isr5, isr6, isr7,
isr8, isr9, isr10, isr11, isr12, isr13, isr14, isr15,
isr16, isr17, isr18, isr19, isr20, isr21, isr22, isr23,
isr24, isr25, isr26, isr27, isr28, isr29, isr30, isr31,
isr32, isr33, isr34, isr35, isr36, isr37, isr38, isr39,
isr40, isr41, isr42, isr43, isr44, isr45, isr46, isr47,
isr48, isr49, isr50, isr51, isr52, isr53, isr54, isr55,
isr56, isr57, isr58, isr59, isr60, isr61, isr62, isr63,
isr64, isr65, isr66, isr67, isr68, isr69, isr70, isr71,
isr72, isr73, isr74, isr75, isr76, isr77, isr78, isr79,
isr80, isr81, isr82, isr83, isr84, isr85, isr86, isr87,
isr88, isr89, isr90, isr91, isr92, isr93, isr94, isr95,
isr96, isr97, isr98, isr99, isr100, isr101, isr102, isr103,
isr104, isr105, isr106, isr107, isr108, isr109, isr110, isr111,
isr112, isr113, isr114, isr115, isr116, isr117, isr118, isr119,
isr120, isr121, isr122, isr123, isr124, isr125, isr126, isr127,
isr128, isr129, isr130, isr131, isr132, isr133, isr134, isr135,
isr136, isr137, isr138, isr139, isr140, isr141, isr142, isr143,
isr144, isr145, isr146, isr147, isr148, isr149, isr150, isr151,
isr152, isr153, isr154, isr155, isr156, isr157, isr158, isr159,
isr160, isr161, isr162, isr163, isr164, isr165, isr166, isr167,
isr168, isr169, isr170, isr171, isr172, isr173, isr174, isr175,
isr176, isr177, isr178, isr179, isr180, isr181, isr182, isr183,
isr184, isr185, isr186, isr187, isr188, isr189, isr190, isr191,
isr192, isr193, isr194, isr195, isr196, isr197, isr198, isr199,
isr200, isr201, isr202, isr203, isr204, isr205, isr206, isr207,
isr208, isr209, isr210, isr211, isr212, isr213, isr214, isr215,
isr216, isr217, isr218, isr219, isr220, isr221, isr222, isr223,
isr224, isr225, isr226, isr227, isr228, isr229, isr230, isr231,
isr232, isr233, isr234, isr235, isr236, isr237, isr238, isr239,
isr240, isr241, isr242, isr243, isr244, isr245, isr246, isr247,
isr248, isr249, isr250, isr251, isr252, isr253, isr254, isr255,
};
// Initialize all IDT entries
void init_idt(void) {
for (int i = 0; i < 256; i++) {
set_idt(i, isr_table[i], 0);
}
load_idt(idt);
}

View File

@ -1,246 +1,196 @@
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "../include/limine.h"
#include "acpi.h"
#include "common.h"
#include "print.h"
// credit owed to https://wiki.osdev.org/Limine_Bare_Bones for the limine setup code
__attribute__((used, section(".limine_requests")))
static volatile u64 limine_base_revision[] = LIMINE_BASE_REVISION(4);
__attribute__((used, section(".limine_requests")))
static volatile struct limine_framebuffer_request fb_req = {
.id = LIMINE_FRAMEBUFFER_REQUEST_ID,
.revision = 0
};
__attribute__((used, section(".limine_requests")))
static volatile struct limine_memmap_request mem_req = {
.id = LIMINE_MEMMAP_REQUEST_ID,
.revision = 0,
};
__attribute__((used, section(".limine_requests")))
static volatile struct limine_hhdm_request hhdm_req = {
.id = LIMINE_HHDM_REQUEST_ID,
.revision = 0
};
__attribute__((used, section(".limine_requests")))
static volatile struct limine_rsdp_request rsdp_req = {
.id = LIMINE_RSDP_REQUEST_ID,
.revision = 0
};
u64 hhdm_offset;
__attribute__((used, section(".limine_requests_start")))
static volatile u64 limine_requests_start_marker[] = LIMINE_REQUESTS_START_MARKER;
__attribute__((used, section(".limine_requests_end")))
static volatile u64 limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER;
void* memcpy(void* restrict dst, const void* src, size_t n) {
u8* restrict pdst = (u8* restrict)dst;
const u8* restrict psrc = (const u8* restrict)src;
for(size_t i = 0; i < n; i++) {
pdst[i] = psrc[i];
}
return dst;
}
void* memset(void* s, int c, size_t n) {
u8* p = (u8*) s;
for(size_t i = 0; i < n; i++) {
p[i] = (u8)c;
}
return s;
}
void* memmove(void* dst, const void* src, size_t n) {
u8* restrict pdst = (u8* restrict)dst;
const u8* restrict psrc = (const u8* restrict)src;
if(src > dst) {
for(size_t i = 0; i < n; i++) {
pdst[i] = psrc[i];
}
} else if(src < dst) {
for(size_t i = n; i > 0; i--) {
pdst[i-1] = psrc[i-1];
}
}
return dst;
}
int memcmp(const void* s1, const void* s2, size_t n) {
const u8* p1 = (const u8* )s1;
const u8* p2 = (const u8* )s2;
for(size_t i = 0; i < n; i++) {
if(p1[i] != p2[i]) {
return p1[i] < p2[i] ? -1 : 1;
}
}
return 0;
}
static void hang() {
for(;;) {
asm ("hlt");
}
}
struct limine_framebuffer* fb;
void draw(u8 vect) {
for(size_t y = 0; y < fb->height; y++) {
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
)*vect;
}
}
}
extern void init_idt(void);
extern u32 fg;
extern u32 bg;
void print_memmap_entry(struct limine_memmap_entry* entry) {
u32 savefg = fg;
u32 savebg = bg;
static const char* type_strs[] = {
"Usable",
"Reserved",
"ACPI Reclaimable",
"ACPI NVS",
"BAD!!!",
"Bootloader Reclaimable",
"Executable and Modules",
"Framebuffer",
"ACPI Tables",
};
static u32 type_colors[] = {
0x00AF00,
0xAF1F00,
0x7f7f00,
0x7f7f00,
0xFF0000,
0x007f7f,
0x408000,
0x0000FF,
0x00FF00
};
bg = type_colors[entry->type];
fg = ~bg;
u64 addr = entry->base;
u64 end = addr + entry->length;
print("[");
print(type_strs[entry->type]);
print("]");
print64(addr);
print(" - ");
print64(end);
print("\n");
fg = savefg;
bg = savebg;
}
u32 apic_get_local_base();
void apic_enable();
void kmain() {
if(LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
hang();
}
if(fb_req.response == NULL || fb_req.response->framebuffer_count < 1) {
hang();
}
fb = fb_req.response->framebuffers[0];
print_init(fb);
init_idt();
if(!mem_req.response) {
print("Failed to get memory map :(\n)");
hang();
}
if(!hhdm_req.response) {
print("Failed to get higher half direct mapping\n.");
hang();
}
hhdm_offset = hhdm_req.response->offset;
if(!rsdp_req.response) {
print ("Failed to find rsdp\n.");
hang();
}
rsdp = (struct acpi_rsdp_header*)(rsdp_req.response->address);
for(size_t i = 0; i < mem_req.response->entry_count; i++) {
print_memmap_entry(mem_req.response->entries[i]);
}
print("Found RSDP @ 0x");
print64((u64)rsdp);
put('\n');
print("With signature: ");
printn((char*)rsdp->signature, sizeof(rsdp->signature));
print(" v");
print8(rsdp->revision);
print("\nRSDT at 0x");
struct acpi_rsdt* rsdt =
(struct acpi_rsdt*)(
(rsdp->revision? rsdp->ptr64:rsdp->ptr32) + hhdm_offset
);
print64((u64)rsdt);
print("\nSDT Signature: ");
printn((const char*) rsdt->signature, sizeof(rsdt->signature));
print("\nAPIC Local Base: ");
/* 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("\nAPIC Enabled");
hang();
}
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>
#include "../include/limine.h"
#include "acpi.h"
#include "alloc.h"
#include "common.h"
#include "print.h"
// credit owed to https://wiki.osdev.org/Limine_Bare_Bones for the limine setup code
__attribute__((used, section(".limine_requests")))
static volatile u64 limine_base_revision[] = LIMINE_BASE_REVISION(4);
__attribute__((used, section(".limine_requests")))
static volatile struct limine_framebuffer_request fb_req = {
.id = LIMINE_FRAMEBUFFER_REQUEST_ID,
.revision = 0
};
__attribute__((used, section(".limine_requests")))
static volatile struct limine_hhdm_request hhdm_req = {
.id = LIMINE_HHDM_REQUEST_ID,
.revision = 0
};
__attribute__((used, section(".limine_requests")))
static volatile struct limine_rsdp_request rsdp_req = {
.id = LIMINE_RSDP_REQUEST_ID,
.revision = 0
};
u64 hhdm_offset;
__attribute__((used, section(".limine_requests_start")))
static volatile u64 limine_requests_start_marker[] = LIMINE_REQUESTS_START_MARKER;
__attribute__((used, section(".limine_requests_end")))
static volatile u64 limine_requests_end_marker[] = LIMINE_REQUESTS_END_MARKER;
void* memcpy(void* restrict dst, const void* src, size_t n) {
u8* restrict pdst = (u8* restrict)dst;
const u8* restrict psrc = (const u8* restrict)src;
for(size_t i = 0; i < n; i++) {
pdst[i] = psrc[i];
}
return dst;
}
void* memset(void* s, int c, size_t n) {
u8* p = (u8*) s;
for(size_t i = 0; i < n; i++) {
p[i] = (u8)c;
}
return s;
}
void* memmove(void* dst, const void* src, size_t n) {
u8* restrict pdst = (u8* restrict)dst;
const u8* restrict psrc = (const u8* restrict)src;
if(src > dst) {
for(size_t i = 0; i < n; i++) {
pdst[i] = psrc[i];
}
} else if(src < dst) {
for(size_t i = n; i > 0; i--) {
pdst[i-1] = psrc[i-1];
}
}
return dst;
}
int memcmp(const void* s1, const void* s2, size_t n) {
const u8* p1 = (const u8* )s1;
const u8* p2 = (const u8* )s2;
for(size_t i = 0; i < n; i++) {
if(p1[i] != p2[i]) {
return p1[i] < p2[i] ? -1 : 1;
}
}
return 0;
}
void hang() {
for(;;) {
asm ("hlt");
}
}
struct limine_framebuffer* fb;
void draw(u8 vect) {
for(size_t y = 0; y < fb->height; y++) {
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
)*vect;
}
}
}
extern void init_idt(void);
extern u32 fg;
extern u32 bg;
u32 apic_get_local_base();
void apic_enable();
void setup_identity_mapping();
void kmain() {
if(LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
hang();
}
if(fb_req.response == NULL || fb_req.response->framebuffer_count < 1) {
hang();
}
fb = fb_req.response->framebuffers[0];
print_init(fb);
init_idt();
if(!hhdm_req.response) {
print("Failed to get higher half direct mapping\n.");
hang();
}
hhdm_offset = hhdm_req.response->offset;
if(!rsdp_req.response) {
print ("Failed to find rsdp\n.");
hang();
}
alloc_init();
rsdp = (struct acpi_rsdp_header*)(rsdp_req.response->address);
print("Found RSDP @ 0x");
print64((u64)rsdp);
put('\n');
print("With signature: ");
printn((char*)rsdp->signature, sizeof(rsdp->signature));
print(" v");
print8(rsdp->revision);
print("\nRSDT at 0x");
struct acpi_rsdt* rsdt =
(struct acpi_rsdt*)(
(rsdp->revision? rsdp->ptr64:rsdp->ptr32) + hhdm_offset
);
print64((u64)rsdt);
print("\nSDT Signature: ");
printn((const char*) rsdt->signature, sizeof(rsdt->signature));
print("\nAPIC Local Base: ");
/* 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("\nAPIC Enabled");
hang();
}

388
src/map.c Normal file
View File

@ -0,0 +1,388 @@
#include "alloc.h"
#include "common.h"
#include "print.h"
// MMIO (Memory-Mapped I/O) Mapping for ACPI and other hardware registers
//
// CRITICAL: MMIO regions are NOT regular RAM!
// - They're not in Limine's memory map as "usable"
// - They're often above the RAM limit
// - Limine does NOT map them automatically
// - You must manually map them before accessing
// Page table entry structure
struct page_entry {
u64 present : 1;
u64 writable : 1;
u64 user : 1;
u64 write_through : 1;
u64 cache_disabled : 1; // IMPORTANT for MMIO!
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;
};
extern u64 hhdm_offset;
// Get current page tables
static u64 get_cr3() {
u64 cr3;
asm volatile("mov %%cr3, %0" : "=r"(cr3));
return cr3 & ~0xFFF;
}
static u64 alloc_page_table() {
void* a = alloc((1<<12) / PAGE_SIZE);
return a? virt_to_phys(a) : 0;
}
// Get or create a page table entry at any level
static struct page_entry* get_or_create_table(struct page_entry *table, u64 index) {
if (!table[index].present) {
u64 new_table_phys = alloc_page_table();
if (new_table_phys == 0) {
return NULL;
}
table[index].present = 1;
table[index].writable = 1;
table[index].user = 0;
table[index].frame = new_table_phys >> 12;
}
u64 next_table_phys = (u64)table[index].frame << 12;
return (struct page_entry*)phys_to_virt(next_table_phys);
}
// Map a MMIO page with proper cache settings
// physical_addr: Physical address of MMIO region
// size: Size in bytes (will be rounded up to 4KB pages)
// Returns: Virtual address to access the MMIO region
void* map_mmio(u64 physical_addr, u64 size) {
print("Mapping MMIO region:\n");
print(" Physical: 0x");
print64(physical_addr);
print("\n Size: 0x");
print64(size);
print(" (");
print64(size);
print(" bytes)\n");
// Align physical address down to page boundary
u64 phys_base = physical_addr & ~(PAGE_SIZE-1);
u64 offset_in_page = physical_addr & (PAGE_SIZE-1);
// Calculate number of pages needed
u64 total_size = size + offset_in_page;
u64 num_pages = (total_size + PAGE_SIZE - 1) / PAGE_SIZE;
print(" Aligned physical: 0x");
print64(phys_base);
print("\n Offset in page: 0x");
print64(offset_in_page);
print("\n Pages needed: ");
print64(num_pages);
print("\n");
// For MMIO, we typically map to the HHDM region
// Virtual address = Physical address + HHDM offset
u64 virt_base = phys_base + hhdm_offset;
print(" Target virtual: 0x");
print64(virt_base);
print("\n");
// Get current page tables
u64 pml4_phys = get_cr3();
struct page_entry *pml4 = (struct page_entry*)phys_to_virt(pml4_phys);
// Map each page
for (u64 i = 0; i < num_pages; i++) {
u64 current_phys = phys_base + (i * PAGE_SIZE);
u64 current_virt = virt_base + (i * PAGE_SIZE);
// Extract indices
u64 pml4_index = (current_virt >> 39) & 0x1FF;
u64 pdpt_index = (current_virt >> 30) & 0x1FF;
u64 pd_index = (current_virt >> 21) & 0x1FF;
u64 pt_index = (current_virt >> 12) & 0x1FF;
// Walk/create page table hierarchy
struct page_entry *pdpt = get_or_create_table(pml4, pml4_index);
if (!pdpt) {
print("ERROR: Failed to get/create PDPT\n");
return NULL;
}
struct page_entry *pd = get_or_create_table(pdpt, pdpt_index);
if (!pd) {
print("ERROR: Failed to get/create PD\n");
return NULL;
}
struct page_entry *pt = get_or_create_table(pd, pd_index);
if (!pt) {
print("ERROR: Failed to get/create PT\n");
return NULL;
}
// Map the page with MMIO-appropriate settings
pt[pt_index].present = 1;
pt[pt_index].writable = 1;
pt[pt_index].user = 0;
pt[pt_index].cache_disabled = 1; // CRITICAL: Disable caching for MMIO!
pt[pt_index].write_through = 0;
pt[pt_index].no_execute = 1; // Don't execute from MMIO
pt[pt_index].frame = current_phys >> 12;
// Flush TLB for this page
asm volatile("invlpg (%0)" :: "r"(current_virt) : "memory");
}
print(" MMIO mapped successfully!\n");
print(" Access at virtual: 0x");
print64(virt_base + offset_in_page);
print("\n\n");
// Return virtual address (with original offset)
return (void*)(virt_base + offset_in_page);
}
// Unmap MMIO region
void unmap_mmio(void *virtual_addr, u64 size) {
u64 virt_base = (u64)virtual_addr & ~0xFFF;
u64 num_pages = (size + ((u64)virtual_addr & 0xFFF) + 0xFFF) / 4096;
u64 pml4_phys = get_cr3();
struct page_entry *pml4 = (struct page_entry*)phys_to_virt(pml4_phys);
for (u64 i = 0; i < num_pages; i++) {
u64 current_virt = virt_base + (i * 4096);
u64 pml4_index = (current_virt >> 39) & 0x1FF;
u64 pdpt_index = (current_virt >> 30) & 0x1FF;
u64 pd_index = (current_virt >> 21) & 0x1FF;
u64 pt_index = (current_virt >> 12) & 0x1FF;
if (!pml4[pml4_index].present) continue;
struct page_entry *pdpt = phys_to_virt((u64)pml4[pml4_index].frame << 12);
if (!pdpt[pdpt_index].present) continue;
struct page_entry *pd = phys_to_virt((u64)pdpt[pdpt_index].frame << 12);
if (!pd[pd_index].present) continue;
struct page_entry *pt = phys_to_virt((u64)pd[pd_index].frame << 12);
if (!pt[pt_index].present) continue;
// Clear the entry
*((u64*)&pt[pt_index]) = 0;
// Flush TLB
asm volatile("invlpg (%0)" :: "r"(current_virt) : "memory");
}
}
// Check if a physical address is already mapped
int is_mapped(u64 physical_addr) {
u64 virtual_addr = physical_addr + hhdm_offset;
u64 pml4_phys = get_cr3();
struct page_entry *pml4 = phys_to_virt(pml4_phys);
u64 pml4_index = (virtual_addr >> 39) & 0x1FF;
u64 pdpt_index = (virtual_addr >> 30) & 0x1FF;
u64 pd_index = (virtual_addr >> 21) & 0x1FF;
u64 pt_index = (virtual_addr >> 12) & 0x1FF;
if (!pml4[pml4_index].present) return 0;
struct page_entry *pdpt = phys_to_virt((u64)pml4[pml4_index].frame << 12);
if (!pdpt[pdpt_index].present) return 0;
// Check for 1GB huge page
if (pdpt[pdpt_index].huge_page) return 1;
struct page_entry *pd = phys_to_virt((u64)pdpt[pdpt_index].frame << 12);
if (!pd[pd_index].present) return 0;
// Check for 2MB huge page
if (pd[pd_index].huge_page) return 1;
struct page_entry *pt = phys_to_virt((u64)pd[pd_index].frame << 12);
return pt[pt_index].present;
}
// Read from ACPI register (8-bit)
u8 acpi_read8(void *mmio_base, u64 offset) {
volatile u8 *addr = (volatile u8*)((u64)mmio_base + offset);
return *addr;
}
// Read from ACPI register (16-bit)
u16 acpi_read16(void *mmio_base, u64 offset) {
volatile u16 *addr = (volatile u16*)((u64)mmio_base + offset);
return *addr;
}
// Read from ACPI register (32-bit)
u32 acpi_read32(void *mmio_base, u64 offset) {
volatile u32 *addr = (volatile u32*)((u64)mmio_base + offset);
return *addr;
}
// Read from ACPI register (64-bit)
u64 acpi_read64(void *mmio_base, u64 offset) {
volatile u64 *addr = (volatile u64*)((u64)mmio_base + offset);
return *addr;
}
// Write to ACPI register (8-bit)
void acpi_write8(void *mmio_base, u64 offset, u8 value) {
volatile u8 *addr = (volatile u8*)((u64)mmio_base + offset);
*addr = value;
}
// Write to ACPI register (16-bit)
void acpi_write16(void *mmio_base, u64 offset, u16 value) {
volatile u16 *addr = (volatile u16*)((u64)mmio_base + offset);
*addr = value;
}
// Write to ACPI register (32-bit)
void acpi_write32(void *mmio_base, u64 offset, u32 value) {
volatile u32 *addr = (volatile u32*)((u64)mmio_base + offset);
*addr = value;
}
// Write to ACPI register (64-bit)
void acpi_write64(void *mmio_base, u64 offset, u64 value) {
volatile u64 *addr = (volatile u64*)((u64)mmio_base + offset);
*addr = value;
}
// Example: Map and access ACPI PM1a Control Block
void* map_acpi_pm1a_control(u64 physical_addr) {
print("Mapping ACPI PM1a Control Block...\n");
// PM1a Control is typically 2 bytes, but map at least one page
void *mmio = map_mmio(physical_addr, 4096);
if (mmio) {
print("PM1a Control Block mapped at virtual: 0x");
print64((u64)mmio);
print("\n");
}
return mmio;
}
// Example: Map ACPI tables (FADT, MADT, etc.)
void* map_acpi_table(u64 physical_addr, u64 size) {
print("Mapping ACPI table...\n");
print(" Physical: 0x");
print64(physical_addr);
print("\n Size: ");
print64(size);
print(" bytes\n");
void *table = map_mmio(physical_addr, size);
if (table) {
print("ACPI table mapped at virtual: 0x");
print64((u64)table);
print("\n");
}
return table;
}
void print_page_mapping(u64 virtual_addr) {
print("Page mapping for virtual 0x");
print64(virtual_addr);
print(":\n");
u64 pml4_phys = get_cr3();
struct page_entry *pml4 = phys_to_virt(pml4_phys);
u64 pml4_index = (virtual_addr >> 39) & 0x1FF;
u64 pdpt_index = (virtual_addr >> 30) & 0x1FF;
u64 pd_index = (virtual_addr >> 21) & 0x1FF;
u64 pt_index = (virtual_addr >> 12) & 0x1FF;
print(" Indices: PML4[");
print64(pml4_index);
print("] PDPT[");
print64(pdpt_index);
print("] PD[");
print64(pd_index);
print("] PT[");
print64(pt_index);
print("]\n");
if (!pml4[pml4_index].present) {
print(" PML4 entry not present!\n");
return;
}
print(" PML4 entry present, frame=0x");
print64((u64)pml4[pml4_index].frame << 12);
print("\n");
struct page_entry *pdpt = phys_to_virt((u64)pml4[pml4_index].frame << 12);
if (!pdpt[pdpt_index].present) {
print(" PDPT entry not present!\n");
return;
}
print(" PDPT entry present, frame=0x");
print64((u64)pdpt[pdpt_index].frame << 12);
print("\n");
if (pdpt[pdpt_index].huge_page) {
print(" 1GB huge page!\n");
return;
}
struct page_entry *pd = phys_to_virt((u64)pdpt[pdpt_index].frame << 12);
if (!pd[pd_index].present) {
print(" PD entry not present!\n");
return;
}
print(" PD entry present, frame=0x");
print64((u64)pd[pd_index].frame << 12);
print("\n");
if (pd[pd_index].huge_page) {
print(" 2MB huge page!\n");
return;
}
struct page_entry *pt = phys_to_virt((u64)pd[pd_index].frame << 12);
if (!pt[pt_index].present) {
print(" PT entry not present!\n");
return;
}
print(" PT entry present:\n");
print(" Physical frame: 0x");
print64((u64)pt[pt_index].frame << 12);
print("\n Writable: ");
print64(pt[pt_index].writable);
print("\n Cache disabled: ");
print64(pt[pt_index].cache_disabled);
print("\n No execute: ");
print64(pt[pt_index].no_execute);
print("\n");
}

6
src/map.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
#include "common.h"
void* map_mmio(u64, u64);