mirror of
https://github.com/cowmonk/cowos.git
synced 2025-12-26 11:16:50 +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/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
|
||||||
|
|
|
||||||
|
|
@ -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.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
|
console.fb = framebuffer_request.response->framebuffers[0];
|
||||||
for (uint32_t col = 0; col < FB_CHAR_WIDTH; col++) {
|
console.fg_color = 0xFFFFFF; // White
|
||||||
uint32_t px = x + col;
|
console.bg_color = 0x000000; // Black
|
||||||
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
|
|
||||||
if (console.cursor_y >= console.rows) {
|
fb_clear();
|
||||||
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++);
|
|
||||||
}
|
uint32_t *fb = (uint32_t *)console.fb->address;
|
||||||
}
|
size_t pixels = (console.fb->pitch / 4) * console.fb->height;
|
||||||
|
|
||||||
static void print_number(unsigned long num, int base, int width, char pad)
|
for (size_t i = 0; i < pixels; i++) {
|
||||||
{
|
fb[i] = console.bg_color;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
console.cursor_x = 0;
|
||||||
// Add padding if needed
|
console.cursor_y = 0;
|
||||||
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)
|
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) {
|
|
||||||
if (*fmt == '%') {
|
static void
|
||||||
fmt++;
|
draw_char(uint32_t x, uint32_t y, char c, uint32_t fg_color, uint32_t bg_color)
|
||||||
|
{
|
||||||
// Handle width and padding
|
if (!console.fb) return;
|
||||||
char pad = ' ';
|
|
||||||
int width = 0;
|
uint32_t *fb = (uint32_t *)console.fb->address;
|
||||||
|
uint32_t pitch_pixels = console.fb->pitch / 4;
|
||||||
if (*fmt == '0') {
|
|
||||||
pad = '0';
|
// Get the font data for this character
|
||||||
fmt++;
|
const uint8_t *char_data = &IBM_VGA_8x16[c * 16];
|
||||||
}
|
|
||||||
|
// Draw each row of the character
|
||||||
while (*fmt >= '0' && *fmt <= '9') {
|
for (uint32_t row = 0; row < FB_CHAR_HEIGHT; row++) {
|
||||||
width = width * 10 + (*fmt - '0');
|
uint8_t font_row = char_data[row];
|
||||||
fmt++;
|
|
||||||
}
|
// Draw each pixel in the row
|
||||||
|
for (uint32_t col = 0; col < FB_CHAR_WIDTH; col++) {
|
||||||
// Handle format specifiers
|
uint32_t px = x + col;
|
||||||
switch (*fmt) {
|
uint32_t py = y + row;
|
||||||
case 'd':
|
|
||||||
case 'i':
|
|
||||||
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;
|
|
||||||
|
// Check if this pixel should be set (bit test)
|
||||||
case 'x':
|
if (font_row & (0x80 >> col)) {
|
||||||
print_number(va_arg(args, unsigned int), 16, width, pad);
|
fb[py * pitch_pixels + px] = fg_color;
|
||||||
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 {
|
} 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);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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 <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");
|
||||||
|
|
|
||||||
|
|
@ -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
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