Added Memory Paging + Formating Fixes

Memory paging was "fixed", there was previously a stub because I was
working out some compilation issue. Turns out, I had extern keyword
called to the structs. Stupidly, I forgot to declare the struct in the
header the whole time. Luckily that worked itself out, and now vga
memory is mapped.
This commit is contained in:
cowmonk 2025-10-16 13:53:36 -07:00
parent 0d3653c970
commit 6d2e453d27
8 changed files with 477 additions and 446 deletions

1
.gitignore vendored
View file

@ -7,3 +7,4 @@ isodir/boot/limine/limine-bios-cd.bin
isodir/boot/limine/limine-uefi-cd.bin
isodir/EFI/BOOT/BOOTX64.EFI
isodir/EFI/BOOT/BOOTIA32.EFI
compile_flags.txt

View file

@ -7,279 +7,290 @@
static fb_console_t console;
void fb_init(void)
void
fb_init(void)
{
if (framebuffer_request.response == NULL ||
framebuffer_request.response->framebuffer_count < 1) {
return;
}
console.fb = framebuffer_request.response->framebuffers[0];
console.fg_color = 0xFFFFFF; // White
console.bg_color = 0x000000; // Black
console.cursor_x = 0;
console.cursor_y = 0;
console.cols = console.fb->width / FB_CHAR_WIDTH;
console.rows = console.fb->height / FB_CHAR_HEIGHT;
fb_clear();
}
void fb_clear(void)
{
if (!console.fb) return;
uint32_t *fb = (uint32_t *)console.fb->address;
size_t pixels = (console.fb->pitch / 4) * console.fb->height;
for (size_t i = 0; i < pixels; i++) {
fb[i] = console.bg_color;
}
console.cursor_x = 0;
console.cursor_y = 0;
}
void fb_draw_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color)
{
if (!console.fb) return;
uint32_t *fb = (uint32_t *)console.fb->address;
uint32_t pitch_pixels = console.fb->pitch / 4;
for (uint32_t row = y; row < y + h && row < console.fb->height; row++) {
for (uint32_t col = x; col < x + w && col < console.fb->width; col++) {
fb[row * pitch_pixels + col] = color;
if (framebuffer_request.response == NULL ||
framebuffer_request.response->framebuffer_count < 1) {
return;
}
}
}
void fb_set_color(uint32_t fg, uint32_t bg)
{
console.fg_color = fg;
console.bg_color = bg;
}
static void draw_char(uint32_t x, uint32_t y, char c, uint32_t fg_color, uint32_t bg_color)
{
if (!console.fb) return;
uint32_t *fb = (uint32_t *)console.fb->address;
uint32_t pitch_pixels = console.fb->pitch / 4;
// Get the font data for this character
const uint8_t *char_data = &IBM_VGA_8x16[c * 16];
// Draw each row of the character
for (uint32_t row = 0; row < FB_CHAR_HEIGHT; row++) {
uint8_t font_row = char_data[row];
// Draw each pixel in the row
for (uint32_t col = 0; col < FB_CHAR_WIDTH; col++) {
uint32_t px = x + col;
uint32_t py = y + row;
// Check bounds
if (px >= console.fb->width || py >= console.fb->height) continue;
// Check if this pixel should be set (bit test)
if (font_row & (0x80 >> col)) {
fb[py * pitch_pixels + px] = fg_color;
} else {
fb[py * pitch_pixels + px] = bg_color;
}
}
}
}
static void scroll_up(void)
{
if (!console.fb) return;
uint32_t *fb = (uint32_t *)console.fb->address;
uint32_t pitch_pixels = console.fb->pitch / 4;
// Move all lines up by one character height
for (uint32_t y = 0; y < console.fb->height - FB_CHAR_HEIGHT; y++) {
for (uint32_t x = 0; x < console.fb->width; x++) {
fb[y * pitch_pixels + x] = fb[(y + FB_CHAR_HEIGHT) * pitch_pixels + x];
}
}
// Clear the last line
for (uint32_t y = console.fb->height - FB_CHAR_HEIGHT; y < console.fb->height; y++) {
for (uint32_t x = 0; x < console.fb->width; x++) {
fb[y * pitch_pixels + x] = console.bg_color;
}
}
}
void fb_putchar(char c)
{
if (!console.fb) return;
// Handle special characters
switch (c) {
case '\n':
console.cursor_x = 0;
console.cursor_y++;
break;
case '\r':
console.cursor_x = 0;
break;
case '\t':
console.cursor_x = (console.cursor_x + 8) & ~7;
break;
case '\b':
if (console.cursor_x > 0) {
console.cursor_x--;
draw_char(console.cursor_x * FB_CHAR_WIDTH,
console.cursor_y * FB_CHAR_HEIGHT,
' ', console.fg_color, console.bg_color);
}
break;
default:
// Draw the character
draw_char(console.cursor_x * FB_CHAR_WIDTH,
console.cursor_y * FB_CHAR_HEIGHT,
c, console.fg_color, console.bg_color);
console.cursor_x++;
break;
}
// Handle line wrapping
if (console.cursor_x >= console.cols) {
console.fb = framebuffer_request.response->framebuffers[0];
console.fg_color = 0xFFFFFF; // White
console.bg_color = 0x000000; // Black
console.cursor_x = 0;
console.cursor_y++;
}
// Handle scrolling
if (console.cursor_y >= console.rows) {
scroll_up();
console.cursor_y = console.rows - 1;
}
console.cursor_y = 0;
console.cols = console.fb->width / FB_CHAR_WIDTH;
console.rows = console.fb->height / FB_CHAR_HEIGHT;
fb_clear();
}
void fb_puts(const char *str)
void
fb_clear(void)
{
while (*str) {
fb_putchar(*str++);
}
}
static void print_number(unsigned long num, int base, int width, char pad)
{
char digits[] = "0123456789ABCDEF";
char buffer[32];
int pos = 0;
// Convert number to string (reversed)
if (num == 0) {
buffer[pos++] = '0';
} else {
while (num > 0) {
buffer[pos++] = digits[num % base];
num /= base;
if (!console.fb) return;
uint32_t *fb = (uint32_t *)console.fb->address;
size_t pixels = (console.fb->pitch / 4) * console.fb->height;
for (size_t i = 0; i < pixels; i++) {
fb[i] = console.bg_color;
}
}
// Add padding if needed
while (pos < width) {
buffer[pos++] = pad;
}
// Print reversed
while (pos > 0) {
fb_putchar(buffer[--pos]);
}
console.cursor_x = 0;
console.cursor_y = 0;
}
static void print_signed(long num, int width, char pad)
void
fb_draw_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, uint32_t color)
{
if (num < 0) {
fb_putchar('-');
print_number(-num, 10, width, pad);
} else {
print_number(num, 10, width, pad);
}
if (!console.fb) return;
uint32_t *fb = (uint32_t *)console.fb->address;
uint32_t pitch_pixels = console.fb->pitch / 4;
for (uint32_t row = y; row < y + h && row < console.fb->height; row++) {
for (uint32_t col = x; col < x + w && col < console.fb->width; col++) {
fb[row * pitch_pixels + col] = color;
}
}
}
void fb_printf(const char *fmt, ...)
void
fb_set_color(uint32_t fg, uint32_t bg)
{
va_list args;
va_start(args, fmt);
while (*fmt) {
if (*fmt == '%') {
fmt++;
// Handle width and padding
char pad = ' ';
int width = 0;
if (*fmt == '0') {
pad = '0';
fmt++;
}
while (*fmt >= '0' && *fmt <= '9') {
width = width * 10 + (*fmt - '0');
fmt++;
}
// Handle format specifiers
switch (*fmt) {
case 'd':
case 'i':
print_signed(va_arg(args, int), width, pad);
break;
console.fg_color = fg;
console.bg_color = bg;
}
static void
draw_char(uint32_t x, uint32_t y, char c, uint32_t fg_color, uint32_t bg_color)
{
if (!console.fb) return;
uint32_t *fb = (uint32_t *)console.fb->address;
uint32_t pitch_pixels = console.fb->pitch / 4;
// Get the font data for this character
const uint8_t *char_data = &IBM_VGA_8x16[c * 16];
// Draw each row of the character
for (uint32_t row = 0; row < FB_CHAR_HEIGHT; row++) {
uint8_t font_row = char_data[row];
// Draw each pixel in the row
for (uint32_t col = 0; col < FB_CHAR_WIDTH; col++) {
uint32_t px = x + col;
uint32_t py = y + row;
case 'u':
print_number(va_arg(args, unsigned int), 10, width, pad);
break;
case 'x':
print_number(va_arg(args, unsigned int), 16, width, pad);
break;
case 'X':
print_number(va_arg(args, unsigned int), 16, width, pad);
break;
case 'p':
fb_puts("0x");
print_number((unsigned long)va_arg(args, void*), 16, 16, '0');
break;
case 'c':
fb_putchar(va_arg(args, int));
break;
case 's':
{
const char *str = va_arg(args, const char*);
if (str) {
fb_puts(str);
// Check bounds
if (px >= console.fb->width || py >= console.fb->height) continue;
// Check if this pixel should be set (bit test)
if (font_row & (0x80 >> col)) {
fb[py * pitch_pixels + px] = fg_color;
} else {
fb_puts("(null)");
fb[py * pitch_pixels + px] = bg_color;
}
}
break;
case '%':
fb_putchar('%');
break;
default:
fb_putchar('%');
fb_putchar(*fmt);
break;
}
} else {
fb_putchar(*fmt);
}
}
fmt++;
}
va_end(args);
}
static void
scroll_up(void)
{
if (!console.fb) return;
uint32_t *fb = (uint32_t *)console.fb->address;
uint32_t pitch_pixels = console.fb->pitch / 4;
// Move all lines up by one character height
for (uint32_t y = 0; y < console.fb->height - FB_CHAR_HEIGHT; y++) {
for (uint32_t x = 0; x < console.fb->width; x++) {
fb[y * pitch_pixels + x] = fb[(y + FB_CHAR_HEIGHT) * pitch_pixels + x];
}
}
// Clear the last line
for (uint32_t y = console.fb->height - FB_CHAR_HEIGHT; y < console.fb->height; y++) {
for (uint32_t x = 0; x < console.fb->width; x++) {
fb[y * pitch_pixels + x] = console.bg_color;
}
}
}
void
fb_putchar(char c)
{
if (!console.fb) return;
// Handle special characters
switch (c) {
case '\n':
console.cursor_x = 0;
console.cursor_y++;
break;
case '\r':
console.cursor_x = 0;
break;
case '\t':
console.cursor_x = (console.cursor_x + 8) & ~7;
break;
case '\b':
if (console.cursor_x > 0) {
console.cursor_x--;
draw_char(console.cursor_x * FB_CHAR_WIDTH,
console.cursor_y * FB_CHAR_HEIGHT,
' ', console.fg_color, console.bg_color);
}
break;
default:
// Draw the character
draw_char(console.cursor_x * FB_CHAR_WIDTH,
console.cursor_y * FB_CHAR_HEIGHT,
c, console.fg_color, console.bg_color);
console.cursor_x++;
break;
}
// Handle line wrapping
if (console.cursor_x >= console.cols) {
console.cursor_x = 0;
console.cursor_y++;
}
// Handle scrolling
if (console.cursor_y >= console.rows) {
scroll_up();
console.cursor_y = console.rows - 1;
}
}
void
fb_puts(const char *str)
{
while (*str) {
fb_putchar(*str++);
}
}
static void
print_number(unsigned long num, int base, int width, char pad)
{
char digits[] = "0123456789ABCDEF";
char buffer[32];
int pos = 0;
// Convert number to string (reversed)
if (num == 0) {
buffer[pos++] = '0';
} else {
while (num > 0) {
buffer[pos++] = digits[num % base];
num /= base;
}
}
// Add padding if needed
while (pos < width) {
buffer[pos++] = pad;
}
// Print reversed
while (pos > 0) {
fb_putchar(buffer[--pos]);
}
}
static void
print_signed(long num, int width, char pad)
{
if (num < 0) {
fb_putchar('-');
print_number(-num, 10, width, pad);
} else {
print_number(num, 10, width, pad);
}
}
void
fb_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
while (*fmt) {
if (*fmt == '%') {
fmt++;
// Handle width and padding
char pad = ' ';
int width = 0;
if (*fmt == '0') {
pad = '0';
fmt++;
}
while (*fmt >= '0' && *fmt <= '9') {
width = width * 10 + (*fmt - '0');
fmt++;
}
// Handle format specifiers
switch (*fmt) {
case 'd':
case 'i':
print_signed(va_arg(args, int), width, pad);
break;
case 'u':
print_number(va_arg(args, unsigned int), 10, width, pad);
break;
case 'x':
print_number(va_arg(args, unsigned int), 16, width, pad);
break;
case 'X':
print_number(va_arg(args, unsigned int), 16, width, pad);
break;
case 'p':
fb_puts("0x");
print_number((unsigned long)va_arg(args, void*), 16, 16, '0');
break;
case 'c':
fb_putchar(va_arg(args, int));
break;
case 's':
{
const char *str = va_arg(args, const char*);
if (str) {
fb_puts(str);
} else {
fb_puts("(null)");
}
}
break;
case '%':
fb_putchar('%');
break;
default:
fb_putchar('%');
fb_putchar(*fmt);
break;
}
} else {
fb_putchar(*fmt);
}
fmt++;
}
va_end(args);
}

View file

@ -4,69 +4,69 @@
static inline void
outb(uint16_t port, uint8_t val)
{
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
__asm__ volatile ("outb %0, %1" : : "a"(val), "Nd"(port));
}
static inline uint8_t
inb(uint16_t port)
{
uint8_t ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
uint8_t ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret;
}
// Write vga registers for mode change
static void
write_regs(uint8_t *regs)
{
unsigned i;
// Write misc output register
outb(VGA_MISC_WRITE, *regs);
regs++;
// Write sequencer registers (5 registers)
for (i = 0; i < 5; i++) {
outb(VGA_SEQ_INDEX, i);
outb(VGA_SEQ_DATA, *regs);
regs++;
}
// Unlock CRTC registers 0-7 by clearing protect bit
outb(VGA_CRTC_INDEX, 0x03);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) | 0x80);
outb(VGA_CRTC_INDEX, 0x11);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) & ~0x80);
// Update the register values to match
regs[0x03] = regs[0x03] | 0x80;
regs[0x11] = regs[0x11] & ~0x80;
// Write CRTC registers (25 registers)
for (i = 0; i < 25; i++) {
outb(VGA_CRTC_INDEX, i);
outb(VGA_CRTC_DATA, *regs);
regs++;
}
// Write graphics controller registers (9 registers)
for (i = 0; i < 9; i++) {
outb(VGA_GC_INDEX, i);
outb(VGA_GC_DATA, *regs);
regs++;
}
// Write attribute controller registers (21 registers)
for (i = 0; i < 21; i++) {
inb(VGA_INSTAT_READ); // Reset flip-flop
outb(VGA_AC_INDEX, i);
outb(VGA_AC_WRITE, *regs);
regs++;
}
// Enable video display
inb(VGA_INSTAT_READ);
outb(VGA_AC_INDEX, 0x20);
unsigned i;
// Write misc output register
outb(VGA_MISC_WRITE, *regs);
regs++;
// Write sequencer registers (5 registers)
for (i = 0; i < 5; i++) {
outb(VGA_SEQ_INDEX, i);
outb(VGA_SEQ_DATA, *regs);
regs++;
}
// Unlock CRTC registers 0-7 by clearing protect bit
outb(VGA_CRTC_INDEX, 0x03);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) | 0x80);
outb(VGA_CRTC_INDEX, 0x11);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) & ~0x80);
// Update the register values to match
regs[0x03] = regs[0x03] | 0x80;
regs[0x11] = regs[0x11] & ~0x80;
// Write CRTC registers (25 registers)
for (i = 0; i < 25; i++) {
outb(VGA_CRTC_INDEX, i);
outb(VGA_CRTC_DATA, *regs);
regs++;
}
// Write graphics controller registers (9 registers)
for (i = 0; i < 9; i++) {
outb(VGA_GC_INDEX, i);
outb(VGA_GC_DATA, *regs);
regs++;
}
// Write attribute controller registers (21 registers)
for (i = 0; i < 21; i++) {
inb(VGA_INSTAT_READ); // Reset flip-flop
outb(VGA_AC_INDEX, i);
outb(VGA_AC_WRITE, *regs);
regs++;
}
// Enable video display
inb(VGA_INSTAT_READ);
outb(VGA_AC_INDEX, 0x20);
}
void
@ -75,22 +75,22 @@ vga_set_mode_13h(void)
// Register values for VGA mode 13h (320x200, 256 colors)
// Order: Misc, Seq[5], CRTC[25], GC[9], AC[21]
static uint8_t mode_320x200x256[] = {
// Misc output register
0x63,
// Sequencer registers
0x03, 0x01, 0x0F, 0x00, 0x0E,
// CRTC registers
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
0xFF,
// Graphics controller registers
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
0xFF,
// Attribute controller registers
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x41, 0x00, 0x0F, 0x00, 0x00
// Misc output register
0x63,
// Sequencer registers
0x03, 0x01, 0x0F, 0x00, 0x0E,
// CRTC registers
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
0xFF,
// Graphics controller registers
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
0xFF,
// Attribute controller registers
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x41, 0x00, 0x0F, 0x00, 0x00
};
write_regs(mode_320x200x256);
@ -113,6 +113,6 @@ vga_clear_screen(uint8_t color)
uint8_t *vga = (uint8_t *)VGA_GRAPHICS_BUFFER;
// fill entire buffer (64k pixels)
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) {
vga[i] = color;
vga[i] = color;
}
}

