feat: graphical framebuffer support for VGA driver
When GRUB is configured with multiboot2, it may provide a graphical
(RGB) framebuffer instead of legacy VGA text mode. This happens on
UTM/QEMU on macOS and other configurations where the bootloader
switches to a pixel-based display.
- Parse multiboot2 framebuffer tag in kernel_main to detect display mode
- Identity-map the framebuffer address (often at 0xFD000000+) after
paging is enabled, with write-through caching
- Add framebuffer.h describing the boot-time display info
- Embed 8x16 VGA bitmap font (font8x16.h) for pixel-mode rendering
- Rewrite VGA driver to support both text mode and pixel mode:
- Text mode: unchanged behavior writing to 0xB8000
- Pixel mode: renders characters using the bitmap font to the
GRUB-provided framebuffer, with proper VGA color palette mapping
- Auto-detects mode from fb_info at init time
- Multiboot2 header now requests text mode via framebuffer tag, but
gracefully falls back to pixel rendering if GRUB provides RGB
- Reverted grub.cfg gfxpayload=text (caused display issues on UTM)
Tested: boots in both text mode and graphical framebuffer mode.
This commit is contained in:
@@ -38,7 +38,7 @@ add_custom_command(
|
|||||||
add_custom_target(initrd DEPENDS ${INITRD_FILE})
|
add_custom_target(initrd DEPENDS ${INITRD_FILE})
|
||||||
|
|
||||||
# Create grub.cfg for ISO - includes module2 for the initrd
|
# Create grub.cfg for ISO - includes module2 for the initrd
|
||||||
file(WRITE ${CMAKE_BINARY_DIR}/isodir/boot/grub/grub.cfg "set timeout=0\nset default=0\nsearch --set=root --file /boot/kernel.bin\nmenuentry \"ClaudeOS\" {\n set gfxpayload=text\n multiboot2 /boot/kernel.bin\n module2 /boot/initrd.cpio\n}")
|
file(WRITE ${CMAKE_BINARY_DIR}/isodir/boot/grub/grub.cfg "set timeout=0\nset default=0\nsearch --set=root --file /boot/kernel.bin\nmenuentry \"ClaudeOS\" {\n multiboot2 /boot/kernel.bin\n module2 /boot/initrd.cpio\n}")
|
||||||
|
|
||||||
|
|
||||||
# ISO Generation
|
# ISO Generation
|
||||||
|
|||||||
215
src/font8x16.h
Normal file
215
src/font8x16.h
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
/**
|
||||||
|
* @file font8x16.h
|
||||||
|
* @brief Embedded 8x16 VGA bitmap font for graphical framebuffer rendering.
|
||||||
|
*
|
||||||
|
* Each character is 16 bytes: one byte per scanline, MSB is leftmost pixel.
|
||||||
|
* Covers ASCII 32 (space) through 126 (~). Characters outside this range
|
||||||
|
* render as a filled block.
|
||||||
|
*
|
||||||
|
* This is the standard VGA 8x16 font data, in the public domain.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FONT8X16_H
|
||||||
|
#define FONT8X16_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define FONT_WIDTH 8
|
||||||
|
#define FONT_HEIGHT 16
|
||||||
|
#define FONT_FIRST 32
|
||||||
|
#define FONT_LAST 126
|
||||||
|
|
||||||
|
static const uint8_t font8x16_data[][16] = {
|
||||||
|
/* 32: space */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 33: ! */
|
||||||
|
{0x00,0x00,0x18,0x3C,0x3C,0x3C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
|
||||||
|
/* 34: " */
|
||||||
|
{0x00,0x66,0x66,0x66,0x24,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 35: # */
|
||||||
|
{0x00,0x00,0x00,0x6C,0x6C,0xFE,0x6C,0x6C,0x6C,0xFE,0x6C,0x6C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 36: $ */
|
||||||
|
{0x18,0x18,0x7C,0xC6,0xC2,0xC0,0x7C,0x06,0x06,0x86,0xC6,0x7C,0x18,0x18,0x00,0x00},
|
||||||
|
/* 37: % */
|
||||||
|
{0x00,0x00,0x00,0x00,0xC2,0xC6,0x0C,0x18,0x30,0x60,0xC6,0x86,0x00,0x00,0x00,0x00},
|
||||||
|
/* 38: & */
|
||||||
|
{0x00,0x00,0x38,0x6C,0x6C,0x38,0x76,0xDC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
|
||||||
|
/* 39: ' */
|
||||||
|
{0x00,0x30,0x30,0x30,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 40: ( */
|
||||||
|
{0x00,0x00,0x0C,0x18,0x30,0x30,0x30,0x30,0x30,0x30,0x18,0x0C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 41: ) */
|
||||||
|
{0x00,0x00,0x30,0x18,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x18,0x30,0x00,0x00,0x00,0x00},
|
||||||
|
/* 42: * */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x66,0x3C,0xFF,0x3C,0x66,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 43: + */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x7E,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 44: , */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x30,0x00,0x00,0x00},
|
||||||
|
/* 45: - */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 46: . */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
|
||||||
|
/* 47: / */
|
||||||
|
{0x00,0x00,0x00,0x00,0x02,0x06,0x0C,0x18,0x30,0x60,0xC0,0x80,0x00,0x00,0x00,0x00},
|
||||||
|
/* 48: 0 */
|
||||||
|
{0x00,0x00,0x3C,0x66,0xC3,0xC3,0xDB,0xDB,0xC3,0xC3,0x66,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 49: 1 */
|
||||||
|
{0x00,0x00,0x18,0x38,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x00,0x00,0x00,0x00},
|
||||||
|
/* 50: 2 */
|
||||||
|
{0x00,0x00,0x7C,0xC6,0x06,0x0C,0x18,0x30,0x60,0xC0,0xC6,0xFE,0x00,0x00,0x00,0x00},
|
||||||
|
/* 51: 3 */
|
||||||
|
{0x00,0x00,0x7C,0xC6,0x06,0x06,0x3C,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 52: 4 */
|
||||||
|
{0x00,0x00,0x0C,0x1C,0x3C,0x6C,0xCC,0xFE,0x0C,0x0C,0x0C,0x1E,0x00,0x00,0x00,0x00},
|
||||||
|
/* 53: 5 */
|
||||||
|
{0x00,0x00,0xFE,0xC0,0xC0,0xC0,0xFC,0x06,0x06,0x06,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 54: 6 */
|
||||||
|
{0x00,0x00,0x38,0x60,0xC0,0xC0,0xFC,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 55: 7 */
|
||||||
|
{0x00,0x00,0xFE,0xC6,0x06,0x06,0x0C,0x18,0x30,0x30,0x30,0x30,0x00,0x00,0x00,0x00},
|
||||||
|
/* 56: 8 */
|
||||||
|
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7C,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 57: 9 */
|
||||||
|
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0x7E,0x06,0x06,0x06,0x0C,0x78,0x00,0x00,0x00,0x00},
|
||||||
|
/* 58: : */
|
||||||
|
{0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 59: ; */
|
||||||
|
{0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x18,0x18,0x30,0x00,0x00,0x00,0x00},
|
||||||
|
/* 60: < */
|
||||||
|
{0x00,0x00,0x00,0x06,0x0C,0x18,0x30,0x60,0x30,0x18,0x0C,0x06,0x00,0x00,0x00,0x00},
|
||||||
|
/* 61: = */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x7E,0x00,0x00,0x7E,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 62: > */
|
||||||
|
{0x00,0x00,0x00,0x60,0x30,0x18,0x0C,0x06,0x0C,0x18,0x30,0x60,0x00,0x00,0x00,0x00},
|
||||||
|
/* 63: ? */
|
||||||
|
{0x00,0x00,0x7C,0xC6,0xC6,0x0C,0x18,0x18,0x18,0x00,0x18,0x18,0x00,0x00,0x00,0x00},
|
||||||
|
/* 64: @ */
|
||||||
|
{0x00,0x00,0x00,0x7C,0xC6,0xC6,0xDE,0xDE,0xDE,0xDC,0xC0,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 65: A */
|
||||||
|
{0x00,0x00,0x10,0x38,0x6C,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 66: B */
|
||||||
|
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x66,0x66,0x66,0x66,0xFC,0x00,0x00,0x00,0x00},
|
||||||
|
/* 67: C */
|
||||||
|
{0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xC0,0xC0,0xC2,0x66,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 68: D */
|
||||||
|
{0x00,0x00,0xF8,0x6C,0x66,0x66,0x66,0x66,0x66,0x66,0x6C,0xF8,0x00,0x00,0x00,0x00},
|
||||||
|
/* 69: E */
|
||||||
|
{0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
|
||||||
|
/* 70: F */
|
||||||
|
{0x00,0x00,0xFE,0x66,0x62,0x68,0x78,0x68,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
|
||||||
|
/* 71: G */
|
||||||
|
{0x00,0x00,0x3C,0x66,0xC2,0xC0,0xC0,0xDE,0xC6,0xC6,0x66,0x3A,0x00,0x00,0x00,0x00},
|
||||||
|
/* 72: H */
|
||||||
|
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xFE,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 73: I */
|
||||||
|
{0x00,0x00,0x3C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 74: J */
|
||||||
|
{0x00,0x00,0x1E,0x0C,0x0C,0x0C,0x0C,0x0C,0xCC,0xCC,0xCC,0x78,0x00,0x00,0x00,0x00},
|
||||||
|
/* 75: K */
|
||||||
|
{0x00,0x00,0xE6,0x66,0x66,0x6C,0x78,0x78,0x6C,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 76: L */
|
||||||
|
{0x00,0x00,0xF0,0x60,0x60,0x60,0x60,0x60,0x60,0x62,0x66,0xFE,0x00,0x00,0x00,0x00},
|
||||||
|
/* 77: M */
|
||||||
|
{0x00,0x00,0xC6,0xEE,0xFE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 78: N */
|
||||||
|
{0x00,0x00,0xC6,0xE6,0xF6,0xFE,0xDE,0xCE,0xC6,0xC6,0xC6,0xC6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 79: O */
|
||||||
|
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 80: P */
|
||||||
|
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x60,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
|
||||||
|
/* 81: Q */
|
||||||
|
{0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xD6,0xDE,0x7C,0x0C,0x0E,0x00,0x00},
|
||||||
|
/* 82: R */
|
||||||
|
{0x00,0x00,0xFC,0x66,0x66,0x66,0x7C,0x6C,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 83: S */
|
||||||
|
{0x00,0x00,0x7C,0xC6,0xC6,0x60,0x38,0x0C,0x06,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 84: T */
|
||||||
|
{0x00,0x00,0xFF,0xDB,0x99,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 85: U */
|
||||||
|
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 86: V */
|
||||||
|
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0xC6,0x6C,0x38,0x10,0x00,0x00,0x00,0x00},
|
||||||
|
/* 87: W */
|
||||||
|
{0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xD6,0xD6,0xD6,0xFE,0xEE,0x6C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 88: X */
|
||||||
|
{0x00,0x00,0xC6,0xC6,0x6C,0x7C,0x38,0x38,0x7C,0x6C,0xC6,0xC6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 89: Y */
|
||||||
|
{0x00,0x00,0xC3,0xC3,0x66,0x3C,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 90: Z */
|
||||||
|
{0x00,0x00,0xFE,0xC6,0x86,0x0C,0x18,0x30,0x60,0xC2,0xC6,0xFE,0x00,0x00,0x00,0x00},
|
||||||
|
/* 91: [ */
|
||||||
|
{0x00,0x00,0x3C,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 92: \ */
|
||||||
|
{0x00,0x00,0x00,0x80,0xC0,0xE0,0x70,0x38,0x1C,0x0E,0x06,0x02,0x00,0x00,0x00,0x00},
|
||||||
|
/* 93: ] */
|
||||||
|
{0x00,0x00,0x3C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 94: ^ */
|
||||||
|
{0x10,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 95: _ */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00},
|
||||||
|
/* 96: ` */
|
||||||
|
{0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
/* 97: a */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x78,0x0C,0x7C,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
|
||||||
|
/* 98: b */
|
||||||
|
{0x00,0x00,0xE0,0x60,0x60,0x78,0x6C,0x66,0x66,0x66,0x66,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 99: c */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC0,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 100: d */
|
||||||
|
{0x00,0x00,0x1C,0x0C,0x0C,0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
|
||||||
|
/* 101: e */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xFE,0xC0,0xC0,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 102: f */
|
||||||
|
{0x00,0x00,0x1C,0x36,0x32,0x30,0x78,0x30,0x30,0x30,0x30,0x78,0x00,0x00,0x00,0x00},
|
||||||
|
/* 103: g */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0xCC,0x78,0x00,0x00},
|
||||||
|
/* 104: h */
|
||||||
|
{0x00,0x00,0xE0,0x60,0x60,0x6C,0x76,0x66,0x66,0x66,0x66,0xE6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 105: i */
|
||||||
|
{0x00,0x00,0x18,0x18,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 106: j */
|
||||||
|
{0x00,0x00,0x06,0x06,0x00,0x0E,0x06,0x06,0x06,0x06,0x06,0x06,0x66,0x3C,0x00,0x00},
|
||||||
|
/* 107: k */
|
||||||
|
{0x00,0x00,0xE0,0x60,0x60,0x66,0x6C,0x78,0x78,0x6C,0x66,0xE6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 108: l */
|
||||||
|
{0x00,0x00,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x3C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 109: m */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xE6,0xFF,0xDB,0xDB,0xDB,0xDB,0xDB,0x00,0x00,0x00,0x00},
|
||||||
|
/* 110: n */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x66,0x66,0x00,0x00,0x00,0x00},
|
||||||
|
/* 111: o */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0xC6,0xC6,0xC6,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 112: p */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xDC,0x66,0x66,0x66,0x66,0x7C,0x60,0x60,0xF0,0x00,0x00},
|
||||||
|
/* 113: q */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x76,0xCC,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C,0x1E,0x00,0x00},
|
||||||
|
/* 114: r */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xDC,0x76,0x66,0x60,0x60,0x60,0xF0,0x00,0x00,0x00,0x00},
|
||||||
|
/* 115: s */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0x7C,0xC6,0x60,0x38,0x0C,0xC6,0x7C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 116: t */
|
||||||
|
{0x00,0x00,0x10,0x30,0x30,0xFC,0x30,0x30,0x30,0x30,0x36,0x1C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 117: u */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x76,0x00,0x00,0x00,0x00},
|
||||||
|
/* 118: v */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xC3,0xC3,0xC3,0xC3,0x66,0x3C,0x18,0x00,0x00,0x00,0x00},
|
||||||
|
/* 119: w */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xD6,0xD6,0xFE,0x6C,0x00,0x00,0x00,0x00},
|
||||||
|
/* 120: x */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xC6,0x6C,0x38,0x38,0x38,0x6C,0xC6,0x00,0x00,0x00,0x00},
|
||||||
|
/* 121: y */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xC6,0xC6,0xC6,0xC6,0xC6,0x7E,0x06,0x0C,0xF8,0x00,0x00},
|
||||||
|
/* 122: z */
|
||||||
|
{0x00,0x00,0x00,0x00,0x00,0xFE,0xCC,0x18,0x30,0x60,0xC6,0xFE,0x00,0x00,0x00,0x00},
|
||||||
|
/* 123: { */
|
||||||
|
{0x00,0x00,0x0E,0x18,0x18,0x18,0x70,0x18,0x18,0x18,0x18,0x0E,0x00,0x00,0x00,0x00},
|
||||||
|
/* 124: | */
|
||||||
|
{0x00,0x00,0x18,0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00},
|
||||||
|
/* 125: } */
|
||||||
|
{0x00,0x00,0x70,0x18,0x18,0x18,0x0E,0x18,0x18,0x18,0x18,0x70,0x00,0x00,0x00,0x00},
|
||||||
|
/* 126: ~ */
|
||||||
|
{0x00,0x00,0x76,0xDC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* FONT8X16_H */
|
||||||
44
src/framebuffer.h
Normal file
44
src/framebuffer.h
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* @file framebuffer.h
|
||||||
|
* @brief Framebuffer information from the bootloader.
|
||||||
|
*
|
||||||
|
* Stores the display mode and framebuffer address provided by GRUB
|
||||||
|
* via the multiboot2 framebuffer tag. The VGA driver uses this to
|
||||||
|
* decide between text-mode writes (0xB8000) and pixel rendering.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef FRAMEBUFFER_H
|
||||||
|
#define FRAMEBUFFER_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
/** Framebuffer types (matches multiboot2 definitions). */
|
||||||
|
#define FB_TYPE_INDEXED 0
|
||||||
|
#define FB_TYPE_RGB 1
|
||||||
|
#define FB_TYPE_EGA_TEXT 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Framebuffer information structure.
|
||||||
|
* Populated during boot from the multiboot2 framebuffer tag.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
uint32_t addr; /**< Physical address of the framebuffer. */
|
||||||
|
uint32_t pitch; /**< Bytes per scanline. */
|
||||||
|
uint32_t width; /**< Width in pixels (or columns for text). */
|
||||||
|
uint32_t height; /**< Height in pixels (or rows for text). */
|
||||||
|
uint8_t bpp; /**< Bits per pixel. */
|
||||||
|
uint8_t type; /**< FB_TYPE_RGB, FB_TYPE_EGA_TEXT, etc. */
|
||||||
|
|
||||||
|
/* RGB field positions (only valid when type == FB_TYPE_RGB). */
|
||||||
|
uint8_t red_pos;
|
||||||
|
uint8_t red_size;
|
||||||
|
uint8_t green_pos;
|
||||||
|
uint8_t green_size;
|
||||||
|
uint8_t blue_pos;
|
||||||
|
uint8_t blue_size;
|
||||||
|
} framebuffer_info_t;
|
||||||
|
|
||||||
|
/** Global framebuffer info, filled by kernel_main. */
|
||||||
|
extern framebuffer_info_t fb_info;
|
||||||
|
|
||||||
|
#endif /* FRAMEBUFFER_H */
|
||||||
54
src/kernel.c
54
src/kernel.c
@@ -1,6 +1,7 @@
|
|||||||
#include <multiboot2.h>
|
#include <multiboot2.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
#include "gdt.h"
|
#include "gdt.h"
|
||||||
#include "idt.h"
|
#include "idt.h"
|
||||||
#include "pic.h"
|
#include "pic.h"
|
||||||
@@ -17,6 +18,10 @@
|
|||||||
#include "vfs.h"
|
#include "vfs.h"
|
||||||
#include "initrd_fs.h"
|
#include "initrd_fs.h"
|
||||||
#include "keyboard.h"
|
#include "keyboard.h"
|
||||||
|
#include "framebuffer.h"
|
||||||
|
|
||||||
|
/* Global framebuffer info, parsed from multiboot2 tags. */
|
||||||
|
framebuffer_info_t fb_info;
|
||||||
|
|
||||||
void offset_print(const char *str)
|
void offset_print(const char *str)
|
||||||
{
|
{
|
||||||
@@ -60,8 +65,9 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
|||||||
init_pmm(addr);
|
init_pmm(addr);
|
||||||
offset_print("PMM initialized\n");
|
offset_print("PMM initialized\n");
|
||||||
|
|
||||||
/* Scan Multiboot2 tags for the initrd module */
|
/* Scan Multiboot2 tags for the initrd module and framebuffer info */
|
||||||
uint32_t initrd_start = 0, initrd_end = 0;
|
uint32_t initrd_start = 0, initrd_end = 0;
|
||||||
|
memset(&fb_info, 0, sizeof(fb_info));
|
||||||
{
|
{
|
||||||
struct multiboot_tag *tag;
|
struct multiboot_tag *tag;
|
||||||
for (tag = (struct multiboot_tag *)(addr + 8);
|
for (tag = (struct multiboot_tag *)(addr + 8);
|
||||||
@@ -75,7 +81,36 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
|||||||
print_hex(initrd_start);
|
print_hex(initrd_start);
|
||||||
offset_print(" to ");
|
offset_print(" to ");
|
||||||
print_hex(initrd_end);
|
print_hex(initrd_end);
|
||||||
break; /* Use first module */
|
}
|
||||||
|
if (tag->type == MULTIBOOT_TAG_TYPE_FRAMEBUFFER) {
|
||||||
|
struct multiboot_tag_framebuffer *fbt =
|
||||||
|
(struct multiboot_tag_framebuffer *)tag;
|
||||||
|
fb_info.addr = (uint32_t)fbt->common.framebuffer_addr;
|
||||||
|
fb_info.pitch = fbt->common.framebuffer_pitch;
|
||||||
|
fb_info.width = fbt->common.framebuffer_width;
|
||||||
|
fb_info.height = fbt->common.framebuffer_height;
|
||||||
|
fb_info.bpp = fbt->common.framebuffer_bpp;
|
||||||
|
fb_info.type = fbt->common.framebuffer_type;
|
||||||
|
|
||||||
|
if (fb_info.type == FB_TYPE_RGB) {
|
||||||
|
fb_info.red_pos = fbt->framebuffer_red_field_position;
|
||||||
|
fb_info.red_size = fbt->framebuffer_red_mask_size;
|
||||||
|
fb_info.green_pos = fbt->framebuffer_green_field_position;
|
||||||
|
fb_info.green_size = fbt->framebuffer_green_mask_size;
|
||||||
|
fb_info.blue_pos = fbt->framebuffer_blue_field_position;
|
||||||
|
fb_info.blue_size = fbt->framebuffer_blue_mask_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset_print("Framebuffer: type=");
|
||||||
|
print_hex(fb_info.type);
|
||||||
|
offset_print(" addr=");
|
||||||
|
print_hex(fb_info.addr);
|
||||||
|
offset_print(" ");
|
||||||
|
print_hex(fb_info.width);
|
||||||
|
offset_print(" x ");
|
||||||
|
print_hex(fb_info.height);
|
||||||
|
offset_print(" bpp=");
|
||||||
|
print_hex(fb_info.bpp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,6 +118,21 @@ void kernel_main(uint32_t magic, uint32_t addr) {
|
|||||||
init_paging();
|
init_paging();
|
||||||
offset_print("Paging initialized\n");
|
offset_print("Paging initialized\n");
|
||||||
|
|
||||||
|
/* If GRUB provided a graphical framebuffer, identity-map it so
|
||||||
|
* the VGA driver can write pixels to it after paging is enabled. */
|
||||||
|
if (fb_info.addr != 0 && fb_info.type == FB_TYPE_RGB) {
|
||||||
|
uint32_t fb_size = fb_info.pitch * fb_info.height;
|
||||||
|
uint32_t fb_base = fb_info.addr & ~0xFFFu; /* page-align down */
|
||||||
|
uint32_t fb_end = (fb_info.addr + fb_size + 0xFFF) & ~0xFFFu;
|
||||||
|
offset_print(" Mapping framebuffer ");
|
||||||
|
print_hex(fb_base);
|
||||||
|
offset_print(" to ");
|
||||||
|
print_hex(fb_end);
|
||||||
|
for (uint32_t pa = fb_base; pa < fb_end; pa += 4096) {
|
||||||
|
paging_map_page(pa, pa, PAGE_PRESENT | PAGE_WRITE | PAGE_WRITETHROUGH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Test paging: allocate a page and write to it */
|
/* Test paging: allocate a page and write to it */
|
||||||
void *test_page = paging_alloc_page();
|
void *test_page = paging_alloc_page();
|
||||||
if (test_page) {
|
if (test_page) {
|
||||||
|
|||||||
396
src/vga.c
396
src/vga.c
@@ -1,10 +1,14 @@
|
|||||||
/**
|
/**
|
||||||
* @file vga.c
|
* @file vga.c
|
||||||
* @brief VGA text-mode driver implementation.
|
* @brief Display driver supporting both VGA text mode and graphical framebuffer.
|
||||||
*
|
*
|
||||||
* Drives the standard VGA text-mode framebuffer at 0xB8000. The buffer
|
* Supports two modes depending on what GRUB provides:
|
||||||
* is an array of 80×25 16-bit values, where the low byte is the ASCII
|
* - EGA text mode: writes character+attribute pairs to the text buffer
|
||||||
* character and the high byte encodes foreground and background color.
|
* - Graphical (RGB) framebuffer: renders an embedded 8x16 bitmap font
|
||||||
|
* to the pixel framebuffer provided by GRUB
|
||||||
|
*
|
||||||
|
* The mode is detected at init time from the global fb_info structure,
|
||||||
|
* which kernel_main populates from the multiboot2 framebuffer tag.
|
||||||
*
|
*
|
||||||
* This driver registers itself via the REGISTER_DRIVER macro and is
|
* This driver registers itself via the REGISTER_DRIVER macro and is
|
||||||
* automatically discovered during boot.
|
* automatically discovered during boot.
|
||||||
@@ -14,122 +18,295 @@
|
|||||||
#include "driver.h"
|
#include "driver.h"
|
||||||
#include "port_io.h"
|
#include "port_io.h"
|
||||||
#include "pmm.h"
|
#include "pmm.h"
|
||||||
|
#include "framebuffer.h"
|
||||||
|
#include "font8x16.h"
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/** Base address of the VGA text-mode framebuffer. */
|
/* Debug helpers defined in kernel.c */
|
||||||
#define VGA_BUFFER 0xB8000
|
extern void offset_print(const char *str);
|
||||||
|
extern void print_hex(uint32_t val);
|
||||||
|
|
||||||
/** Pointer to the VGA framebuffer, treated as an array of uint16_t. */
|
/* ================================================================
|
||||||
static uint16_t *vga_buffer = (uint16_t *)VGA_BUFFER;
|
* Common state
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
/** Current cursor row (0-based). */
|
/** Current text cursor position. */
|
||||||
static uint8_t cursor_row = 0;
|
static uint32_t cursor_row = 0;
|
||||||
|
static uint32_t cursor_col = 0;
|
||||||
|
|
||||||
/** Current cursor column (0-based). */
|
/** Columns and rows of the text grid. */
|
||||||
static uint8_t cursor_col = 0;
|
static uint32_t text_cols = 80;
|
||||||
|
static uint32_t text_rows = 25;
|
||||||
|
|
||||||
/** Current text attribute byte (foreground | background << 4). */
|
/** Current color attribute (foreground | background << 4). */
|
||||||
static uint8_t text_attr = 0;
|
static uint8_t text_attr = 0x07;
|
||||||
|
|
||||||
|
/** Display mode: 0 = text, 1 = pixel. */
|
||||||
|
static int display_mode = 0;
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* Text mode (EGA) internals
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
/** VGA text-mode framebuffer default base. */
|
||||||
|
#define VGA_TEXT_BUFFER 0xB8000
|
||||||
|
static uint16_t *text_buffer = (uint16_t *)VGA_TEXT_BUFFER;
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a VGA entry (character + attribute) for the framebuffer.
|
|
||||||
*
|
|
||||||
* @param c ASCII character.
|
|
||||||
* @param attr Color attribute byte.
|
|
||||||
* @return 16-bit VGA entry.
|
|
||||||
*/
|
|
||||||
static inline uint16_t vga_entry(char c, uint8_t attr) {
|
static inline uint16_t vga_entry(char c, uint8_t attr) {
|
||||||
return (uint16_t)c | ((uint16_t)attr << 8);
|
return (uint16_t)c | ((uint16_t)attr << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void text_update_cursor(void) {
|
||||||
* Create a color attribute byte from foreground and background colors.
|
uint16_t pos = (uint16_t)(cursor_row * text_cols + cursor_col);
|
||||||
*
|
|
||||||
* @param fg Foreground color (0–15).
|
|
||||||
* @param bg Background color (0–15).
|
|
||||||
* @return Attribute byte.
|
|
||||||
*/
|
|
||||||
static inline uint8_t vga_color(vga_color_t fg, vga_color_t bg) {
|
|
||||||
return (uint8_t)fg | ((uint8_t)bg << 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Update the hardware cursor position via VGA I/O ports.
|
|
||||||
*/
|
|
||||||
static void update_cursor(void) {
|
|
||||||
uint16_t pos = cursor_row * VGA_WIDTH + cursor_col;
|
|
||||||
|
|
||||||
outb(0x3D4, 0x0F);
|
outb(0x3D4, 0x0F);
|
||||||
outb(0x3D5, (uint8_t)(pos & 0xFF));
|
outb(0x3D5, (uint8_t)(pos & 0xFF));
|
||||||
outb(0x3D4, 0x0E);
|
outb(0x3D4, 0x0E);
|
||||||
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
|
outb(0x3D5, (uint8_t)((pos >> 8) & 0xFF));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void text_scroll(void) {
|
||||||
* Scroll the screen up by one line.
|
for (uint32_t i = 0; i < (text_rows - 1) * text_cols; i++) {
|
||||||
*
|
text_buffer[i] = text_buffer[i + text_cols];
|
||||||
* The top line is discarded, all other lines move up, and the bottom
|
|
||||||
* line is filled with spaces.
|
|
||||||
*/
|
|
||||||
static void scroll(void) {
|
|
||||||
/* Move all lines up by one */
|
|
||||||
for (int i = 0; i < (VGA_HEIGHT - 1) * VGA_WIDTH; i++) {
|
|
||||||
vga_buffer[i] = vga_buffer[i + VGA_WIDTH];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clear the last line */
|
|
||||||
uint16_t blank = vga_entry(' ', text_attr);
|
uint16_t blank = vga_entry(' ', text_attr);
|
||||||
for (int i = (VGA_HEIGHT - 1) * VGA_WIDTH; i < VGA_HEIGHT * VGA_WIDTH; i++) {
|
for (uint32_t i = (text_rows - 1) * text_cols; i < text_rows * text_cols; i++) {
|
||||||
vga_buffer[i] = blank;
|
text_buffer[i] = blank;
|
||||||
|
}
|
||||||
|
cursor_row = text_rows - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
cursor_row = VGA_HEIGHT - 1;
|
static void text_clear(void) {
|
||||||
}
|
|
||||||
|
|
||||||
void vga_clear(void) {
|
|
||||||
uint16_t blank = vga_entry(' ', text_attr);
|
uint16_t blank = vga_entry(' ', text_attr);
|
||||||
for (int i = 0; i < VGA_WIDTH * VGA_HEIGHT; i++) {
|
for (uint32_t i = 0; i < text_cols * text_rows; i++) {
|
||||||
vga_buffer[i] = blank;
|
text_buffer[i] = blank;
|
||||||
}
|
}
|
||||||
cursor_row = 0;
|
cursor_row = 0;
|
||||||
cursor_col = 0;
|
cursor_col = 0;
|
||||||
update_cursor();
|
text_update_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_set_color(vga_color_t fg, vga_color_t bg) {
|
static void text_putchar(char c) {
|
||||||
text_attr = vga_color(fg, bg);
|
|
||||||
}
|
|
||||||
|
|
||||||
void vga_putchar(char c) {
|
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
cursor_col = 0;
|
cursor_col = 0;
|
||||||
cursor_row++;
|
cursor_row++;
|
||||||
} else if (c == '\r') {
|
} else if (c == '\r') {
|
||||||
cursor_col = 0;
|
cursor_col = 0;
|
||||||
} else if (c == '\t') {
|
} else if (c == '\t') {
|
||||||
cursor_col = (cursor_col + 8) & ~7;
|
cursor_col = (cursor_col + 8) & ~7u;
|
||||||
if (cursor_col >= VGA_WIDTH) {
|
if (cursor_col >= text_cols) {
|
||||||
cursor_col = 0;
|
cursor_col = 0;
|
||||||
cursor_row++;
|
cursor_row++;
|
||||||
}
|
}
|
||||||
} else if (c == '\b') {
|
} else if (c == '\b') {
|
||||||
if (cursor_col > 0) {
|
if (cursor_col > 0) {
|
||||||
cursor_col--;
|
cursor_col--;
|
||||||
vga_buffer[cursor_row * VGA_WIDTH + cursor_col] = vga_entry(' ', text_attr);
|
text_buffer[cursor_row * text_cols + cursor_col] = vga_entry(' ', text_attr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vga_buffer[cursor_row * VGA_WIDTH + cursor_col] = vga_entry(c, text_attr);
|
text_buffer[cursor_row * text_cols + cursor_col] = vga_entry(c, text_attr);
|
||||||
cursor_col++;
|
cursor_col++;
|
||||||
if (cursor_col >= VGA_WIDTH) {
|
if (cursor_col >= text_cols) {
|
||||||
cursor_col = 0;
|
cursor_col = 0;
|
||||||
cursor_row++;
|
cursor_row++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (cursor_row >= text_rows) {
|
||||||
if (cursor_row >= VGA_HEIGHT) {
|
text_scroll();
|
||||||
scroll();
|
}
|
||||||
|
text_update_cursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
update_cursor();
|
/* ================================================================
|
||||||
|
* Pixel mode (graphical framebuffer) internals
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
/** Pointer to the pixel framebuffer. */
|
||||||
|
static uint8_t *pixel_fb = (uint8_t *)0;
|
||||||
|
|
||||||
|
/** Framebuffer parameters. */
|
||||||
|
static uint32_t fb_pitch = 0;
|
||||||
|
static uint32_t fb_width = 0;
|
||||||
|
static uint32_t fb_height = 0;
|
||||||
|
static uint32_t fb_bpp = 0;
|
||||||
|
|
||||||
|
/** RGB field info. */
|
||||||
|
static uint8_t fb_red_pos = 16, fb_red_size = 8;
|
||||||
|
static uint8_t fb_green_pos = 8, fb_green_size = 8;
|
||||||
|
static uint8_t fb_blue_pos = 0, fb_blue_size = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pack an RGB color into the framebuffer's native pixel format.
|
||||||
|
*/
|
||||||
|
static inline uint32_t pack_color(uint8_t r, uint8_t g, uint8_t b) {
|
||||||
|
(void)fb_red_size; (void)fb_green_size; (void)fb_blue_size;
|
||||||
|
return ((uint32_t)r << fb_red_pos) |
|
||||||
|
((uint32_t)g << fb_green_pos) |
|
||||||
|
((uint32_t)b << fb_blue_pos);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a single pixel in the framebuffer.
|
||||||
|
*/
|
||||||
|
static inline void pixel_set(uint32_t x, uint32_t y, uint32_t color) {
|
||||||
|
if (x >= fb_width || y >= fb_height) return;
|
||||||
|
uint32_t offset = y * fb_pitch + x * (fb_bpp / 8);
|
||||||
|
uint32_t bytes = fb_bpp / 8;
|
||||||
|
|
||||||
|
if (bytes == 4) {
|
||||||
|
*(volatile uint32_t *)(pixel_fb + offset) = color;
|
||||||
|
} else if (bytes == 3) {
|
||||||
|
pixel_fb[offset] = (uint8_t)(color & 0xFF);
|
||||||
|
pixel_fb[offset + 1] = (uint8_t)((color >> 8) & 0xFF);
|
||||||
|
pixel_fb[offset + 2] = (uint8_t)((color >> 16) & 0xFF);
|
||||||
|
} else if (bytes == 2) {
|
||||||
|
*(volatile uint16_t *)(pixel_fb + offset) = (uint16_t)color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* VGA color index to 24-bit RGB mapping.
|
||||||
|
*/
|
||||||
|
static const uint32_t vga_palette[16] = {
|
||||||
|
0x000000, /* 0 black */
|
||||||
|
0x0000AA, /* 1 blue */
|
||||||
|
0x00AA00, /* 2 green */
|
||||||
|
0x00AAAA, /* 3 cyan */
|
||||||
|
0xAA0000, /* 4 red */
|
||||||
|
0xAA00AA, /* 5 magenta */
|
||||||
|
0xAA5500, /* 6 brown */
|
||||||
|
0xAAAAAA, /* 7 light grey */
|
||||||
|
0x555555, /* 8 dark grey */
|
||||||
|
0x5555FF, /* 9 light blue */
|
||||||
|
0x55FF55, /* 10 light green */
|
||||||
|
0x55FFFF, /* 11 light cyan */
|
||||||
|
0xFF5555, /* 12 light red */
|
||||||
|
0xFF55FF, /* 13 light magenta */
|
||||||
|
0xFFFF55, /* 14 yellow */
|
||||||
|
0xFFFFFF, /* 15 white */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get packed foreground/background colors from text_attr.
|
||||||
|
*/
|
||||||
|
static void attr_to_colors(uint32_t *fg_out, uint32_t *bg_out) {
|
||||||
|
uint8_t fg_idx = text_attr & 0x0F;
|
||||||
|
uint8_t bg_idx = (text_attr >> 4) & 0x0F;
|
||||||
|
uint32_t fg_rgb = vga_palette[fg_idx];
|
||||||
|
uint32_t bg_rgb = vga_palette[bg_idx];
|
||||||
|
*fg_out = pack_color((fg_rgb >> 16) & 0xFF, (fg_rgb >> 8) & 0xFF, fg_rgb & 0xFF);
|
||||||
|
*bg_out = pack_color((bg_rgb >> 16) & 0xFF, (bg_rgb >> 8) & 0xFF, bg_rgb & 0xFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render a single glyph at character grid position (col, row).
|
||||||
|
*/
|
||||||
|
static void pixel_render_char(uint32_t col, uint32_t row, char c) {
|
||||||
|
uint32_t fg, bg;
|
||||||
|
attr_to_colors(&fg, &bg);
|
||||||
|
|
||||||
|
const uint8_t *glyph;
|
||||||
|
if (c >= FONT_FIRST && c <= FONT_LAST) {
|
||||||
|
glyph = font8x16_data[c - FONT_FIRST];
|
||||||
|
} else {
|
||||||
|
glyph = 0; /* NULL = solid block for unknown chars */
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t px = col * FONT_WIDTH;
|
||||||
|
uint32_t py = row * FONT_HEIGHT;
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < FONT_HEIGHT; y++) {
|
||||||
|
uint8_t bits = glyph ? glyph[y] : 0xFF;
|
||||||
|
for (uint32_t x = 0; x < FONT_WIDTH; x++) {
|
||||||
|
uint32_t color = (bits & (0x80 >> x)) ? fg : bg;
|
||||||
|
pixel_set(px + x, py + y, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll the pixel framebuffer up by one text row (FONT_HEIGHT pixels).
|
||||||
|
*/
|
||||||
|
static void pixel_scroll(void) {
|
||||||
|
uint32_t row_bytes = FONT_HEIGHT * fb_pitch;
|
||||||
|
uint32_t total_text_bytes = text_rows * row_bytes;
|
||||||
|
|
||||||
|
/* Move all rows up by one */
|
||||||
|
memcpy(pixel_fb, pixel_fb + row_bytes, total_text_bytes - row_bytes);
|
||||||
|
|
||||||
|
/* Clear the last text row */
|
||||||
|
uint32_t dummy, bg;
|
||||||
|
attr_to_colors(&dummy, &bg);
|
||||||
|
uint32_t last_row_y = (text_rows - 1) * FONT_HEIGHT;
|
||||||
|
for (uint32_t y = last_row_y; y < last_row_y + FONT_HEIGHT; y++) {
|
||||||
|
for (uint32_t x = 0; x < text_cols * FONT_WIDTH; x++) {
|
||||||
|
pixel_set(x, y, bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor_row = text_rows - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pixel_clear(void) {
|
||||||
|
uint32_t dummy, bg;
|
||||||
|
attr_to_colors(&dummy, &bg);
|
||||||
|
for (uint32_t y = 0; y < fb_height; y++) {
|
||||||
|
for (uint32_t x = 0; x < fb_width; x++) {
|
||||||
|
pixel_set(x, y, bg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cursor_row = 0;
|
||||||
|
cursor_col = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pixel_putchar(char c) {
|
||||||
|
if (c == '\n') {
|
||||||
|
cursor_col = 0;
|
||||||
|
cursor_row++;
|
||||||
|
} else if (c == '\r') {
|
||||||
|
cursor_col = 0;
|
||||||
|
} else if (c == '\t') {
|
||||||
|
cursor_col = (cursor_col + 8) & ~7u;
|
||||||
|
if (cursor_col >= text_cols) {
|
||||||
|
cursor_col = 0;
|
||||||
|
cursor_row++;
|
||||||
|
}
|
||||||
|
} else if (c == '\b') {
|
||||||
|
if (cursor_col > 0) {
|
||||||
|
cursor_col--;
|
||||||
|
pixel_render_char(cursor_col, cursor_row, ' ');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pixel_render_char(cursor_col, cursor_row, c);
|
||||||
|
cursor_col++;
|
||||||
|
if (cursor_col >= text_cols) {
|
||||||
|
cursor_col = 0;
|
||||||
|
cursor_row++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cursor_row >= text_rows) {
|
||||||
|
pixel_scroll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ================================================================
|
||||||
|
* Public interface
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
|
void vga_clear(void) {
|
||||||
|
if (display_mode == 0)
|
||||||
|
text_clear();
|
||||||
|
else
|
||||||
|
pixel_clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_set_color(vga_color_t fg, vga_color_t bg) {
|
||||||
|
text_attr = (uint8_t)fg | ((uint8_t)bg << 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vga_putchar(char c) {
|
||||||
|
if (display_mode == 0)
|
||||||
|
text_putchar(c);
|
||||||
|
else
|
||||||
|
pixel_putchar(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_puts(const char *str) {
|
void vga_puts(const char *str) {
|
||||||
@@ -153,21 +330,19 @@ void vga_put_dec(uint32_t val) {
|
|||||||
vga_putchar('0');
|
vga_putchar('0');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
char buf[12];
|
char buf[12];
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
while (val > 0) {
|
while (val > 0) {
|
||||||
buf[pos++] = '0' + (val % 10);
|
buf[pos++] = '0' + (val % 10);
|
||||||
val /= 10;
|
val /= 10;
|
||||||
}
|
}
|
||||||
/* Print in reverse */
|
|
||||||
while (pos > 0) {
|
while (pos > 0) {
|
||||||
vga_putchar(buf[--pos]);
|
vga_putchar(buf[--pos]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_show_mem_stats(void) {
|
void vga_show_mem_stats(void) {
|
||||||
uint32_t mem_kb = pmm_get_memory_size() + 1024; /* total including lower */
|
uint32_t mem_kb = pmm_get_memory_size() + 1024;
|
||||||
|
|
||||||
vga_set_color(VGA_LIGHT_CYAN, VGA_BLACK);
|
vga_set_color(VGA_LIGHT_CYAN, VGA_BLACK);
|
||||||
vga_puts("=== ClaudeOS Memory Statistics ===\n");
|
vga_puts("=== ClaudeOS Memory Statistics ===\n");
|
||||||
@@ -199,18 +374,75 @@ void vga_show_mem_stats(void) {
|
|||||||
vga_set_color(VGA_LIGHT_GREY, VGA_BLACK);
|
vga_set_color(VGA_LIGHT_GREY, VGA_BLACK);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* --- Driver registration --- */
|
/* ================================================================
|
||||||
|
* Driver registration
|
||||||
|
* ================================================================ */
|
||||||
|
|
||||||
/**
|
|
||||||
* VGA probe: always succeeds since VGA text mode is always available
|
|
||||||
* on the target platform (i386).
|
|
||||||
*/
|
|
||||||
static driver_probe_result_t vga_probe(void) {
|
static driver_probe_result_t vga_probe(void) {
|
||||||
return DRIVER_PROBE_OK;
|
return DRIVER_PROBE_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int vga_init(void) {
|
int vga_init(void) {
|
||||||
text_attr = vga_color(VGA_LIGHT_GREY, VGA_BLACK);
|
text_attr = (uint8_t)VGA_LIGHT_GREY | ((uint8_t)VGA_BLACK << 4);
|
||||||
|
|
||||||
|
if (fb_info.type == FB_TYPE_EGA_TEXT || fb_info.addr == 0) {
|
||||||
|
/* Text mode (or no framebuffer tag — assume legacy text mode) */
|
||||||
|
display_mode = 0;
|
||||||
|
text_cols = 80;
|
||||||
|
text_rows = 25;
|
||||||
|
|
||||||
|
if (fb_info.addr != 0) {
|
||||||
|
text_buffer = (uint16_t *)(uint32_t)fb_info.addr;
|
||||||
|
text_cols = fb_info.width;
|
||||||
|
text_rows = fb_info.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset_print(" VGA: text mode ");
|
||||||
|
print_hex(text_cols);
|
||||||
|
offset_print(" VGA: x ");
|
||||||
|
print_hex(text_rows);
|
||||||
|
} else if (fb_info.type == FB_TYPE_RGB) {
|
||||||
|
/* Graphical framebuffer — render with bitmap font */
|
||||||
|
display_mode = 1;
|
||||||
|
pixel_fb = (uint8_t *)(uint32_t)fb_info.addr;
|
||||||
|
fb_pitch = fb_info.pitch;
|
||||||
|
fb_width = fb_info.width;
|
||||||
|
fb_height = fb_info.height;
|
||||||
|
fb_bpp = fb_info.bpp;
|
||||||
|
|
||||||
|
fb_red_pos = fb_info.red_pos;
|
||||||
|
fb_red_size = fb_info.red_size;
|
||||||
|
fb_green_pos = fb_info.green_pos;
|
||||||
|
fb_green_size = fb_info.green_size;
|
||||||
|
fb_blue_pos = fb_info.blue_pos;
|
||||||
|
fb_blue_size = fb_info.blue_size;
|
||||||
|
|
||||||
|
/* Calculate text grid from pixel dimensions */
|
||||||
|
text_cols = fb_width / FONT_WIDTH;
|
||||||
|
text_rows = fb_height / FONT_HEIGHT;
|
||||||
|
if (text_cols == 0) text_cols = 1;
|
||||||
|
if (text_rows == 0) text_rows = 1;
|
||||||
|
|
||||||
|
offset_print(" VGA: pixel mode ");
|
||||||
|
print_hex(fb_width);
|
||||||
|
offset_print(" VGA: x ");
|
||||||
|
print_hex(fb_height);
|
||||||
|
offset_print(" VGA: bpp=");
|
||||||
|
print_hex(fb_bpp);
|
||||||
|
offset_print(" VGA: text grid ");
|
||||||
|
print_hex(text_cols);
|
||||||
|
offset_print(" VGA: x ");
|
||||||
|
print_hex(text_rows);
|
||||||
|
offset_print(" VGA: addr=");
|
||||||
|
print_hex((uint32_t)pixel_fb);
|
||||||
|
} else {
|
||||||
|
/* Indexed or unknown — fall back to text mode */
|
||||||
|
display_mode = 0;
|
||||||
|
text_cols = 80;
|
||||||
|
text_rows = 25;
|
||||||
|
offset_print(" VGA: unknown fb type, assuming text mode\n");
|
||||||
|
}
|
||||||
|
|
||||||
vga_clear();
|
vga_clear();
|
||||||
|
|
||||||
vga_set_color(VGA_LIGHT_GREEN, VGA_BLACK);
|
vga_set_color(VGA_LIGHT_GREEN, VGA_BLACK);
|
||||||
|
|||||||
Reference in New Issue
Block a user