mirror of
https://github.com/cowmonk/cowos.git
synced 2025-10-27 06:23:26 +00:00
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:
parent
0d3653c970
commit
6d2e453d27
8 changed files with 477 additions and 446 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
11
kernel/include/mm/paging.h
Normal file
11
kernel/include/mm/paging.h
Normal 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 */
|
||||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
#include <string.h>
|
||||
#include <klibc/string.h>
|
||||
|
||||
size_t
|
||||
strlen(const char* str)
|
||||
|
|
|
|||
125
kernel/mm/paging.c
Normal file
125
kernel/mm/paging.c
Normal 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);
|
||||
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue