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/boot/limine/limine-uefi-cd.bin
isodir/EFI/BOOT/BOOTX64.EFI isodir/EFI/BOOT/BOOTX64.EFI
isodir/EFI/BOOT/BOOTIA32.EFI isodir/EFI/BOOT/BOOTIA32.EFI
compile_flags.txt

View file

@ -7,279 +7,290 @@
static fb_console_t console; static fb_console_t console;
void fb_init(void) void
fb_init(void)
{ {
if (framebuffer_request.response == NULL || if (framebuffer_request.response == NULL ||
framebuffer_request.response->framebuffer_count < 1) { framebuffer_request.response->framebuffer_count < 1) {
return; 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;
} }
}
}
void fb_set_color(uint32_t fg, uint32_t bg) console.fb = framebuffer_request.response->framebuffers[0];
{ console.fg_color = 0xFFFFFF; // White
console.fg_color = fg; console.bg_color = 0x000000; // Black
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.cursor_x = 0; console.cursor_x = 0;
console.cursor_y++; console.cursor_y = 0;
} console.cols = console.fb->width / FB_CHAR_WIDTH;
console.rows = console.fb->height / FB_CHAR_HEIGHT;
// Handle scrolling fb_clear();
if (console.cursor_y >= console.rows) {
scroll_up();
console.cursor_y = console.rows - 1;
}
} }
void fb_puts(const char *str) void
fb_clear(void)
{ {
while (*str) { if (!console.fb) return;
fb_putchar(*str++);
}
}
static void print_number(unsigned long num, int base, int width, char pad) uint32_t *fb = (uint32_t *)console.fb->address;
{ size_t pixels = (console.fb->pitch / 4) * console.fb->height;
char digits[] = "0123456789ABCDEF";
char buffer[32];
int pos = 0;
// Convert number to string (reversed) for (size_t i = 0; i < pixels; i++) {
if (num == 0) { fb[i] = console.bg_color;
buffer[pos++] = '0';
} else {
while (num > 0) {
buffer[pos++] = digits[num % base];
num /= base;
} }
}
// Add padding if needed console.cursor_x = 0;
while (pos < width) { console.cursor_y = 0;
buffer[pos++] = pad;
}
// Print reversed
while (pos > 0) {
fb_putchar(buffer[--pos]);
}
} }
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) { if (!console.fb) return;
fb_putchar('-');
print_number(-num, 10, width, pad); uint32_t *fb = (uint32_t *)console.fb->address;
} else { uint32_t pitch_pixels = console.fb->pitch / 4;
print_number(num, 10, width, pad);
} 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; console.fg_color = fg;
va_start(args, fmt); console.bg_color = bg;
}
while (*fmt) { static void
if (*fmt == '%') { draw_char(uint32_t x, uint32_t y, char c, uint32_t fg_color, uint32_t bg_color)
fmt++; {
if (!console.fb) return;
// Handle width and padding uint32_t *fb = (uint32_t *)console.fb->address;
char pad = ' '; uint32_t pitch_pixels = console.fb->pitch / 4;
int width = 0;
if (*fmt == '0') { // Get the font data for this character
pad = '0'; const uint8_t *char_data = &IBM_VGA_8x16[c * 16];
fmt++;
}
while (*fmt >= '0' && *fmt <= '9') { // Draw each row of the character
width = width * 10 + (*fmt - '0'); for (uint32_t row = 0; row < FB_CHAR_HEIGHT; row++) {
fmt++; uint8_t font_row = char_data[row];
}
// Handle format specifiers // Draw each pixel in the row
switch (*fmt) { for (uint32_t col = 0; col < FB_CHAR_WIDTH; col++) {
case 'd': uint32_t px = x + col;
case 'i': uint32_t py = y + row;
print_signed(va_arg(args, int), width, pad);
break;
case 'u': // Check bounds
print_number(va_arg(args, unsigned int), 10, width, pad); if (px >= console.fb->width || py >= console.fb->height) continue;
break;
case 'x': // Check if this pixel should be set (bit test)
print_number(va_arg(args, unsigned int), 16, width, pad); if (font_row & (0x80 >> col)) {
break; fb[py * pitch_pixels + px] = fg_color;
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 { } 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++; }
}
static void
va_end(args); 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 static inline void
outb(uint16_t port, uint8_t val) 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 static inline uint8_t
inb(uint16_t port) inb(uint16_t port)
{ {
uint8_t ret; uint8_t ret;
__asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port)); __asm__ volatile ("inb %1, %0" : "=a"(ret) : "Nd"(port));
return ret; return ret;
} }
// Write vga registers for mode change // Write vga registers for mode change
static void static void
write_regs(uint8_t *regs) write_regs(uint8_t *regs)
{ {
unsigned i; unsigned i;
// Write misc output register // Write misc output register
outb(VGA_MISC_WRITE, *regs); outb(VGA_MISC_WRITE, *regs);
regs++; regs++;
// Write sequencer registers (5 registers) // Write sequencer registers (5 registers)
for (i = 0; i < 5; i++) { for (i = 0; i < 5; i++) {
outb(VGA_SEQ_INDEX, i); outb(VGA_SEQ_INDEX, i);
outb(VGA_SEQ_DATA, *regs); outb(VGA_SEQ_DATA, *regs);
regs++; regs++;
} }
// Unlock CRTC registers 0-7 by clearing protect bit // Unlock CRTC registers 0-7 by clearing protect bit
outb(VGA_CRTC_INDEX, 0x03); outb(VGA_CRTC_INDEX, 0x03);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) | 0x80); outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) | 0x80);
outb(VGA_CRTC_INDEX, 0x11); outb(VGA_CRTC_INDEX, 0x11);
outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) & ~0x80); outb(VGA_CRTC_DATA, inb(VGA_CRTC_DATA) & ~0x80);
// Update the register values to match // Update the register values to match
regs[0x03] = regs[0x03] | 0x80; regs[0x03] = regs[0x03] | 0x80;
regs[0x11] = regs[0x11] & ~0x80; regs[0x11] = regs[0x11] & ~0x80;
// Write CRTC registers (25 registers) // Write CRTC registers (25 registers)
for (i = 0; i < 25; i++) { for (i = 0; i < 25; i++) {
outb(VGA_CRTC_INDEX, i); outb(VGA_CRTC_INDEX, i);
outb(VGA_CRTC_DATA, *regs); outb(VGA_CRTC_DATA, *regs);
regs++; regs++;
} }
// Write graphics controller registers (9 registers) // Write graphics controller registers (9 registers)
for (i = 0; i < 9; i++) { for (i = 0; i < 9; i++) {
outb(VGA_GC_INDEX, i); outb(VGA_GC_INDEX, i);
outb(VGA_GC_DATA, *regs); outb(VGA_GC_DATA, *regs);
regs++; regs++;
} }
// Write attribute controller registers (21 registers) // Write attribute controller registers (21 registers)
for (i = 0; i < 21; i++) { for (i = 0; i < 21; i++) {
inb(VGA_INSTAT_READ); // Reset flip-flop inb(VGA_INSTAT_READ); // Reset flip-flop
outb(VGA_AC_INDEX, i); outb(VGA_AC_INDEX, i);
outb(VGA_AC_WRITE, *regs); outb(VGA_AC_WRITE, *regs);
regs++; regs++;
} }
// Enable video display // Enable video display
inb(VGA_INSTAT_READ); inb(VGA_INSTAT_READ);
outb(VGA_AC_INDEX, 0x20); outb(VGA_AC_INDEX, 0x20);
} }
void void
@ -75,22 +75,22 @@ vga_set_mode_13h(void)
// Register values for VGA mode 13h (320x200, 256 colors) // Register values for VGA mode 13h (320x200, 256 colors)
// Order: Misc, Seq[5], CRTC[25], GC[9], AC[21] // Order: Misc, Seq[5], CRTC[25], GC[9], AC[21]
static uint8_t mode_320x200x256[] = { static uint8_t mode_320x200x256[] = {
// Misc output register // Misc output register
0x63, 0x63,
// Sequencer registers // Sequencer registers
0x03, 0x01, 0x0F, 0x00, 0x0E, 0x03, 0x01, 0x0F, 0x00, 0x0E,
// CRTC registers // CRTC registers
0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F, 0x5F, 0x4F, 0x50, 0x82, 0x54, 0x80, 0xBF, 0x1F,
0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3, 0x9C, 0x0E, 0x8F, 0x28, 0x40, 0x96, 0xB9, 0xA3,
0xFF, 0xFF,
// Graphics controller registers // Graphics controller registers
0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
0xFF, 0xFF,
// Attribute controller registers // Attribute controller registers
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x41, 0x00, 0x0F, 0x00, 0x00 0x41, 0x00, 0x0F, 0x00, 0x00
}; };
write_regs(mode_320x200x256); write_regs(mode_320x200x256);
@ -113,6 +113,6 @@ vga_clear_screen(uint8_t color)
uint8_t *vga = (uint8_t *)VGA_GRAPHICS_BUFFER; uint8_t *vga = (uint8_t *)VGA_GRAPHICS_BUFFER;
// fill entire buffer (64k pixels) // fill entire buffer (64k pixels)
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) { 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 <stddef.h>
#include <bootloader.h> #include <bootloader.h>
#include <drivers/video/framebuffer.h> #include <drivers/video/framebuffer.h>
#include <mm/paging.h>
static void static void
hcf(void) hcf(void)
@ -20,6 +21,7 @@ kernel_main(void)
/* Initialize framebuffer console */ /* Initialize framebuffer console */
fb_init(); fb_init();
map_vga_memory();
/* Test print */ /* Test print */
fb_puts("Hello World\n"); fb_puts("Hello World\n");

View file

@ -1,4 +1,4 @@
#include <string.h> #include <klibc/string.h>
size_t size_t
strlen(const char* str) 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);
}