22// SPDX-License-Identifier: Apache-2.0 OR MIT
33// Copyright Tock Contributors 2025.
44
5- //! Minimal VGA peripheral implementation for the Tock x86_q35 chip crate .
5+ //! Minimal VGA peripheral implementation for the x86_q35 chip.
66//!
7- //! Supports classic 80×25 text mode out-of-the-box and exposes a stub for
8- //! setting planar 16-colour graphics modes (640×480 and 800×600). These
9- //! extra modes will be filled in later once the driver is integrated with a
10- //! future framebuffer capsule.
7+ //! This module exposes a **text-mode** VGA writer only. Mode selection is
8+ //! enforced at the type level via a capability trait (`TextModeCap`), and we
9+ //! provide a concrete alias `VgaText = Vga<TextMode>`.
1110//!
11+ //! Graphics modes are intentionally not present yet; adding them will mean
12+ //! introducing a new capability type (e.g., `GraphicsMode`) and a separate
13+ //! adapter, so code that expects text-only APIs cannot accidentally compile
14+ //! against graphics.
1215//!
1316//! NOTE!!!
1417//!
1518//! This file compiles and provides working text-
1619//! mode console support so the board can swap from the UART mux to a VGA
17- //! console. Graphical modes are *disabled at runtime* until a framebuffer
18- //! capsule implementation lands. The low-level register writes for 640×480 and 800×600 are
19- //! nonetheless laid out so they can be enabled by flipping a constant.
20+ //! console.
2021//!
2122//! VGA peripheral driver for the x86_q35 chip.
2223//!
2829//! `ProcessConsole` to this driver or to the legacy serial mux.
2930
3031use core:: cell:: Cell ;
32+ use core:: marker:: PhantomData ;
3133use kernel:: utilities:: StaticRef ;
3234use tock_cells:: volatile_cell:: VolatileCell ;
3335
@@ -130,14 +132,20 @@ impl ColorCode {
130132 }
131133}
132134
133- /// All VGA modes supported by the x86_q35 chip crate.
134- #[ non_exhaustive]
135- #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
136- pub enum VgaMode {
137- Text80x25 ,
138- Graphics640x480_16 ,
139- Graphics800x600_16 ,
135+ // Capability marker traits (type-level gating)
136+ mod screen_cap {
137+ // Sealed so only this module creates capabilities.
138+ pub trait Sealed { }
139+
140+ /// Capability: this instance supports the text-plane writer.
141+ pub trait TextModeCap : Sealed { }
142+
143+ /// The only mode we expose right now.
144+ pub struct TextMode ;
145+ impl Sealed for TextMode { }
146+ impl TextModeCap for TextMode { }
140147}
148+ pub use screen_cap:: { TextMode , TextModeCap } ;
141149
142150// Constants for memory-mapped text mode buffer
143151
@@ -147,8 +155,6 @@ const TEXT_BUFFER_ADDR: usize = 0xB8000;
147155// Buffer dimensions
148156pub ( crate ) const TEXT_BUFFER_WIDTH : usize = 80 ;
149157pub ( crate ) const TEXT_BUFFER_HEIGHT : usize = 25 ;
150- /// Physical address where QEMU exposes the linear-frame-buffer BAR.
151- const LFB_PHYS_BASE : u32 = 0xE0_00_0000 ;
152158
153159const VGA_CELLS : StaticRef < [ VolatileCell < u16 > ; TEXT_BUFFER_WIDTH * TEXT_BUFFER_HEIGHT ] > =
154160 unsafe { StaticRef :: new ( TEXT_BUFFER_ADDR as * const _ ) } ;
@@ -224,30 +230,9 @@ pub struct VgaDevice;
224230impl VgaDevice {
225231 /// Global, row-major, bracket-indexable view.
226232 const TEXT : TextBuf = TextBuf :: new ( ) ;
227- /// Program the requested mode on the VGA controller.
228- pub fn set_mode ( mode : VgaMode ) {
229- match mode {
230- VgaMode :: Text80x25 => Self :: program_text_mode ( ) ,
231- VgaMode :: Graphics640x480_16 => panic ! ( "VGA 640×480 mode not implemented" ) ,
232- VgaMode :: Graphics800x600_16 => panic ! ( "VGA 800×600 mode not implemented" ) ,
233- }
234- }
235233
236- /// Only needed for graphics modes (linear framebuffer @ LFB_PHYS_BASE).
237- pub fn map_for_mode ( mode : VgaMode , page_dir : & mut x86:: registers:: bits32:: paging:: PD ) {
238- use x86:: registers:: bits32:: paging:: { PAddr , PDEntry , PDFlags , PDFLAGS } ;
239-
240- if matches ! (
241- mode,
242- VgaMode :: Graphics640x480_16 | VgaMode :: Graphics800x600_16
243- ) {
244- let pde_idx = ( LFB_PHYS_BASE >> 22 ) as usize ;
245- let pa = PAddr :: from ( LFB_PHYS_BASE ) ;
246- let mut flags = PDFlags :: new ( 0 ) ;
247- flags. write ( PDFLAGS :: P :: SET + PDFLAGS :: RW :: SET + PDFLAGS :: PS :: SET ) ;
248- page_dir[ pde_idx] = PDEntry :: new ( pa, flags) ;
249- }
250- }
234+ // We only expose programming of the text controller here.
235+ // (No graphics mode type/impl exists yet by design.)
251236
252237 // --- private ---
253238
@@ -308,9 +293,8 @@ impl VgaDevice {
308293}
309294
310295// Public API - the VGA struct providing text console implementation
311-
312- /// Simple text-mode VGA console.
313- pub struct Vga {
296+ // Generic over capability M. We only implement methods for M: TextModeCap.
297+ pub struct Vga < M > {
314298 col : Cell < usize > ,
315299 row : Cell < usize > ,
316300 /// Current VGA text attribute byte for newly written characters.
@@ -321,8 +305,9 @@ pub struct Vga {
321305 // UTF-8 decode state
322306 utf8_rem : Cell < u8 > , // remaining continuation bytes
323307 utf8_acc : Cell < u32 > , // codepoint acc
308+ _mode : PhantomData < M > ,
324309}
325- impl Vga {
310+ impl < M : TextModeCap > Vga < M > {
326311 pub const fn new ( ) -> Self {
327312 Self {
328313 col : Cell :: new ( 0 ) ,
@@ -331,6 +316,7 @@ impl Vga {
331316 attr : Cell :: new ( ColorCode :: new ( Color :: LightGray , Color :: Black , false ) . as_u8 ( ) ) ,
332317 utf8_rem : Cell :: new ( 0 ) ,
333318 utf8_acc : Cell :: new ( 0 ) ,
319+ _mode : PhantomData ,
334320 }
335321 }
336322
@@ -571,14 +557,6 @@ impl Vga {
571557 self . update_hw_cursor ( ) ;
572558 }
573559}
574- const _: ( ) = {
575- // Exhaustively touch every current VgaMode variant
576- match VgaMode :: Text80x25 {
577- VgaMode :: Text80x25 => ( ) ,
578- VgaMode :: Graphics640x480_16 => ( ) ,
579- VgaMode :: Graphics800x600_16 => ( ) ,
580- }
581- } ;
582560
583561// stub for future graphic options implementation
584562pub fn framebuffer ( ) -> Option < ( * mut u8 , usize ) > {
@@ -588,11 +566,14 @@ pub fn framebuffer() -> Option<(*mut u8, usize)> {
588566/// Initialise 80×25 text mode and start with a clean screen.
589567pub ( crate ) fn new_text_console ( _page_dir_ptr : & mut x86:: registers:: bits32:: paging:: PD ) {
590568 // Program 80×25 text mode
591- VgaDevice :: set_mode ( VgaMode :: Text80x25 ) ;
569+ VgaDevice :: program_text_mode ( ) ;
592570
593571 // Wipe the BIOS banner so the kernel starts on a blank page.
594572 let blank: u16 = 0x0720 ; // white-on-black space
595573 for cell in & VgaDevice :: TEXT {
596574 cell. set ( blank) ;
597575 }
598576}
577+
578+ /// Convenience alias: concrete text-mode VGA writer
579+ pub type VgaText = Vga < TextMode > ;
0 commit comments