Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions bootloader/src/drivers/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,27 @@ impl OutputDriver {
/// Write a line to the global output driver
/// This is the main function to use for output throughout the codebase
pub fn write_line(message: &str) -> bool {
// Keep default boot output high-signal to conserve context.
// Verbose output can be re-enabled by toggling `VERBOSE_OUTPUT`.
if !crate::VERBOSE_OUTPUT {
let trimmed = message.trim_start();
let noisy_prefixes = [
"✓ ",
"Collecting ",
"Getting ",
"Setting ",
"Allocating ",
"Copying ",
"Exiting ",
"Entering ",
"Finalizing ",
"Found ",
];
if noisy_prefixes.iter().any(|p| trimmed.starts_with(p)) {
return true;
}
}

let driver_ptr = GLOBAL_OUTPUT_DRIVER.load(Ordering::SeqCst);
if driver_ptr.is_null() {
return false;
Expand Down
61 changes: 61 additions & 0 deletions docs/logging.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Logging policy (TheseusOS)

This project relies heavily on logs during bring-up, but **default boot output must stay high-signal**.
Excessive logs waste developer time and (when using AI tools) consume precious context.

## Goals

- **Default config is quiet**: only high-signal INFO, plus WARN/ERROR.
- **Debugging is opt-in**: turn on DEBUG/TRACE intentionally, ideally scoped to a module.
- **Critical boot failures are unmissable**: emit to **serial** and **ISA debugcon (0xE9)**.

## Current knobs

### Kernel log level

- Default: `kernel/src/config.rs` → `DEFAULT_LOG_LEVEL` (should remain relatively quiet, e.g. `Info`).
- Per-module overrides: `MODULE_LOG_LEVELS` (prefer adding temporary overrides while debugging specific areas).

### Verbose output toggles

- `VERBOSE_KERNEL_OUTPUT`: enables extra debug traces.
- `PRINT_HARDWARE_INVENTORY`: UEFI inventory dump (very noisy; keep off by default).

### USB/xHCI diagnostics

- `USB_ENABLE_POLLING_FALLBACK`: keep `false` for normal runs.
- `USB_IDLE_IMAN_DIAGNOSTICS`: off by default (can spam QEMU host logs depending on tracing).
- `USB_XHCI_EVENT_RING_DIAGNOSTICS`: off by default (enables ring snapshots / extra warnings).
- `USB_RUN_MSIX_SELF_TEST`: on by default (useful, high-signal correctness check).

### QEMU debug flags (host-side)

In `startQemu.sh` headless mode:

- Default `-d` flags are intentionally minimal to avoid enormous output.
- Override with:

```bash
QEMU_DEBUG_FLAGS="int,guest_errors,cpu_reset" ./startQemu.sh headless 10
```

## Log level guidance

- **ERROR**: the system cannot proceed or will be incorrect; should be user-visible.
- **WARN**: unexpected but recoverable; should stand out.
- **INFO**: major milestones only ("kernel started", "ACPI init ok", "xHCI MSI enabled").
- **DEBUG**: detailed state dumps (descriptors, per-port state, per-device enumeration steps).
- **TRACE**: extremely chatty loops or per-register/per-TRB style logs; never default-on.

## Anti-logspam patterns

- Use **one-shot** logs ("first time we saw X")
- Use **rate limiting** for repeated warnings
- Use **module-scoped verbosity** rather than raising the global default
- Keep interrupt handlers quiet by default

## Notes

If you add new logging:
- ask: "Would I want to see this on every boot?" If not, it probably belongs in DEBUG/TRACE.
- prefer structured summaries over per-item dumps.
17 changes: 13 additions & 4 deletions kernel/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,20 @@
//! configuration in a single place.

/// When `true` enable verbose kernel debug output (many debug traces).
pub const VERBOSE_KERNEL_OUTPUT: bool = true;
///
/// Default is `false` to keep boot logs high-signal and conserve context when
/// iterating with AI tooling.
pub const VERBOSE_KERNEL_OUTPUT: bool = false;

/// When `true` the kernel will idle (keep running) after initialization.
/// When `false` the kernel will exit QEMU immediately (useful for CI).
pub const KERNEL_SHOULD_IDLE: bool = true;

/// When `true`, dump the UEFI hardware inventory entries during driver init.
pub const PRINT_HARDWARE_INVENTORY: bool = true;
///
/// Default is `false` to avoid logspam; use the monitor or enable verbose logs
/// when actively debugging device discovery.
pub const PRINT_HARDWARE_INVENTORY: bool = false;

/// When `true`, enable serial output to COM1.
pub const ENABLE_SERIAL_OUTPUT: bool = true;
Expand Down Expand Up @@ -64,8 +70,11 @@ pub const USB_RUN_SW_INT_SELF_TEST: bool = false;

use crate::logging::{LogLevel, OutputTarget};

/// Default log level for modules without specific configuration
pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Trace;
/// Default log level for modules without specific configuration.
///
/// Keep this relatively quiet by default; enable DEBUG/TRACE via the kernel
/// monitor (`loglevel ...`) or by changing this constant when doing deep bring-up.
pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info;

/// Per-module log level overrides
///
Expand Down
10 changes: 5 additions & 5 deletions kernel/src/drivers/usb/xhci/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2812,7 +2812,7 @@ impl XhciDriver {

let mut first_connected = None;
for state in &states {
log_info!("xHCI {} port{:02} {}", ident, state.index, state.summary());
log_debug!("xHCI {} port{:02} {}", ident, state.index, state.summary());
if first_connected.is_none() && state.connected && !state.overcurrent {
first_connected = Some(*state);
}
Expand Down Expand Up @@ -3753,15 +3753,15 @@ impl XhciDriver {
product_id,
device_release
);
log_info!(
log_debug!(
"xHCI {} class={:#04x} subclass={:#04x} protocol={:#04x} max_packet_ep0={}",
ident,
device_class,
device_subclass,
device_protocol,
max_packet_size
);
log_info!(
log_debug!(
"xHCI {} strings: manufacturer={} product={} serial={} configurations={}",
ident,
manufacturer_index,
Expand All @@ -3775,14 +3775,14 @@ impl XhciDriver {
.map(|byte| format!("{:02x}", byte))
.collect::<Vec<_>>()
.join(" ");
log_info!(
log_debug!(
"xHCI {} device descriptor (first {} bytes): {}",
ident,
descriptor.len(),
partial
);
} else {
log_info!(
log_debug!(
"xHCI {} device descriptor returned {} byte(s): {:02x?}",
ident,
descriptor.len(),
Expand Down
5 changes: 4 additions & 1 deletion startQemu.sh
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ if [[ "$HEADLESS" == "true" || "$HEADLESS" == "headless" ]]; then
# QEMU_MONITOR_ARGS=( -chardev pipe,id=mon0,path=/tmp/qemu-monitor -monitor chardev:mon0 -chardev pipe,id=serial0,path=/tmp/qemu-serial -serial chardev:serial0)
QEMU_PAUSE_ARGS=()
QEMU_DEBUG_ARGS=( -device isa-debugcon,chardev=debugcon )
QEMU_DEBUG_CHAR_ARGS=( -chardev stdio,id=debugcon -d int,guest_errors,cpu_reset) #,trace:usb_* )
# QEMU debug flags can create *massive* log output. Keep defaults high-signal.
# Override with: QEMU_DEBUG_FLAGS="int,guest_errors,cpu_reset" ./startQemu.sh headless 10
QEMU_DEBUG_FLAGS=${QEMU_DEBUG_FLAGS:-guest_errors}
QEMU_DEBUG_CHAR_ARGS=( -chardev stdio,id=debugcon -d "${QEMU_DEBUG_FLAGS}" ) #,trace:usb_* )
else
echo "Starting QEMU in headed mode..."
echo " QEMU Debug Driver output: debug.log"
Expand Down