m³OS docs GitHub

Phase 09

Framebuffer And Shell

Make the OS pleasant to interact with by adding on-screen text output and a very small shell for manual exploration.

Complete

Learning goal

Understand how UI can remain a userspace concern in a microkernel.

Category

productivity

Why this phase matters

Make the OS pleasant to interact with by adding on-screen text output and a very small shell for manual exploration.

How it works in m3OS

Phase 9 adds the first interactive layer to m³OS: a pixel framebuffer text console, keyboard IPC, and a tiny shell with built-in file commands. The additions are:

How it builds on earlier phases

This phase builds on Storage And VFS and turns that foundation into Framebuffer And Shell.

Implementation outline

  • Parse framebuffer information from boot data and expose a simple drawing API.
  • Add text rendering with a fixed bitmap font.
  • Extend the console service to own the visible terminal state.
  • Build a tiny shell that speaks only to documented services.
  • Keep the command model simple and text-oriented.

Task progress snapshot

16 of 16 tracked tasks are complete.

Documentation targets

  • Documentation deliverables have not been listed yet.

Deferred follow-on work

  • Pipes and redirection
  • Job control
  • Full-screen applications
  • Advanced graphics or windowing

Source materials

Important code

Code spotlight cards

Code spotlight

Parse framebuffer information for text-mode rendering

kernel/src/fb/mod.rs L468-L488

Parse framebuffer information for text-mode rendering. Why it matters: The framebuffer info from the bootloader must be parsed before any pixels can be drawn. Focus on `init` in `kernel/src/fb/mod.rs` while you trace the snippet.

/// Initialise the framebuffer text console.
///
/// Called once from `kernel_main` before `task::run()`.  Extracts the raw
/// pointer and layout from `fb`, stores them in the global [`CONSOLE`], and
/// clears the screen.
///
/// # Safety
/// `fb` must be `&'static mut` (derived from `boot_info.framebuffer`).  The
/// caller must not access `boot_info.framebuffer` again after this call.
///
/// Returns `true` if the framebuffer was large enough to enable the text console.
pub fn init(fb: &'static mut FrameBuffer) -> bool {
    let info: FrameBufferInfo = fb.info();
    // Extract the raw mutable pointer from the &'static mut FrameBuffer.
    // SAFETY: fb is &'static mut so the pointer is valid for the kernel
    // lifetime.  We store it inside a Mutex<Option<FbConsole>> so it is
    // only ever accessed with the lock held, preventing aliased writes.
    let buf_ptr: *mut u8 = fb.buffer_mut().as_mut_ptr();
    // SAFETY: buf_ptr and info are both derived from &'static mut FrameBuffer.
    unsafe { init_from_parts(buf_ptr, info) }
}

Code spotlight

Implement line input with basic editing

userspace/shell/src/main.rs L41-L64

Implement line input with basic editing. Why it matters: Interactive use requires at minimum line-buffered input with backspace support. Focus on `read_line` in `userspace/shell/src/main.rs` while you trace the snippet.

/// Read a line from stdin, handling backspace and character echo.
/// Returns the number of valid bytes (excluding null terminator).
fn read_line(buf: &mut [u8; MAX_LINE]) -> usize {
    let mut pos = 0usize;
    loop {
        let mut byte = [0u8; 1];
        let n = read(STDIN_FILENO, &mut byte);
        if n <= 0 {
            // EOF or error — return what we have.
            if pos > 0 {
                return pos;
            }
            // Yield CPU briefly (~10ms) and retry.
            syscall_lib::nanosleep(1);
            continue;
        }

        let ch = byte[0];

        if ch == b'\n' || ch == b'\r' {
            // Echo newline (stdin_feeder sends \n but doesn't echo it).
            let _ = write(STDOUT_FILENO, b"\n");
            return pos;
        }

Key files

How real OSes differ

  • Real systems have richer terminal stacks, GPU drivers, process launch models, shells, libraries, and compatibility layers.
  • Production terminal emulators handle hundreds of escape sequences and support Unicode.
  • A learning system should stop once text I/O and a few commands make the service architecture visible and satisfying to use.

Success criteria

  • Text appears on screen in addition to serial output.
  • Keyboard input reaches the shell through userspace services.
  • The shell can run a handful of built-in commands.
  • File-oriented commands such as `ls` and `cat` exercise the VFS path.

Related phases

Keep exploring the roadmap