# Framebuffer Console: `tty.rs` ## Назначение Драйвер графического вывода текста на framebuffer. Использует PSF2 (PC Screen Font 2) шрифты для отрисовки символов. Является основным визуальным каналом вывода ядра (через info! макрос). ## Структура Console ```rust pub struct Console<'a> { framebuffer: &'a Framebuffer<'a>, // ссылка на Limine framebuffer font: &'static [u8], // PSF2 шрифт pub x: usize, // текущая позиция X (колонка) pub y: usize, // текущая позиция Y (строка) pub fg_color: u32, // цвет текста (RGB) pub bg_color: u32, // цвет фона (RGB) } ``` ## PSF2 Header ```rust #[repr(C, packed)] struct Psf2Header { magic: u32, // 0x864AB572 (PSF2 magic) version: u32, header_size: u32, // размер заголовка flags: u32, num_glyphs: u32, // количество глифов bytes_per_glyph: u32, // байт на глиф height: u32, // высота глифа в пикселях width: u32, // ширина глифа в пикселях } ``` Шрифт — `font.psf` (8×16, встроен через `include_bytes!`). ## Операции ### clear() Заполняет весь framebuffer нулями. Сбрасывает позицию курсора в (0, 0). ```rust pub fn clear(&mut self) { unsafe { core::ptr::write_bytes(fb.addr(), 0, (fb.pitch() * fb.height()) as usize); } self.x = 0; self.y = 0; } ``` ### scroll() Сдвигает содержимое framebuffer вверх на высоту шрифта. Новые строки заполняются нулями. ```rust fn scroll(&mut self) { let shift = font_height * pitch; // смещение на 1 строку let size = pitch * (height - font_height); // сколько копировать unsafe { ptr::copy(addr.add(shift), addr, size); ptr::write_bytes(addr.add(size), 0, shift); } self.y -= font_height; } ``` ### draw_glyph(glyph_index, x, y) Рисует глиф (символ) в заданной позиции. ```rust fn draw_glyph(&mut self, glyph_index: u32, x: usize, y: usize) { let bytes_per_line = (width + 7) / 8; // пиксели → байты let glyph_offset = header_size + (glyph_index * bytes_per_glyph); for cy in 0..height { let glyph_row = self.font[glyph_offset + cy * bytes_per_line]; for cx in 0..width { if (glyph_row & (0x80 >> cx)) != 0 { // Пиксель включён — рисуем fg_color let offset = ((y + cy) * fb_pitch) + ((x + cx) * 4); unsafe { fb_addr.add(offset).cast::().write_volatile(self.fg_color); } } // Если пиксель выключен — фон остаётся (нет очистки) } } } ``` - `width=8`, `bytes_per_line=1`: каждый ряд глифа = 1 байт. - `(0x80 >> cx)`: проверка бита слева направо (MSB first). - `write_volatile`: запрещает компилятору оптимизировать запись в MMIO. ### write_char(c) Печатает символ: - `\n` → переход на новую строку. - Другие символы → draw_glyph. Если символ > num_glyphs → глиф 0. - Перенос строки по ширине экрана. - Скроллинг при достижении низа. ## fmt::Write реализация ```rust impl fmt::Write for Console<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { for c in s.chars() { self.write_char(c); } Ok(()) } } ``` ## Использование в kmain() ```rust let fb = fb_res.framebuffers().next().expect("No framebuffer"); let mut console = tty::Console::new(&fb, KERNEL_FONT); console.clear(); info!(console, "BOOT", "LIS4 Kernel Starting..."); // ... остальные логи let _ = writeln!(console, "{}", logo); // ASCII art при загрузке ``` ## Детали реализации - **Цвета**: write_volatile для 32-битного пикселя. Формат — RGBA? (зависит от режима framebuffer). - **Фон**: не перерисовывается. Только пиксели текста. Для полной очистки — clear(). - **PSF2 magic**: `0x864AB572` — проверяется в заголовке. - **Производительность**: draw_glyph простая, без буферизации. Для скроллинга — memcpy всего framebuffer. ## Зависимости - `KERNEL_FONT: &[u8]` — встроен в main.rs через `include_bytes!("font.psf")`. - `limine::framebuffer::Framebuffer` — через HHDM отображённый framebuffer.