kernel: route routine status to the log, not the framebuffer console
Now that the user-space display service owns the framebuffer, the bootstrap console shrinks to fatal-only. status/statusPrint go to the diagnostic log alone, so routine boot output no longer scribbles on a screen the compositor is about to paint — and a driver's recoverable fault report stays off it too. A new fatal/fatalPrint keeps panics and kernel-mode faults on screen, forcing the console back on so a dying machine's last words show even over a live display. console.zig now documents its early-boot + fatal-fallback role.
This commit is contained in:
parent
88ed3c5417
commit
c3e9c59086
|
|
@ -2,12 +2,15 @@
|
|||
//! into the linear framebuffer the bootloader handed us. No firmware, no driver
|
||||
//! — just pixels.
|
||||
//!
|
||||
//! This is a **bootstrap** console — a stop-gap so early boot has something on
|
||||
//! screen. The framebuffer is a general graphics surface, *not* inherently a text
|
||||
//! terminal; once the driver machinery exists it becomes a proper graphics device
|
||||
//! driver and this text-grid crutch goes away. It is therefore kept **separate
|
||||
//! from the diagnostic [log](log.zig)** — the log fans out to serial/debugcon/file,
|
||||
//! while this only paints the handful of user-facing status lines and panics.
|
||||
//! This is a **bootstrap / fatal-fallback** console. The driver machinery now exists — the
|
||||
//! user-space **display service** ([../services/display](../services/display/display.zig),
|
||||
//! docs/display.md) owns the framebuffer in normal operation — so this no longer paints
|
||||
//! routine status. It exists for the two cases the display service can't cover: **early
|
||||
//! boot**, before the service has claimed the framebuffer, and **fatal errors** (a kernel
|
||||
//! panic or a kernel-mode fault), which force it back on (`setSuppressed`) so a dying
|
||||
//! machine's last words reach the screen even over a live display. It is kept **separate
|
||||
//! from the diagnostic [log](log.zig)** — the log fans out to serial/debugcon/file and
|
||||
//! carries all routine kernel output; this only paints those fatal cases.
|
||||
//!
|
||||
//! The module owns a single console and a `present` flag; `write` is a no-op when
|
||||
//! the firmware handed over no framebuffer (a headless machine), so the kernel
|
||||
|
|
|
|||
|
|
@ -156,12 +156,13 @@ fn kmain(boot_information: *const BootInformation) noreturn {
|
|||
log.print(" page tables: root = 0x{x:0>16}\n", .{architecture.activePageTable()});
|
||||
log.print(" kernel segs: {d} (mapped with W^X permissions)\n", .{boot_information.kernel_segment_count});
|
||||
|
||||
// Now on our own tables, the framebuffer window is write-combining: bring up
|
||||
// the on-screen console and clear it (a fast burst here, not the loader's
|
||||
// uncached crawl). From here `status` reaches the screen as well as the log.
|
||||
// Now on our own tables, the framebuffer window is write-combining: bring up the
|
||||
// on-screen console and clear it to a blank canvas (a fast burst here, not the loader's
|
||||
// uncached crawl). Routine boot output goes only to the log; this console now exists for
|
||||
// early-boot and fatal (`fatal`/panic) output, until the display service takes over.
|
||||
console.init(fb);
|
||||
log.write(if (console.present())
|
||||
"/system/kernel: framebuffer console online (bootstrap; graphics driver later)\n"
|
||||
"/system/kernel: framebuffer ready (early-boot + fatal fallback; the display service drives it in normal operation)\n"
|
||||
else
|
||||
"/system/kernel: no framebuffer (headless) -> logging to serial/debugcon only\n");
|
||||
|
||||
|
|
@ -414,11 +415,22 @@ fn bringUpSecondaries() void {
|
|||
log.print("/system/kernel: {d}/{d} cores online\n", .{ scheduler.onlineCount(), cores.len });
|
||||
}
|
||||
|
||||
/// A user-facing status line: to the diagnostic `log` *and* the on-screen console
|
||||
/// (if a framebuffer is present). The verbose log uses `log.*` directly and never
|
||||
/// touches the framebuffer.
|
||||
/// A user-facing status line. Now that the user-space **display service** owns the
|
||||
/// framebuffer in normal operation (docs/display.md), routine kernel output goes to the
|
||||
/// diagnostic `log` (serial/debugcon/RAM) *only* — never to the on-screen console, which
|
||||
/// the compositor is about to paint over. For a message that must reach the screen even so
|
||||
/// — a panic or a fatal fault, when the machine is going down — use `fatal`.
|
||||
fn status(message: []const u8) void {
|
||||
log.write(message);
|
||||
}
|
||||
|
||||
/// A fatal, user-facing message: to the diagnostic log *and* the on-screen console, forcing
|
||||
/// the console back on (`setSuppressed(false)`) first — a dying machine's last words outrank
|
||||
/// any display service holding the framebuffer. The console is otherwise silent in normal
|
||||
/// operation (see `status`); it exists now only for early-boot and fatal output.
|
||||
fn fatal(message: []const u8) void {
|
||||
log.write(message);
|
||||
console.setSuppressed(false);
|
||||
console.write(message);
|
||||
}
|
||||
|
||||
|
|
@ -427,6 +439,11 @@ fn statusPrint(comptime fmt: []const u8, args: anytype) void {
|
|||
status(std.fmt.bufPrint(&buffer, fmt, args) catch return);
|
||||
}
|
||||
|
||||
fn fatalPrint(comptime fmt: []const u8, args: anytype) void {
|
||||
var buffer: [256]u8 = undefined;
|
||||
fatal(std.fmt.bufPrint(&buffer, fmt, args) catch return);
|
||||
}
|
||||
|
||||
/// Frames (4 KiB pages) to whole MiB.
|
||||
fn mib(pages: u64) u64 {
|
||||
return pages * abi.page_size / (1024 * 1024);
|
||||
|
|
@ -486,17 +503,15 @@ fn onException(state: *const architecture.CpuState) noreturn {
|
|||
}
|
||||
|
||||
log.checkpoint(cp_exception);
|
||||
// The machine is going down: force the console back on even if a display service
|
||||
// was holding the framebuffer, so the exception actually reaches the screen.
|
||||
console.setSuppressed(false);
|
||||
const core = scheduler.currentCpuIndex();
|
||||
// A fault is user-facing enough to paint on screen too (via statusPrint), on
|
||||
// top of the diagnostic log.
|
||||
statusPrint("\nCPU EXCEPTION on core {d}: {s} (vector {d})\n", .{ core, architecture.exceptionName(state.vector), state.vector });
|
||||
statusPrint(" error code : 0x{x}\n", .{state.error_code});
|
||||
statusPrint(" IP : 0x{x:0>16}\n", .{architecture.instructionPointer(state)});
|
||||
statusPrint(" SP : 0x{x:0>16}\n", .{architecture.stackPointer(state)});
|
||||
if (architecture.faultAddress(state)) |address| statusPrint(" fault addr : 0x{x:0>16}\n", .{address});
|
||||
// The machine is going down: paint the exception on screen too — `fatalPrint` forces the
|
||||
// console back on even if a display service was holding the framebuffer — on top of the
|
||||
// diagnostic log.
|
||||
fatalPrint("\nCPU EXCEPTION on core {d}: {s} (vector {d})\n", .{ core, architecture.exceptionName(state.vector), state.vector });
|
||||
fatalPrint(" error code : 0x{x}\n", .{state.error_code});
|
||||
fatalPrint(" IP : 0x{x:0>16}\n", .{architecture.instructionPointer(state)});
|
||||
fatalPrint(" SP : 0x{x:0>16}\n", .{architecture.stackPointer(state)});
|
||||
if (architecture.faultAddress(state)) |address| fatalPrint(" fault addr : 0x{x:0>16}\n", .{address});
|
||||
|
||||
var buffer: [128]u8 = undefined;
|
||||
log.recordPanic(std.fmt.bufPrint(&buffer, "CPU exception {s} (vector {d}) on core {d} at IP 0x{x}", .{ architecture.exceptionName(state.vector), state.vector, core, architecture.instructionPointer(state) }) catch "cpu exception");
|
||||
|
|
@ -511,10 +526,9 @@ pub const panic = std.debug.FullPanic(struct {
|
|||
_ = first_trace_address;
|
||||
log.checkpoint(cp_panic);
|
||||
log.recordPanic(message);
|
||||
console.setSuppressed(false); // a panic outranks any display service holding the screen
|
||||
status("\nKERNEL PANIC: ");
|
||||
status(message);
|
||||
status("\n");
|
||||
fatal("\nKERNEL PANIC: "); // a panic outranks any display service holding the screen
|
||||
fatal(message);
|
||||
fatal("\n");
|
||||
architecture.halt();
|
||||
}
|
||||
}.panic);
|
||||
|
|
|
|||
Loading…
Reference in New Issue