View file

@ -0,0 +1,11 @@
#ifndef PAGING_H
#define PAGING_H
#include <limine.h>
volatile struct limine_hhdm_request hhdm_request;
volatile struct limine_kernel_address_request kernel_address_request;
void map_vga_memory(void);
#endif /* ifndef PAGING_H */

View file

@ -3,6 +3,7 @@
#include <stddef.h>
#include <bootloader.h>
#include <drivers/video/framebuffer.h>
#include <mm/paging.h>
static void
hcf(void)
@ -20,6 +21,7 @@ kernel_main(void)
/* Initialize framebuffer console */
fb_init();
map_vga_memory();
/* Test print */
fb_puts("Hello World\n");

View file

@ -1,4 +1,4 @@
#include <string.h>
#include <klibc/string.h>
size_t
strlen(const char* str)

125
kernel/mm/paging.c Normal file
View file

@ -0,0 +1,125 @@
#include <stdint.h>
#include <stddef.h>
#include <limine.h>
#include <mm/paging.h>
#define PAGE_PRESENT (1ULL << 0)
#define PAGE_WRITABLE (1ULL << 1)
#define PAGE_USER (1ULL << 2)
#define PAGE_SIZE_2MB (1ULL << 7)
#define PAGE_SIZE 4096
// Get hhdm offset
extern volatile struct limine_hhdm_request hhdm_request;
extern volatile struct limine_kernel_address_request kernel_address_request;
// Static storage for page tables
static uint64_t pdpt[512] __attribute__((aligned(4096)));
static uint64_t pd[512] __attribute__((aligned(4096)));
// Get current cr3 value (PML address)
static uint64_t
get_cr3(void)
{
uint64_t cr3;
__asm__ volatile("mov %%cr3, %0" : "=r"(cr3));
return cr3;
}
// Set cr3 to flush TLB
static void
set_cr3(uint64_t cr3)
{
__asm__ volatile("mov %0, %%cr3" : : "r"(cr3) : "memory");
}
// Convert physical address to virt address using hhdm
static void*
phys_to_virt(uint64_t phys)
{
if (hhdm_request.response == NULL) {
// Fallback if hhdm is not available
return (void *)(phys + 0xffff800000000000ULL);
}
return (void *)(phys + hhdm_request.response->offset);
}
// Convert virt address to physical address
static uint64_t
virt_to_phys(void *virt)
{
uint64_t addr = (uint64_t)virt;
// Check if this is a kernel address
if (kernel_address_request.response != NULL) {
uint64_t kernel_virt_base = kernel_address_request.response->virtual_base;
uint64_t kernel_phys_base = kernel_address_request.response->physical_base;
// If address is in kernel space, convert using kernel base
if (addr >= kernel_virt_base && addr < kernel_virt_base + 0x200000) {
return kernel_phys_base + (addr - kernel_virt_base);
}
}
// Otherwise, in hhdm range
if (hhdm_request.response == NULL) {
// Fallback to default if hhdm not avail
return (addr - 0xffff800000000000ULL);
}
return (addr - hhdm_request.response->offset);
}
void
map_vga_memory(void)
{
// Get current PML4 from cr3
uint64_t cr3 = get_cr3();
uint64_t *pml4 = (uint64_t *)phys_to_virt(cr3 & ~0xFFF);
// VGA memory starts at 0xA0000 (640KB)
// Map entire lower 1MB region for simplcity
/* For address 0xA0000:
* PML4 index = 0 (bits 47-39)
* PDPT index = 0 (bits 38-30)
* PD index = 0 (bits 29-21)
* PT index = 160 (0xA0) (bits 20-12)
*/
// Check if PML4[0] is present
if (!(pml4[0] & PAGE_PRESENT)) {
// Clear PDPT
for (int i = 0; i < 512; i++) {
pdpt[i] = 0;
}
// Install PDPT (use physical address)
pml4[0] = virt_to_phys(pdpt) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
}
// Get PDPT (convert physical address from entry to virt for access)
uint64_t *pdpt_ptr = (uint64_t *)phys_to_virt(pml4[0] & ~0xFFF);
// Check if PDPT[0] is present
if (!(pdpt_ptr[0] & PAGE_PRESENT)) {
// Clear pd
for (int i = 0; i < 512; i++) {
pd[i] = 0;
}
// Install pd (use physical address)
pdpt_ptr[0] = virt_to_phys(pd) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
}
// Get pd (convert physical address from entry to virt for access)
uint64_t *pd_ptr = (uint64_t *)phys_to_virt(pdpt_ptr[0] & ~0xFFF);
// Check if we can use 2MB pages
if (!(pd_ptr[0] & PAGE_PRESENT)) {
// Map the first 2MB as a large page (0x0 - 0x200000)
// This include VGA memory at 0xA0000-0xBFFFF
pd_ptr[0] = 0x0 | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER | PAGE_SIZE_2MB;
}
// Flush TLB
set_cr3(cr3);
}

