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.
Learning goal
Understand how UI can remain a userspace concern in a microkernel.
Category
productivity
Components touched
Builds on
Unlocked by this phase
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
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
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
Phase 08
CompleteStorage And VFS
Expose files through userspace services so programs can read named resources instead of relying on embedded data or ad hoc kernel hooks.
Phase 10
CompleteSecure Boot
Sign the kernel's EFI binary so it can boot on real hardware with UEFI Secure Boot enabled, without needing to disable the firmware security check.