151 lines
5.1 KiB
Markdown
151 lines
5.1 KiB
Markdown
# 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::<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 реализация
|
||
|
||
```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.
|