rpi5: stop enabling the firmware-KMS overlay
nextbsd-fkms brings up the firmware-KMS node, which VideoCoreKMS.kext binds.
That driver cannot program a plane on 2712 -- the firmware does not service
SET_PLANE (nextbsd-kernel-extensions#48, measured) -- so it has no hardware
cursor and no path to one.
VideoCore6KMS.kext programs the HVS, pixelvalves and HDMI PHY directly and does
not need that node. The two must never both be loaded, because they drive the
same display, so leaving the node disabled removes the way to get that wrong.
Verified on a Pi 500+ with the overlay disabled: VideoCore6KMS binds, EDID
reads over the firmware mailbox with no DDC adapter, the connector reports the
attached panel by name, and a modeset at its native 2560x1440 at 60 puts an image
on screen with no errors. Confirmed twice, once observed directly on the panel.
hdmi_force_hotplug=1 is deliberately left alone. Removing it was tested and
breaks the display outright: bcm2835_mbox_fb_init fails with err=5, no
framebuffer is allocated and the EDID mailbox errors, on both HDMI ports. See
[6 lines not shown]
rpi5: enable the v3d and full-KMS device-tree overlays
nextbsd-kernel-extensions#61 ships two more overlays in
rpi5-overlays.tar.gz. Shipping an overlay does not enable it -- the firmware
applies only what config.txt names -- so without these lines both files land on
the FAT32 partition and are never read.
nextbsd-v3d enables v3d at 2000000, which ships disabled. Measured on a Pi 500+:
the node comes up with the "disabled" gone and IRQs 70/71 resolved, and
enabling it disturbs neither the firmware framebuffer nor firmware KMS -- fb0
still comes up and vc4_fkms0 still attaches with /dev/dri/card0.
It does NOT by itself give 3D. Nothing in tree binds "brcm,2712-v3d", so
/dev/dri stays card0 with no renderD128. GL additionally needs a v3d DRM
driver, the drm_gpu_scheduler it depends on, and mesa-libs built with vc4 and
v3d in GALLIUM_DRIVERS (nextbsd#427).
nextbsd-vc4-kms enables the seven nodes the full KMS port needs: the vc6
master, hvs, both pixelvalves, both HDMI controllers and ddc0. Measured on the
[19 lines not shown]
rpi5: drop framebuffer_depth=32 from config.txt
The setting existed because the console runs on the firmware framebuffer,
where an unset depth yields 16bpp, bcm2835_fbd(4) then asks for 24, and the
console comes up dim and blue-cast. With VideoCoreKMS autoloading
(nextbsd-kernel-extensions#185) the intent is that KMS owns the display and
the firmware's depth stops mattering.
NOT VERIFIED ON HARDWARE. The Pi was unreachable when this was written, so
nobody has looked at a console without this line. Three things say it may
still be required, and they are recorded in the file rather than left for
someone to rediscover:
- the firmware allocates the console framebuffer before any kext can load,
so autoload does not change what happens at boot
- KMS does not take over the console. Measured with KMS loaded and
/dev/dri/card0 present:
fb0: <BCM2835 VT framebuffer driver> on simplebus0
[12 lines not shown]
rpi5: stage device-tree overlays onto the FAT32 boot partition (#429)
The rpi5 image ships VideoCoreKMS.kext but not the overlay that enables
its device-tree node, so the driver loads cleanly and then cannot bind:
kextload: loaded VideoCoreKMS.kext (dependency-ordered) RC=0
ofwbus0: <firmwarekms> irq 12 disabled compat raspberrypi,rpi-firmware-kms-2712 (no driver attached)
no /dev/dri
No package can fix this. pkg(8) installs into the UFS root; the FAT32
firmware partition is neither mounted at install time nor in any package's
file list. This staging block is the only thing that writes it.
Overlays come from nextbsd-kernel-extensions' continuous release, published
beside the kexts, so an overlay stays versioned with the driver it enables.
A missing asset is not fatal -- the image still boots, the driver simply
cannot bind, which is exactly the pre-#429 behaviour.
The config.txt note said no dtoverlay lines, and it was right about VENDOR
[9 lines not shown]
Follow the nextbsd-kernel-extensions rename
nextbsd-kernel-modules is now nextbsd-kernel-extensions, matching the
NextBSD-kernel-extensions package it produces. References also move off
the pre-rename nextbsd-redux org name, which worked only via redirect.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
Claude-Session: https://claude.ai/code/session_01PazZbkdGvuW6yjpLbREcfJ
boot-test: stop burning 480s on the SC-RUNLOOP marker (#424)
Same fix as nextbsd-userland#159, applied to this copy of the harness --
which is the one nextbsd-kernel's CI actually uses. Its workflow curls
tests/boot-test.sh from this repo, so the userland fix does not reach it.
scrltest does its work correctly -- the log shows "run-loop callback fired
with the watched key" every run -- and then SIGSEGVs during teardown, before
it can print SC-RUNLOOP-OK. Neither SC-RUNLOOP-OK nor SC-RUNLOOP-FAIL ever
reaches the stream.
This block had no local timeout, so it fell through to the global
`set timeout 480` and sat there for eight minutes before reporting
"SC-RUNLOOP marker not seen" -- which is also misleading, since the test ran
and passed. That is why boot tests take ~10 minutes regardless of outcome.
Bounds the block to 30s (restoring the previous timeout after it) and matches
the crash explicitly so it is reported as a crash rather than an absent
marker. The gate still fails -- the crash is real -- it just fails in seconds
[7 lines not shown]
ci: publish the Pi 5 image to continuous instead of racing it
`release` needed only [build, img-test], so it did not wait for
build-rpi5. Its download step already pulls every artifact in the run
and its publish glob already matches NextBSD-arm64-rpi5-*.img.zip, so
the image was never actually excluded -- the rpi5 lane (a second FreeBSD
VM plus the kernel8.img fetch) just always finished last and `release`
had already grabbed the artifacts. In run 32811952970: release started
05:21:28, build (rpi5 arm64) finished 05:23:23.
The stale comment described this as a deliberate hold-back until the
board booted real hardware (nextbsd-kernel#85). That is closed and the
Pi 5 desktop is screenshotted, so the hold-back is moot -- and it was
never enforced anyway, only lucky.
Add build-rpi5 to release's needs and require it to succeed, for the
same reason `build` is required: it is a build, not a boot test, so a
failure is real rather than the emulator flaking. It carries the same
build_needed guard as `build`, so it skips exactly when `build` skips,
[6 lines not shown]
docs: capture the Pi 5 desktop with import(1) so window content is included
xwd(1) returned the desktop with the About This Computer body and the Dock
missing -- both windows were IsViewable at correct geometry, but their
pixels were absent from every xwd path tried (-root, -id against the
window's own drawable, and -root -screen).
ImageMagick's import(1) captures them. The screenshot now shows the panel
with real hardware info -- ARM Cortex-A76 r4p1, 16351 MB, NextBSD 15.1,
XLibre -- which is the point of putting it in a call for testing.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
docs: replace the Pi 5 desktop screenshot with a correctly decoded one
The first upload was decoded wrong by my xwd converter, which took
bytes-per-pixel from the row stride (bpl/w = 4) instead of from bpp (3).
Reading 3-byte pixels at a 4-byte step scrambled the channels into grey
and stopped the content at 3/4 width, which looked like a black band.
Both artefacts were in the decoder. The board renders a full-width
1920x1080 desktop in full colour.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
docs: add a Gershwin-on-Pi-5 desktop screenshot for the call for testing
Captured from the board itself over ssh with xwd(1) against the running
X display, so it is a real framebuffer dump rather than a photograph.
Committed here rather than uploaded as a discussion attachment: GitHub's
user-attachments CDN has no public API, and a file in the repo cannot rot
out from under the announcement later.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
build: one image for the Pi 5 family, and publish it on merge (#421)
Three changes that belong together.
Ship every BCM2712 device tree and drop device_tree= from config.txt.
The firmware selects a DTB by board revision -- 'This selection is
automatic, and allows the same SD card image to be used in a variety of
devices' -- so pinning one file is precisely what made this image Pi
500/500+ only: any other board was handed a device tree for hardware it
is not. Eight blobs, 627 KB against a 100 MB boot partition.
Rename to NextBSD-arm64-rpi5-<date>.img.zip. Arch first, so it sorts
with the other arm64 images. That ordering was previously unavailable
because three globs did NextBSD--* and would have matched both
images -- one of them a bare build.sh
LICENSE
NOTICE
pkglist.txt
PORTING.md
[20 lines not shown]
build: one image for the Pi 5 family, and publish it on merge
Three changes that belong together.
Ship every BCM2712 device tree and drop device_tree= from config.txt.
The firmware selects a DTB by board revision -- 'This selection is
automatic, and allows the same SD card image to be used in a variety of
devices' -- so pinning one file is precisely what made this image Pi
500/500+ only: any other board was handed a device tree for hardware it
is not. Eight blobs, 627 KB against a 100 MB boot partition.
Rename to NextBSD-arm64-rpi5-<date>.img.zip. Arch first, so it sorts
with the other arm64 images. That ordering was previously unavailable
because three globs did NextBSD--* and would have matched both
images -- one of them a bare build.sh
LICENSE
NOTICE
pkglist.txt
PORTING.md
[21 lines not shown]
build: set framebuffer_depth=32 for the rpi500 image (#419)
Dropped in error. Depth, unlike width and height, is not ignored by the
firmware, and getting it wrong is merely visible rather than fatal --
which is how it slipped through.
Left unset the firmware allocates 16bpp and bcm2835_fbd asks it for 24:
changing fb bpp from 16 to 24
fb0: 1920x1080(1920x1080 at 0,0) 24bpp
and the console comes up with a blue cast and text nearly invisible.
With the setting:
keeping existing fb bpp of 32
fb0: 1920x1080(1920x1080 at 0,0) 32bpp
24bpp is three bytes per pixel with no padding, so a driver writing
32-bit pixels lands a byte out of alignment on every one.
[3 lines not shown]
build: give the rpi500 image a working display (#418)
Without these the firmware sets up no display and allocates no
framebuffer, vt(4) reports 'init without driver', and the machine boots
to a black screen -- which on this board is indistinguishable from a
kernel that never started.
max_framebuffers is what makes the firmware allocate one at all;
display_auto_detect lets it probe what is attached.
hdmi_force_hotplug is deliberate. Measured on a Pi 500+: the firmware
reported 'hotplug 0' with a monitor attached and its EDID perfectly
readable -- so DDC works and hotplug detect does not, which is what a
micro-HDMI adapter that skips pin 19 looks like. Raspberry Pi OS carries
the same workaround as the 'D' in video=HDMI-A-1:1280x720 at 60D, so the
fault is common enough that the vendor image ships a fix for it.
No hardcoded resolution. Forcing hdmi_group/hdmi_mode and
framebuffer_width/height was measured to be ignored, and letting the
[10 lines not shown]
build: add the Raspberry Pi 500+ image target (BOARD=rpi500) (#414)
* build: add the Raspberry Pi 500+ image target (BOARD=rpi500)
NextBSD boots on this board and reaches mountroot with the NVMe
enumerated, and there has been no image to install. This adds one.
The root half needed no change at all -- same packages, same makefs,
same tree -- so the lane branches only where the boot half does, which
is why it lives in build.sh rather than in a script of its own.
What is actually different is the boot half, and all of it follows from
the BCM2712 bootloader living in EEPROM: it reads config.txt off the
first FAT partition, loads and patches the DTB named there, loads
kernel8.img, and enters it at EL2 with x0 = the FDT. No loader(8), no
UEFI. So the image is MBR with a FAT32 type 0x0c partition rather than
GPT with an ESP, it carries config.txt + a DTB + kernel8.img rather than
loader.efi, and it produces no ISO -- an ISO 9660 image has no FAT
partition and no config.txt, so the firmware never opens it. That is not
[31 lines not shown]
arm64: fix the ISO's UEFI boot path, boot-test aarch64 in CI, re-enable the arm64 lane (#407)
The aarch64 ISO built and published but would not boot on any arm64 firmware.
release/arm64/mkisoimages.sh derives the El Torito ESP's UEFI fallback loader
name from install-boot.sh's get_uefi_bootname(), which resolves the target as
${TARGET:-$(uname -m)}. We cross-assemble aarch64 in an amd64 VM, so unset it
meant the ISO shipped /EFI/BOOT/bootx64.efi and no BOOTAA64.EFI. Pass TARGET.
Also: normalize ARCH=aarch64 -> arm64 (MACHINE vs MACHINE_ARCH); stop the mfsroot
lib closure cribbing x86-64 libs from the build VM on the cross lane; make both
boot harnesses arch-aware (virt + AAVMF + virtio-scsi CD + virtio-gpu) with the
loader handshake hardened from nextbsd-userland's; run each arch's boot test on a
native runner; de-matrix the release job so two arches cannot race the delete.
ci: give the arm64 guest a display adapter (virt has none)
qemu's `virt` machine instantiates NO display adapter, unlike q35 which
always has a VGA one (-display none only suppresses the HOST window, not
the emulated device). So on arm64 the firmware exposed no GOP, the loader
handed the kernel no framebuffer, vt(4) never attached, and /dev/ttyv0
did not exist — every console-on-screen path went untested on the one
arch where it actually breaks.
That is not hypothetical: nextbsd-userland#55 was a missing login on the
arm64 framebuffer, and it reached a release precisely because no CI guest
on that arch had a framebuffer to lose a login on. It took booting the
published image in UTM to see it.
Add -device virtio-gpu-pci to the arm64 lane so the tested machine has
the same shape as the machines users actually run — UTM and desktop qemu
VMs ship virtio-gpu-pci, which is where the bug showed up. amd64 needs
nothing: q35's VGA is already there.
[7 lines not shown]
tests: run the boot harnesses on macOS too (HVF + Homebrew/MacPorts firmware)
The harnesses only knew Linux: KVM-or-TCG, and firmware paths from the
Debian/Ubuntu packages. On a Mac that meant no accelerator and no
firmware, i.e. no local repro of a CI boot failure.
Add Hypervisor.framework as the middle acceleration tier, gated on the
guest arch matching the host's (a hypervisor can only run its own arch —
an amd64 image on Apple Silicon is emulation regardless), and say so
explicitly when falling back to cross-arch TCG so a 20-minute boot isn't
mistaken for a hang. Firmware search picks up Homebrew, MacPorts and
/usr/local, after the Linux paths CI uses.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
ci: correct the arm64 runner's acceleration note; arch-accurate ISO banner
The first green run (31831562114) shows GitHub's ubuntu-24.04-arm runner
has no /dev/kvm: the arm64 guest ran on same-arch TCG, not KVM as the
comment claimed. It is fast anyway — 1m51s (img) and 1m47s (iso) against
the KVM-accelerated amd64 leg's 2m49s — because the win is being off
CROSS-arch emulation, not the accelerator. tests/qemu-arch.sh already
prefers KVM whenever /dev/kvm appears, so nothing has to change if that
does.
Also make the mkisoimages.sh banner tell the truth per arch: amd64 gets
BIOS + UEFI, arm64 is UEFI-only (it ships no cdboot), which the GPT image
step a few lines up already reports correctly.
Co-Authored-By: Claude Opus 5 (1M context) <noreply at anthropic.com>
ci: boot-test arm64 natively, then re-enable the arm64 lane
#360 disabled arm64 because nothing in CI could boot an aarch64 image:
both boot jobs ran qemu-system-x86 on an x86 runner. Give them an arm64
leg, then restore the build matrix entry.
tests/qemu-arch.sh (new, sourced by both harnesses) holds the whole
per-arch qemu shape — binary, machine, UEFI firmware, NIC, TCG cpu, CD
attachment, KVM detection. amd64 is q35 + OVMF + e1000 + -cdrom; arm64 is
virt + AAVMF/QEMU_EFI + virtio-net (romfile= — the arm64 qemu packages
ship no efi-virtio.rom) + a virtio-scsi CD, since `virt` has no IDE and a
plain -cdrom would land the ISO on a virtio-blk instead of a cd0. ARCH
comes from the environment (CI passes the matrix arch) or is inferred
from the NextBSD-<arch>-<date> artifact name.
tests/loader.exp.inc (new) is the loader serial handshake, lifted from
nextbsd-userland's tests/boot-test.sh where it was hardened against this
exact class of flake: input paced at ~25 cps, every command synced on the
loader's next "OK " prompt rather than on the echo of what we typed (the
[15 lines not shown]
build: fix the arm64 ISO's UEFI boot path (TARGET=arm64 for mkisoimages.sh)
The aarch64 ISO built and published but would not boot on any arm64
firmware — the reason the arm64 lane was disabled in #360.
release/arm64/mkisoimages.sh builds the El Torito ESP with make_esp_file()
and lets it derive the UEFI fallback loader name from install-boot.sh's
get_uefi_bootname(), which resolves the target as ${TARGET:-$(uname -m)}.
We cross-assemble the aarch64 image in an amd64 FreeBSD VM, so with TARGET
unset that returned amd64: the aarch64 ISO shipped /EFI/BOOT/bootx64.efi
and no BOOTAA64.EFI, which arm64 firmware simply doesn't look for. (The
amd64 script passes `bootx64` explicitly, so this is a no-op there — and
the .img path was never affected: build.sh names that ESP itself.)
Also:
- Normalize ARCH=aarch64 -> arm64 up front. arm64 is FreeBSD's MACHINE and
is what the download mirror, the src tree's release/<arch>/ scripts, the
nextbsd-pkg continuous-<arch> tag and our artifact names all use;
[9 lines not shown]
build: drop pkg build residue (cached tarballs + repo catalogues) before makefs
Two things pkg leaves in the rootfs ride into every image and are dead weight
at runtime:
- PKG_CACHEDIR (/var/cache/pkg): the .pkg tarballs from the
NextBSD-everything and pkglist.txt installs. There was no `pkg clean` in
this script at all, so they all shipped.
- PKG_DBDIR (/var/db/pkg/repos/<repo>/db): the repository catalogues fetched
by the two `pkg update` calls. `pkg clean` is scoped to the cache and does
not touch these; no pkg subcommand does, and PKG_DBDIR cannot be relocated
because local.sqlite (the installed-package registry, which must ship)
lives there too. So they go with an explicit rm.
Both regenerate on the installed system -- pkg redownloads tarballs on demand
and refetches catalogues on any install/fetch/search (REPO_AUTOUPDATE defaults
to YES) or an explicit `pkg update`.
Motivation from the downstream gershwin-on-freebsd image, which hit this hard:
[11 lines not shown]
ci: allow workflow_dispatch to publish the continuous release
The release job was gated to push/repository_dispatch only, so a manual
"Run workflow" (workflow_dispatch) built + boot-tested green but skipped
publishing. Add workflow_dispatch to the event gate so a hand-triggered
run republishes `continuous`.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply at anthropic.com>
tests: unmute console, gate trace, guard teardown — boot-test observability (#369) (#375)
nextbsd/main's tests/boot-test.sh had drifted behind nextbsd-userland's copy and
still (a) never un-muted the console, (b) forced mach.debug_enable + launchd_trace
unconditionally, and (c) called close/wait unguarded. This copy is what the
nextbsd-kernel smoke-test fetches (build.yml: curl .../nextbsd/main/tests/boot-test.sh)
and what the ISO build uses, so those inherit the same problems that made the
amd64 boot markers invisible/flaky in the #369 investigation.
Port the three fixes proven in that investigation:
- `set boot_mutemsgs=NO` at the loader OK prompt, alongside the existing serial
console vars. nextbsd-overlays bakes boot_mutemsgs="YES" for a macOS-clean
login console; that mutes kernel printf for the whole boot, and the on-image
markers ride the same console, so muted CI times out on markers that WERE
emitted. RB_MUTEMSGS gates kernel printf only — markers come via the tty, so
un-muting is what makes them visible; it never hid userland output.
- Gate mach.debug_enable + launchd_trace behind BOOT_TRACE=1 (default off). With
the console un-muted the trace is thousands of blocking kernel printfs over the
emulated UART — it buries the markers and perturbs the notifyd/syslogd Mach
[9 lines not shown]
test: boot CI verbose so boot_mutemsgs doesn't hide markers (#363) (#364)
The shipped image now sets boot_mutemsgs="YES" (nextbsd-overlays), which mutes
kernel console output — including 'vfs.pivot: / is now unionfs', which
iso-boot-test.sh sequences its stages on. Muted, the harness consumed the
login: prompt in the wrong stage and timed out (the live boot itself was fine
— it reached getty + login).
Boot the CI harnesses with 'boot -v': RB_VERBOSE bypasses the kernel mute so CI
sees every marker, while shipped images (booted normally) stay quiet. Applied
to both iso-boot-test.sh and img-boot-test.sh for consistency.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply at anthropic.com>
build: seed pkg-free /etc from nextbsd-overlays (#362)
The user-editable /etc config (master.passwd, group, sshd_config, pam.d,
fstab, ...) was shipped inside the NextBSD-userland package as plain files, so
pkg upgrade would clobber a user's edits (no @config, no .pkgnew). Split it out
to the new nextbsd-overlays repo and seed it here at assembly time — laid down
by build.sh, not any package, so pkg has no record of it and upgrade can never
touch it (same guarantee os-release already has).
- clone nextbsd-overlays, cp -R rootfs/. $RF/ after the Apple /private layout,
before pwd_mkdb (which regenerates pwd.db from the seeded master.passwd)
- harden the post-install guard to /sbin/launchd (master.passwd is no longer a
package artifact once the userland strip lands)
- fix three stale build.sh comments that referenced the old overlays/ dir
Additive for now (the package still ships /etc until the userland strip PR);
cp -R overwrites with identical content. Becomes the sole provider afterward.
Co-authored-by: Claude Opus 4.8 (1M context) <noreply at anthropic.com>