← Back · NextBSD research · ticket: nextbsd#363 (link on commit)
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.
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.
Every kernel printf funnels through subr_prf.c and splits into two independent sinks:
dmesg) and /dev/klog → syslogd. Never gated by the console mute.cnputc/cnputs in kern_cons.c — emitted only if (!cn_mute).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:
| Concern | Reality (verified in source) |
|---|---|
| Panics must stay visible | panic() 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 working | getty 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 lost | TOLOG 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.
The console mute can be armed from the loader, and the verbose escape is kernel-enforced — no logic to write:
| Loader key | Effect | Note |
|---|---|---|
boot_mute="YES" → RB_MUTE | Fully silent from cninit — no banner, no attach spew; the mute persists into runtime (covers USB-eject etc.) | Most macOS-like |
boot_mutemsgs="YES" → RB_MUTEMSGS | Shows the copyright banner, then mutes; also persists into runtime | Prints 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.
/var/log/kextd.log and gates its chatter behind if (verbose) — it never touches ttyv0. No change.if (bootverbose) (iokit_catalogue.c). Silent on normal boot already. No change.kldload produces (daN: <...>, umass0, linker lines) plus runtime attach/detach (ugenX.Y ... detached on eject). These are unconditional printfs across every driver — impractical to gate per-driver, and per-driver gating wouldn't cover runtime anyway. The console mute is the correct, universal lever.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.
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.
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.-v anyway; we just document it. (No effect on normal users.)boot_mute is set; only if we later want the boot-visible/runtime-quiet split.boot_verbose into all three boot harnesses (disk test, live iso-test, userland ci-image-boot).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_efifb→vt_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":
vt(4) framebuffer splash (replace the boot logo / load a splash image). Framebuffer-only (efifb UEFI, vt-vga/vbe BIOS; not raw serial). Drawable, but to look Apple-like it needs #272's flicker-free handoff.Grey, still cube. Calm, minimal.
Grey with a dark spinner (contrast on light grey).
Black, still cube. Sleek, high-contrast.
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.