From b59779ca4abe021f320af4236d0f3e7d11418b2c Mon Sep 17 00:00:00 2001 From: Faynot Date: Fri, 26 Jun 2026 22:07:16 +0300 Subject: [PATCH] feat: change font and release greate tty output --- kernel/src/cpu/idt.rs | 12 +--- kernel/src/cpu/interrupts.rs | 18 ++--- kernel/src/debug.rs | 26 +++---- kernel/src/events.rs | 12 +--- kernel/src/font.psf | Bin 0 -> 9975 bytes kernel/src/main.rs | 13 ++-- kernel/src/mem/allocator.rs | 8 +-- kernel/src/mem/buddy.rs | 20 ++---- kernel/src/mem/paging.rs | 10 +-- kernel/src/mem/pm_manages.rs | 25 ++----- kernel/src/mem/pmm.rs | 4 +- kernel/src/mem/vmm.rs | 41 +---------- kernel/src/tty.rs | 133 +++++++++++++++++++++++++++++++++++ 13 files changed, 183 insertions(+), 139 deletions(-) create mode 100644 kernel/src/font.psf create mode 100644 kernel/src/tty.rs diff --git a/kernel/src/cpu/idt.rs b/kernel/src/cpu/idt.rs index ef8d12c..6cf9310 100644 --- a/kernel/src/cpu/idt.rs +++ b/kernel/src/cpu/idt.rs @@ -53,17 +53,7 @@ impl InterruptDescriptorTable { pub fn set_handler(&mut self, vector: u8, handler: u64) { // 0x8E = Interrupt Gate, Ring 0, Present - self.entries[vector as usize].set_handler(handler, 0x28, 0x8E); // 0x28 - Kernel CS в Limine (по стандарту 5-й сегмент) + self.entries[vector as usize].set_handler(handler, 0x28, 0x8E); } - pub unsafe fn load(&'static self) { - let ptr = IdtPtr { - limit: (core::mem::size_of::() - 1) as u16, - base: self as *const _ as u64, - }; - // Исправление для Rust 2024: явный unsafe блок внутри unsafe fn - unsafe { - asm!("lidt [{}]", in(reg) &ptr, options(readonly, nostack, preserves_flags)); - } - } } diff --git a/kernel/src/cpu/interrupts.rs b/kernel/src/cpu/interrupts.rs index 6bec560..a7f744d 100644 --- a/kernel/src/cpu/interrupts.rs +++ b/kernel/src/cpu/interrupts.rs @@ -1,12 +1,10 @@ use core::arch::global_asm; use core::arch::asm; -use crate::mem::vmm::KERNEL_SPACE; // Оставили только один импорт +use crate::mem::vmm::KERNEL_SPACE; use crate::mem::address::VirtAddr; -// Глобальная статическая таблица дескрипторов прерываний (IDT) pub static mut IDT: crate::cpu::idt::InterruptDescriptorTable = crate::cpu::idt::InterruptDescriptorTable::new(); -// Низкоуровневый ассемблерный трамплин (Context Save & Restore) global_asm!( ".global page_fault_stub", "page_fault_stub:", @@ -80,10 +78,8 @@ pub extern "C" fn rust_page_fault_handler(error_code: u64) { let present = (error_code & 0x1) != 0; let virt_addr = VirtAddr(fault_addr); - // 1. Сначала применяем все отложенные отзывы прав из других Actor'ов (чтобы избежать Deadlock) process_deferred_mmu_events(); - // 2. Теперь захватываем VMM для обработки текущего сбоя let mut vmm_guard = KERNEL_SPACE.lock(); if let Some(space) = vmm_guard.as_mut() { @@ -91,11 +87,11 @@ pub extern "C" fn rust_page_fault_handler(error_code: u64) { Ok(_) => return, Err(e) => { panic!( - "KERNEL PANIC: Необработанный сбой виртуальной памяти (Page Fault)!\n\ - Адрес: {:#X}\n\ - Режим: {}\n\ - Присутствие: {}\n\ - Причина VMM: {:?}", + "KERNEL PANIC: Unprocessed failure of virtual memory (Page Fault)!\n\ + Address: {:#X}\n\ + Mode: {}\n\ + Presence: {}\n\ + Cause VMM: {:?}", fault_addr, if write { "WRITE" } else { "READ" }, if present { "YES (Protection Violation)" } else { "NO (Not Present)" }, @@ -105,7 +101,7 @@ pub extern "C" fn rust_page_fault_handler(error_code: u64) { } } else { panic!( - "KERNEL PANIC: Критический Page Fault до аллокации глобального KERNEL_SPACE!\n\ + "KERNEL PANIC: Critical Page Fault before alocate global KERNEL_SPACE!\n\ Адрес сбоя: {:#X}", fault_addr ); diff --git a/kernel/src/debug.rs b/kernel/src/debug.rs index 601c4ef..6e7ab6f 100644 --- a/kernel/src/debug.rs +++ b/kernel/src/debug.rs @@ -1,8 +1,5 @@ pub mod serial; -use embedded_graphics::pixelcolor::Rgb888; -use embedded_graphics::prelude::RgbColor; - pub enum LogLevel { Info, Warn, Error, } @@ -16,11 +13,11 @@ impl LogLevel { } } - pub fn console_color(&self) -> Rgb888 { + pub fn console_color(&self) -> u32 { match self { - LogLevel::Info => Rgb888::GREEN, - LogLevel::Warn => Rgb888::YELLOW, - LogLevel::Error => Rgb888::RED, + LogLevel::Info => 0x00FF00, // GREEN + LogLevel::Warn => 0xFFFF00, // YELLOW + LogLevel::Error => 0xFF0000, // RED } } } @@ -29,24 +26,23 @@ impl LogLevel { macro_rules! log { ($console:expr, $level:expr, $module:expr, $($arg:tt)*) => {{ use core::fmt::Write; - use embedded_graphics::pixelcolor::Rgb888; // Visual screen output $console.set_color($level.console_color()); let _ = write!($console, "[ LOG ] "); - - $console.set_color(Rgb888::WHITE); + + $console.set_color(0xFFFFFF); // WHITE let _ = write!($console, "{:<6} | ", $module); let _ = writeln!($console, $($arg)*); // Serial debug output let mut sp = unsafe { $crate::debug::serial::SerialPort::init() }; let _ = writeln!( - sp, - "{}[{:>5}]\x1b[0m {:<8} | {}", - $level.serial_color_code(), - "LOG", - $module, + sp, + "{}[{:>5}]\x1b[0m {:<8} | {}", + $level.serial_color_code(), + "LOG", + $module, format_args!($($arg)*) ); }}; diff --git a/kernel/src/events.rs b/kernel/src/events.rs index 67e9bdc..afb2d3e 100644 --- a/kernel/src/events.rs +++ b/kernel/src/events.rs @@ -1,14 +1,10 @@ use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; -const QUEUE_SIZE: usize = 1024; // Должно быть степенью двойки для быстрой битовой маски +const QUEUE_SIZE: usize = 1024; const QUEUE_MASK: usize = QUEUE_SIZE - 1; -/// Lock-free MPSC (Multi-Producer, Single-Consumer) очередь. -/// Оптимизирована для передачи токенов инвалидации без блокировок. pub struct RevocationQueue { buffer: [AtomicU64; QUEUE_SIZE], - // Используем паддинг (cache line size = 64 bytes) для предотвращения False Sharing - // между head (изменяется VMM) и tail (изменяется Cap-системой). #[doc(hidden)] _pad0: [u8; 64], head: AtomicUsize, @@ -29,15 +25,12 @@ impl RevocationQueue { } } - /// Вызывается со стороны Actor'ов и подсистемы Capabilities (Multi-Producer) pub fn push(&self, token_sig: u64) -> Result<(), &'static str> { let mut tail = self.tail.load(Ordering::Relaxed); loop { let head = self.head.load(Ordering::Acquire); if tail.wrapping_sub(head) >= QUEUE_SIZE { - // Очередь переполнена. В проде здесь должен быть триггер ballooning'а - // или принудительный yield для VMM, но пока возвращаем ошибку. return Err("Revocation queue overflow"); } @@ -56,13 +49,12 @@ impl RevocationQueue { } } - /// Вызывается только из активного VMM контекста (Single-Consumer) pub fn pop(&self) -> Option { let head = self.head.load(Ordering::Relaxed); let tail = self.tail.load(Ordering::Acquire); if head == tail { - return None; // Очередь пуста + return None; } let token = self.buffer[head & QUEUE_MASK].load(Ordering::Acquire); diff --git a/kernel/src/font.psf b/kernel/src/font.psf new file mode 100644 index 0000000000000000000000000000000000000000..13a44896846cf2821bc74957cc3a25f34997a9b5 GIT binary patch literal 9975 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 F@IOy3wEqAA literal 0 HcmV?d00001 diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 93fc6e7..e9c6a5f 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -18,8 +18,12 @@ use crate::mem::pm_manages::{PMActor, PMRequest, PMResult}; pub mod cap; pub mod cpu; pub mod events; +pub mod tty; + mod mem; +static KERNEL_FONT: &[u8] = include_bytes!("font.psf"); + #[macro_use] pub mod debug; @@ -164,6 +168,7 @@ static _END_MARKER: RequestsEndMarker = RequestsEndMarker::new(); #[unsafe(no_mangle)] unsafe extern "C" fn kmain() -> ! { + assert!(BASE_REVISION.is_supported()); let fb_res = FRAMEBUFFER_REQUEST.get_response().expect("Limine: No Framebuffer"); @@ -173,7 +178,8 @@ unsafe extern "C" fn kmain() -> ! { let hhdm_offset = hhdm_res.offset(); let fb = fb_res.framebuffers().next().expect("Limine: No active framebuffer found"); - let mut console = Console::new(FramebufferDisplay { framebuffer: &fb }); + + let mut console = tty::Console::new(&fb, KERNEL_FONT); console.clear(); info!(console, "BOOT", "LISA Kernel Starting..."); @@ -224,7 +230,7 @@ unsafe extern "C" fn kmain() -> ! { unsafe { core::arch::asm!("sti", options(nomem, nostack, preserves_flags)); } - // --- Тестирование подсистемы Capability --- + // Capability test let root_cnode = cap::CNode::new(256); if let Some(frame) = mem::pmm::alloc_frame() { @@ -252,7 +258,7 @@ unsafe extern "C" fn kmain() -> ! { } } - // --- Тестирование PMActor (Lock-Free Очереди) --- + // PMActor test info!(console, "PM", "--- PMActor Buddy Test ---"); let actor_base_phys = PhysAddr(0x4000_0000); @@ -323,7 +329,6 @@ unsafe extern "C" fn kmain() -> ! { - // --- Логотип --- let logo = r#" ########### ################## diff --git a/kernel/src/mem/allocator.rs b/kernel/src/mem/allocator.rs index 1fb1d51..2b203b2 100644 --- a/kernel/src/mem/allocator.rs +++ b/kernel/src/mem/allocator.rs @@ -25,7 +25,7 @@ impl Locked { pub fn lock(&self) -> LockedGuard<'_, A> { while self.lock.compare_exchange_weak(false, true, Ordering::Acquire, Ordering::Relaxed).is_err() { - core::hint::spin_loop(); // Уступка в spinlock для снижения нагрузки на шину + core::hint::spin_loop(); } LockedGuard { lock: &self.lock, @@ -49,14 +49,12 @@ impl DerefMut for LockedGuard<'_, A> { fn deref_mut(&mut self) -> &mut Self::Target { self.data } } -/// Узел односвязного списка свободных блоков struct ListNode { next: Option<&'static mut ListNode>, } const BLOCK_SIZES: &[usize] = &[8, 16, 32, 64, 128, 256, 512, 1024, 2048]; -/// Slab аллокатор для гранулярного выделения памяти pub struct SlabAllocator { list_heads: [Option<&'static mut ListNode>; BLOCK_SIZES.len()], heap_start: usize, @@ -80,13 +78,11 @@ impl SlabAllocator { self.heap_end = start + size; } - /// Поиск индекса блока под требуемый размер fn list_index(layout: &Layout) -> Option { let required_block_size = layout.size().max(layout.align()); BLOCK_SIZES.iter().position(|&s| s >= required_block_size) } - /// Резервный Bump-аллокатор для нарезки новых Slab-блоков fn fallback_alloc(&mut self, layout: Layout) -> *mut u8 { let alloc_start = (self.next_bump + layout.align() - 1) & !(layout.align() - 1); let alloc_end = alloc_start.checked_add(layout.size()).unwrap_or(self.heap_end + 1); @@ -143,8 +139,6 @@ unsafe impl GlobalAlloc for Locked { } } None => { - // Крупные регионы освобождаются через вызовы дескрипторов VMM/PMM, - // глобальный аллокатор ядра их не трекает. } } } diff --git a/kernel/src/mem/buddy.rs b/kernel/src/mem/buddy.rs index 5e98617..88fc44a 100644 --- a/kernel/src/mem/buddy.rs +++ b/kernel/src/mem/buddy.rs @@ -37,15 +37,12 @@ extern crate alloc; use alloc::vec::Vec; -// ══════════════════════════════════════════════════════════════════════════════ // Constants & helpers -// ══════════════════════════════════════════════════════════════════════════════ - /// Maximum allocation order. /// `2^11 × 4 096 bytes = 8 MiB` per single allocation. pub const MAX_ORDER: usize = 11; -/// ⌈log₂(n)⌉ — the minimum order whose block size covers `page_count` pages. +/// ⌈log2(n)⌉ — the minimum order whose block size covers `page_count` pages. /// /// ```text /// order_for(1) = 0 (2^0 = 1) @@ -63,10 +60,7 @@ pub fn order_for(page_count: usize) -> usize { } } -// ══════════════════════════════════════════════════════════════════════════════ // BuddyAllocator -// ══════════════════════════════════════════════════════════════════════════════ - /// Buddy allocator over a contiguous, pre-committed range of physical pages. /// /// All page indices stored in free lists are **relative to the start of the @@ -89,8 +83,7 @@ pub struct BuddyAllocator { } impl BuddyAllocator { - // ─── Construction ───────────────────────────────────────────────────────── - + //Construction /// Create a new allocator over `total_pages` pages, **all initially free**. /// /// Uses a greedy largest-first decomposition to build the initial free lists @@ -127,7 +120,7 @@ impl BuddyAllocator { // Size constraint: 2^order ≤ remaining → order ≤ ⌊log₂(remaining)⌋. let size_order = (usize::BITS as usize - 1) - - remaining.leading_zeros() as usize; // ⌊log₂(remaining)⌋ + - remaining.leading_zeros() as usize; // ⌊log2(remaining)⌋ let order = MAX_ORDER.min(align_order).min(size_order); let block_size = 1usize << order; @@ -140,8 +133,7 @@ impl BuddyAllocator { this } - // ─── Allocation ─────────────────────────────────────────────────────────── - + //Allocation /// Allocate a 2^`order`-page block. /// /// Returns the **relative** page index of the block's first page, or `None` @@ -206,7 +198,7 @@ impl BuddyAllocator { self.alloc(order).map(|idx| (idx, order)) } - // ─── Deallocation ───────────────────────────────────────────────────────── + //Deallocation /// Return a 2^`order`-page block at **relative** index `block_idx` to the /// free pool, coalescing with free buddies up the order chain. @@ -269,7 +261,7 @@ impl BuddyAllocator { self.free_lists[order].push(block_idx); } - // ─── Introspection ──────────────────────────────────────────────────────── + //Introspection /// Number of pages currently available for allocation. #[inline] diff --git a/kernel/src/mem/paging.rs b/kernel/src/mem/paging.rs index fb5a30a..e9c5478 100644 --- a/kernel/src/mem/paging.rs +++ b/kernel/src/mem/paging.rs @@ -29,7 +29,7 @@ pub struct PageTable { } impl PageTable { - // ── Bulk mapping ───────────────────────────────────────────────────────── + //Bulk mapping /// Map a contiguous physical range to a contiguous virtual range. /// Allocates intermediate page-table pages from the PMM as needed. @@ -48,7 +48,7 @@ impl PageTable { } } - // ── Single-page operations ──────────────────────────────────────────────── + //Single-page operations /// Map a single 4 KiB page. /// Allocates intermediate PT pages from the PMM if they do not exist. @@ -134,7 +134,7 @@ impl PageTable { Some(PhysAddr((p1e & PTE_ADDR_MASK) | (virt.0 & 0xFFF))) } - // ── CR3 ────────────────────────────────────────────────────────────────── + // CR3 /// Load this page table into CR3 (full TLB flush, no PCID). /// @@ -151,7 +151,7 @@ impl PageTable { } } -// ── Private walk helpers ────────────────────────────────────────────────────── +//Private walk helpers impl PageTable { /// Walk (or create) the path P4 → P3 → P2 → P1, returning a mutable @@ -201,7 +201,7 @@ impl PageTable { } } -// ── PMM shim ───────────────────────────────────────────────────────────────── +//PMM shim /// Allocate a single physical frame for page-table use. /// This thin wrapper avoids a direct dependency cycle between paging ↔ pmm. diff --git a/kernel/src/mem/pm_manages.rs b/kernel/src/mem/pm_manages.rs index b64a1d7..ed74704 100644 --- a/kernel/src/mem/pm_manages.rs +++ b/kernel/src/mem/pm_manages.rs @@ -49,9 +49,7 @@ use crate::mem::pmm::PAGE_SIZE; extern crate alloc; -// ══════════════════════════════════════════════════════════════════════════════ // Message packing constants -// ══════════════════════════════════════════════════════════════════════════════ const QUEUE_SIZE: usize = 1024; // power-of-two const QUEUE_MASK: usize = QUEUE_SIZE - 1; @@ -67,10 +65,7 @@ mod packing { pub const ARG_MASK: u64 = 0x000F_FFFF; // 20 bits } -// ══════════════════════════════════════════════════════════════════════════════ // Request type -// ══════════════════════════════════════════════════════════════════════════════ - /// Asynchronous request submitted to a `PMActor` inbox. /// /// `channel_id` identifies where the response should be routed. @@ -163,9 +158,7 @@ impl PMRequest { } } -// ══════════════════════════════════════════════════════════════════════════════ // Response type -// ══════════════════════════════════════════════════════════════════════════════ /// Result returned by `PMActor::process_messages()` for each completed request. #[derive(Debug, Clone, Copy)] @@ -194,10 +187,7 @@ pub enum PMResult { Freed { pages_returned: usize }, } -// ══════════════════════════════════════════════════════════════════════════════ // Lock-free MPSC inbox -// ══════════════════════════════════════════════════════════════════════════════ - /// MPSC ring buffer for PMRequest values. /// /// Producers (any core, any context) call `send`; the owning PMActor calls @@ -268,10 +258,7 @@ impl PMActorQueue { } } -// ══════════════════════════════════════════════════════════════════════════════ // PM Actor -// ══════════════════════════════════════════════════════════════════════════════ - /// An autonomous physical-memory actor. /// /// Owns a `BuddyAllocator` over its capital range and a lock-free MPSC inbox. @@ -284,16 +271,12 @@ impl PMActorQueue { pub struct PMActor { /// Unique identity within the actor federation. pub actor_id: u64, - /// Root strong capability over the entire managed physical range. pub root_untyped: Capability, - /// `(inclusive_start, exclusive_end)` physical addresses. pub managed_range: (PhysAddr, PhysAddr), - /// Inbox — producers write here, actor reads here. queue: PMActorQueue, - /// Local buddy allocator. Only ever touched in `process_messages`. buddy: BuddyAllocator, } @@ -319,7 +302,7 @@ impl PMActor { } } - // ─── Producer API (callable from any context) ────────────────────────── + //Producer API (callable from any context) /// Submit a request to this actor's inbox. /// @@ -329,7 +312,7 @@ impl PMActor { self.queue.send(req) } - // ─── Consumer API (actor's own scheduled context) ───────────────────── + //Consumer API (actor's own scheduled context) /// Drain the inbox and execute all pending requests. /// @@ -370,7 +353,7 @@ impl PMActor { responses } - // ─── Introspection ──────────────────────────────────────────────────── + //Introspection /// Free pages remaining in this actor's buddy pool. #[inline] @@ -385,7 +368,7 @@ impl PMActor { } } -// ── Private handler implementations ────────────────────────────────────────── +//Private handler implementations impl PMActor { fn handle_allocate( diff --git a/kernel/src/mem/pmm.rs b/kernel/src/mem/pmm.rs index aacf4a7..a1a2509 100644 --- a/kernel/src/mem/pmm.rs +++ b/kernel/src/mem/pmm.rs @@ -71,7 +71,7 @@ impl BitmapPMM { *PMM.lock() = Some(pmm); } - // ── Core operations ─────────────────────────────────────────────────────── + //Core operations /// Mark a frame as free. Idempotent (double-free is a no-op, not UB). pub fn free_frame(&mut self, phys_addr: PhysAddr) { @@ -175,7 +175,7 @@ impl BitmapPMM { } } -// ── Module-level convenience functions ─────────────────────────────────────── +//Module-level convenience functions pub fn alloc_frame() -> Option { PMM.lock().as_mut()?.alloc_frame() diff --git a/kernel/src/mem/vmm.rs b/kernel/src/mem/vmm.rs index 4f07d29..df532d5 100644 --- a/kernel/src/mem/vmm.rs +++ b/kernel/src/mem/vmm.rs @@ -37,10 +37,7 @@ use crate::events::MMU_REVOCATION_QUEUE; extern crate alloc; -// ══════════════════════════════════════════════════════════════════════════════ // Error type -// ══════════════════════════════════════════════════════════════════════════════ - #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum VmError { /// PMM returned `None` — no physical frames available. @@ -80,9 +77,7 @@ impl core::fmt::Display for VmError { } } -// ══════════════════════════════════════════════════════════════════════════════ // VMA flags -// ══════════════════════════════════════════════════════════════════════════════ bitflags::bitflags! { #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -113,9 +108,7 @@ impl VmaFlags { } } -// ══════════════════════════════════════════════════════════════════════════════ // VMA backing -// ══════════════════════════════════════════════════════════════════════════════ #[derive(Debug)] pub enum VmaBacking { @@ -159,9 +152,7 @@ impl VmaBacking { } } -// ══════════════════════════════════════════════════════════════════════════════ // VMA region -// ══════════════════════════════════════════════════════════════════════════════ #[derive(Debug)] pub struct VmaRegion { @@ -180,9 +171,7 @@ impl VmaRegion { } } -// ══════════════════════════════════════════════════════════════════════════════ // ASID / PCID allocator (bitmap-based, const-initializable, O(1) amortised) -// ══════════════════════════════════════════════════════════════════════════════ /// x86-64 PCIDs: 0 (kernel, no PCID tagging) and 4095 (reserved by spec). /// Valid user ASIDs: 1 – 4094 inclusive. @@ -262,9 +251,7 @@ fn free_asid(asid: u16) { ASID_ALLOC.lock().free(asid); } -// ══════════════════════════════════════════════════════════════════════════════ // CPU feature detection (call once during boot, before first activate()) -// ══════════════════════════════════════════════════════════════════════════════ /// Set to `true` at boot if CPUID.07H:EBX[10] = 1 (INVPCID supported). static INVPCID_SUPPORTED: AtomicBool = AtomicBool::new(false); @@ -302,9 +289,7 @@ pub fn init_cpu_features() { INVPCID_SUPPORTED.store(supported, Ordering::Relaxed); } -// ══════════════════════════════════════════════════════════════════════════════ // Address space -// ══════════════════════════════════════════════════════════════════════════════ pub struct AddressSpace { /// Hardware PCID written to CR3 bits 11:0. @@ -317,8 +302,6 @@ pub struct AddressSpace { hhdm: u64, } -// ── Private helpers ─────────────────────────────────────────────────────────── - impl AddressSpace { #[inline] unsafe fn pml4_raw(&self) -> *mut PageTable { @@ -392,11 +375,7 @@ impl AddressSpace { } } -// ── Public API ──────────────────────────────────────────────────────────────── - impl AddressSpace { - // ─── Construction ────────────────────────────────────────────────────── - /// Allocate a fresh, empty address space with a zeroed PML4. pub fn new(hhdm: u64) -> Result { let pml4_phys = pmm::alloc_frame().ok_or(VmError::OutOfMemory)?; @@ -480,8 +459,6 @@ impl AddressSpace { Ok(virt) } - // ─── Zero-copy shared mapping (new) ─────────────────────────────────── - /// Map `page_count` pages of physical memory owned by `owner_cap` into /// this address space at `virt`. /// @@ -533,8 +510,6 @@ impl AddressSpace { Ok(virt) } - // ─── Demand paging ───────────────────────────────────────────────────── - /// Handle a hardware page fault at `fault_addr`. /// /// Returns `Ok(())` if the fault was a valid lazy demand-page (caller should @@ -579,8 +554,6 @@ impl AddressSpace { Ok(()) } - // ─── Unmapping ───────────────────────────────────────────────────────── - /// Unmap the VMA containing `virt`, free its frames (if owned), flush TLB. pub fn unmap_region(&mut self, virt: VirtAddr) -> Result<(), VmError> { let idx = self.find_idx(virt).ok_or(VmError::RegionNotFound)?; @@ -591,8 +564,6 @@ impl AddressSpace { Ok(()) } - // ─── Capability revocation ───────────────────────────────────────────── - /// Atomically unmap all VMAs associated with `cap_token` (skip PINNED). /// /// Hardware access is terminated before this function returns. @@ -618,14 +589,14 @@ impl AddressSpace { tlb_flush_asid(self.asid); } - // ─── Address translation ─────────────────────────────────────────────── + //Address translation /// Walk the live page table to translate `virt` → physical address. pub fn translate(&self, virt: VirtAddr) -> Option { unsafe { (*self.pml4_raw()).translate(virt, self.hhdm) } } - // ─── Activation ──────────────────────────────────────────────────────── + //Activation /// Load this address space into the CPU (context switch). /// @@ -646,8 +617,6 @@ impl AddressSpace { } } - // ─── Introspection ───────────────────────────────────────────────────── - #[inline] pub fn regions(&self) -> &[VmaRegion] { &self.regions } #[inline] pub fn region_count(&self) -> usize { self.regions.len() } @@ -670,10 +639,7 @@ impl Drop for AddressSpace { } } -// ══════════════════════════════════════════════════════════════════════════════ // TLB management -// ══════════════════════════════════════════════════════════════════════════════ - /// Flush all TLB entries tagged with `asid` (PCID) on the current core. /// /// Uses `INVPCID` type-1 (single-context flush) when available (Broadwell+, @@ -714,10 +680,7 @@ pub fn tlb_flush_all() { } } -// ══════════════════════════════════════════════════════════════════════════════ // Global kernel address space -// ══════════════════════════════════════════════════════════════════════════════ - /// The one kernel address space. Initialised once during boot. pub static KERNEL_SPACE: Locked> = Locked::new(None); diff --git a/kernel/src/tty.rs b/kernel/src/tty.rs new file mode 100644 index 0000000..91881d9 --- /dev/null +++ b/kernel/src/tty.rs @@ -0,0 +1,133 @@ +use core::fmt; +use limine::framebuffer::Framebuffer; + +#[derive(Debug)] +#[repr(C, packed)] +struct Psf2Header { + magic: u32, + version: u32, + header_size: u32, + flags: u32, + num_glyphs: u32, + bytes_per_glyph: u32, + height: u32, + width: u32, +} + +pub struct Console<'a> { + framebuffer: &'a Framebuffer<'a>, + font: &'static [u8], + pub x: usize, + pub y: usize, + pub fg_color: u32, + pub bg_color: u32, +} + +impl<'a> Console<'a> { + pub fn new(framebuffer: &'a Framebuffer<'a>, font: &'static [u8]) -> Self { + Self { + framebuffer, + font, + x: 0, + y: 0, + fg_color: 0xFFFFFF, // White + bg_color: 0x000000, // Black + } + } + + pub fn set_color(&mut self, fg: u32) { + self.fg_color = fg; + } + + pub fn clear(&mut self) { + let fb = self.framebuffer; + unsafe { + core::ptr::write_bytes(fb.addr(), 0, (fb.pitch() * fb.height()) as usize); + } + self.x = 0; + self.y = 0; + } + + fn header(&self) -> &Psf2Header { + unsafe { &*(self.font.as_ptr() as *const Psf2Header) } + } + + fn scroll(&mut self) { + let header = self.header(); + let font_height = header.height as usize; + let fb = self.framebuffer; + let pitch = fb.pitch() as usize; + let height = fb.height() as usize; + + let shift = font_height * pitch; + let size = pitch * (height - font_height); + + unsafe { + let addr = fb.addr(); + core::ptr::copy(addr.add(shift), addr, size); + core::ptr::write_bytes(addr.add(size), 0, shift); + } + self.y -= font_height; + } + + fn draw_glyph(&mut self, glyph_index: u32, x: usize, y: usize) { + let header = self.header(); + let bytes_per_line = (header.width + 7) / 8; + let glyph_offset = header.header_size + (glyph_index * header.bytes_per_glyph); + + let fb = self.framebuffer; + let fb_pitch = fb.pitch() as usize; + let fb_addr = fb.addr(); + + for cy in 0..header.height { + let glyph_row = self.font[(glyph_offset + cy * bytes_per_line) as usize]; + for cx in 0..header.width { + if (glyph_row & (0x80 >> cx)) != 0 { + let offset = ((y + cy as usize) * fb_pitch) + ((x + cx as usize) * 4); + unsafe { + fb_addr.add(offset).cast::().write_volatile(self.fg_color); + } + } + } + } + } + + pub fn write_char(&mut self, c: char) { + let (font_width, font_height, num_glyphs) = { + let h = self.header(); + (h.width as usize, h.height as usize, h.num_glyphs) + }; + + if c == '\n' { + self.x = 0; + self.y += font_height; + } else { + if self.x + font_width > self.framebuffer.width() as usize { + self.x = 0; + self.y += font_height; + } + + let glyph_index = if (c as u32) < num_glyphs { + c as u32 + } else { + 0 // symbol placeholder + }; + + self.draw_glyph(glyph_index, self.x, self.y); + self.x += font_width; + } + + if self.y + font_height > self.framebuffer.height() as usize { + self.scroll(); + } + } +} + +impl fmt::Write for Console<'_> { + fn write_str(&mut self, s: &str) -> fmt::Result { + for c in s.chars() { + self.write_char(c); + } + Ok(()) + } +}