Fixed small errors in PIC signalling, added code for allocation and MMIO mapping
This commit is contained in:
parent
4ca9447efa
commit
d4e1c29f07
4
bochs.bxrc
Normal file
4
bochs.bxrc
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
vga: extension=vgahw
|
||||||
|
ata0-master: type=disk, path="image.hdd", mode=flat
|
||||||
|
boot: disk
|
||||||
|
memory: guest=1024, host=1024
|
||||||
26
flake.lock
generated
26
flake.lock
generated
@ -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
|
|
||||||
}
|
|
||||||
0
image.hdd.lock
Normal file
0
image.hdd.lock
Normal file
BIN
obj/src/int.c.o
BIN
obj/src/int.c.o
Binary file not shown.
@ -1,6 +1,7 @@
|
|||||||
obj/src/main.c.o: src/main.c src/../include/limine.h src/acpi.h \
|
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/../include/limine.h:
|
||||||
src/acpi.h:
|
src/acpi.h:
|
||||||
src/common.h:
|
src/common.h:
|
||||||
|
src/alloc.h:
|
||||||
src/print.h:
|
src/print.h:
|
||||||
|
|||||||
BIN
obj/src/main.c.o
BIN
obj/src/main.c.o
Binary file not shown.
196
src/alloc.c
Normal file
196
src/alloc.c
Normal 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
16
src/alloc.h
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
64
src/apic.c
64
src/apic.c
@ -1,16 +1,51 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
|
#include "map.h"
|
||||||
|
|
||||||
// stub of a PIC layout, we don't need the whole thing
|
// stub of a PIC layout, we don't need the whole thing
|
||||||
// as we only care about initializing it to disable it
|
// as we only care about initializing it to disable it
|
||||||
enum {
|
enum {
|
||||||
PIC_COMM_MASTER = 0x20,
|
PIC_COMM_MASTER = 0x20,
|
||||||
PIC_COMM_SLAVE = 0x21,
|
PIC_COMM_SLAVE = 0xA0,
|
||||||
PIC_DATA_MASTER = 0xA0,
|
PIC_DATA_MASTER = 0x21,
|
||||||
PIC_DATA_SLAVE = 0xA1,
|
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() {
|
static void pic_disable() {
|
||||||
|
pic_init();
|
||||||
outb(PIC_DATA_MASTER, ~0);
|
outb(PIC_DATA_MASTER, ~0);
|
||||||
outb(PIC_DATA_SLAVE, ~0);
|
outb(PIC_DATA_SLAVE, ~0);
|
||||||
}
|
}
|
||||||
@ -63,11 +98,34 @@ void apic_enable() {
|
|||||||
pic_disable();
|
pic_disable();
|
||||||
print("\nPIC Disabled\n");
|
print("\nPIC Disabled\n");
|
||||||
apic_set_local_base(apic_get_local_base());
|
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);
|
volatile u32* reg = apic_reg(0xF0);
|
||||||
print("Local Base Set\nReg 0xF0 at 0x");
|
print("Reg 0xF0 at 0x");
|
||||||
print64((u64) reg);
|
print64((u64) reg);
|
||||||
// set enable flag
|
// set enable flag
|
||||||
*reg = (*reg | 0x100);
|
*reg = (*reg | 0x100);
|
||||||
print("\nReg written\n");
|
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() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@ -34,9 +34,9 @@ static inline void outd(u16 port, u32 value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void* memcpy(void* restrict dst, const void* src, size_t n);
|
void* memcpy(void* dst, const void* src, size_t n);
|
||||||
void* memset(void* s, int c, size_t n);
|
void* memset(void* s, int c, size_t n);
|
||||||
void* memmove(void* dst, const void* src, size_t n);
|
void* memmove(void* dst, const void* src, size_t n);
|
||||||
int memcmp(const void* s1, const void* s2, size_t n);
|
int memcmp(const void* s1, const void* s2, size_t n);
|
||||||
|
void hang();
|
||||||
extern u64 hhdm_offset;
|
extern u64 hhdm_offset;
|
||||||
|
|||||||
62
src/main.c
62
src/main.c
@ -5,6 +5,7 @@
|
|||||||
#include "../include/limine.h"
|
#include "../include/limine.h"
|
||||||
|
|
||||||
#include "acpi.h"
|
#include "acpi.h"
|
||||||
|
#include "alloc.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "print.h"
|
#include "print.h"
|
||||||
|
|
||||||
@ -20,12 +21,6 @@ static volatile struct limine_framebuffer_request fb_req = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
__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")))
|
__attribute__((used, section(".limine_requests")))
|
||||||
static volatile struct limine_hhdm_request hhdm_req = {
|
static volatile struct limine_hhdm_request hhdm_req = {
|
||||||
.id = LIMINE_HHDM_REQUEST_ID,
|
.id = LIMINE_HHDM_REQUEST_ID,
|
||||||
@ -97,7 +92,7 @@ int memcmp(const void* s1, const void* s2, size_t n) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hang() {
|
void hang() {
|
||||||
for(;;) {
|
for(;;) {
|
||||||
asm ("hlt");
|
asm ("hlt");
|
||||||
}
|
}
|
||||||
@ -123,53 +118,12 @@ extern void init_idt(void);
|
|||||||
|
|
||||||
extern u32 fg;
|
extern u32 fg;
|
||||||
extern u32 bg;
|
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();
|
u32 apic_get_local_base();
|
||||||
void apic_enable();
|
void apic_enable();
|
||||||
|
void setup_identity_mapping();
|
||||||
|
|
||||||
void kmain() {
|
void kmain() {
|
||||||
if(LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
|
if(LIMINE_BASE_REVISION_SUPPORTED(limine_base_revision) == false) {
|
||||||
@ -185,10 +139,7 @@ void kmain() {
|
|||||||
print_init(fb);
|
print_init(fb);
|
||||||
init_idt();
|
init_idt();
|
||||||
|
|
||||||
if(!mem_req.response) {
|
|
||||||
print("Failed to get memory map :(\n)");
|
|
||||||
hang();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!hhdm_req.response) {
|
if(!hhdm_req.response) {
|
||||||
print("Failed to get higher half direct mapping\n.");
|
print("Failed to get higher half direct mapping\n.");
|
||||||
@ -202,11 +153,10 @@ void kmain() {
|
|||||||
hang();
|
hang();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
alloc_init();
|
||||||
|
|
||||||
rsdp = (struct acpi_rsdp_header*)(rsdp_req.response->address);
|
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");
|
print("Found RSDP @ 0x");
|
||||||
print64((u64)rsdp);
|
print64((u64)rsdp);
|
||||||
|
|||||||
388
src/map.c
Normal file
388
src/map.c
Normal 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");
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user