View file

@ -1,119 +0,0 @@
#include <stdint.h>
#include <stddef.h>
#include <limine.h>
#define PAGE_PRESENT (1ULL << 0)
#define PAGE_WRITABLE (1ULL << 1)
#define PAGE_USER (1ULL << 2)
#define PAGE_SIZE_2MB (1ULL << 7)
#define PAGE_SIZE 4096
// Get hhdm offset
extern volatile struct limine_hhdm_request hhdm_request;
extern volatile struct limine_kernel_address_request kernel_address_request;
// Static storage for page tables
static uint64_t pdpt[512] __attribute__((aligned(4096)));
static uint64_t pd[512] __attribute__((aligned(4096)));
// Get current cr3 value (PML address)
static uint64_t get_cr3(void)
{
uint64_t cr3;
__asm__ volatile("mov %%cr3, %0" : "=r"(cr3));
return cr3;
}
// Set cr3 to flush TLB
static void set_cr3(uint64_t cr3)
{
__asm__ volatile("mov %0, %%cr3" : : "r"(cr3) : "memory");
}
// Convert physical address to virt address using hhdm
static inline void *phys_to_virt(uint64_t phys)
{
if (hhdm_request.response == NULL) {
// Fallback if hhdm is not available
return (void *)(phys + 0xffff800000000000ULL);
}
return (void *)(phys + hhdm_request.response->offset);
}
// Convert virt address to physical address
static inline uint64_t virt_to_phys(void *virt)
{
uint64_t addr = (uint64_t)virt;
// Check if this is a kernel address
if (kernel_address_request.response != NULL) {
uint64_t kernel_virt_base = kernel_address_request.response->virtual_base;
uint64_t kernel_phys_base = kernel_address_request.response->physical_base;
// If address is in kernel space, convert using kernel base
if (addr >= kernel_virt_base && addr < kernel_virt_base + 0x200000) {
return kernel_phys_base + (addr - kernel_virt_base);
}
}
// Otherwise, in hhdm range
if (hhdm_request.response == NULL) {
// Fallback to default if hhdm not avail
return (addr - 0xffff800000000000ULL);
}
return (addr - hhdm_request.response->offset);
}
void map_vga_memory(void)
{
// Get current PML4 from cr3
uint64_t cr3 = get_cr3();
uint64_t *pml4 = (uint64_t *)phys_to_virt(cr3 & ~0xFFF);
// VGA memory starts at 0xA0000 (640KB)
// Map entire lower 1MB region for simplcity
/* For address 0xA0000:
* PML4 index = 0 (bits 47-39)
* PDPT index = 0 (bits 38-30)
* PD index = 0 (bits 29-21)
* PT index = 160 (0xA0) (bits 20-12)
*/
// Check if PML4[0] is present
if (!(pml4[0] & PAGE_PRESENT)) {
// Clear PDPT
for (int i = 0; i < 512; i++) {
pdpt[i] = 0;
}
// Install PDPT (use physical address)
pml4[0] = virt_to_phys(pdpt) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
}
// Get PDPT (convert physical address from entry to virt for access)
uint64_t *pdpt_ptr = (uint64_t *)phys_to_virt(pml4[0] & ~0xFFF);
// Check if PDPT[0] is present
if (!(pdpt_ptr[0] & PAGE_PRESENT)) {
// Clear pd
for (int i = 0; i < 512; i++) {
pd[i] = 0;
}
// Install pd (use physical address)
pdpt_ptr[0] = virt_to_phys(pd) | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER;
}
// Get pd (convert physical address from entry to virt for access)
uint64_t *pd_ptr = (uint64_t *)phys_to_virt(pdpt_ptr[0] & ~0xFFF);
// Check if we can use 2MB pages
if (!(pd_ptr[0] & PAGE_PRESENT)) {
// Map the first 2MB as a large page (0x0 - 0x200000)
// This include VGA memory at 0xA0000-0xBFFFF
pd_ptr[0] = 0x0 | PAGE_PRESENT | PAGE_WRITABLE | PAGE_USER | PAGE_SIZE_2MB;
}
// Flush TLB
set_cr3(cr3);
}