← Back · NextBSD research · ticket: nextbsd#363 (link on commit)

Quiet console — kernel spew off ttyv0

Make the login console behave like macOS: no kernel / IOKit / driver text flying across ttyv0 on a normal boot or when you yank a USB stick — but full output under boot -v, everything still in dmesg+syslog, and panics always visible. The surprise: FreeBSD already does all the hard parts. This is a one-line loader change.

Status: draft for discussion (local, uncommitted). Mechanism verified in the releng base kernel source. No kernel patch, no kextd change, no service ordering.

Bottom line Add boot_mute="YES" to the nextbsd-overlays loader fragment. It silences boot and runtime console text, auto-exempts boot -v, keeps dmesg+syslog intact, and stays panic-visible (the kernel force-unmutes on panic). The only real work is making CI boot verbose so the boot-test still sees its markers.

Contents

  1. Why "quiet but not blind" is already solved
  2. The one lever & the verbose escape
  3. Why kextd/IOKit aren't the fix
  4. The change set
  5. The one real risk: CI
  6. What to decide (shop talk)
  7. Optional: a boot splash (mockups)

1. Why "quiet but not blind" is already solved

Every kernel printf funnels through subr_prf.c and splits into two independent sinks:

So muting the console (cn_mute) suppresses only the on-screen display. Capture is untouched — dmesg and syslog still record everything, for free. Three properties fall out that dissolve the tradeoff I worried about:

ConcernReality (verified in source)
Panics must stay visiblepanic() runs cn_mute = 0 (kern_shutdown.c:941, "Unmute when panic"). A muted console is force-unmuted on panic. You can never blind the box to a panic.
getty/login must keep workinggetty runs on /dev/console via the vt(4) tty path; cn_mute only gates the low-level kernel cnputc/cngetc. The login: prompt, echo, and typing are unaffected while muted.
Nothing lostTOLOG path is never muted → dmesg + syslog capture the full stream regardless.

This is exactly macOS's split: kernel logging is always captured (unified log there, dmesg+syslog here); the screen shows raw text only in verbose mode.

2. The one lever & the verbose escape

The console mute can be armed from the loader, and the verbose escape is kernel-enforced — no logic to write:

Loader keyEffectNote
boot_mute="YES"RB_MUTEFully silent from cninit — no banner, no attach spew; the mute persists into runtime (covers USB-eject etc.)Most macOS-like
boot_mutemsgs="YES"RB_MUTEMSGSShows the copyright banner, then mutes; also persists into runtimePrints one -- Muting boot messages -- line

Both RB_MUTE and RB_MUTEMSGS explicitly cancel themselves when RB_VERBOSE is set (kern_cons.c). So boot -v → full output, a normal boot → silent, from a single key. No launchd job, no ordering, no sysctl toggling needed for the base case.

Because cn_mute set at boot persists, requirement #4 (runtime device-event spew on ttyv0) is covered by the same key — no separate runtime mechanism required.

3. Why kextd/IOKit aren't the fix

4. The change set

A. Primary — one loader key in nextbsd-overlays/rootfs/boot/loader.conf.d/nextbsd.conf:

# Quiet console like macOS: no kernel/driver text on ttyv0 during a normal
# boot or at runtime (USB eject, attach/detach). boot -v shows everything;
# dmesg + syslog capture everything regardless; panic() force-unmutes.
boot_mute="YES"

That's the whole feature. No kernel patch, no kextd change, no service ordering.

B. Optional (only for a different product choice) — if you ever want "banner/boot visible but runtime silent," that's a launchd job (com.apple.consmute.plist, RunAtLoad) running [ "$(sysctl -n debug.bootverbose)" = 0 ] && sysctl kern.consmute=1. Redundant if boot_mute is set; not recommended for the base case.

C. Kernel — none. boot_mute, the verbose exclusion, and the panic-unmute are all stock releng features. Consistent with the no-kernel-fork doctrine.

5. The one real risk: CI

Must handle nextbsd/tests/boot-test.sh greps the serial console for expected kernel lines. With boot_mute those lines vanish and the boot-test breaks. Fix: the CI boot path already drops to the loader OK prompt and sets serial vars — also set boot_verbose="YES" there, so CI boots verbose (sees everything) while shipped images stay muted. Same verbose escape, used deliberately. This touches boot-test.sh (disk) and iso-boot-test.sh (live) + possibly nextbsd-userland's ci-image-boot handshake.

6. What to decide (shop talk)

  1. boot_mute (fully silent, no banner) vs boot_mutemsgs (banner then silent)? Fully silent is the most Mac-like; the banner variant leaves a one-line breadcrumb.
  2. Accept the kdb caveat? A manual break-to-debugger on a non-verbose boot has no console I/O until a panic clears the mute. Developers boot -v anyway; we just document it. (No effect on normal users.)
  3. Belt-and-suspenders launchd job (B) — ship it or not? Not needed if boot_mute is set; only if we later want the boot-visible/runtime-quiet split.
  4. Scope of the CI verbose flip — confirm we wire boot_verbose into all three boot harnesses (disk test, live iso-test, userland ci-image-boot).

7. Optional: a boot splash to fill the quiet gap (mockups)

With boot_mutemsgs the kernel-boot phase is a blank/quiet screen until login:. A boot splash could fill that gap. All four combinations you asked to see are mocked to scale below — grey vs black background × static vs spinner — using the real nextbsd.org cube (the spinners animate in the browser).

Foundation — nextbsd#272 This is the "Apple framebuffer / flicker-free" research you remembered: #272 — seamless vt(4) → drm-fbdev handoff (deferred takeover). Today the console clears to black when a DRM driver attaches: aperture removal rips out efifb, the vt_efifbvt_fb repaint clears the screen, and i915 may re-modeset — FreeBSD's vt(4) has no deferred-takeover like Linux fbcon. #272's scope is to preserve the framebuffer across the handoff (copy-forward the boot image, engage i915 fastset) so there's no flash, and it explicitly names "a boot splash/logo that survives the handoff — foundation for an Apple-style graphical boot" as the follow-on. So the splash below is a layer on top of #272 — a splash shipped before #272 would flash to black mid-boot when the GPU driver loads.

Feasibility A splash is not just "draw a logo":

1 — grey · static

Grey, still cube. Calm, minimal.

2 — grey · spinner

Grey with a dark spinner (contrast on light grey).

3 — black · static

Black, still cube. Sleek, high-contrast.

4 — black · white spinner

The full macOS look — black + white spinner.

All four use the real nextbsd.org cube SVG; the spinners are a CSS mock of the 12-spoke macOS throbber (they animate here in the browser). On hardware, options 2 & 4 (spinner) need the framebuffer draw loop that doesn't exist in FreeBSD today, and all four need #272 to survive the GPU-driver handoff without flashing.

Verified in the releng base: sys/kern/subr_prf.c (TOCONS/TOLOG split), sys/kern/kern_cons.c (cn_mute, RB_MUTE/RB_MUTEMSGS verbose-exclusion, kern.consmute), sys/kern/kern_shutdown.c:941 (panic unmute), sys/kern/subr_boot.c:72-77 (boot_* flags), sys/kern/init_main.c:139 (debug.bootverbose). NextBSD: nextbsd-kernel/.../iokit_catalogue.c (already bootverbose-gated), nextbsd-userland/.../kextd.c + com.apple.kextd.plist (log-file, verbose-gated), com.apple.getty.plist (getty on /dev/console). Loader fragment: nextbsd-overlays/rootfs/boot/loader.conf.d/nextbsd.conf.