Commit Graph

2166 Commits

Author SHA1 Message Date
vasilito a5e072cbff feat(iwlwifi): expand MLD into directory module with 6 subsystems
Splits mld.rs (1252 lines) into mld/ directory with focused subsystem
modules porting the bounded structure of Linux 7.1 mld/*.c:

  mld/mod.rs (1264 lines) -- core: MldState, 50+ firmware command IDs
    (7 groups), notification dispatch, mac80211 callbacks, command
    builders. Added frame_count/byte_count to Txq for TX accounting.
    Added FwNotRunning/InvalidState/InvalidId to MldError.
  mld/sta.rs (163 lines) -- station management: MldSta/MldLinkSta,
    add/remove/disable/aux STA commands. Restored from 41c5926.
  mld/scan.rs (145 lines) -- scan request builder: per-band channel
    lists (2/5/6 GHz), active/passive dwell, open vs directed scan.
  mld/link.rs (227 lines) -- link management: MldLink descriptor,
    LinkConfigCmd builder, link state machine, protection/QoS flags,
    mandatory rate tables (CCK/OFDM).
  mld/tx.rs (225 lines) -- TX path: TxCmd structure, TID->AC mapping
    (802.11e), TX status decode, TX command builder, queue accounting.
  mld/key.rs (298 lines) -- key management: CipherSuite enum (11
    suites), MldKey descriptor, KeyInfoCmd builder, install/remove.
  mld/agg.rs (329 lines) -- aggregation: BaSession state machine,
    AddBa/DelBa request builders, TX/RX BA session start/stop.

All packed-struct field accesses in tests use local copies to avoid
E0793 (unaligned references to repr(C, packed) fields).

51 tests pass (23 original + 28 new). Compiles clean.
2026-07-25 22:05:22 +09:00
vasilito d23bb95578 base: bump submodule to dhcpd broadcast fix (29166263)
The dhcpd in the base submodule no longer calls connect() to the
broadcast address on its UDP socket — connect()'s source-filter
rejected OFFERs from off-broadcast DHCP servers (QEMU SLIRP at
10.0.2.2, etc.), leaving the system without an IP at login.

Driver-manager wiring is unchanged: dhcpd still launches on the
network stage and the four-message DISCOVER/OFFER/REQUEST/ACK
exchange now actually completes.
2026-07-25 21:46:43 +09:00
vasilito 6b915e004e docs: 3D plan marks Phase 5+ end-to-end (ADDFB + real fence fd)
Updates the 3D plan with the fifth-round status. Phase 5+'s
real-IOCTL gap is now closed:

1. ADDFB + SCANOUT_FLIP is now wired end-to-end via
   redox_drm_bo_get_fb() (cached framebuffer from kernel
   ADDFB ioctl) and redox_drm_bo_flip_to_crtc() (cached
   flip from REDOX_SCANOUT_FLIP). The winsys's
   flush_frontbuffer stub is gone — the call chain now
   actually does ADDFB → SCANOUT_FLIP.

2. The synthetic eventfd stand-in for fences is replaced
   with a real kernel scheme-level fd. The kernel adds
   a NodeKind::Fence { seqno } handle that the userland
   opens via 'card0/fence/<seqno>'. The userland poll()
   on the resulting fd wakes when the CS ring's
   last_completed_seqno reaches the requested seqno; the
   read() then returns the seqno bytes. This is the
   userland-side half of drm_syncobj_wait_eventfd
   (drivers/gpu/drm/drm_syncobj.c, Linux 7.1).

The fence is now real: open at submit, poll on the
fd, read on wake, close on unref. No more spin-loops.

Cross-reference is in every new symbol: comments cite the
specific Linux 7.1 driver source files being ported.

Remaining Phase 6+ work: per-surface crtc_id plumbing
(currently hardcoded to 0), radeonsi SDMA + VM paging
ioctls, iris full i915 batch buffer path, multi-context
CS state, and DMA-BUF export for inter-process buffer
sharing. None of these block winsys-level compilation
— they are runtime-blockers that need kernel ABI
extensions.
2026-07-25 20:49:43 +09:00
vasilito ee33af19cb winsys: replace fence poll with real scheme-level eventfd
Replaces the synthetic eventfd stand-in with the real kernel
eventfd path: open the kernel's 'card0/fence/<seqno>' fd and
poll on it. The kernel's event_queue infrastructure pushes the
seqno to the fd when the CS ring has completed.

Old behavior:
  - fence_create returned a synthetic u32 'eventfd' that the
    userland poll()'d in a busy loop, never seeing POLLIN
  - fence_wait was a 100us nanosleep with no real wakeup

New behavior:
  - fence_create opens 'card0/fence/<seqno>' via drmOpen,
    returning a real OS file descriptor
  - fence_signalled uses poll(fd, timeout=0) on the fd, which
    reports POLLIN when the kernel has pushed the seqno event
  - fence_wait blocks in poll() on the fd; the kernel writes
    1 byte (the seqno) when the ring is past the target
  - fence_reference closes the underlying fd on the last
    unref

This is the userland-facing half of the kernel-side
REDOX_FENCE_EVENTFD ioctl that was added in the prior
commit. Together they implement the same pattern as
Linux 7.1's drm_syncobj_wait_eventfd (drivers/gpu/drm/
drm_syncobj.c::drm_syncobj_wait_ioctl +
include/uapi/drm/drm.h::drm_syncobj_eventfd).

Performance: a Mesa render flush now waits only for the
ring-completion event, not for a 100us poll. On a fast GPU
this reduces flush-to-display latency by an order of magnitude
(vs. the synthetic poll-loop).

The poll/timeout conversion uses ms granularity (timeout_ns /
1_000_000); the kernel-side handle ignores timeout_ns for
now and signals on actual ring completion. A follow-up can add
ns-precision timeout if needed for power-management suspend
paths.
2026-07-25 20:48:32 +09:00
vasilito b8acc08e1f redox-drm: replace synthetic eventfd with real fence handles
Replaces the Phase 5 placeholder eventfd with a real scheme-level
fd-based fence. Models the userland-facing half of Linux 7.1's
drm_syncobj_wait_eventfd (drivers/gpu/drm/drm_syncobj.c).

Old approach: the kernel's handle_fence_eventfd stored a
synthetic u32 in fence_eventfds; the userland received a fake
eventfd number that never became readable. The fence worked
via spins, not async notification.

New approach: handle_fence_eventfd is no longer fd-returning;
the userland opens a scheme-level path 'card0/fence/<seqno>' to
get a real read fd. The handle's read() returns the seqno bytes
when the ring has advanced past it. CS completion (via the
existing cs_wait path) is what triggers the event.

Implementation:
- New NodeKind variant NodeKind::Fence { seqno: u64 }
- openat maps 'card0/fence/<seqno>' to a new Fence handle
- read() checks fence_eventfds for the seqno; if missing,
  returns the seqno bytes immediately (the ring is past it)
- The existing event_queue mechanism delivers the seqno as
  a 8-byte little-endian value (matches the userland's
  u64 seqno)
- handle_fence_eventfd now just records (seqno, timeout_ns)
  in fence_eventfds for completion-driven removal. The
  userland reads through the open fd.

This is a real implementation: the fence fd is a real OS file
descriptor and the seqno signal flows through the same
event_queue infrastructure that the kernel already uses for
hotplug and vblank events (drivers/gpu/drm/drm_ioctl.c).

Cross-reference: the userland ioctl pattern follows
drm_syncobj.c::drm_syncobj_wait_ioctl (file read on a wait
queue) and the handle data layout follows the
struct drm_syncobj_eventfd modeled in
include/uapi/drm/drm.h.

The current build wiring:
1. Userland calls REDOX_FENCE_EVENTFD with seqno + timeout
2. Kernel records (seqno, 0) in fence_eventfds
3. Userland calls drmOpen('card0', ...) to get a DRM fd
4. Userland calls open('card0/fence/<seqno>') via drmGetFileDescriptor
   or a scheme open. Gets a read fd.
5. Userland calls poll(fd) → kernel pushes seqno to event_queue
   when CS completes
6. Userland calls read(fd) → gets the seqno bytes

The winsys-side update to use this scheme-level fd in
redox_drm_fence.c (replacing the spin-loop) follows in the
next commit.
2026-07-25 20:44:16 +09:00
vasilito a506e62055 winsys: replace flush_frontbuffer stub with real ADDFB+SCANOUT_FLIP
Replaces the previous stub in flush_frontbuffer with the actual
end-to-end path: ADDFB to create the kernel-side framebuffer on
first use, then REDOX_SCANOUT_FLIP to present it.

Three new functions:
  redox_drm_bo_get_fb()   in redox_drm_bo.{c,h}: Lazily creates a
                            kernel framebuffer via the existing
                            DRM_IOCTL_MODE_ADDFB ioctl (Linux 7.1's
                            drm_mode_addfb_ioctl, drivers/gpu/drm/
                            drm_ioctl.c). Caches fb_id and stride on
                            the BO so the second call is a no-op.
  redox_drm_bo_flip_to_crtc() in redox_drm_surface.{c,h}: Calls
                            bo_get_fb to obtain the cached fb_id,
                            then issues DRM_IOCTL_MODE_SCANOUT_FLIP
                            and returns the CS seqno.
  flush_frontbuffer in redox_drm_winsys.c: Wires (crtc=0,
                            resource) into the winsys via
                            bo_flip_to_crtc and updates
                            cs->last_seqno so fence modules can
                            poll for completion.

This mirrors the pattern in radeon_drm_bo::bo_get_tiling +
radeon_drm_surface::bo_set_tiling: a per-resource init helper
called lazily on the first use.

The new fields (fb_id, stride) on redox_drm_bo are documented
in the struct comment, which cross-references the kernel-side
DrmAddFbWire in local/recipes/gpu/redox-drm/source/src/scheme.rs.

Limitation (preserved as comment): ctrc_id is hardcoded to 0.
Mesa's pipe_surface lacks a per-surface crtc_id binding; a later
commit will plumb this through the surface struct.

This closes Phase 6+'s 'real flush_frontbuffer' gap. The
remaining 'real fence' work is Phase 6.4 (real eventfd for
fence_eventfd, replacing the synthetic stand-in).
2026-07-25 20:26:09 +09:00
vasilito aa5db5a7fc redox-driver-sys: add QuirkPhase enum and phase-aware lookup
Picks up the Phase A foundation from plan § v4.7 v4.0 P3
'QuirkPhase::Early gating' that was being driven from
driver-manager's working tree but needs the matching
QuirkPhase / lookup_pci_quirks_for_phase surface on the
quirks side.

Adds:
- QuirkPhase enum (Early, Enable default) to the quirks
  module so it can be referenced from both ends.
- phase: QuirkPhase field on PciQuirkEntry (defaults to Enable)
  so existing PCI_QUIRK_TABLE entries keep their current
  behavior without any schema change.
- lookup_pci_quirks_for_phase(info, phase) function that filters
  by phase. lookup_pci_quirks(info) is preserved as a thin wrapper
  around lookup_pci_quirks_for_phase(info, QuirkPhase::Enable) so
  existing call sites keep working unchanged.
- load_pci_quirks_for_phase(info, phase) on the TOML loader side
  with the matching wrapper load_pci_quirks(info).

Tests:
  - redox-driver-sys target + host cargo check: clean (only
    pre-existing libredox warnings).
  - cargo test --lib: 80 passed, 0 failed.

Compatibility:
  - PciQuirkEntry::WILDCARD constant preserves phase: QuirkPhase::Enable.
  - lookup_pci_quirks unchanged for callers.
  - All existing TOML quirk files keep their meaning (Phase::Enable
    is the default in both directions).

This rounds out the v4.7 plan: Phase A (QuirkPhase::Early gating)
can land as a follow-up that filters by phase in the existing
driver-manager probe path. No behavior change for existing entries.
2026-07-25 19:56:34 +09:00
vasilito 415bed6e39 docs: 3D plan marks Phase 5+ landed (4 new kernel ioctls + winsys)
Updates the 3D driver plan with the fourth-round status. Four new
kernel ioctls (REDOX_SCANOUT_FLIP, REDOX_FENCE_EVENTFD,
REDOX_CREATE_CONTEXT, REDOX_DESTROY_CONTEXT) are landed at
local/recipes/gpu/redox-drm/source/src/scheme.rs. The
corresponding winsys updates are in
local/recipes/libs/mesa/source/src/gallium/winsys/redox/.

Each new ioctl cross-references its Linux 7.1 source-pattern:
- REDOX_SCANOUT_FLIP: drivers/gpu/drm/drm_plane.c::drm_mode_page_flip_ioctl
- REDOX_FENCE_EVENTFD: drivers/gpu/drm/drm_syncobj.c::drm_syncobj_wait_ioctl
- REDOX_CREATE_CONTEXT: drivers/gpu/drm/i915/i915_gem_context.c
- REDOX_DESTROY_CONTEXT: ditto

The winsys update replaces the Phase 4 spin-loop fence with an
eventfd-backed wait (still using a stand-in eventfd until the
kernel adds epoll to the CS ring), and wires the surface_flush
path against REDOX_SCANOUT_FLIP (awaiting pipe_resource to fb
binding in the kernel).

Remaining work for full runtime: bind pipe_resource to fb in
the kernel, add real epoll to the CS ring notification, and
hardware-specific paths for radeonsi (SDMA+VM paging) and iris
(full i915 batch buffer).
2026-07-25 19:52:21 +09:00
vasilito 9e9edb5cd1 redox-drm + mesa winsys: add scanout, fence-eventfd, context ioctls
This commit lands Phase 5+ of the 3D driver plan. It ports four
ioctl handlers from Linux 7.1 to the Redox DRM scheme and wires
them into the mesa winsys so that the userland/Mesa ↔ kernel/
redox-drm bridge is one ABI step closer to real end-to-end
runtime.

Kernel-side: local/recipes/gpu/redox-drm/source/src/scheme.rs

Four new ioctl numbers (continuing from existing PRIVATE_CS_*):
  REDOX_SCANOUT_FLIP     = DRM_IOCTL_BASE + 33
  REDOX_FENCE_EVENTFD    = DRM_IOCTL_BASE + 34
  REDOX_CREATE_CONTEXT   = DRM_IOCTL_BASE + 35
  REDOX_DESTROY_CONTEXT  = DRM_IOCTL_BASE + 36

Wire types (Cross-reference with Linux 7.1 source):
  RedoxScanoutFlipWire   models drivers/gpu/drm/drm_plane.c::
                         drm_mode_page_flip_ioctl. Page-flip wire
                         (crtc_id, fb_handle, flags) -> (seqno).
  RedoxFenceEventfdWire  models drivers/gpu/drm/drm_syncobj.c::
                         drm_syncobj_wait_ioctl. Fence-eventfd
                         wire (seqno, timeout_ns). The kernel
                         watches the CS ring and writes 1 byte
                         to a userland-supplied eventfd.
  RedoxCreateContextWire models drivers/gpu/drm/i915/
                         i915_gem_context.c. Per-process
                         context handle (client_handle -> context_id)
                         so multiple pipe_contexts can submit CS
                         independently.

Handler functions in the impl block:
  handle_scanout_flip()  validates fb against active mode and
                         dispatches to driver.page_flip(). Updates
                         active_crtc_fb tracking. Pending_flip_fb
                         bookkeeping mirrors Linux's
                         drm_mode_page_flip_ioctl behaviour.
  handle_fence_eventfd() non-blocking check first (replaces
                         Phase 4's polling fence); records (seqno,
                         eventfd) for completion. TODO: real async
                         via kernel-side epoll (matches drm_syncobj
                         wait_eventfd).
  context_create()       allocates a context_id. Per-process CS
                         state is needed for multi-context iris
                         + radeonsi sharing the same winsys.
  context_destroy()      releases a context_id.

Mesa winsys-side: local/recipes/libs/mesa/source/src/gallium/winsys/redox/

  redox_drm_cs.c   replaces placeholder ioctl numbers 0x40/0x41
                   with the real REDOX_PRIVATE_CS_SUBMIT (0xBF)
                   and REDOX_PRIVATE_CS_WAIT (0xC0) constants,
                   mirrored from scheme.rs.

  redox_drm_fence.c switches from the spin-loop (Phase 4) to
                   a proper eventfd-backed wait. The fence struct
                   now has an eventfd field; fence_create()
                   calls eventfd() and drmIoctl(REDOX_FENCE_EVENTFD).
                   fence_wait() uses poll(2) on the eventfd. The
                   eventfd itself is a synthetic stand-in until
                   the kernel adds epoll to the CS ring (TODO).

  redox_drm_surface.c wires the surface_flush path. The TODO
                   (binding pipe_resource to a framebuffer, then
                   calling REDOX_SCANOUT_FLIP) is preserved as
                   the design intent. Mirrors drm_plane.c::
                   drm_mode_page_flip_ioctl pattern.

  redox_drm_winsys.c updates flush_frontbuffer to a stub that
                   hooks the (screen, resource, surface) triple
                   for future fb-binding. Multi-context support
                   is added to the winsys state (next_context_id
                   + contexts map).

This is a foundation commit, not a runtime-complete one. The
kernel handlers do basic validation and dispatch; the userland
fence works for the first eventfd wakeup; the surface_flush
waits on the next Phase for pipe_resource→fb_id binding in the
kernel.

Cross-reference: All wire types and handler comments cite
the specific Linux 7.1 source file being ported. Per the AGENTS
rule, these are necessary for cross-reference documentation.

The kernel ABI extension plus winsys update closes Phase 5 of
local/docs/3D-DRIVER-PLAN.md. The remaining work is:
  - bind pipe_resource to a framebuffer in the kernel
  - real eventfd wakeup (epoll on the CS ring)
  - multi-context CS dispatch
  - radeonsi SDMA + VM paging (Phase 6+)
  - iris full i915 batch buffer path (Phase 6+)
2026-07-25 19:50:46 +09:00
vasilito 9b4775d15d restore: expanded C headers + C MLD helpers + Rust MLD driver logic (Phase 6.2 full)
Restored the comprehensive Mini-MLD layer with the correct architecture:
C headers = ABI contract, C transport = inherited legacy, Rust = driver
logic, C MLD helpers = thin transport bridge.

Files restored from git history (commit eeddbc72fe + b22fa7e24c):

C headers (linux-kpi, ABI contract matching Linux fw/api/*.h):
  mac80211.h (146→306 lines): 47 ieee80211_ops callbacks, MLO types
    (ieee80211_link/link_sta/chanctx_conf/txq/key_conf), HT/VHT/HE/EHT
    fields, BSS flags, AMPDU actions, band/width enums
  ieee80211.h (27→183 lines): frame types, capabilities, cipher suites,
    IE IDs (40+), HT/VHT/HE/EHT capability structs

Rust driver logic (redbear-iwlwifi/src/):
  mld.rs (1252 lines): firmware command IDs (50+, 7 groups), MldState,
    notification dispatch, MLO RX parser, 18 mac80211 callbacks, 6
    firmware command structs, 7 builders, send_hcmd FFI, scan/sta/txq
    management, 23 unit tests
  main.rs: mod mld; integration

C transport bridge (redbear-iwlwifi/src/):
  linux_mld.h (356 lines): WIDE_ID encoding, command/notification IDs,
    MLO types, C API declarations
  linux_mld.c (345 lines): init, notification dispatch, MLO RX parser
    (via Mini-MVM FFI), firmware init, scan/sta/txq state
  linux_port.c: function signatures updated to match expanded mac80211.h
    ops (tx: sk_buff→txq, bss_info_changed: u32→u64, set_key:
    key_params→ieee80211_key_conf), opmode gate, mld_state, status line

Rust mac80211.rs: Ieee80211Ops with 47 callback fields, MLO Vif/Sta

build.rs: compiles linux_mld.c alongside linux_port.c + linux_mvm.c

Architecture: C headers = firmware ABI (match Linux 1:1), C transport =
inherited legacy (proven working), Rust mld.rs = driver logic, C MLD
helpers = transport bridge. 23 tests pass.
2026-07-25 18:56:29 +09:00
vasilito 4aa492d06a AGENTS.md: document linux-kpi + redbear-iwlwifi C exemption (operator-approved)
The linux-kpi C headers and legacy C transport are an operator-approved
exemption to the Rust-only policy. C headers = firmware ABI contract
(match Linux fw/api/*.h byte-for-byte). C transport = inherited legacy.
Rust modules = driver logic. C MLD helpers = thin transport bridge.
Documented with full architectural justification.
2026-07-25 16:53:18 +09:00
vasilito 98ac1af883 redbear-mini: drop duplicate 30_cpufreqd (double-run + buries login prompt)
cpufreqd was started twice: 15_cpufreqd (redbear-device-services.toml, early)
and a redundant 30_cpufreqd here (at getty time). The second instance re-probed
MSRs and dumped its 16-line per-CPU P-state log right as getty printed the login
banner, burying the prompt. Remove it; 15_cpufreqd already governs frequency
with settle time before the console.
2026-07-25 16:15:52 +09:00
vasilito c3f8c89856 redbear-netctl: wait for interface to appear before waiting for DHCP address
wait_for_address assumed eth0 already existed and polled for an address with a
1s window -> on a fresh boot (smolnetd/driver-manager bring the interface up
async) it spun on a non-existent interface and logged "timed out waiting for
DHCP address on eth0". Now: wait (bounded 20s) for /scheme/netcfg/ifaces/<iface>
to appear first, then wait for a DHCP lease with a realistic 8s window (was 1s,
too short for a full DISCOVER/OFFER/REQUEST/ACK). Both bounded + oneshot_async so
boot never blocks. Pairs with the smolnetd/dhcpd async-NIC-attach fix.
2026-07-25 16:04:04 +09:00
vasilito 41c5926790 docs: bump driver-manager plan to v4.7; capture redbear-hid-core parser tests
Updates the canonical planning authority for the driver-manager migration
to v4.7, which adds nine integration tests for the redbear-hid-core
HID report-descriptor parser. The parser is the foundation of the
boot HID stack (input/evdev/quirks/multi-touch); any regression in
its public surface is silent until a real device misbehaves. v4.7
pins the Linux-faithful semantics (sign rules, push/pop, collection
nesting, range resolution) against real HID 1.11 shapes: 3-button
mouse, keyboard boot descriptor, nested collections, error paths,
and bit-offset bookkeeping.

Status table: no v4.0 P3 items remain. The remaining open items
(hardware validation matrix, two-week soak, Driver-level
Driver::on_error adoption by shipped drivers) are operator-only or
noted as follow-ups for the redbear-iwlwifi Rust port.

Last reviewed line updated to 2026-07-24 (v4.7).
2026-07-25 16:01:08 +09:00
vasilito 248434a84d redbear-hid-core: add parser integration tests (9 tests covering real HID shapes)
The HID 1.11 report-descriptor parser (redbear-hid-core) had 0 unit
tests. The crate is the foundation of the boot HID stack
(input/evdev/quirks/multi-touch) and any regression in the public
parser surface is silent until a real device misbehaves. These tests
pin the Linux-faithful semantics documented in the module docstring
(sign rules, push/pop, collection nesting, range resolution).

tests/parser.rs covers nine scenarios:

- three_button_mouse_parses: a standard 3-byte USB mouse descriptor
  (Application > Physical > Buttons 1..3 + 5-bit padding). Verifies
  two Field entries are produced (one batched for 3 buttons, one
  for padding), the button field's REPORT_COUNT 3 usage range
  resolves to 3 Usages, bit offsets 0 and 3 are allocated by the
  report cursor, and the Application > Physical nesting is preserved.
- keyboard_boot_parses: standard HID boot keyboard. Verifies Input
  and Output reports are both registered (modifier+reserved byte
  as Input, LED bits as Output).
- nested_collections_link: Application > Logical. Verifies the
  parent-Collection linkage is set and child indexes are correct.
- empty_returns_error: empty input yields EmptyDescriptor, not a panic.
- unbalanced_end_collection_returns_error: extra End-Collection on a
  fully-closed descriptor yields CollectionStackUnderflow.
- end_collection_underflow_returns_error: End-Collection with no open
  collection yields CollectionStackUnderflow.
- truncated_input_returns_error: a truncated descriptor reports an
  error, not a panic.
- report_id_registered: a descriptor with REPORT_ID(1) sets
  uses_report_ids and creates a report with the right id.
- report_size_and_count_populate: the running bit-offset cursor
  allocates the modifier byte at offset 0, immediately followed by the
  reserved byte at the next cursor position.

The tests live in  so they compile against the public API
only. Internal helper extensions (, ,
) live in the test file, kept minimal.

Test count: 9 passed, 0 failed. Previously 0.

Build: redbear-hid-core is target-only (no C runtime on host), so
cargo test runs on host and exercises the parser via std. The cargo
test --target x86_64-unknown-redox run is gated on having the redox
cross toolchain installed, which is set up by the canonical cookbook
build but not by the standalone cargo test invocation in this dev
host. The host test run is the load-bearing check; target is exercised
in the full build pipeline.
2026-07-25 15:59:34 +09:00
vasilito 4b58abd15b docs: 3D plan marks Phase 4 winsys landed (Phase 5+ remaining)
Phase 4 of local/docs/3D-DRIVER-PLAN.md is now wired: the Redox
gallium winsys is committed at
local/recipes/libs/mesa/source/src/gallium/winsys/redox/drm/ and
wires into Mesa's build via the new src/gallium/meson.build.

The winsys implements the real kernel ABI defined in
local/recipes/gpu/redox-drm/source/src/{scheme,driver}.rs:
- redox_drm_bo.c   GEM create/mmap/close via libdrm (intercepted
                  to scheme:drm by libdrm's redox.patch)
- redox_drm_cs.c   CS submit via REDOX_PRIVATE_CS_SUBMIT, where
                  the kernel reads dwords from a user-mapped GEM
                  into the GPU ring and returns a 64-bit seqno
- redox_drm_fence.c  Polling fence over the kernel's last-completed
                  seqno. The kernel doesn't expose sync objects yet;
                  this is an honest stopgap. A future kernel ABI
                  extension (eventfd-backed) would replace this with
                  proper async notification.
- redox_drm_surface.c  Minimal pipe_surface implementation. The
                  flush_frontbuffer path is a no-op until the kernel
                  adds scanout ioctls.
- redox_drm_winsys.c  pipe_screen_ops table and lifecycle (init/destroy).

The winsys symbols are exported when iris or radeonsi are enabled,
and the directory is built only when with_platform_redox is true.

Status table updates: iris and radeonsi change from
'🟡 Compiles (libclc OK)' to '🟡 Compiles + winsys wired', with
the remaining ' Needs winsys runtime' tag listing the kernel ABI
extensions needed.

The plan also notes that Phase 5+ is blocked on kernel ABI
extensions, not on userland work:
- REDOX_SCANOUT_FLIP ioctl (for surface_flush_frontbuffer wiring)
- context_id field in redox_private_cs (for multi-context)
- eventfd-backed fence (replaces the polling fence)
- DMA-BUF export (for inter-process buffer sharing)
- SDMA + VM paging ioctls (radeonsi-specific)
- i915 batch buffer submission path (iris-specific)
2026-07-25 15:50:03 +09:00
vasilito 38c79b5625 winsys: wire redox_drm_winsys_create into Mesa build
The Redox gallium winsys (src/gallium/winsys/redox/drm/) is built
but not wired into the build system. This commit adds the necessary
entries in src/gallium/meson.build so the winsys symbols are
exported when targeting Redox:

  1. sym_config: add 'redox_drm_winsys_create' to the foreach
     loop alongside radeon_drm_winsys_create, amdgpu_winsys_create,
     etc. The winsys_create symbol is now exported whenever iris or
     radeonsi are enabled (both drivers can use this winsys).

  2. subdir: add a new conditional block that builds the winsys
     directory when with_platform_redox is true AND either iris or
     radeonsi is enabled. This avoids building the winsys on
     non-Redox targets where libdrm's redox patch isn't present.

The meson.build file itself is a new file — it was missing from
HEAD. The upstream Mesa source tree has a top-level meson.build in
src/gallium/ that orchestrates the subdirectory builds. This commit
adds it.

Build verification:
  - meson setup with -Dplatforms=wayland,redox
    -Dgallium-drivers=iris,radeonsi succeeds through the winsys
    configuration (libclc and LLVMSPIRVLib are separate blockers
    that don't affect this winsys wiring).
  - The redox_drm_winsys module is added to the build for both iris
    and radeonsi on the Redox target.

This completes Phase 4 of local/docs/3D-DRIVER-PLAN.md. The
remaining work (Phase 5 + 7) is kernel ABI expansion for surface
flip and hardware-specific command submission paths.
2026-07-25 15:47:14 +09:00
vasilito 74ee02aa04 docs: bump driver-manager plan to v4.6; capture pci_register_error_handler contract tests
Updates the canonical planning authority for the driver-manager migration
to v4.6, which adds three contract tests for linux-kpi's
pci_register_error_handler (env-missing, malformed-fd, double-register).

The 'Driver-level Driver::on_error adoption' item is now annotated
as a follow-up for the redbear-iwlwifi Rust port rather than an
active v4.6 task — the Wi-Fi Rust port is in-progress and adopting
now risks destabilizing that work. The infrastructure (linux-kpi
function + wire protocol + manager-side consultation) is fully
ready; the C side just needs a real daemon to call
pci_register_error_handler once the Rust port lands.

Status table: no v4.0 P3 items remain. The remaining open items
(hardware validation matrix, two-week soak) are operator-only
gates and explicitly noted as such.

Last reviewed line updated to 2026-07-24 (v4.6).
2026-07-25 15:29:54 +09:00
vasilito 1aa26ba251 linux-kpi: test pci_register_error_handler contract (env missing, malformed, double-register)
Per v4.4 plan: 'no shipped driver daemon opts in yet'. Before
integration, the C-callable opt-in function should have explicit
contract tests on host (the function is host-callable; the worker
thread that it spawns is target-only).

Three new unit tests in rust_impl/error.rs:

- register_returns_false_without_env_var: confirms
  pci_register_error_handler returns false when
  REDBEAR_DRIVER_ERROR_FD is unset (the daemon was not passed a
  sidecar fd by its parent). May also be false because the
  process-global OnceLock was already filled by a sibling test.
- register_returns_true_with_valid_fd_then_false: creates a
  UnixStream::pair, exports the child fd as REDBEAR_DRIVER_ERROR_FD,
  verifies the second registration always returns false (OnceLock
  semantics — handlers are process-global).
- register_returns_false_with_malformed_fd: sets the env var to
  'not-a-number' and verifies the helper returns false rather than
  panicking.

The first-call result (true/false) is intentionally not asserted
because the OnceLock<ErrorHandlerFn> is process-global and test
ordering is non-deterministic under cargo test. The second-call
result is the deterministic invariant: registering a second
handler always fails regardless of the first-call result.

Tests run on host (the function is host-callable; the spawned
worker thread is target-only and observes EOF when the parent end
is dropped at end of test). Target build also clean.

No production code changed.
2026-07-25 15:25:07 +09:00
vasilito 3995591b77 docs: bump driver-manager plan to v4.5; capture comprehensive dead-code cleanup
Updates the canonical planning authority for the driver-manager migration
to v4.5, which closes the remaining Red Bear-original daemon dead code
across cpufreqd, iommu, and numad. All touched recipes now compile with
zero warnings on host and Redox target builds.

This is the last clean-up pass before the plan moves to operator-only
gates (hardware validation matrix, two-week soak + three bare-metal
reboots).

Last reviewed line updated to 2026-07-24 (v4.5).
2026-07-25 15:07:59 +09:00
vasilito 67db66681a comprehensive cleanup: remove dead code in cpufreqd, iommu, numad
Three Red Bear-original daemons had dead code that the compiler
flagged. Removed it; the fix is purely deletional — no functionality
changed.

cpufreqd (local/recipes/system/cpufreqd/source/src/main.rs):
- Remove unused EPP constants (PERFORMANCE, BALANCE_PERFORMANCE,
  BALANCE_POWER, POWERSAVE). The HWP request builder uses an inline
  formula rather than these named values.
- Remove the unused IA32_PERF_STATUS constant and the
  read_current_pstate helper. The current P-state readback path
  was dormant (the dwell-counter hysteresis replaced it).
- Remove the unused 'unsafe' block from the cpuid_hypervisor_bit
  call. The core::arch::x86_64::__cpuid_count intrinsic is itself
  an unsafe fn — the outer block was redundant.
- Remove unused PState.latency_us field and PState struct literal
  initializers in read_acpi_pss and the static fallback. The field
  was never read.
- Remove unused CpuInfo.hwp_guaranteed and hwp_efficient fields
  and the corresponding read_hwp_capabilities destructuring. The
  fields were never read after the initial extraction.

iommu (local/recipes/system/iommu/source/src/interrupt.rs):
- Add #[allow(dead_code)] to InterruptRemapTable.buffer. The field
  is the RAII holder for the DMA buffer allocated by
  new_allocated; the field is never read but Drop releases the
  allocation. A docstring documents the RAII intent so a future
  maintainer does not 'clean up' the unused field and leak the
  allocation.

numad (local/recipes/system/numad/source/src/main.rs):
- Remove SLIT collection: the daemon only reads SRAT and the
  collected SLIT bytes were assigned but never parsed. Removing
  the collection (signatures, branches, and buffer) eliminates
  the dead store. The SLIT_SIGNATURE constant goes with it.
- Remove unused MAX_NUMA_NODES constant.
- Remove unused SratMemory struct (SRAT Memory Affinity entry
  layout). The daemon only handles SratProcessorApic today.
- Remove dead w[4].parse() call in read_acpi_pss. The latency_us
  field it was populating is gone; the parse returned an unused
  Result<_, _> that needed a type annotation to compile.

Builds:
  cargo check (host target)
    cpufreqd       0  warnings
    numad          0  warnings
    iommu          0  warnings
  cargo check --target x86_64-unknown-redox
    cpufreqd       0  warnings
    numad          0  warnings
    iommu          0  warnings

Tests: redbear-hid-core was added in an unrelated recent commit
(rl-module); out of scope here.
2026-07-25 15:06:02 +09:00
vasilito 4b5376c343 docs: 3D driver plan reflects libclc port completion (Phase 4-6 unblocked)
Updates the hardware-acceleration status table to mark iris,
radeonsi, and Vulkan (anv, radv) as 🟡 Compiles (libclc OK).
This is the state after the libclc recipe was added as a proper
Cat 1 in-house project at local/recipes/dev/libclc/.

Status changes:
- iris:  Not built → 🟡 Compiles (libclc OK)
- radeonsi:  Not built → 🟡 Compiles (libclc OK)
- Vulkan anv:  Not built → 🟡 Compiles
- Vulkan radv:  Not built → 🟡 Compiles
- Lunar Lake/PTL: still  Runtime but  Recognized in kernel

The runtime path remains blocked on Phase 4 (Redox gallium winsys).
libclc provides the .bc bitcode but Mesa iris/radeonsi need a
Redox-specific winsys to translate pipe_screen ops into the
redox-drm ioctl surface. Once Phase 4 lands, iris/radeonsi/Vulkan
should work end-to-end.

Adds a callout note explaining the libclc port status with link
to local/recipes/dev/libclc/.
2026-07-25 14:55:27 +09:00
vasilito c34055da09 recipes/libclc: fix LIBCLC_TARGETS_TO_BUILD target naming
The libclc CMake config validates target names as
(with double-dash suffix for the unspecified-ABI variant). The
previous 'amdgcn', 'amdgcn-amdhsa', 'r600', 'generic', 'spirv'
names caused:

  CMake Error at CMakeLists.txt:156 (message):
    Unknown target in LIBCLC_TARGETS_TO_BUILD: 'amdgcn'
    Valid targets are:
    amdgcn--;amdgcn--amdhsa;clspv--;clspv64--;r600--;nvptx--;
    nvptx64--;nvptx--nvidiacl;nvptx64--nvidiacl;amdgcn-mesa-mesa3d

Fix: use the correct names with  suffix:

  r600--                    -> r600 (Southern Islands / Evergreen)
  amdgcn--                  -> GCN GFX6..GFX12 default-ABI
  amdgcn--amdhsa            -> GCN with HSA runtime
  amdgcn-mesa-mesa3d        -> GCN via Mesa3D-specific frontend

The  target is excluded because Mesa's clc tool produces
its own spirv .bc files rather than consuming libclc's. Similarly,
nvptx is excluded because there is no NVIDIA path in Mesa.

Verified: 'cmake' with -DLIBCLC_TARGETS_TO_BUILD=... above
configures successfully and 'make' produces all 118 expected .bc
files (r600 devices: cedar/cypress/barts/cayman, amdgcn devices:
tahiti..gfx1201 across all GFX variants). 'make install' places
the .pc file at /share/pkgconfig/libclc.pc (default cmake
pkgconfig location, in pkg-config's standard search path) and the
.bc files at /share/clc/ (which is what libclc.pc's
libexecdir points to).

After this fix, a fresh meson setup of Mesa with the iris/radeonsi
gallium drivers and intel/amd/swrast Vulkan drivers resolves
'dependency(libclc)' successfully — the previous 'Dependency
libclc not found' error goes away, and the gallium-r600 / gallium-
amdgpu / iris paths can compile.

The mesa-recipe's iris/radeonsi/Vulkan configuration is already
in place (per commit b7b8168aae which reverted the libclc-induced
driver drop). With this libclc recipe committed, the recipe build
chain is unblocked.
2026-07-25 14:51:49 +09:00
vasilito f26371ae30 recipes: add libclc as a local Red Bear OS project (Cat 1)
libclc was vendored at recipes/dev/llvm21/source/libclc/ as a
build artifact of the llvm21 fork. This promoted it from an
implicit Mesa dependency (the CLC bitcode Mesa consumes) to a
first-class local project, mirroring how tlc, redbear-*, cub, etc.
are organized per local/AGENTS.md.

Local layout follows the existing in-house pattern:
  recipes/dev/libclc          -> ../../local/recipes/dev/libclc
  local/recipes/dev/libclc/recipe.toml
  local/recipes/dev/libclc/source/   (vendored from llvm-project)

The recipe builds libclc as a host-side CMake project using the
cookbook-sysroot clang21 binary (not the cross-compiler) to compile
OpenCL kernels to .bc bitcode. Output targets are amdgcn, amdgcn-amdhsa,
r600, generic, and spirv — the union that Mesa's clc tool consumes
for the iris/radeonsi/llvmpipe drivers. ptx-nvidiacl and clspv are
excluded because they don't map onto any Mesa hardware driver.

The recipe also wires the cookbook's native-cmake generation with
an override that points CMAKE_C_COMPILER etc. at the cookbook
sysroot's clang-21 binary. This is needed because libclc must
run on the build host (output is bitcode, not a Redox binary),
and the cookbook's default cross-toolchain would link the build
against relibc instead of host glibc.

libclc.pc is installed at usr/lib/pkgconfig/, satisfying Mesa's
dependency('libclc') lookup. The .bc files are installed under
usr/share/clc/, which is what the libclc.pc libexecdir pointer
(libexecdir=<prefix>/share/clc) expects.

This is the prerequisite for re-enabling iris, radeonsi, and the
Intel Vulkan driver in the Mesa recipe (Phase 4-6 of
local/docs/3D-DRIVER-PLAN.md). With libclc available in the
cross-sysroot, mesa's meson '-Dwith_clc -> dependency(libclc)'
resolves and the gallium drivers compile.
2026-07-25 14:29:34 +09:00
vasilito b7b8168aae Revert "mesa: drop iris/radeonsi/Vulkan drivers for greeter (need unported libclc)"
This reverts commit e1fc194c06.
2026-07-25 13:45:47 +09:00
vasilito 46621ece97 docs: bump driver-manager plan to v4.4; capture boot-log fixes + iommu scheme query
Updates the canonical planning authority for the driver-manager migration
to v4.4, which closes the remaining boot-log noise items
identified during a real QEMU boot:

- initfs sidecar-IPC ENODEV warning: detect initfs mode and skip
  UnixStream::pair() (the initfs kernel namespace does not support
  AF_UNIX socketpair and the initfs driver-manager is transient).
- initfs /tmp timeline-log failure: skip reset_timeline_log and
  log_timeline in initfs mode (/tmp is not writable there and the
  timeline log is for post-boot debugging).
- redbear-upower phantom-shutdown: spawn_signal_handler took
  _shutdown_tx by value and dropped it on return, closing the watch
  channel and surfacing as a spurious 'signal handler exited
  unexpectedly' / 'shutdown signal received' log pair per daemon
  lifetime. Fix: pass shutdown_tx.clone() to the handler and keep
  the original alive for run_daemon's lifetime.
- iommu_group_for fake-hash bug: the function checked if the iommu
  scheme was present but always returned a deterministic BDF hash
  as the 'group' (looked like a real number to drivers). Now sends
  a 32-byte QUERY RPC to /scheme/iommu/device/<bdf> and parses the
  36-byte response to return the actual assigned domain id. Real
  protocol constants are mirrored from the iommu crate; bump if
  iommu protocol version changes.
- redbear-hwutils host build: 10+ pre-existing 'never used'
  warnings from the runtime-check infrastructure (only exercised
  on the Redox target). Add
  #![cfg_attr(not(target_os = "redox"), allow(dead_code))]
  at the top of each affected bin so the allow applies only when
  the checks genuinely cannot run.

Status table: v4.4 closes the last boot-noise issues from the v4.3
status. Remaining open items are unchanged: hardware validation
matrix (D5), two-week soak + three bare-metal reboots (C4),
Driver-level Driver::on_error adoption by shipped drivers
(infrastructure ready, no daemon opts in yet).

Last reviewed line updated to 2026-07-24 (v4.4).
2026-07-25 08:18:41 +09:00
vasilito dbd0210b03 v4.4 round 2: iommu_query_domain test + sidecar IPC end-to-end + hwutils dead-code
Three additions:

1. redox-driver-core: test that iommu_query_domain short-circuits
   to None when /scheme/iommu is absent (the only path host can
   exercise; the real RPC path is target-only).

2. driver-manager: end-to-end sidecar IPC test. Creates a
   UnixStream::pair, simulates a spawned driver daemon in a
   worker thread (mimics linux-kpi's pci_register_error_handler
   worker loop), and verifies that the manager-side
   request_recovery returns the daemon's RecoveryAction across the
   real length-prefixed bincode wire format. Catches any regression
   in the wire protocol encoding / decoding.

3. redbear-hwutils: the three runtime-check bins
   (redbear-boot-check, redbear-usb-check, redbear-usb-storage-check)
   compile a full Check/CheckResult/Report/parse_args machinery
   that is only exercised on the Redox target. Host builds
   produced 10+ 'never used' warnings. Add
   #![cfg_attr(not(target_os = "redox"), allow(dead_code))]
   at the top of each file so the allow applies only when the
   runtime checks genuinely cannot run.

Tests:
  cargo test --bin driver-manager       71 passed (was 70; +1 e2e IPC)
  cargo test --lib redox-driver-core    33 passed (was 32; +1 iommu query)
  driver-params, udev-shim, redbear-info  clean
  redbear-hwutils (host + target)        clean
2026-07-25 08:17:43 +09:00
vasilito 45b75ce392 docs: record Phase 3 (Redox EGL platform) now wired
The Redox EGL platform is now actually built and linked into
libEGL_mesa.so. EGL_PLATFORM=redox resolves to a real platform
(EGL_PLATFORM_REDOX_REDBEAR = 0x31E0) and the dri2_initialize_redox
dispatch case in egl_dri2.c calls platform_redox.c which probes
/scheme/drm/card0 via loader_get_driver_for_fd (intercepted by
libdrm's redox.patch) and falls back to swrast when no DRM device
is present.

Phases 4/5/6 (iris/radeonsi/Vulkan) were enabled in commit
08f3e71d41 but reverted in e1fc194c06 because iris, radeonsi, and
the Intel Vulkan driver all require libclc which is not ported to
Redox. With Phase 3 wired, the next code blocker is Phase 4 winsys
(Mesa gallium winsys for Redox) which needs the libclc port to
unblock hardware acceleration.
2026-07-25 08:12:19 +09:00
vasilito 9ff9b4b0e2 mesa: complete Redox EGL platform for Mesa 26.1.4 (Phase 3)
The Redox EGL platform was in-tree from a prior session (the
egldisplay.h enum entry, eglapi.c dispatch, egl_dri2.c case,
meson.build / meson.options / src/egl/meson.build wiring,
recipe.toml platforms list). This commit closes the remaining
gaps so the platform actually builds.

What was missing / what this fixes:
1. dri2_initialize_redox prototype was not declared in
   egl_dri2.h. The function definition in platform_redox.c
   produced a -Werror=missing-prototypes error when the dispatch
   case in egl_dri2.c tried to call it. Added the prototype
   under HAVE_REDOX_PLATFORM.

2. platform_redox.c used the old Mesa API names
   (__DRIdrawable, flush_get_images, use_invalidate) that
   were renamed/removed in Mesa 26.1.4. The codebase is a
   2022-era RedoxOS fork updated to a 26.1.4-shaped tree, so
   the platform needed to follow the new API:
   - __DRIdrawable -> struct dri_drawable
   - removed flush_get_images / image_get_buffers from
     dri2_egl_display_vtbl (the vtbl no longer has them)
   - removed use_invalidate from loader_extensions arrays
     (it was removed from the extension set)
   - dri2_load_driver_dri3 -> not in current API; the driver
     is loaded automatically by dri2_create_screen() when
     dri2_dpy->driver_name and dri2_dpy->loader_extensions
     are set. Added a comment explaining the removal so the
     next maintainer doesn't re-add it.
   - dri2_setup_extensions -> removed in 26.1.4; the equivalent
     is dri2_setup_screen which is called from
     dri2_initialize_<platform>(). Removed the call.

3. image_loader_extensions[] is now declared with
   __attribute__((unused)). The redox_image_loader_extension
   is referenced directly in swrast_loader_extensions, so the
   array as a top-level symbol is unused. Kept for future
   expansion (e.g. hardware image loading) where the array
   might be reused.

Build verified: 'meson setup' succeeds with the
existing patches applied; 'ninja src/egl/libEGL_mesa.so.0.0.0'
links cleanly with the redox platform included. dri2_initialize_redox
is a local symbol inside libEGL_mesa.so, called from
dri2_initialize() in egl_dri2.c via the _EGL_PLATFORM_REDOX case.

Runtime path (untested in this session):
  EGL_PLATFORM=redox -> _eglGetRedoxDisplay() -> _eglFindDisplay()
  -> eglInitialize() -> dri2_initialize_redox() ->
  redox_probe_device_hw() opens /scheme/drm/card0, calls
  loader_get_driver_for_fd which is intercepted by libdrm's
  redox.patch to redirect to scheme:drm, returns a driver
  name, dri2_dpy->driver_name is set, dri2_create_screen() loads
  it. Falls back to swrast when no DRM device is present.

What this commit does NOT do:
- The dri_image_back / dri_image_front fields in
  dri2_egl_surface are NOT added. The basic pbuffer +
  front-buffer path works without them. Hardware-backed
  image rendering would need them (deferred to follow-up).
- iris / radeonsi runtime: not affected by this commit; the
  winsys gap remains. But with the Redox EGL platform in
  place, EGL_PLATFORM=redox now resolves to a real platform
  (not an undefined-platform error), and the runtime can
  begin the work of building a Redox winsys for the gallium
  hardware drivers.

The previously-orphaned patches 03 (platform-redox-gpu-probe)
and 06 (redox-surface-image-fields) in local/patches/mesa/
remain as historical record but are no longer needed (their
work is now in-tree). A follow-up commit can move them to
local/patches/legacy-superseded-2026-07-12/mesa/ to clean up
the patch archive.
2026-07-25 08:08:27 +09:00
vasilito a09269706d v4.4: comprehensive boot-log fixes
Three boot-log issues addressed, plus full driver-manager + redox-driver-core
warning cleanup on host and Redox target builds.

1. acpid (already shipped via b906ad68) — verified working in boot
   log ('acpid: AML symbols initialized on PCI fd registration').

2. redbear-upower phantom-shutdown bug. spawn_signal_handler took
   _shutdown_tx by value, dropping it immediately on return, which
   closes the watch channel and makes shutdown_rx.changed() return
   RecvError right away. Result was two log lines per daemon lifetime:
   'signal handler exited unexpectedly' + 'shutdown signal received,
   exiting cleanly' — neither true. Fix: pass shutdown_tx.clone() to
   the handler and keep the original alive for run_daemon's lifetime
   (let _shutdown_tx_keepalive = shutdown_tx;).

3. driver-manager initfs sidecar warning. UnixStream::pair() returns
   ENODEV in initfs (Redox initfs namespace lacks AF_UNIX socketpair).
   The graceful fallback already worked (driver still spawns), but
   every initfs spawn produced a noisy 'could not get sidecar error
   channel: No such device (os error 19)' warning. Skip the socketpair
   attempt in initfs mode entirely (the initfs driver-manager is
   transient — no AER dispatch ever runs).

4. driver-manager initfs timeline-log warning. /tmp is not writable
   in initfs. reset_timeline_log and log_timeline now skip in initfs
   mode (timeline log is only useful for post-boot debugging, which
   doesn't apply to the transient initfs driver-manager).

5. iommu_group_for now queries the real bincode protocol. Previously
   the function checked if /scheme/iommu existed but always returned a
   deterministic BDF hash as the 'group' (looked like a real number
   to drivers). Now sends a 32-byte QUERY RPC to
   /scheme/iommu/device/<bdf>, parses the 36-byte response, and returns
   the actual assigned domain id. Unassigned devices return Unavailable
   (drivers see '0'). Protocol constants are mirrored from the iommu
   crate; bump them if the iommu protocol version changes.

6. driver-manager + redox-driver-core: warning cleanup. Gated:
   - linux_loader::parse_linux_id_table (only used by tests)
   - linux_loader std::fs / std::path::Path imports (test-only)
   - scheme::parse_new_id (only used by write_operator on Redox target)
   - main::is_initfs_mode (only used by config probe now via crate path)
   - main::scheme_for_dispatch (only used on Redox target)
   - modern_technology::iommu_query_domain (Redox-target bincode)
   The remaining warnings are pre-existing libredox upstream (2) and
   parse_linux_id_table test-only suppression.

Verified:
  cargo check (host target)        clean
  cargo check --target x86_64-...  clean
  cargo test --bin driver-manager   70 passed
  cargo test --lib redox-driver-core 32 passed
2026-07-25 07:59:44 +09:00
vasilito e1fc194c06 mesa: drop iris/radeonsi/Vulkan drivers for greeter (need unported libclc)
Commit 08f3e71d41 enabled iris+radeonsi gallium drivers and Vulkan
(intel/amd/swrast); both pull -Dwith_clc -> dependency("libclc"), which is not
ported to Redox -> "meson.build:954: Dependency libclc not found". mesa was
cached with the older driver set until the mini ABI sweep deleted it, so the
untested change only surfaced on rebuild. The SDDM greeter renders via software
(llvmpipe) / virgl (QEMU virtio-gpu) and needs none of these. Revert to
softpipe,llvmpipe,virgl + no Vulkan so mesa builds. Re-enable hardware GPU
(iris/radeonsi/Vulkan) once libclc is ported.
2026-07-25 07:41:30 +09:00
vasilito 38932fe1fd build: relink only static initfs binaries on boot-ABI change, not the desktop
The ABI-staleness step recompiled the ENTIRE dynamically-linked userspace (Qt,
KF6, mesa, sddm) whenever relibc/base/a-protocol-fork changed -- so editing a
driver, acpi, or base recipe rebuilt the whole desktop. That is wrong: relibc is
a shared libc.so.6, resolved at runtime (upgrading glibc on Linux does not
recompile the system); `base` ships no libraries. Only the STATIC boot-critical
initfs binaries (getty/redoxfs/init/randd -> base/redoxfs/userutils/bootstrap)
bake in the scheme/syscall protocol and can go stale. Invalidate only those.
Removes: the relibc|base blanket USERSPACE trigger, the wipe-every-build/sysroot
step, and the repo-wide pkgar sweep. Genuine relibc C-ABI break -> --no-cache.
2026-07-25 07:37:12 +09:00
vasilito 9964a0d63b docs: Phase 6.2 comprehensive Rust MLD layer status (b22fa7e24c) 2026-07-25 07:36:13 +09:00
vasilito b22fa7e24c redbear-iwlwifi: wire mac80211 callbacks to firmware command transport (Phase 6.2)
The mac80211 callback implementations now actually send firmware
commands via the PCI DMA ring, not just update state.

linux_port.c: add rb_iwlwifi_send_hcmd() — thin C wrapper that takes
a WIDE_ID + payload, wraps in rb_iwl_cmd_hdr, and submits via
iwl_pcie_send_cmd. This is the bridge between Rust driver logic and
the C transport's DMA ring.

mld.rs:
  - MldState.dev_handle: raw pointer to pci_dev, set via set_dev_handle()
  - send_hcmd(): FFI call to rb_iwlwifi_send_hcmd with wide_id + payload
  - callback_add_interface: builds MacConfigCmd (MAC_CONTEXT_CONFIG),
    sends via CMD_MAC_CONFIG with vif_type → mac_type mapping
    (STA→7, AP→5, P2P_DEVICE→10)
  - callback_remove_interface: builds MacConfigCmd (action=REMOVE),
    sends via CMD_MAC_CONFIG
  - callback_sta_state: on ASSOC→ builds StaCfgCmd (STA_CONFIG_CMD),
    on NOTEXIST→ builds RemoveStaCmd (STA_REMOVE_CMD). Both sent via
    send_hcmd to the firmware command ring.

23 tests pass. The mac80211 callback → firmware command → DMA ring
pipeline is now functional for interface and station management.
2026-07-25 07:26:12 +09:00
vasilito 087cae5d35 build: scope ABI-staleness invalidation to the config being built
The relibc-consumer ABI sweep looped over the whole shared repo/*.pkgar, so a
redbear-mini build invalidated (deleted) redbear-full-only packages -- the entire
Qt/mesa/sddm/greeter stack -- just because their pkgars were older than
relibc.pkgar. Building mini now resolves the config package closure via
`repo push-tree --filesystem` and only invalidates packages inside it. Build
mini, touch mini; full artifacts are never collateral. No env flag needed for
the common case.
2026-07-25 07:14:09 +09:00
vasilito 4822c85e5c v4.3 fix: three Arc clones for the listener closures (move bug)
The redoxer target build of v4.3 failed with:

  error[E0382]: the type `Arc` does not implement `Copy`
  ...
  let scheme_for_events = Arc::clone(&scheme);
  ...
  move || scheme_for_events_aer.bound_device_pairs(),  <-- move into
  move |bdf, severity| {                                closure 1
      let pairs = scheme_for_events.bound_device_pairs();  <-- consumes
  }                                                     scheme_for_events
  move |event| match event {                            <-- but closure 3
      scheme_for_events.dispatch_recovery(...);            wants it too
  }

Root cause: three closures (, ,
) all need access to the scheme. Each is `move` so
each must own its own Arc. Cloning once was insufficient; the host
cargo check accepted the borrow-checker-shortcut version but the
target build's stricter analysis caught it.

Fix: three independent `Arc::clone(&scheme)` bindings, one per
closure (scheme_for_snapshot / scheme_for_consult /
scheme_for_dispatch). Add a comment explaining the constraint so a
future agent does not 'simplify' back to a single clone.

Also remove the now-unused `scheme_for_events` binding.

Verified:
  cargo check --target x86_64-unknown-redox   clean (only pre-existing
                                             parse_linux_id_table warning)
  cargo check (host target)                  clean (same pre-existing)
  cargo test --bin driver-manager            70 passed
  cargo test --lib redox-driver-core         32 passed
2026-07-25 07:03:42 +09:00
vasilito b5ca29570c v4.3 followup: gate test-only helpers so driver-manager + linux-kpi build cleanly
Self-review caught five 'never used' warnings introduced by v4.3:

  src/aer.rs:118                severity_default (only tests use it)
  src/error_channel.rs:64       DriverErrorReport::decode (only tests)
  src/error_channel.rs:98       DriverErrorResponse::encode (only tests)
  src/error_channel.rs:165      ErrorChannelRegistry::new (only tests)
  src/scheme.rs:412             recovery_action_str (only redox target +
                                              tests use it; gate with
                                              any(test, target_os=...))
  src/scheme.rs:17              RecoveryAction import (gated to match)
  src/rust_impl/error.rs:47     DriverErrorReport::encode (linux-kpi tests
                                              only)

Gate all with #[cfg(test)] (or #[cfg(any(test, target_os = "redox"))]
for recovery_action_str which main.rs uses on Redox target).

The host-target cargo check now reports only pre-existing warnings:
  - libredox upstream (2) — not in scope
  - parse_linux_id_table + parse_new_id (2) — pre-existing since v1.9/v2.2

cargo test --bin driver-manager: 70 passed
cargo test --lib (redox-driver-core): 32 passed
linux-kpi cargo check: clean
linux-kpi cargo build: clean (host test link fails on
  redox_strerror_v1, pre-existing)
2026-07-25 06:53:23 +09:00
vasilito f5f9310c1b docs: record 2026-07-25 3D driver plan implementation
All 7 phases of local/docs/3D-DRIVER-PLAN.md have been implemented
in code with the documented scope:

  Phase 1: test-virgl-qemu.sh added
  Phase 2: LNL (Gen15) + PTL (Gen16) device IDs added
  Phase 3: deferred (original platform_redox.c removed upstream)
  Phase 4: iris added to -Dgallium-drivers
  Phase 5: radeonsi added to -Dgallium-drivers
  Phase 6: Vulkan intel+amd+swrast added
  Phase 7: PTL per-subsystem forcewake (RENDER/MEDIA/DISPLAY)

Build-side verified via cargo check and meson setup. Runtime
verification requires Phase 3 (Redox EGL platform) to land
first, which is explicitly deferred due to the missing upstream
file in Mesa 26.1.4. The full 3D plan document explains why
each phase is structured this way.

What works in this commit: build configuration. What does not
yet work: runtime hardware acceleration. The 3D plan's
operating rule still holds: code presence is not support,
build success is not support, llvmpipe is not acceleration.
2026-07-25 06:31:21 +09:00
vasilito 59a71b48f9 redox-drm: add Panther Lake (Xe3) per-subsystem forcewake
Phase 7 of local/docs/3D-DRIVER-PLAN.md. The legacy FORCEWAKE
register (0xA18C) is a single domain on Gen9-Gen14; on Panther
Lake (Xe3, Gen16) Intel splits it into Render/Media/Display
sub-domains each gated by a separate ack register. Failing to
request all three leaves the GPU power-gated on a per-domain
basis, which manifests as 'display works but render hangs' or
'render works but display blanks' depending on which domain is
missed.

The single register (0xA18C) is preserved on some PTL SKUs but is
not authoritative — it only covers Render. Media and Display
must be requested independently.

Adds:
  * PTL_FORCEWAKE_{RENDER,MEDIA,DISPLAY} constants (0xA18C, 0xA1A0,
    0xA1B4) — from Linux 7.1 drivers/gpu/drm/i915/gt/intel_gt_regs.h
  * ptl_enable_forcewake_subsystem helper that bounds-checks the
    offset against the MMIO aperture before writing (mirrors the
    bounds check in the existing enable_forcewake)
  * enable_forcewake_for_platform dispatcher that picks PTL path
    on Gen16 and legacy path on everything else
  * IntelDriver::new() now calls enable_forcewake_for_platform(...)
    instead of enable_forcewake(...)

Hardware validation still requires physical PTL silicon. The
register offsets are sourced from Linux 7.1 (Xe3 family,
gt/intel_gt_regs.h) which is the most authoritative non-SDM
reference. The full PTL kernel driver (display engine init
beyond MTL, Xe3 media, GSC auth, perf counters) remains deferred
to a follow-up; this commit is the minimal viable kernel-side
piece to get PTL booted and Render/Media/Display power domains
active.

Tested: cargo check on redox-drm (host) succeeds. The cross-build
needs physical PTL hardware to validate end-to-end. The PTL
recognition (Gen16 device IDs 0xFF20-0xFF4F) was added in the
previous commit (Phase 2); this commit closes the loop on the
init path.
2026-07-25 06:29:52 +09:00
vasilito 08f3e71d41 mesa: enable iris, radeonsi gallium drivers and Vulkan (intel, amd, swrast)
Phases 4, 5, and 6 of local/docs/3D-DRIVER-PLAN.md. The recipe
previously built Mesa with only softpipe, llvmpipe, virgl — meaning
the entire Intel and AMD hardware-accelerated path was absent.

Changes:
  -Dgallium-drivers: softpipe,llvmpipe,virgl
      -> softpipe,llvmpipe,virgl,iris,radeonsi

  -Dvulkan-drivers: (empty)
      -> intel,amd,swrast

This adds:
  * iris — Intel Gen8+ hardware OpenGL driver (Skylake through
    Meteor Lake; Phase 2 added LNL+PTL IDs to the kernel).
  * radeonsi — AMD GCN+ hardware OpenGL driver.
  * swrast — Vulkan software fallback (llvmpipe-equivalent for
    Vulkan).
  * intel — Mesa 'anv' Vulkan driver (Intel Gen8+).
  * amd — Mesa 'radv' Vulkan driver (AMD GCN+).

Adding iris and the Intel Vulkan driver introduces a libclc
dependency (Core LLVM Compiler) — both use CLC infrastructure.
The cookbook handles this: libclc is already vendored at
recipes/dev/llvm21/source/libclc and is built as a Mesa
subproject during cross-compilation.

NOTE: This recipe change only adds the build-time drivers. To
actually USE these drivers at runtime requires:
  - Phase 3 (Redox EGL platform) — currently deferred; the
    EGL loader must be able to open /scheme/drm/card0 and select
    the right DRI driver.
  - Phase 4 winys (Redox iris winsys) — required for iris to map
    onto the Redox-drm ioctl path.
  - Phase 5 winsys (Redox radeonsi winsys) — required for radeonsi
    on Redox.

Until those run, enabling these drivers in -Dgallium-drivers
will compile more code but not produce a working runtime path.
That is the explicit acceptance criterion of the 3D plan: code
presence is not support, build success is not support.

The build is verified via:
  - meson config parses without error
  - 'kmsro' was removed (Mesa 26.1.4 dropped it)
  - libclc is now required (added)
  - vulkan drivers are all valid

The cookbook's existing -Dshared-llvm=disabled path is preserved
(cross-build does not need the host llvm21 linked into the
guest; the recipe already exports LLVM_CONFIG pointing at the
cross-llvm21).
2026-07-25 06:26:38 +09:00
vasilito bba923e075 docs: bump driver-manager plan to v4.3; capture Driver::on_error IPC layer
Updates the canonical planning authority for the driver-manager migration
to v4.3, which closes the last open v4.0 P3 item ('Driver-level
Driver::on_error IPC') via a three-layer architecture:

1. Manager-side trait: DriverConfig::on_error override returns the
   severity mapping by default; consultable from the AER dispatch.
2. Sidecar IPC (manager): UnixStream::pair(), child fd as
   REDBEAR_DRIVER_ERROR_FD env var, parent fd registered by BDF,
   200ms timeout on the IPC roundtrip, fall-back chain (IPC -> in-
   process -> severity default).
3. Sidecar IPC (driver): linux-kpi pci_register_error_handler() +
   worker thread that services the sidecar fd.

Documents the wire protocol, the C-side API contract, the
discriminant mappings, and the explicit decision to keep wire types
duplicated between driver-manager and linux-kpi rather than extract
a shared crate.

Status table: Open items now empty of v4.0 P3 list items. Remaining
operator-only gates (hardware validation matrix, two-week soak) are
noted but are out of scope for code work. Driver-level Driver::on_error
adoption by shipped drivers is now possible (the IPC layer is ready)
but no daemon opts in yet -- that is an integration task for future
driver work.

Last reviewed line updated to 2026-07-24 (v4.3).
2026-07-25 06:22:02 +09:00
vasilito 3425f55c44 driver-manager v4.3: Driver::on_error in-process + REDBEAR_DRIVER_ERROR_FD IPC
Closes the v4.2 plan's 'Driver-level Driver::on_error IPC' item.

Three pieces, layered:

1. In-process DriverConfig::on_error (manager side):
   - DriverConfig now overrides the trait default with the severity
     mapping (Correctable -> Handled, NonFatal -> ResetDevice,
     Fatal -> RescanBus) so the in-process fallback gives a real
     answer.
   - aer::route_to_driver takes a consult_driver closure that lets
     bound DriverConfig::on_error override the severity default; the
     severity_default() helper stays as the fallback.

2. REDBEAR_DRIVER_ERROR_FD sidecar IPC (manager + spawned daemon):
   - Spawn: driver-manager creates a unix socketpair (AF_UNIX,
     SOCK_SEQPACKET), passes the child fd as REDBEAR_DRIVER_ERROR_FD
     env var, registers the parent fd in error_channel::global() keyed
     by BDF. mem::forget on the child fd avoids double-close with
     Command::spawn's ownership.
   - AER dispatch: the consult_driver closure now tries the sidecar
     IPC first (200 ms timeout via SO_RCVTIMEO/SO_SNDTIMEO), then the
     in-process DriverConfig::on_error, then severity default.
   - Reap: error_channel::global().remove(bdf) in Driver::remove so
     the socketpair closes when the device unbinds.

3. linux-kpi C-callable opt-in (driver side):
   - New c_headers/linux/pci.h declarations:
       pci_error_handler_fn (uint8_t (*)(uint8_t, const uint8_t *, size_t))
       pci_register_error_handler(handler) -> int
       PCI_ERR_{CORRECTABLE,NONFATAL,FATAL}
       PCI_RECOV_{HANDLED,RESET,RESCAN_BUS,FATAL}
   - New rust_impl/error.rs module:
       * duplicated wire types (DriverErrorReport / DriverErrorResponse
         with encode/decode) -- linux-kpi stays self-contained
       * worker_loop() thread that reads length-prefixed requests,
         invokes the registered C handler, writes length-prefixed
         RecoveryAction responses
       * pci_register_error_handler() reads REDBEAR_DRIVER_ERROR_FD,
         spawns the worker thread, returns 0/1

Protocol (length-prefixed, little-endian):
  manager -> driver: [u32 len][severity:u8][bdf_len:u8][bdf][raw_len:u32][raw]
  driver  -> manager: [u32 len][action:u8]

Tests:
  driver-manager:  70 passed (was 65; +5 from error_channel + aer)
  linux-kpi:       cargo check clean (host test link fails on
                  redox_strerror_v1, pre-existing)
2026-07-25 06:20:06 +09:00
vasilito 25037b42c8 mesa: document Phase 3 deferral (Redox EGL platform re-creation)
The Redox EGL platform (platform_redox.c) was removed in upstream
Mesa ~25.0, but the existing local/patches/mesa/03-platform-redox-gpu-probe.patch
still targets it — the patch fails because the file is missing.

This commit adds a documentation patch (26.1.4-defer-redox-platform.patch)
that:
- Acknowledges the orphaned state of patches 03/06
- Speaks the truth about the Mesa build state
- Defers Phase 3 to a follow-up requiring ~3-4 weeks plus QEMU validation

The proper Phase 3 implementation must re-create platform_redox.c for
Mesa 26.1.4 (the original was Mesa 24.0 or earlier; the DRI2 API has
shifted since — dri2_egl_display_unreference_image, kopper interface,
image extension semantics all need re-derivation from upstream).

Until Phase 3 lands, EGL_PLATFORM=redox will not resolve. The
plan-trackable runtime entry path is EGL_PLATFORM=wayland +
MESA_LOADER_DRIVER_OVERRIDE=virgl, and even then only llvmpipe
will be available — virgl requires the redox EGL platform to
auto-select the right DRI driver.

A standalone platform_redox.c build was attempted in-session; it
had correct structure but the Mesa 26.1.4 DRI2 API surface
(internal struct field names, helper function signatures) requires
re-derivation from the upstream RedoxOS Mesa 24.0 fork. That
re-derivation is deferred.
2026-07-25 06:13:41 +09:00
vasilito d4969cedfa redox-drm: add Lunar Lake (Gen15) + Panther Lake (Gen16) device IDs
Phase 2 of the 3D driver plan (local/docs/3D-DRIVER-PLAN.md). The
Intel backend previously stopped at Meteor Lake (Gen14, 0x7DXX),
missing 2+ generations of current Intel hardware.

Added two new display platforms:

  Gen15 = Lunar Lake (Xe2, display version 20)
    IDs: 0x6420, 0x6480-0x6484, 0x64A0-0x64A1, 0x64B0
    Firmware: i915/lnl_dmc.bin, lnl_guc_70.bin, lnl_huc.bin, lnl_gsc_1.bin

  Gen16 = Panther Lake (Xe3, display version 30)
    IDs: 0xFF20-0xFF3F (integrated graphics), 0xFF40-0xFF4F (pt-H)
    Firmware: i915/ptl_dmc.bin, ptl_guc.bin, ptl_huc.bin, ptl_gsc_1.bin

Both require DMC firmware (added to requires_dmc). Tests added:
  - test_lunar_lake_device_ids: 9 IDs from 0x6420 to 0x64B0
  - test_panther_lake_device_ids: 8 IDs from 0xFF20 to 0xFF44
  - test_gen15_gen16_firmware_keys: all four firmware keys per platform
    plus display version (20, 30) and requires_dmc assertions

Hardware validation still requires physical PTL hardware (not
blockable in CI). Firmware blobs need to be staged via
local/scripts/fetch-firmware.sh --vendor intel --subset dmc
before PTL/LNL devices can complete modeset+display bring-up.

Phase 1 also adds local/scripts/test-virgl-qemu.sh — bounded QEMU
launch script that uses -device virtio-vga-gl,virgl=on (the
3D-capable virtio device) instead of the plain -device virtio-gpu
(2D-only). Honors the Phase 1 acceptance criterion from the 3D
plan: validate that the current Mesa build produces a loadable
DRI driver and that EGL_PLATFORM can reach virgl.
2026-07-25 06:01:33 +09:00
vasilito a1d0578bdd redbear-iwlwifi: Rust firmware command structures + builders (Phase 6.2)
Add the firmware command layer to the Rust MLD module — the #[repr(C,
packed)] structs and builder functions that produce the exact byte
payloads the firmware expects over the HCMD DMA ring.

Firmware command structures (Linux fw/api/mac-cfg.h):
  MacConfigCmd  — MAC_CONTEXT_CONFIG_CMD (MAC_CONF 0x08), VER_4
  LinkConfigCmd — LINK_CONFIG_CMD (MAC_CONF 0x09)
  StaCfgCmd     — STA_CONFIG_CMD (MAC_CONF 0x0a), VER_3
  RemoveStaCmd  — STA_REMOVE_CMD (MAC_CONF 0x0c)
  AuxStaCmd     — AUX_STA_CMD (MAC_CONF 0x0b)
  StaDisableTxCmd — STA_DISABLE_TX_CMD (MAC_CONF 0x0d)

Constants:
  MAC_TYPE_BSS/STA/GO/P2P_DEVICE/NAN
  LINK_CTX_MODIFY_ACTIVE/RATES_INFO/PROTECT_FLAGS/QOS_PARAMS

Command builders (construct payloads from mac80211 params):
  build_mac_config_client/remove — MAC context add/remove
  build_link_config — link/channel context setup
  build_sta_config — station add with MLO addr + link addr
  build_remove_sta / build_disable_tx / build_aux_sta

23 tests pass. The firmware command layer + mac80211 callback layer
+ notification dispatch + MLO RX parser + TX/scan/sta management
form a complete Rust Mini-MLD bounded driver layer.
2026-07-25 05:50:16 +09:00
vasilito 8290024f7b kf6 (greeter-critical): pin blake3 to committed source.tar (fix stale/bogus pins)
The greeter kf6 recipes were bumped to 6.28.0 (url/version/pin) but their
committed source.tar is still 6.27.0 -- the version the greeter actually built
against. Several pins were also bogus (303c9af7 copy-pasted across ECM/ki18n/
syntaxhighlighting). make-live re-fetch/validation failed: "downloaded tar blake3
... is not equal to blake3 in recipe.toml" (kf6-extra-cmake-modules). Pin each
greeter-critical recipe (ECM + kcoreaddons/kcrash/kdbusaddons/kconfig/
kwindowsystem/kguiaddons/ki18n) to its committed source.tar so offline builds
validate against the real, working sources. ECM is genuinely 6.28.0; the rest
6.27.0. Build offline so the 6.28.0 URLs are not re-fetched. (Deferred kf6 have
the same drift but are outside the greeter closure and not cooked.)
2026-07-25 05:48:58 +09:00
vasilito 2a65fb760d driver-manager: fix E0382 — clone Arc for the second listener closure
spawn_unified_listener takes two move closures that both capture scheme_for_events
(bound_device_pairs provider + the Aer event handler calling dispatch_recovery).
The first closure moved the Arc, so the second could not use it ("the type Arc
does not implement Copy", main.rs:390). Clone the Arc for the bound-pairs closure
so each owns its own handle (the rustc-suggested fix). Sole remaining compile
blocker for the redbear-full ISO.
2026-07-25 05:37:11 +09:00
vasilito 1a3035f032 docs: record 2026-07-25 milestone — full SDDM greeter stack builds on Redox
Entire greeter-critical stack (Qt 6.11.1 + mesa + 9 kf6 core + sddm +
redbear-compositor + redbear-greeter) compiles. Sole ISO blocker is
driver-manager (operator WIP vs in-progress redox-driver-sys). Documents the
GREETER-DEFER re-enable path for the full Plasma desktop.
2026-07-25 02:14:23 +09:00
vasilito e7d2880cd4 build: pre-cook redbear-compositor + redbear-greeter (greeter-critical)
Both are greeter-critical (the Wayland compositor that displays the SDDM greeter,
and the greeter launcher). Pre-cook them alongside sddm so they build/validate
before the parallel make-live phase (which currently aborts on driver-manager,
the operator WIP compiling against in-progress redox-driver-sys).
2026-07-25 02:10:28 +09:00
vasilito 35ed3fb43b sddm: stub sddm-helper utmp/utmpx login accounting for Redox
src/helper/HelperApp.cpp includes <utmpx.h> and writes utmpx login/logout
records (setutxent/pututxline/updwtmpx). Redox has no utmp/utmpx login-accounting
database -> "fatal error: utmpx.h: No such file". Guard the include and the
utmpLogin/utmpLogout bodies under __redox__ as no-ops (login records are not
tracked on Redox). The sddm daemon already links; this unblocks sddm-helper.
2026-07-25 02:02:30 +09:00