Files
Elyz/kernel/docs/tty.md
2026-07-07 16:40:41 +03:00

5.1 KiB
Raw Permalink Blame History

Framebuffer Console: tty.rs

Назначение

Драйвер графического вывода текста на framebuffer. Использует PSF2 (PC Screen Font 2) шрифты для отрисовки символов.

Является основным визуальным каналом вывода ядра (через info! макрос).

Структура Console

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

#[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).

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 вверх на высоту шрифта. Новые строки заполняются нулями.

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)

Рисует глиф (символ) в заданной позиции.

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::<u32>().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 реализация

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()

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.