On QEMU's default i440FX machine type, rdmsr on unsupported MSRs
(0x19c IA32_THERM_STATUS, 0x1a2 IA32_TEMPERATURE_TARGET) causes a
kernel #GP that kills the process. Same pattern as cpufreqd: spawn a
child with --probe-msr to test readability before the main loop. If
probe fails, disable all MSR reads and report all CPUs as Unknown.
coretempd uses syscall::call::write() for init notification, which
sends raw bytes — not an fd transfer via CallFlags::FD that the Scheme
init type expects. Changing to Scheme would cause init to block forever
in call_ro waiting for an fd that never arrives in the expected format.
The oneshot_async + resilience pattern is correct for coretempd.
- 29_activate_console.service: oneshot -> oneshot_async (unblocks init
scheduler, enabling getty 2 -> login)
- 15_coretempd.service: oneshot_async -> {scheme="coretemp"} (init
now correctly registers the scheme fd)
- cpufreqd: child-process MSR probe detects QEMU's lack of MSR 0x199
and gracefully degrades to monitoring-only mode
- coretempd: notification failure is now non-fatal (WARN instead of ?)
- driver-manager: "no match entries" downgraded from warn to debug
(infrastructure daemons intentionally have no hw match)
When handle_irq() returns Ok(None) (no IRQ event received),
also call poll_hotplug() to detect connector changes via
HPD register polling fallback. Events are fed through the
same event channel to the scheme handler.
- Fix redox_pci_enable_device to track enabled state instead of noop.
redox_pci_set_master now logs bus master enable.
- Fix redox_request_irq to return the IRQ fd instead of open+close.
redox_free_irq now accepts fd via dev_id and actually closes it.
- SETPLANE now returns EOPNOTSUPP instead of silently succeeding,
with warning about DC dependency.
- OBJ_SETPROPERTY now accepts CRTC_ID (property 30) as a noop
(connector routing is managed by SETCRTC).
- Add blob registry (blobs: BTreeMap<u32, Vec<u8>>) to DrmScheme with
create_blob()/blob_data() methods for property blob storage.
- Fix GETPROPBLOB to return actual blob data instead of echoing back
the request payload. Unknown blob IDs return zero-length blobs.
- Add MODE_ATOMIC ioctl stub: test-only commits return success,
nonblock/page-flip commits delegate to legacy path.
- Add CRTC_PROP_GAMMA_LUT_SIZE (immutable range, min=0 max=256)
and CRTC_PROP_GAMMA_LUT (atomic blob) properties.
- Update crtc_count in GETRESOURCES from 1 to 4 (matches AmdDriver).
- Rename synthetic EDID monitor name from 'Synthetic DP' to
'RedBearSynthDP' for honest origin identification.
- Support 4 CRTCs instead of hardcoded 1 (AMD GPUs have 4-6 CRTCs)
- Add CONN_PROP_DPMS (ID 31) and CONN_PROP_EDID (ID 32) connector properties.
DPMS is an enum property (On/Standby/Suspend/Off). EDID is an immutable blob.
- Add DrmModeObjSetPropertyWire struct and wire OBJ_SETPROPERTY ioctl to
call driver.set_property() with proper error dispatch. Unknown properties
are silently ignored (not errors).
- Add set_property() to GpuDriver trait with default Unsupported impl.
AmdDriver implements DPMS property set by mapping connector_id -> CRTC and
calling DisplayCore::set_dpms().
Lines 649-651 had VramManager and info!() calls that don't belong
in handle_irq(). These were likely from a bad merge. The variables
fb_phys and fb_size are local to new() and don't exist in handle_irq().
- Add VramManager (vram.rs): bump-allocator with free-list coalescing for BAR2 VRAM
aperture. gem_create auto-selects VRAM for scanout buffers (width>0 && height>0)
with fallback to system RAM on exhaustion. gem_close frees VRAM when gpu_addr is
within BAR2 range. ensure_gem_gpu_mapping detects VRAM-backed buffers and skips
GTT mapping.
- Add amdgpu_dc_upload_firmware() stub documenting DMUB firmware upload sequence
prerequisites (requires Linux DC tree compilation).
- Replace generic 'unavailable' CS ioctl/virgl error messages with specific
messages documenting what component is needed (amdgpu core driver, Mesa radeonsi/
iris cross-compilation, CS ioctl backend).
- Fix ASIC detection: use PCI device_id instead of broken MMIO offset-0 read.
Add proper device_id->ASIC family lookup table covering Navi10-Navi33 (RDNA1/RDNA2/RDNA3).
Add per-family properties (DCN revision, firmware name, OTG/HUBP base offsets, HPD register).
- Wire quirk flags from Rust to C: replace pci_get_quirk_flags/pci_has_quirk stubs
(previously always returned 0/false) with stored quirk_flags set via new FFI
redox_pci_set_quirk_flags(). Quirk-aware IRQ policy now actually works.
- Store firmware blobs from Rust to C: add redox_firmware_store() FFI to pass
firmware blobs from AmdDriver.firmware HashMap into C-side storage. C side
can now fall back to scheme:firmware if blobs not pre-stored.
- Fix connector descriptors: replace hardcoded 600x340mm fake dimensions with
per-ASIC-family connector tables (desktop dGPU vs APU layout). Set mm_width/
mm_height to 0 (unprobed — needs DC hardware detection). HPD register offset
now comes from per-family asic_props table.
- Fix register offsets: replace hardcoded OTG base 0x4800 / HUBP base 0x5800
(Navi23-specific) with per-DCN-revision dispatch from asic_props table
(DCN2.0=0x4000/0x5000, DCN3.0=0x4800/0x5800, DCN3.2=0x5000/0x6000).
Add pcid-spawner to initfs binaries for early boot driver spawning.
Add pcid.d/00-storage.toml with initfs-path driver commands.
pcid-spawner uses the channel protocol which works; driver-manager
hangs on pcid config handle reads.
- Skip binary existence check in probe(): Redox scheme paths
(especially /scheme/initfs/) may block on open/stat indefinitely.
Command::new() spawn fails cleanly if binary missing.
- In initfs mode: use synchronous probe, do bounded deferred
retries, then exit. Rootfs instance handles hotplug.
- Avoids pcid config handle read hang that blocks async threads.
Extracted from local/reference/linux-7.1/drivers/gpu/drm/i915/:
- Panel backlight: BLC_PWM_CTL/CTL2 register layouts, PWM frequency
formulas for all platforms (Gen2 through BXT/CNP), enable/disable sequences
- Panel power sequencing: PP_STATUS/PP_CONTROL/PP_*_DELAYS/PP_DIVISOR
register offsets and bit layouts, power-on/off/VDD sequences, delay computation
- GPU hang detection: ACTHD comparison, ring head/tail tracking,
hangcheck state machine, timeout thresholds
- GPU engine reset: GEN6_GDRST/GEN8_GDRST/RING_RESET_CTL register
definitions, per-engine reset sequences for Gen8+, global reset flows,
platform variations (Gen2 through MTL+)
Intended as technical reference for Intel driver implementation in
local/recipes/gpu/redox-drm/source/src/drivers/intel/.
Four fixes from the code quality and Linux cross-reference audit:
1. DP AUX endianness (dp_aux.rs): Data packing must be big-endian
(MSB first, bits [31:24] = byte 0), matching Linux i915
intel_dp_aux_pack(). Fix send: (3-j)*8 shift. Fix receive:
to_be_bytes(). This was the #1 correctness bug — wrong endianness
would corrupt all DP AUX transactions.
2. Cursor pipe_select collision (cursor.rs): Mode and pipe select
were using the same bit positions. Fix: pipe_select at [29:28],
mode_64x64_argb = 0x27 per Intel PRM CUR_CTL register layout
and Linux MCURSOR_MODE_64_ARGB_AX + CURSOR_PIPE_SELECT.
3. Missing DP link training constants (dp_link.rs): Add
DP_LANE_CR_DONE, DP_LANE_CHANNEL_EQ_DONE, DP_LANE_SYMBOL_LOCKED
used in clock_recovery() and channel_equalization().
4. Missing ARL device ID (info.rs): Add 0x7D67 Arrow Lake-S
from Linux INTEL_ARL_S_IDS.
Replace the hard stub in display.rs::read_edid_block() with a real
GMBUS I2C EDID read. Fixes the #1 plan gap identified in the
code quality audit.
- display.rs: add gmbus: Option<GmbusController> to IntelDisplay
struct and new() constructor. read_edid_block() now calls
gmbus.read_edid() via GymbusPort::from_connector_index().
Falls back to DriverError if no GMBUS controller available.
- mod.rs: pass gmbus controller (cloned) to IntelDisplay::new()
This completes the EDID path for Gen9 platforms (Gen8-9 have
GMBUS, Xe2 uses DP AUX). The synthetic 1080p fallback remains
as the final safety net.
Add cursor_set() and cursor_move() to IntelDriver GpuDriver impl,
enabling hardware cursor plane operations through the DRM interface.
- cursor_set(): map cursor FB to GPU address, set surface via
curbase register, enable via curcntr, with hot_x/hot_y params
- cursor_move(): update curpos register with clamped x/y (max 8191)
Phase 3 (Full KMS) now at 4/5 — only atomic modesetting remains.
The atomic modesetting ioctl (ATOMIC_COMMIT) requires scheme.rs
changes to define the ioctl number and wire into GpuDriver trait.
All 5 phases: 0 ✅ 1 ✅ 2 ✅ 3 🚧 4/5 4 ✅
Implement redox_private_cs_submit() in the Intel GpuDriver,
completing Phase 4 (Render Path). This is the userspace GPU
command submission interface used by Mesa.
- redox_private_cs_submit(): map source GEM buffer to GPU address,
extract batch commands as u32 slice from src_offset with
byte_count dwords, submit to render ring via ring.submit_batch()
- Returns RedoxPrivateCsSubmitResult with seqno (0 for now —
fence integration deferred)
This completes all 4 modules of Phase 4:
batch.rs ✅ fence.rs ✅ execlists.rs ✅ Mesa winsys ✅
Remaining across all phases:
Phase 2: DBUF detailed programming
Phase 3: Atomic modesetting (requires scheme.rs changes)
Add display_transcoder.rs — TRANS_DDI_FUNC_CTL programming for
platforms with separate transcoders (Xe2/Gen12+ where pipe != transcoder).
- Transcoder::configure(): program TRANS_DDI_FUNC_CTL (0x60400 +
0x1000 per transcoder) with DDI select, DP/HDMI mode select,
port width (1/2/4 lanes), and enable bit
- disable(): clear TRANS_DDI_FUNC_ENABLE
- is_enabled(): check TRANS_DDI_FUNC_ENABLE status
- EDP transcoder at 0x6F400 for pipe 3
Wire into IntelDriver::set_crtc — configure transcoder after
modesetting, using pipe.port and TransDdiMode::Dp with 4 lanes.
Only active when has_separate_transcoder == true.
Linux reference: intel_ddi.c (TRANS_DDI_FUNC_CTL programming)
Add display_watermark.rs — DBUF slice enable and per-pipe
watermark programming for Xe2/Gen12+ platforms.
- init_xe2(): enable DBUF_CTL_S1 (0x45008) and DBUF_CTL_S2 (0x4500C)
with DBUF_SLICE_ENABLE + DBUF_TRACKER_STATE_SERVICE
- program_pipe_watermarks(): set PLANE_BUF_CFG (0x7017C) and
PLANE_WM (0x70240) per pipe — zero for initial program, needs
real values for production
- compute_min_cdclk(): calculate minimum CDCLK from pixel clock,
lane count, and bits-per-pixel
Wire into IntelDriver — initialized after power wells, before DMC.
Linux reference: intel_dbuf.c, skl_watermark.c
Add regs_gen12.rs implementing IntelRegs trait for Gen12 (TGL/ADL)
and Gen12_7 (MTL/ARL) display engines. Gen12 shares most display
register offsets with Gen9 but has different forcewake and DMC.
- Gen12Regs: same pipe/plane/DDI/cursor/vblank offsets as Gen9
but with Gen12 forcewake (0xa188/0xdfc) and DMC (0x80000+)
- Gen12DisplayRegs: Gen12-specific display registers:
TRANS_DDI_FUNC_CTL (0x60400) — separate transcoder control
DBUF_CTL_S1/S2 (0x45008/0x4500C) — display buffer slices
PLANE_CTL/SURF/STRIDE at standard plane offsets
Update mod.rs generation selector: Gen12/Gen12_7 → Gen12Regs.
Xe2 continues to use Xe2Regs, Gen9 uses Gen9Regs.
Linux reference: intel_display_regs.h, xe_gt_regs.h
Add display_dpll.rs — pixel clock PLL management.
Gen9 (SKL/KBL/CFL): enable LCPLL1/LCPLL2 at 0x46010/0x46014
and WRPLL1 at 0x46040 with WRPLL_REF_BCLK reference clock.
Poll PLL_LOCK bit for confirmation.
Xe2 (ARL/BMG): enable DPLL_CTRL1/DPLL_CTRL2 at 0x6C058/0x6C05C
with PLL_POWER_ENABLE. get_pll_for_clock() returns pdiv=1 or 2
based on pixel clock threshold (300 MHz).
Wire into IntelDriver constructor between CDCLK and display init.
Linux reference: intel_dpll_mgr.c (skl_wrpll, icl_dpll)
Rewrite display_cdclk.rs with generation-aware clock programming.
Gen9 (SKL/KBL/CFL): 337.5/450/540/675 MHz via CDCLK_CTL (0x46000)
with decimal + freq_select encoding. Existing code preserved.
Xe2 (ARL/BMG): 307.2/384/556.8/652.8 MHz via CDCLK_FREQ (0x46200)
with different freq_select/decimal encoding. Xe2 frequency table
ported from Linux intel_cdclk.c (DISPLAY_VER >= 20 path).
DisplayClock::new() now takes &IntelDeviceInfo for gen selection.
CDCLK init reads current hardware state rather than assuming defaults.
Linux reference: intel_cdclk.c (bxt_set_cdclk, skl_set_cdclk)
Rewrite display_power.rs to support both Gen9 (Skylake) and Xe2
(Arrow Lake/Battlemage) power well initialization.
Gen9 path (unchanged): single POWER_WELL_CTL register at 0x45400
with bitmask for PW1/PW2/DDI_A-E/AUX_A-D domains.
Xe2 path (new): multiple power well controllers:
- HSW_PWR_WELL_CTL1 (0x45400) — PW1/PW2 per-index REQ/STATE
- ICL_PWR_WELL_CTL_AUX1 (0x45440) — 4 AUX channels
- ICL_PWR_WELL_CTL_DDI1 (0x45450) — 4 DDI ports
- DC_STATE_EN (0x45504) — DC power state control
Each well uses 2-bit per-index encoding (REQ=0x2, STATE=0x1).
DisplayPower::new() now takes &IntelDeviceInfo to select
generation-appropriate initialization path.
Linux reference: intel_display_power_well.c (xelpdp_aux_power_well_*)
Document the fundamental architectural rule: Red Bear OS is a FULL FORK.
We do not depend on Redox. We reuse Redox code only when needed — and
when we do, we fork it into our own repos.
Key rules:
- Own your dependencies (local/sources/ or local/recipes/)
- No waiting for upstream (fix in our fork)
- Frozen snapshots only (never auto-pull)
- Upstream gitlab URLs are temporary (91 remaining, to be forked)
- Our code, our fixes (fix forward when APIs break)
- Durable state (commit to local/sources/)
Fix 4 E0277 errors in daemon/src/lib.rs where scheme_root()
and create_this_scheme_fd() return syscall::error::Error but
the function returns syscall::Error. Add .map_err() conversions.
redox-driver-sys errors (6 remaining E0308/E0061 in dma.rs/io.rs)
are pre-existing API mismatches between libredox and redox_syscall
crate versions — not addressed here.
Replace stub EDID reading with real DP AUX I2C-over-AUX EDID reads
for Xe2 platforms. For non-Xe2 platforms, continue using GMBUS.
- detect_display_topology(): accept Option<&[DpAux]> parameter,
try DP AUX read_edid() first for Xe2, fall back to display.read_edid()
(GMBUS) for Gen9 platforms
- IntelDriver::new(): pass dp_aux channels to detect_display_topology
- refresh_connectors(): pass dp_aux from self
Display detection flow for Arrow Lake:
DDI_BUF_CTL polling → DP AUX EDID → EDID parsing → mode list
(falls back to synthetic 1920x1080@60 if DP AUX fails)
Compiled: 0 new errors
Add enable_d2d_links() for Xe2/Arrow Lake platforms where the display
connection requires D2D (die-to-die) link setup before connector
detection. Programs DDI_BUF_CTL with D2D_LINK_ENABLE (bit 29) and
polls D2D_LINK_STATE (bit 28) for each port.
Called from IntelDriver::new() when generation == GenXe2, before
power well initialization.
Linux reference: intel_ddi.c (XE2LPD_DDI_BUF_D2D_LINK_ENABLE)
Compiled: 0 new errors
Add dp_aux.rs implementing DisplayPort AUX channel for EDID reads
and DPCD capability queries. Critical for Xe2/Arrow Lake which lacks
GMBUS and must use DP AUX for all EDID operations.
- dp_aux.rs: DpAux struct with per-port AUX channel (CTL at 0x64010,
DATA at 0x64014, 0x100 stride). Implements do_transfer() with
native read/write and I2C-over-AUX protocols, wait_for_completion()
with busy/done/timeout/receive_error detection, read_dpcd() for
DPCD register access, read_dpcd_caps() for capability enumeration,
and read_edid() via I2C-over-AUX (MOT-based segmented reads)
- mod.rs: declare dp_aux module, add DpAux import, add dp_aux: Vec<DpAux>
field to IntelDriver, initialize one DpAux per port in constructor
Linux reference: intel_dp_aux.c, intel_dp_aux_regs.h
Compiled: 0 new errors (pre-existing daemon errors unrelated)
Kernel, relibc, and base forks now use the full pre-patched source
from the frozen 0.1.0 release archives (including .git history).
Build verification:
- kernel: BUILDS from local/sources/kernel
- relibc: BUILDS from local/sources/relibc
- base: BUILDS from local/sources/base
- redoxfs: BUILDS from local/sources/redoxfs
The mini ISO build fails due to pre-existing cached pkgar signature
issues (not migration-related).