#include #include #include #include #define VGA_PORT_CMD 0x3D4 #define VGA_PORT_DATA 0x3D5 #define VGA_CHAR(ch, attrib) ((uint16_t)(ch) | ((uint16_t)(attrib) << 8)) #define DEFAULT_ATTRIB 0x07 static uint16_t *g_console_fb = (uint16_t *)0xb8000; static const unsigned int k_console_width = 80; static const unsigned int k_console_height = 25; static unsigned int g_console_cursor_xpos = 0; static unsigned int g_console_cursor_ypos = 0; static void init_vga_cursor(void) { unsigned int start = 0, end = 15; outportb(VGA_PORT_CMD, 0x0A); outportb(VGA_PORT_DATA, (inportb(VGA_PORT_DATA) & 0xC0) | start); outportb(VGA_PORT_CMD, 0x0B); outportb(VGA_PORT_DATA, (inportb(VGA_PORT_DATA) & 0xE0) | end); } static void move_vga_cursor(unsigned int x, unsigned int y) { unsigned int offset = y * k_console_width + x; outportb(VGA_PORT_CMD, 0x0F); outportb(VGA_PORT_DATA, (uint8_t)(offset & 0xFF)); outportb(VGA_PORT_CMD, 0x0E); outportb(VGA_PORT_DATA, (uint8_t)((offset >> 8) & 0xFF)); } void ml_console_init(void) { g_console_cursor_xpos = 0; g_console_cursor_ypos = 5; init_vga_cursor(); move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos); } static void scroll_display() { uint16_t *src = g_console_fb + k_console_width; uint16_t *dst = g_console_fb; size_t n = k_console_width * (k_console_height - 1) * 2; memmove(dst, src, n); dst = g_console_fb + ((k_console_height - 1) * k_console_width); for (int i = 0; i < k_console_width; i++) { dst[i] = VGA_CHAR(0, DEFAULT_ATTRIB); } } static void handle_ctrl(int c) { switch (c) { case '\n': g_console_cursor_xpos = 0; g_console_cursor_ypos++; if (g_console_cursor_ypos >= k_console_height) { scroll_display(); g_console_cursor_ypos = k_console_height - 1; } break; default: break; } move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos); } void ml_console_putchar(int c) { if (iscntrl(c)) { handle_ctrl(c); return; } g_console_fb[(g_console_cursor_ypos * k_console_width) + g_console_cursor_xpos] = VGA_CHAR(c, DEFAULT_ATTRIB); g_console_cursor_xpos++; if (g_console_cursor_xpos >= k_console_width) { g_console_cursor_xpos = 0; g_console_cursor_ypos++; } if (g_console_cursor_ypos >= k_console_height) { scroll_display(); g_console_cursor_ypos = k_console_height - 1; g_console_cursor_xpos = 0; } move_vga_cursor(g_console_cursor_xpos, g_console_cursor_ypos); }