From fd60edc823807dc549eb116261611d8dcbd19872 Mon Sep 17 00:00:00 2001 From: Vasilito Date: Tue, 14 Apr 2026 10:50:04 +0100 Subject: [PATCH] Refresh status docs and add a visible changelog Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .gitignore | 2 + AGENTS.md | 15 +- CHANGELOG.md | 15 + CONTRIBUTING.md | 7 + INTEGRATION_REPORT.md | 19 + README.md | 55 +- docs/01-REDOX-ARCHITECTURE.md | 34 +- docs/02-GAP-ANALYSIS.md | 80 +- docs/03-WAYLAND-ON-REDOX.md | 30 +- docs/04-LINUX-DRIVER-COMPAT.md | 18 + docs/05-KDE-PLASMA-ON-REDOX.md | 67 +- docs/AGENTS.md | 11 +- docs/README.md | 24 +- local/AGENTS.md | 17 +- local/docs/AMD-FIRST-INTEGRATION.md | 2 +- local/docs/INPUT-SCHEME-ENHANCEMENT.md | 543 ++++++ local/docs/IOMMU-SPEC-REFERENCE.md | 1954 +++++++++++++++++++++ local/docs/NETWORKING-RTL8125-NETCTL.md | 83 + local/docs/QT6-PORT-STATUS.md | 348 ++++ local/docs/REDBEAR-INFO-RUNTIME-REPORT.md | 64 + 20 files changed, 3311 insertions(+), 77 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 local/docs/INPUT-SCHEME-ENHANCEMENT.md create mode 100644 local/docs/IOMMU-SPEC-REFERENCE.md create mode 100644 local/docs/NETWORKING-RTL8125-NETCTL.md create mode 100644 local/docs/QT6-PORT-STATUS.md create mode 100644 local/docs/REDBEAR-INFO-RUNTIME-REPORT.md diff --git a/.gitignore b/.gitignore index 99ab0283..9ca2162b 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ recipes/**/source.tar.tmp # Build artifacts — target/ dirs are everywhere target wget-log +/sysroot/ +local/docs/*.log # Explicitly track our OWN source code (recipes with path="source" where we wrote the code) # Only recipes under these categories contain our hand-written source: diff --git a/AGENTS.md b/AGENTS.md index 9a5e0e9c..96c167de 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -232,18 +232,17 @@ See `local/docs/AMD-FIRST-INTEGRATION.md` for the full plan. | ~~P0: Fix ACPI for AMD~~ | ~~4-6 weeks~~ | ✅ Complete — boots on modern AMD bare metal | | ~~P1: Driver infrastructure~~ | ~~8-12 weeks~~ | ✅ Complete — redox-driver-sys + linux-kpi + firmware-loader + pcid /config + MSI-X (compiles) | | ~~P2: AMD GPU display~~ | ~~12-16 weeks~~ | ✅ Complete — redox-drm + AMD DC port + Intel driver (compiles, no HW validation) | -| P3: POSIX + input | 4-8 weeks | relibc gaps + evdevd (parallel with P1/P2) | -| P4: Wayland compositor | 4-6 weeks | Smithay Redox backends | -| P5: Full amdgpu | 16-24 weeks | Complete GPU driver via LinuxKPI (parallel) | -| P6: KDE Plasma | 12-16 weeks | Qt6 → KDE Frameworks → KWin → Plasma Shell | +| ~~P3: POSIX + input~~ | ~~4-8 weeks~~ | 🚧 Build-side work substantially complete — relibc gaps exported to downstream consumers, evdevd/udev-shim/libevdev/libinput/D-Bus build; runtime validation still open | +| P4: Wayland compositor | 4-6 weeks | 🚧 Partial — libwayland/Qt6 Wayland/Mesa EGL+GBM+GLES2/Qt6 OpenGL now build, but compositor/runtime validation is still incomplete | +| ~~P5: DML2 enablement~~ | ~~partial~~ | 🚧 DML2 config enabled, 63 DML source files in build, TTM compiled, libdrm amdgpu ✅, `iommu` daemon now builds; hardware validation still open | +| P6: KDE Plasma | 12-16 weeks | 🚧 In progress — Qt6 ✅, KF6 32/32 ✅, Mesa EGL/GBM/GLES2 ✅, kf6-kcmutils ✅, kf6-kwayland ✅, kdecoration ✅, KWin 🔄 building | -**Total to KDE Plasma on AMD**: ~48 weeks (~11 months) with 2 developers (P0 complete). +**Total to KDE Plasma on AMD**: ~48 weeks (~11 months) with 2 developers (P0-P2 complete; P3/P4 build-side substantially advanced, runtime still open). ### Critical Path ``` -P0 (ACPI boot) ✅ DONE → P1 (driver infra) ✅ DONE → P2 (AMD display) ✅ DONE → P4 (Wayland) → P6 (KDE) - P3 (POSIX+input) ──────────────┘ - P5 (full amdgpu, parallel) +P0 (ACPI boot) ✅ → P1 (driver infra) ✅ → P2 (AMD display) ✅ → P3 (POSIX+input, build-side) 🚧 → P4 (Wayland runtime) 🚧 → P6 (KDE) + P5 (full amdgpu, parallel) ``` ### Custom Crates (P1/P2) diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..7c5e6246 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,15 @@ +# Changelog + +This file tracks user-visible changes in Red Bear OS. + +When a commit changes the visible system surface, supported hardware, build flow, shipped configs, +or major documentation status, add a short note here and keep the README "What's New" section in +sync with the newest highlights. + +## 2026-04-14 + +- Added a user-visible GitHub-facing "What's New" section to the root README and linked it to this running changelog. +- Added a new `redbear-kde` configuration and documented current KDE bring-up status as in-progress rather than not started. +- Refreshed top-level and docs status notes so historical roadmap documents no longer read as the current repo state. +- Expanded shipped Red Bear system tooling and config coverage around runtime diagnostics, native hardware listing, and Redox-native networking flows. +- Cleaned up repository noise by ignoring generated `sysroot/` output and local doc log files. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6cb1d7b..3a365310 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -104,6 +104,13 @@ Since **Rust** is a relatively small and new language compared to others like C Please follow our [Git style](https://doc.redox-os.org/book/creating-proper-pull-requests.html) for pull requests. +For user-visible work, keep the root [`CHANGELOG.md`](CHANGELOG.md) current and refresh the +README "What's New" section with the latest highlights so GitHub visitors can immediately see what +changed. + +When a commit changes the visible system surface, supported hardware, build flow, shipped configs, +or key docs, add a short user-facing changelog note in the same change. + ## GitLab ### Identity diff --git a/INTEGRATION_REPORT.md b/INTEGRATION_REPORT.md index e42caecd..e1a0601b 100644 --- a/INTEGRATION_REPORT.md +++ b/INTEGRATION_REPORT.md @@ -4,6 +4,25 @@ **Project**: Red Bear OS Build System (based on Redox OS) **Status**: Assessment Complete +> **Status correction (2026-04-14):** This report is a historical assessment snapshot and is no +> longer an accurate statement of current repository status. The repo now contains substantial work +> that this report still describes as missing, including `redox-driver-sys`, `linux-kpi`, +> `firmware-loader`, `redox-drm`, the AMD display path, the Qt6 stack, `config/redbear-kde.toml`, +> and a large `local/recipes/kde/` tree. + +## Current Snapshot + +| Area | Current repo state | +|---|---| +| ACPI / bare-metal | Complete in-tree | +| Driver infrastructure | Present and compiling in `local/recipes/drivers/` | +| DRM / display | Present and compiling in `local/recipes/gpu/`; hardware validation still pending | +| POSIX/input | Implemented in-tree with remaining validation work | +| Wayland | Partial runtime path | +| KDE | In progress with a mix of true builds and scaffolding | + +Read this file as historical context, not as the canonical current-state document. + --- ## Executive Summary diff --git a/README.md b/README.md index 73a077b4..02284b33 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,28 @@ Red Bear OS is a derivative of [Redox OS](https://www.redox-os.org) — a general-purpose, Unix-like, microkernel-based operating system written in Rust. It tracks upstream Redox, incorporating its improvements while adding custom drivers, filesystems, and hardware support. +## What's New + +- KDE bring-up moved forward: `config/redbear-kde.toml` exists, the Qt6 stack builds in-tree, and the KDE recipe tree is now populated. +- Native Red Bear runtime tooling expanded with `redbear-info`, `redbear-hwutils` (`lspci`, `lsusb`), and a Redox-native `netctl` flow. +- Build and status docs were refreshed to distinguish current in-tree progress from older historical roadmap text. + +See [CHANGELOG.md](./CHANGELOG.md) for the running user-visible change log. + +## Current Phase Snapshot + +| Phase | Status | Notes | +|---|---|---| +| P0 ACPI boot | ✅ Complete | In-tree and documented in `local/docs/ACPI-FIXES.md` | +| P1 driver infra | ✅ Complete | Compile-oriented infrastructure present | +| P2 DRM / display | ✅ Code complete | Hardware validation still pending | +| P3 POSIX + input | 🚧 In progress | relibc exports now cover the rebuilt `signalfd`/`timerfd`/`eventfd`/`open_memstream` consumer path; runtime validation remains | +| P4 Wayland runtime | 🚧 Partial | `libwayland` and `seatd` now build, and KDE config starts seatd, but compositor/DRM/input runtime validation is still incomplete | +| P5 AMD accel / IOMMU | 🚧 Partial | `iommu` daemon now builds, but hardware validation and full acceleration are still open | +| P6 KDE Plasma | 🚧 In progress | Mix of real builds, shims, and stubs | + +There is no distinct first-class **P7** phase artifact in this repository today; later work appears as milestone-style follow-on work beyond the tracked P6 boundary. + ## What's Different from Upstream Redox | Component | Status | Detail | @@ -26,8 +48,9 @@ Red Bear OS is a derivative of [Redox OS](https://www.redox-os.org) — a genera | Intel GPU driver | ✅ Compiles | Display pipe modesetting + MSI-X (no HW validation) | | ext4 filesystem | ✅ Compiles | Read/write ext4 alongside RedoxFS | | ACPI for AMD bare metal | ✅ Complete | x2APIC, MADT, FADT shutdown/reboot, power methods | +| Wired networking | 🚧 Improved | native net stack present, Redox-native `netctl` shipped, RTL8125 autoload wired through the existing Realtek path | | Custom branding | ✅ | Boot identity, hostname, os-release | -| POSIX gaps (relibc) | 🚧 In progress | eventfd, signalfd, timerfd, open_memstream | +| POSIX gaps (relibc) | 🚧 In progress | implementations exist in-tree; runtime validation against Wayland stack is still ongoing | ## Project Structure @@ -58,6 +81,36 @@ make live CONFIG_NAME=redbear-full # Live ISO (redbear-live.iso) make qemu # Boot in QEMU ``` +## Native hardware listing tools + +Red Bear configs now include a small native `redbear-hwutils` package that ships `lspci` and +`lsusb`. `lspci` reads the existing `/scheme/pci/.../config` surface, while `lsusb` walks the +native `usb.*` schemes exposed by `xhcid`, so there is no dependency on the unfinished WIP +`pciutils` or `usbutils` ports. + +## Networking + +Red Bear ships the existing native Redox wired networking path (`pcid-spawner` → NIC daemon → +`smolnetd`/`dhcpd`/`netcfg`) together with a small Redox-native `netctl` compatibility command. +Profiles live under `/etc/netctl`, the shipped examples live under `/etc/netctl/examples`, and the +boot service applies the enabled profile with `netctl --boot`. + +RTL8125 is wired into the existing native Realtek autoload path by matching `10ec:8125` in the +`rtl8168d` driver config. This keeps the implementation in the Redox userspace driver model rather +than introducing a separate Linux netdevice compatibility layer. + +## Runtime diagnostics + +Red Bear ships `redbear-info` as the canonical runtime integration/debugging command. It is a +passive report over live system surfaces and is intended to help answer questions like: + +- which Red Bear integrations are merely installed versus actually active, +- whether the networking stack is up, with current IP, DNS, and default route, +- whether hardware discovery surfaces such as PCI, USB, DRM, and RTL8125 are visible. + +Use `redbear-info --verbose` for evidence-backed human output, `redbear-info --json` for machine- +readable diagnostics, and `redbear-info --test` for suggested follow-up commands. + ## Sync with Upstream Redox ```bash diff --git a/docs/01-REDOX-ARCHITECTURE.md b/docs/01-REDOX-ARCHITECTURE.md index 1870be57..59e25f19 100644 --- a/docs/01-REDOX-ARCHITECTURE.md +++ b/docs/01-REDOX-ARCHITECTURE.md @@ -111,7 +111,13 @@ All drivers are **userspace daemons** that access hardware through: **Storage**: ided (IDE), ahcid (SATA), nvmed (NVMe), usbscsid (USB SCSI) -**Network**: e1000d (Intel GigE), rtl8168d (Realtek), ixgbed (Intel 10G) +**Network**: e1000d (Intel GigE), rtl8168d (Realtek 8168/8169/8125 path), ixgbed (Intel 10G), virtio-netd (VirtIO) + +The native wired stack in this tree is userspace end to end: `pcid-spawner` autoloads NIC daemons, +drivers expose `network.*` schemes through `driver-network`, `smolnetd` provides the `ip`/`tcp`/ +`udp`/`icmp`/`netcfg` schemes, and `dhcpd` plus config files under `/etc/net/` supply runtime +addressing. Red Bear additionally ships a small native `netctl` compatibility command for profile- +driven wired setup. **Audio**: ac97d, ihdad (Intel HD Audio), sb16d (Sound Blaster) @@ -179,17 +185,19 @@ Architectures: i586, x86_64, aarch64, riscv64gc. ### Known POSIX Gaps (blocking Wayland) -These are the specific missing features found in libwayland's `redox.patch`: +These were the specific missing features originally identified from libwayland's `redox.patch`. +Today, most exist in-tree in relibc, but downstream Wayland consumers still carry compatibility +patches, so this table is a current-state summary rather than an untouched historical claim. | Missing API | Used By | Status | |-------------|---------|--------| -| `signalfd` / `SFD_CLOEXEC` | libwayland event loop | Not implemented | -| `timerfd` / `TFD_CLOEXEC` / `TFD_TIMER_ABSTIME` | libwayland timers | Not implemented | -| `eventfd` / `EFD_CLOEXEC` | libwayland server | Not implemented | -| `F_DUPFD_CLOEXEC` | libwayland fd management | Not implemented | -| `MSG_CMSG_CLOEXEC` | libwayland socket recv | Not implemented | -| `MSG_NOSIGNAL` | libwayland connection | Not implemented | -| `open_memstream` | libdrm, libwayland | Not implemented | +| `signalfd` / `SFD_CLOEXEC` | libwayland event loop | Implemented in-tree; downstream libwayland still patched around usage | +| `timerfd` / `TFD_CLOEXEC` / `TFD_TIMER_ABSTIME` | libwayland timers | Implemented in-tree; downstream libwayland still patched around usage | +| `eventfd` / `EFD_CLOEXEC` | libwayland server | Implemented in-tree; downstream libwayland still patched around usage | +| `F_DUPFD_CLOEXEC` | libwayland fd management | Implemented in-tree | +| `MSG_CMSG_CLOEXEC` | libwayland socket recv | Implemented in-tree | +| `MSG_NOSIGNAL` | libwayland connection | Implemented in-tree; downstream libwayland still omits flag | +| `open_memstream` | libdrm, libwayland | Implemented in-tree; downstream libwayland still bypasses usage | ## 6. Build System (This Repository) @@ -257,8 +265,8 @@ Config: `config/wayland.toml` ### Key Blockers for Wayland -1. **relibc POSIX gaps** (signalfd, timerfd, eventfd, open_memstream) +1. **Downstream Wayland compatibility patches remain** (`libwayland/redox.patch` still bypasses some interfaces even though relibc-side APIs now exist in-tree) 2. **No GPU acceleration** (only software rendering) -3. **No libinput** (requires evdev + udev) -4. **No DRM/KMS** (libdrm has all GPU drivers disabled) -5. **cosmic-comp**: missing keyboard input, performance issues +3. **Input/runtime integration remains incomplete** (`evdevd`, `udev-shim`, and libinput exist, but compositor input is not fully validated) +4. **DRM/KMS runtime validation remains incomplete** (`redox-drm` exists in-tree, but full Wayland/driver runtime integration is still open) +5. **cosmic-comp**: keyboard/input integration and performance issues remain diff --git a/docs/02-GAP-ANALYSIS.md b/docs/02-GAP-ANALYSIS.md index 1dec96e1..5a32c597 100644 --- a/docs/02-GAP-ANALYSIS.md +++ b/docs/02-GAP-ANALYSIS.md @@ -7,6 +7,34 @@ This document maps the distance between current Redox OS 0.9.0 and three goals: 2. **KDE Plasma desktop** → see [05-KDE-PLASMA-ON-REDOX.md](05-KDE-PLASMA-ON-REDOX.md) 3. **Linux driver compatibility layer** → see [04-LINUX-DRIVER-COMPAT.md](04-LINUX-DRIVER-COMPAT.md) +## Status Correction (2026-04-14) + +Most of this document is a historical roadmap and no longer reflects the repository's current state. +Use the matrix below as the authoritative phase summary before reading the older milestone text. + +| Layer / Phase | Current repo state | Evidence | +|---|---|---| +| P0 ACPI / bare-metal boot | Complete in-tree | `local/docs/ACPI-FIXES.md`, `local/patches/kernel/redox.patch`, `local/patches/base/redox.patch` | +| P1 driver infrastructure | Complete in-tree, compile-oriented | `local/recipes/drivers/redox-driver-sys/`, `local/recipes/drivers/linux-kpi/`, `local/recipes/system/firmware-loader/` | +| P2 DRM / AMD+Intel display | Complete in-tree, hardware validation pending | `local/docs/P2-AMD-GPU-DISPLAY.md`, `local/recipes/gpu/redox-drm/`, `local/recipes/gpu/amdgpu/` | +| P3 POSIX + input | Implemented in-tree; consumer-visible `signalfd`/`timerfd`/`eventfd`/`open_memstream` header-export path fixed in this repo pass; runtime validation still pending | `recipes/core/relibc/source/src/header/`, `recipes/core/relibc/source/include/sys/signalfd.h`, `local/patches/relibc/`, `local/recipes/system/evdevd/`, `local/recipes/system/udev-shim/` | +| P4 Wayland stack | Partially complete | `recipes/wip/wayland/`, `recipes/wip/libs/other/libinput/`, `recipes/wip/services/seatd/` | +| P5 AMD acceleration / IOMMU | Partial | `local/recipes/gpu/amdgpu/`, `local/recipes/system/iommu/` (now buildable via surfaced recipe) | +| P6 KDE Plasma | In progress with mixed real builds and stubs/shims | `config/redbear-kde.toml`, `local/recipes/kde/`, `local/docs/QT6-PORT-STATUS.md` | + +### Ordered Remaining Gaps + +1. **Validate the completed P3→P4 bridge in practice**: `libwayland` now rebuilds with `signalfd`, `timerfd`, `eventfd`, `open_memstream`, `MSG_CMSG_CLOEXEC`, and `MSG_NOSIGNAL` restored, but compositor/runtime validation is still outstanding. +2. **Complete P4 runtime path**: libinput/seatd/GBM/Wayland compositor integration is still incomplete even though the base libraries now build, `seatd` now builds for Redox, and the KDE runtime config now starts a seatd service. +3. **Separate KDE real builds from scaffolding**: parts of the KDE stack are genuine builds, while others are shimmed or stubbed only to satisfy dependency resolution. +4. **Hardware validation remains open** for AMD/Intel DRM and the IOMMU path, even though the IOMMU daemon now builds. + +### P7 Note + +The repository's tracked phase model currently stops at **P6**. What a user might call "P7" +only appears here as later milestone-style work (for example M7/M8 below), not as a first-class +implemented phase with its own config/recipe/doc boundary. + ## Dependency Chain: Hardware → KDE Desktop ``` @@ -34,28 +62,28 @@ This document maps the distance between current Redox OS 0.9.0 and three goals: | API | Status | Where to implement | Effort | |-----|--------|--------------------|--------| -| `signalfd`/`signalfd4` | **Missing** | `relibc/src/header/signal/mod.rs` + `signal/types.rs` | Medium | -| `timerfd_create/settime/gettime` | **Missing** | `relibc/src/header/sys_timerfd/` (NEW directory) | Medium | -| `eventfd`/`eventfd_read`/`eventfd_write` | **Missing** | `relibc/src/header/sys_eventfd/` (NEW directory) | Low | -| `F_DUPFD_CLOEXEC` | **Missing** | `relibc/src/header/fcntl/mod.rs` (add constant) | Low | -| `MSG_CMSG_CLOEXEC` | **Missing** | `relibc/src/header/sys_socket/mod.rs` | Low | -| `MSG_NOSIGNAL` | **Missing** | `relibc/src/header/sys_socket/mod.rs` | Low | -| `open_memstream` | **Missing** | `relibc/src/header/stdio/src.rs` | Low | +| `signalfd`/`signalfd4` | **Implemented in-tree** | `relibc/src/header/signal/mod.rs` + `signal/signalfd.rs` | Runtime validation still needed | +| `timerfd_create/settime/gettime` | **Implemented in-tree** | `relibc/src/header/sys_timerfd/` | Runtime validation still needed | +| `eventfd`/`eventfd_read`/`eventfd_write` | **Implemented in-tree** | `relibc/src/header/sys_eventfd/` | Runtime validation still needed | +| `F_DUPFD_CLOEXEC` | **Implemented in-tree** | `relibc/src/header/fcntl/mod.rs` | Verify against downstream consumers | +| `MSG_CMSG_CLOEXEC` | **Implemented in-tree** | `relibc/src/header/sys_socket/mod.rs` | Verify against downstream consumers | +| `MSG_NOSIGNAL` | **Implemented in-tree** | `relibc/src/header/sys_socket/mod.rs` | Verify against downstream consumers | +| `open_memstream` | **Implemented in-tree** | `relibc/src/header/stdio/open_memstream.rs` | Verify against downstream consumers | | UDS + FD passing | **Done** | Already implemented | — | | `epoll` (event scheme) | **Done** | Redox `scheme:event` | — | | `mmap`/`mprotect` | **Done** | Kernel syscalls | — | | `fork`/`exec` | **Done** | Userspace via `thisproc:` scheme | — | -**Proof of gap**: See `recipes/wip/wayland/libwayland/redox.patch` — all 7 missing APIs are stubbed there. +**Current blocker**: The build-side relibc/libwayland bridge is now in place, but downstream Wayland still needs runtime validation and the wider compositor stack (`evdevd`/`seatd`/DRM/GBM) is still incomplete. ### Layer 2: GPU / Display Infrastructure | Component | Status | Where to implement | Concrete doc | |-----------|--------|--------------------|-------------| -| DRM/KMS scheme | **Missing** | New daemon: `redox-drm` crate | [04 §3](04-LINUX-DRIVER-COMPAT.md) | +| DRM/KMS scheme | **Present in-tree** | `local/recipes/gpu/redox-drm/` | [04 §3](04-LINUX-DRIVER-COMPAT.md) | | GPU driver (Intel) | Experimental modeset only | `redox-drm/src/drivers/intel/` | [04 §3](04-LINUX-DRIVER-COMPAT.md) | -| GEM buffers | **Missing** | `redox-drm/src/gem.rs` | [04 §3](04-LINUX-DRIVER-COMPAT.md) | -| DMA-BUF sharing | **Missing** | `redox-drm/src/dmabuf.rs` | [04 §3](04-LINUX-DRIVER-COMPAT.md) | +| GEM buffers | **Present in-tree** | `local/recipes/gpu/redox-drm/source/src/gem.rs` | [04 §3](04-LINUX-DRIVER-COMPAT.md) | +| DMA-BUF sharing | **Present in-tree** | `local/recipes/gpu/redox-drm/source/src/dmabuf.rs` | [04 §3](04-LINUX-DRIVER-COMPAT.md) | | Mesa hardware backend | **Missing** | Mesa winsys for Redox DRM | [03 §3.4](03-WAYLAND-ON-REDOX.md) | | GPU OpenGL | Software only | Blocked on GPU driver | [04](04-LINUX-DRIVER-COMPAT.md) | @@ -63,17 +91,17 @@ This document maps the distance between current Redox OS 0.9.0 and three goals: | Component | Status | Where to implement | Concrete doc | |-----------|--------|--------------------|-------------| -| evdev daemon | **Missing** | New: `recipes/core/evdevd/` | [03 §2](03-WAYLAND-ON-REDOX.md) | -| udev shim | **Missing** | New: `recipes/wip/wayland/udev-shim/` | [03 §2](03-WAYLAND-ON-REDOX.md) | -| libinput | **Missing** | `recipes/wip/wayland/libinput/` (NEW) | [03 §2](03-WAYLAND-ON-REDOX.md) | +| evdev daemon | **Present in-tree** | `local/recipes/system/evdevd/` | [03 §2](03-WAYLAND-ON-REDOX.md) | +| udev shim | **Present in-tree** | `local/recipes/system/udev-shim/` | [03 §2](03-WAYLAND-ON-REDOX.md) | +| libinput | **Present as WIP port** | `recipes/wip/libs/other/libinput/` | [03 §2](03-WAYLAND-ON-REDOX.md) | | XKB layouts | **Done** | `xkeyboard-config` ported | — | -| seatd | Recipe exists, untested | `recipes/wip/wayland/seatd/` | — | +| seatd | Builds and is wired into KDE config, runtime unvalidated | `recipes/wip/services/seatd/`, `config/redbear-kde.toml` | — | ### Layer 4: Wayland Protocol | Component | Status | Recipe | Blocker | |-----------|--------|--------|---------| -| libwayland | Patched, broken timers | `recipes/wip/wayland/libwayland/` | Layer 1 POSIX gaps | +| libwayland | Patched, downstream compatibility workarounds remain | `recipes/wip/wayland/libwayland/` | Reduce/remove `redox.patch` and verify runtime behavior | | cosmic-comp | No keyboard input | `recipes/wip/wayland/cosmic-comp/` | Layer 3 libinput | | smallvil (Smithay) | Basic, slow | `recipes/wip/wayland/smallvil/` | Layer 2+3 for DRM+input | | wlroots/sway/hyprland | Not tested | `recipes/wip/wayland/wlroots/` | Layer 2+3 | @@ -82,28 +110,28 @@ This document maps the distance between current Redox OS 0.9.0 and three goals: | Component | Status | Concrete doc | |-----------|--------|-------------| -| Qt 6 | Not ported | [05 Phase KDE-A](05-KDE-PLASMA-ON-REDOX.md) | -| KDE Frameworks | Not ported | [05 Phase KDE-B](05-KDE-PLASMA-ON-REDOX.md) | -| KWin | Not ported | [05 Phase KDE-C](05-KDE-PLASMA-ON-REDOX.md) | -| Plasma Shell | Not ported | [05 Phase KDE-C](05-KDE-PLASMA-ON-REDOX.md) | +| Qt 6 | Ported in-tree | [05 Phase KDE-A](05-KDE-PLASMA-ON-REDOX.md) | +| KDE Frameworks | Partially ported in-tree | [05 Phase KDE-B](05-KDE-PLASMA-ON-REDOX.md) | +| KWin | Recipe exists, still incomplete | [05 Phase KDE-C](05-KDE-PLASMA-ON-REDOX.md) | +| Plasma Shell | Recipe exists, still incomplete | [05 Phase KDE-C](05-KDE-PLASMA-ON-REDOX.md) | | D-Bus | **Ported** | `config/x11.toml` has it working | ### Layer 6: Linux Driver Compatibility | Component | Status | Concrete doc | |-----------|--------|-------------| -| `redox-driver-sys` crate | Not started | [04 §3](04-LINUX-DRIVER-COMPAT.md) | -| `linux-kpi` C headers | Not started | [04 §3](04-LINUX-DRIVER-COMPAT.md) | -| i915 C driver port | Not started | [04 §4](04-LINUX-DRIVER-COMPAT.md) | -| amdgpu C driver port | Not started | [04 §5](04-LINUX-DRIVER-COMPAT.md) | +| `redox-driver-sys` crate | Present in-tree | [04 §3](04-LINUX-DRIVER-COMPAT.md) | +| `linux-kpi` C headers | Present in-tree | [04 §3](04-LINUX-DRIVER-COMPAT.md) | +| i915 C driver port | Not started as Linux C port | [04 §4](04-LINUX-DRIVER-COMPAT.md) | +| amdgpu C driver port | Present in-tree, hardware validation pending | [04 §5](04-LINUX-DRIVER-COMPAT.md) | --- ## Concrete Roadmap with Milestones ### Milestone M1: "libwayland works natively" (2-4 weeks) -- Implement 7 POSIX APIs in relibc (see Layer 1 table) -- Remove `redox.patch` from libwayland recipe +- Build-side part now substantially complete: relibc exports the needed consumer-visible POSIX headers/symbols and `libwayland` rebuilds with only residual Redox-specific build tweaks +- Remaining work: runtime validation (`wayland-rs_simple_window`, compositor bring-up) - **Test**: `wayland-rs_simple_window` runs without crashes - **Delivers**: libwayland, wayland-protocols, libdrm all build natively diff --git a/docs/03-WAYLAND-ON-REDOX.md b/docs/03-WAYLAND-ON-REDOX.md index 43fd5d9a..6004ab35 100644 --- a/docs/03-WAYLAND-ON-REDOX.md +++ b/docs/03-WAYLAND-ON-REDOX.md @@ -8,11 +8,31 @@ Get a working Wayland compositor on Redox OS that can run KDE Plasma application - `config/wayland.toml` exists — launches `cosmic-comp` or `smallvil` via `orbital-wayland` - 21 Wayland recipes in `recipes/wip/wayland/` — most untested -- `libwayland` 1.24.0 builds with `redox.patch` that stubs out 7 POSIX APIs +- `libwayland` 1.24.0 now rebuilds with a much smaller `redox.patch`; the P3 POSIX path (`signalfd`, `timerfd`, `eventfd`, `open_memstream`, `MSG_CMSG_CLOEXEC`, `MSG_NOSIGNAL`) is back on the native path, and the remaining patch is down to Redox-specific build quirks - `smallvil` (Smithay) runs as basic compositor, performance poor -- `cosmic-comp` builds but has no keyboard input (missing libinput) +- `cosmic-comp` builds but still has no working keyboard input; the remaining issue is runtime/input integration, not simply the absence of a libinput recipe - `libdrm` builds with all GPU drivers disabled - Mesa uses OSMesa (software rendering only) +- **evdevd** (`scheme:evdev`) provides Linux-compatible `/dev/input/eventX` interface +- **udev-shim** (`scheme:udev`) provides udev-like device enumeration +- **seatd** now builds for Redox and is wired into the KDE runtime config, but DRM-lease/runtime validation is still open +- **redox-drm** (`scheme:drm`) provides DRM/KMS with AMD + Intel GPU support + +--- + +## Status Correction (2026-04-14) + +This document is partly historical. The repo already contains substantial P3/P4 work in-tree, +but the downstream Wayland stack is still not free of compatibility patches. + +What is actually true today: +- relibc now contains in-tree implementations for `signalfd`, `timerfd`, `eventfd`, `open_memstream`, `MSG_CMSG_CLOEXEC`, and `MSG_NOSIGNAL` support paths +- the relibc module wiring plus the consumer-visible `signalfd` / `timerfd` / `eventfd` / `open_memstream` export path were fixed in this repo pass +- `libwayland/redox.patch` has been reduced to residual Redox-specific build tweaks (`wayland-scanner` detection and `F_DUPFD_CLOEXEC` guard), so the old POSIX bypasses are no longer the main blocker +- `evdevd`, `udev-shim`, and `redox-drm` exist in-tree, but full compositor/runtime validation remains open +- `seatd` now also builds in-tree for Redox and is started by the KDE runtime config, but has not yet been validated end-to-end with the compositor/DRM path + +Read the step-by-step sections below as design history plus implementation notes, not as an exact current-state checklist. --- @@ -20,8 +40,10 @@ Get a working Wayland compositor on Redox OS that can run KDE Plasma application ### What to implement -These are the 7 APIs that libwayland's `redox.patch` removes. Each must be added -to `relibc` (repo: https://gitlab.redox-os.org/redox-os/relibc). +Historically these were the 7 APIs that `libwayland/redox.patch` worked around. They now exist +in-tree in relibc, and this repo pass restored the full build-side path for `signalfd`, `timerfd`, +`eventfd`, `open_memstream`, and the related message flags. The remaining work is no longer basic +POSIX availability, but runtime validation of the full Wayland stack. #### 1.1 `signalfd` / `signalfd4` diff --git a/docs/04-LINUX-DRIVER-COMPAT.md b/docs/04-LINUX-DRIVER-COMPAT.md index 87460839..9bfc188a 100644 --- a/docs/04-LINUX-DRIVER-COMPAT.md +++ b/docs/04-LINUX-DRIVER-COMPAT.md @@ -1,5 +1,23 @@ # 04 — Linux Driver Compatibility Layer: Concrete Implementation Path +> **Status note (2026-04-14):** This file is now partly historical design material. The repository +> already contains `local/recipes/drivers/redox-driver-sys/`, `local/recipes/drivers/linux-kpi/`, +> `local/recipes/system/firmware-loader/`, `local/recipes/gpu/redox-drm/`, and +> `local/recipes/gpu/amdgpu/`. Treat the sections below as architecture rationale and porting notes, +> not as an accurate statement that those components are still "not started". + +## Current State Snapshot + +| Component | Current repo state | +|---|---| +| `redox-driver-sys` | Present and compiling in `local/recipes/drivers/redox-driver-sys/` | +| `linux-kpi` | Present and compiling in `local/recipes/drivers/linux-kpi/` | +| `firmware-loader` | Present and compiling in `local/recipes/system/firmware-loader/` | +| `redox-drm` | Present and compiling in `local/recipes/gpu/redox-drm/` | +| Intel path | Compile-oriented, no hardware validation yet | +| AMD path | Compile-oriented via `amdgpu` + AMD DC port, no hardware validation yet | +| IOMMU | Partial — daemon now builds, hardware validation still TODO in `local/recipes/system/iommu/` | + ## Goal Enable running Linux GPU drivers (amdgpu, i915, nouveau) on Redox OS with minimal diff --git a/docs/05-KDE-PLASMA-ON-REDOX.md b/docs/05-KDE-PLASMA-ON-REDOX.md index 3cf81c8d..065135e3 100644 --- a/docs/05-KDE-PLASMA-ON-REDOX.md +++ b/docs/05-KDE-PLASMA-ON-REDOX.md @@ -1,5 +1,30 @@ # 05 — KDE Plasma on Redox: Concrete Implementation Path +> **Status note (2026-04-14):** This file mixes current status with older forward-looking porting +> instructions. `config/redbear-kde.toml` already exists, the Qt6 stack is built, many KF6 recipes +> exist under `local/recipes/kde/`, and the current gap is no longer "start KDE from scratch". +> The real frontier is distinguishing true builds from shimmed/stubbed packages and then closing +> the KWin / Plasma runtime path. + +## Current State Snapshot + +| Area | Current repo state | +|---|---| +| Qt6 | Built in-tree (`qtbase`, `qtdeclarative`, `qtsvg`, `qtwayland`) | +| KF6 | Mixed: many real builds, some still partial | +| `config/redbear-kde.toml` | Present with KDE session launcher | +| `kwin`, `plasma-workspace`, `plasma-desktop` | Recipes exist, still marked TODO | +| `kirigami` | Stub-only package for dependency resolution | +| `kf6-kio` | Heavy shim-based build recipe | +| `kf6-kcmutils` | Stripped widget-only build recipe | +| `libxcvt` | Now builds as a real package; no longer needs to stay in the KWin stub bucket | + +### What remains true from this document + +- KWin / Plasma assembly is still the main functional blocker. +- Mesa/GBM/libinput/seatd integration still matters for a real session. +- QML/QtQuick-heavy components remain riskier than the already-built widget/core stack. + ## Goal Run KDE Plasma 6 desktop environment on Redox OS, starting with a minimal viable @@ -8,15 +33,45 @@ desktop and expanding to full Plasma. ## Prerequisites (from docs 03 and 04) Before KDE work begins, these MUST be complete: -- [x] relibc POSIX gaps fixed (signalfd, timerfd, eventfd, etc.) -- [x] evdevd + libinput working -- [x] DRM/KMS scheme working (at least Intel modesetting) -- [x] Wayland compositor running (Smithay/smallvil) -- [x] Mesa EGL + software OpenGL (already ported) +- [~] relibc POSIX APIs now reach `libwayland` on the native build path, but runtime validation of the full Wayland base still blocks calling the prerequisite fully complete in practice +- [x] evdevd compiled, libevdev built, libinput 1.30.2 built (comprehensive redox.patch) +- [x] DRM/KMS scheme daemon compiled (redox-drm: 15+ ioctls, AMD+Intel drivers) +- [x] Wayland: libwayland + wayland-protocols built +- [x] Mesa: OSMesa + LLVMpipe software rendering (EGL platform_redox.c exists, Orbital-only) +- [x] D-Bus 1.16.2 built for Redox +- [x] Qt6: qtbase (Core+Gui+Widgets+DBus+Wayland), qtdeclarative, qtsvg, qtwayland ALL BUILT +- [ ] Mesa EGL+GBM with LLVMpipe (platform_redox.c needs GBM extension — planned) +- [ ] libdrm amdgpu+intel enablement (in progress) ## Three-Phase KDE Implementation -### Phase KDE-A: Qt Foundation (2-3 months) +### Phase KDE-A: Qt Foundation — ✅ COMPLETE + +Qt6 core stack fully built for x86_64-unknown-redox: + +| Module | Version | Status | Libraries | +|--------|---------|--------|-----------| +| qtbase | 6.11.0 | ✅ | Core, Gui, Widgets, Concurrent, Xml, DBus, WaylandClient | +| qtdeclarative | 6.11.0 | ✅ | QML, QtQuick (JIT disabled) | +| qtsvg | 6.11.0 | ✅ | Svg, SvgWidgets | +| qtwayland | 6.11.0 | ✅ | WaylandClient (compositor disabled) | + +### Phase KDE-B: KF6 Frameworks — 🔄 IN PROGRESS (21/30+ built) + +Built: ecm, kcoreaddons, kwidgetsaddons, kconfig, ki18n, kcodecs, kguiaddons, +kcolorscheme, kauth, kwindowsystem, knotifications, kjobwidgets, kconfigwidgets, +karchive, sonnet, kcompletion, kitemviews, kitemmodels, solid + +Building: kdbusaddons, kcrash + +Recipes ready: kiconthemes, kservice, kpackage, kglobalaccel, kxmlgui, ktextwidgets, +kio, kbookmarks, kdeclarative, kcmutils, kirigami, plasma-framework + +### Phase KDE-C: KDE Plasma Assembly — 📋 PLANNED + +Recipes created: kwin, plasma-workspace, plasma-desktop +Config: config/redbear-kde.toml +Blocked on: KF6 completion, Mesa EGL/GBM, libdrm amdgpu+intel **Goal**: A Qt application displays a window on the Redox Wayland compositor. diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 61332084..612fba2c 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -1,7 +1,8 @@ # DOCS — ARCHITECTURE & INTEGRATION DOCUMENTATION -7 comprehensive technical documents covering Redox architecture, gap analysis, and integration paths. -For AMD-first integration, see `local/docs/AMD-FIRST-INTEGRATION.md`. +7 technical documents covering Redox architecture, gap analysis, and integration paths. +Some are now historical roadmap documents; check each file's top-level status note before treating it as current state. +For current Red Bear OS status, also read `local/docs/AMD-FIRST-INTEGRATION.md` and `local/docs/QT6-PORT-STATUS.md`. ## STRUCTURE @@ -22,8 +23,8 @@ docs/ |----------|----------|-------------| | How does the kernel work? | 01 | §1 Microkernel, §2 Scheme System | | How do drivers access hardware? | 01 | §3 Driver Model, §6 Build System | -| What's missing for Wayland? | 02 | Layer 1-4 gap matrix | -| How to fix POSIX gaps? | 03 | §1 (signalfd, timerfd, eventfd implementations) | +| What's missing for Wayland? | 02 | Status correction + ordered remaining gaps | +| How to fix POSIX gaps? | 03 | Status correction + historical §1 notes | | How to build evdevd? | 03 | §2 (evdev input daemon architecture) | | How to build DRM/KMS? | 03 | §3 (drmd daemon, Intel driver) | | How to port a Wayland compositor? | 03 | §4 (Smithay Redox backends) | @@ -38,7 +39,7 @@ docs/ ## KEY NUMBERS -- **POSIX gaps**: 7 APIs blocking libwayland (signalfd, timerfd, eventfd, F_DUPFD_CLOEXEC, MSG_CMSG_CLOEXEC, MSG_NOSIGNAL, open_memstream) +- **POSIX gap story**: APIs now largely exist in-tree, but downstream Wayland consumers still carry compatibility patches - **Wayland recipes**: 21 in `recipes/wip/wayland/` - **KDE apps**: 9 WIP recipes in `recipes/wip/kde/` - **To Wayland compositor**: ~26 weeks (2 developers) diff --git a/docs/README.md b/docs/README.md index a8b93f17..6c9afaf0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -3,6 +3,11 @@ Technical documentation for forking Redox OS to include Wayland protocol support, KDE Plasma desktop environment, and a Linux driver compatibility layer. +> **Status note (2026-04-14):** several documents below are historical implementation plans whose +> original "missing / not started" language is now stale. The repo already contains substantial +> Red Bear OS work under `local/`; use each document's top-level status notes together with +> `local/docs/AMD-FIRST-INTEGRATION.md` and `local/docs/QT6-PORT-STATUS.md` for current state. + ## Documents | # | Document | Description | @@ -14,16 +19,19 @@ KDE Plasma desktop environment, and a Linux driver compatibility layer. | 05 | [KDE Plasma on Redox](05-KDE-PLASMA-ON-REDOX.md) | Feasibility study and implementation plan for KDE Plasma | | 06 | [Build System Setup](06-BUILD-SYSTEM-SETUP.md) | How to build Redox from this repository | -## Current State Summary (as of Redox 0.9.0) +## Current State Summary (as of 2026-04-14) - **Display server**: Orbital (custom, scheme-based) — works -- **Wayland**: Experimental, WIP. Smallvil (Smithay) and cosmic-comp partially working. - libwayland patched with shimmed-out `signalfd`, `timerfd`, `eventfd`. -- **X11**: Working via X.org dummy driver inside Orbital. -- **Mesa**: Software-rendered only (LLVMpipe/OSMesa). No GPU acceleration. -- **GPU drivers**: VESA framebuffer + VirtIO GPU only. Experimental Intel modesetting. -- **KDE**: 19 app recipes in WIP, no KDE Plasma infrastructure. -- **Linux driver compat**: None. Redox explicitly chose source-level porting over binary compat. +- **Wayland**: libwayland + wayland-protocols built. Smallvil/cosmic-comp remain partial runtime experiments. +- **Qt6**: qtbase 6.11.0 (Core+Gui+Widgets+DBus+Wayland), qtdeclarative, qtsvg, qtwayland ALL BUILT +- **D-Bus**: 1.16.2 built for Redox. Qt6DBus enabled. +- **KF6 Frameworks**: mixed state — many real builds, but some packages are still shimmed or stubbed. +- **Mesa**: software-rendered path is present; full GBM / hardware-validated Wayland path is still incomplete. +- **GPU drivers**: redox-drm scheme daemon and AMD+Intel compile-oriented paths exist; hardware validation is still pending. +- **Input**: evdevd compiled, libevdev built, libinput 1.30.2 built +- **Networking**: native wired stack present (`pcid-spawner` → NIC daemon → `smolnetd`/`dhcpd`/`netcfg`), Red Bear ships a native `netctl` command, and RTL8125 is wired into the existing Realtek autoload path +- **KDE**: `redbear-kde.toml` exists and the recipe tree is populated, but the runtime stack is still incomplete. +- **Linux driver compat**: linux-kpi (31 C headers + 13 Rust FFI), redox-driver-sys, firmware-loader all compile. ## Quick Start diff --git a/local/AGENTS.md b/local/AGENTS.md index 77c59afd..ec0dae55 100644 --- a/local/AGENTS.md +++ b/local/AGENTS.md @@ -72,7 +72,7 @@ redox-master/ ← git pull updates mainline Redox │ │ ├── branding/ ← redbear-release (os-release, hostname, motd) │ │ ├── drivers/ ← redox-driver-sys, linux-kpi │ │ ├── gpu/ ← redox-drm (AMD + Intel display drivers), amdgpu (C port) -│ │ ├── system/ ← evdevd, udev-shim, firmware-loader, redbear-meta +│ │ ├── system/ ← cub, evdevd, udev-shim, firmware-loader, redbear-hwutils, redbear-info, redbear-netctl, redbear-meta │ │ ├── wayland/ ← Wayland compositor (Phase 4) │ │ └── kde/ ← KDE Plasma (Phase 6) │ ├── patches/ @@ -249,15 +249,22 @@ redbear-live.toml │ └── minimal.toml │ └── base.toml └── [packages] redbear-release, redox-driver-sys, linux-kpi, - firmware-loader, redox-drm, evdevd, udev-shim, - redbear-meta + firmware-loader, redox-drm, cub, redbear-hwutils, + redbear-netctl, evdevd, udev-shim, redbear-meta NOTE: ext4d is inherited from desktop.toml (mainline package) + NOTE: cub is included via redbear-desktop.toml and depends on the custom + recipe symlink (recipes/system/cub → local/recipes/system/cub) being + created by integrate-redbear.sh or apply-patches.sh before building. + NOTE: redbear-netctl provides a Redox-native `netctl` command with profiles + in /etc/netctl and a boot-time `netctl --boot` service. + NOTE: redbear-info is the canonical runtime integration report. Keep it updated when + Red Bear adds new tools, schemes, services, or hardware integration paths. redbear-minimal.toml └── minimal.toml (mainline) └── base.toml - └── [packages] redbear-release, redox-driver-sys, firmware-loader, - evdevd, udev-shim + └── [packages] redbear-release, redbear-hwutils, redbear-netctl, + redox-driver-sys, firmware-loader, evdevd, udev-shim ``` Config comparison: diff --git a/local/docs/AMD-FIRST-INTEGRATION.md b/local/docs/AMD-FIRST-INTEGRATION.md index dfe30719..1177449a 100644 --- a/local/docs/AMD-FIRST-INTEGRATION.md +++ b/local/docs/AMD-FIRST-INTEGRATION.md @@ -26,7 +26,7 @@ the LinuxKPI compatibility approach — a clean Rust rewrite would take 5+ years | ACPI | ✅ Complete | RSDP/SDT checksums, MADT types 0x4/0x5/0x9/0xA, LVT NMI, FADT shutdown/reboot | | x2APIC | ✅ Works | Auto-detected via CPUID, APIC/SMP functional | | HPET | ✅ Works | Timer initialized from ACPI | -| IOMMU | ❌ Missing | No VT-d or AMD-Vi support | +| IOMMU | 🚧 Buildable, unvalidated | `iommu` daemon now builds, but no VT-d/AMD-Vi hardware validation yet | | AMD GPU | 🚧 In progress | MMIO mapped, DC port compiles, MSI-X wired, no hardware validation yet | | Wi-Fi/BT | ❌ Missing | No wireless support | | USB | ⚠️ Variable | Some USB controllers work, others don't | diff --git a/local/docs/INPUT-SCHEME-ENHANCEMENT.md b/local/docs/INPUT-SCHEME-ENHANCEMENT.md new file mode 100644 index 00000000..5cbd4fa6 --- /dev/null +++ b/local/docs/INPUT-SCHEME-ENHANCEMENT.md @@ -0,0 +1,543 @@ +# INPUTD SCHEME API ENHANCEMENT DESIGN + +**Target**: `recipes/core/base/source/drivers/inputd` +**Scope**: Userspace-only `inputd` scheme enhancement +**Date**: 2026-04-13 + +## 1. Goal + +Enhance `inputd` so it can do all of the following without breaking any existing callers: + +1. Let producers register under stable names such as `ps2-keyboard`, `ps2-mouse`, or `usb-hid0`. +2. Expose per-device consumer streams so services such as `evdevd` can subscribe to one device only. +3. Publish hotplug notifications for device add/remove. +4. Expose currently registered devices through the scheme root directory. + +This is an **additive** design. Existing paths, existing event payloads, existing VT behavior, and existing display/control behavior must continue to work unchanged. + +## 2. Current Implementation Summary + +The current `inputd` implementation in `recipes/core/base/source/drivers/inputd/src/main.rs` has these important properties: + +- `Handle` only supports `Producer`, `Consumer`, `Display`, `Control`, and `SchemeRoot`. +- `openat()` only recognizes `producer`, `consumer`, `consumer_bootlog`, `handle`, `handle_early`, and `control`. +- All producers write anonymous `orbclient::Event` bytes into the same `Handle::Producer` path. +- Legacy consumers are per-VT handles. `write()` only delivers input bytes to the **active VT** consumer set. +- `SchemeRoot` exists, but it is not a real directory yet: it does not enumerate entries. +- `lib.rs` only exposes `ProducerHandle`, `ConsumerHandle`, `DisplayHandle`, and `ControlHandle`. + +Current callers confirm the limitation: + +- `ps2d` opens one `ProducerHandle` and sends both keyboard and mouse events into the same stream. +- `usbhidd` also opens one `ProducerHandle` and sends keyboard/mouse/button/scroll data into the same stream. +- local `evdevd` reads `/scheme/input/consumer`, receives anonymous mixed `orbclient::Event` values, and manually translates them. + +## 3. Design Principles + +1. **Keep legacy behavior intact**: `/scheme/input/producer` and `/scheme/input/consumer` must keep working exactly as they do today. +2. **Do not change event payloads**: device-specific streams still carry serialized `orbclient::Event` values. +3. **Keep all logic in userspace**: no kernel changes, no new kernel scheme semantics. +4. **Make enumeration path-driven**: device names are visible as entries below `/scheme/input/`. +5. **Use explicit hotplug events**: device discovery and liveness must not depend on polling failed opens. + +## 4. Scheme Path Layout + +The enhanced namespace is: + +```text +/scheme/input/ — SchemeRoot (directory listing) +/scheme/input/producer — Legacy producer (unchanged) +/scheme/input/producer/{name} — Named producer: ps2-keyboard, ps2-mouse, usb-hid0 +/scheme/input/consumer — Legacy consumer (unchanged) +/scheme/input/{device_name} — Per-device consumer: reads events from one named producer +/scheme/input/events — Hotplug event stream +/scheme/input/handle/{display} — Display handle (unchanged) +/scheme/input/control — Control commands (unchanged) +``` + +Legacy-only paths that must remain valid even though they are not part of the new API surface: + +```text +/scheme/input/consumer_bootlog — Existing bootlog VT consumer +/scheme/input/handle_early/{display} — Existing early framebuffer handoff path +``` + +### 4.1 Root Directory Listing + +`SchemeRoot` should become a real directory endpoint backed by `getdents`, not by overloading `read()`. + +The root listing should expose: + +- static entries: `producer`, `consumer`, `consumer_bootlog`, `events`, `handle`, `handle_early`, `control` +- one dynamic entry per registered device name from `devices` + +That keeps the namespace honest while still allowing device enumeration from `/scheme/input/`. + +`InputDeviceLister` in `lib.rs` should filter out the reserved static names and return only dynamic device entries. + +## 5. Handle Model + +The `Handle` enum in `main.rs` should become: + +```rust +enum Handle { + Producer, + NamedProducer { + name: String, + }, + Consumer { + events: EventFlags, + pending: Vec, + needs_handoff: bool, + notified: bool, + vt: usize, + }, + DeviceConsumer { + device_name: String, + events: EventFlags, + pending: Vec, + notified: bool, + }, + HotplugEvents { + events: EventFlags, + pending: Vec, + notified: bool, + }, + Display { + events: EventFlags, + pending: Vec, + notified: bool, + device: String, + is_earlyfb: bool, + }, + Control, + SchemeRoot, +} +``` + +Notes: + +- `Producer` remains the legacy anonymous producer path. +- `NamedProducer` only needs the registered name. Device ID lookup stays in shared scheme state. +- `DeviceConsumer` is byte-oriented like the legacy consumer, but without VT or handoff state. +- `HotplugEvents` stores serialized variable-length hotplug records in `pending`. +- `SchemeRoot` remains a dedicated handle variant, but now supports directory enumeration. + +## 6. Scheme Open Semantics + +`openat()` should parse paths as follows: + +### 6.1 Existing Paths + +- `producer` with no child component → `Handle::Producer` +- `consumer` → current VT consumer allocation logic +- `consumer_bootlog` → current VT 1 logic +- `handle/{display}` → unchanged +- `handle_early/{display}` → unchanged +- `control` → unchanged + +### 6.2 New Paths + +- `producer/{name}` → `Handle::NamedProducer { name }` +- `events` → `Handle::HotplugEvents { ... }` +- any other top-level non-reserved path component → `Handle::DeviceConsumer { device_name, ... }` + +### 6.3 Name Validation + +Named producer registration must reject: + +- empty names +- names containing `/` +- reserved names: `producer`, `consumer`, `consumer_bootlog`, `events`, `handle`, `handle_early`, `control` +- duplicate live names already present in `devices` + +Recommended error behavior: + +- invalid name → `EINVAL` +- duplicate name → `EEXIST` +- open of `/scheme/input/{device_name}` for a currently unknown device → `ENOENT` + +## 7. State Management + +`InputScheme` should add: + +```rust +devices: BTreeMap, +next_device_id: AtomicUsize, +``` + +Purpose: + +- `devices` maps device name → current device ID +- `next_device_id` allocates monotonically increasing IDs + +Behavior: + +1. When `NamedProducer` opens successfully: + - allocate `device_id = next_device_id.fetch_add(1, Ordering::SeqCst) as u32` + - insert `devices.insert(name.clone(), device_id)` + - serialize a `DEVICE_ADD` hotplug message + - append it to every `Handle::HotplugEvents.pending` + - set `notified = false` on those hotplug handles + - set `has_new_events = true` + +2. When `NamedProducer` closes: + - remove the entry from `devices` + - serialize a `DEVICE_REMOVE` hotplug message with the removed ID and name + - append it to every `Handle::HotplugEvents.pending` + - set `notified = false` + - set `has_new_events = true` + +3. Device IDs are never reused. If `ps2-keyboard` disappears and later comes back, it gets a new `device_id`. + +No additional kernel state is required. This is ordinary daemon-side bookkeeping. + +## 8. Event Routing Logic + +The existing preprocessing path in `write()` must remain in place: + +- special Super+Fn VT switching behavior stays in `inputd` +- keymap translation still happens in `inputd` +- the emitted payload remains serialized `orbclient::Event` + +After that preprocessing step, routing changes as follows. + +### 8.1 Legacy Producer + +Input written to `/scheme/input/producer` follows the current legacy route: + +- deliver to the existing legacy consumer path +- preserve current active-VT behavior +- do **not** deliver to any `DeviceConsumer` +- do **not** generate hotplug events + +### 8.2 Named Producer + +Input written to `/scheme/input/producer/{name}` must be fanned out to: + +1. the matching `DeviceConsumer` handles where `device_name == name` +2. the existing legacy consumer path used by Orbital and other old clients + +That means named producers are **supersets** of legacy routing, not replacements. + +### 8.3 Device Consumer + +`/scheme/input/{device_name}` only receives events from the named producer with the exact same name. + +It must never receive: + +- anonymous legacy producer traffic +- events from other named producers +- display or control events + +### 8.4 Routing Sketch + +```text +legacy producer write + -> existing input normalization + -> legacy VT consumer fan-out only + +named producer write(name) + -> existing input normalization + -> device consumers for name + -> legacy VT consumer fan-out +``` + +Implementation-wise, the simplest approach is: + +1. detect whether the writer is `Producer` or `NamedProducer { name }` +2. run the existing event transformation code once +3. serialize transformed `Event` values once +4. if named, append to matching `DeviceConsumer.pending` +5. append to the legacy consumer path using the current active-VT logic +6. clear `notified` on affected readers and set `has_new_events = true` + +## 9. Hotplug Event Stream + +`/scheme/input/events` is a read-only stream of variable-length hotplug records. + +### 9.1 Binary Format + +```rust +#[repr(C)] +struct InputHotplugEvent { + kind: u32, // 1 = DEVICE_ADD, 2 = DEVICE_REMOVE + device_id: u32, // Unique device identifier + name_len: u32, // Length of device name + _reserved: u32, // Future use +} +// Followed by name_len bytes of UTF-8 device name +``` + +Constants: + +```rust +const DEVICE_ADD: u32 = 1; +const DEVICE_REMOVE: u32 = 2; +``` + +### 9.2 Stream Semantics + +- The stream is append-only and ordered by daemon observation. +- Each record is serialized as header bytes followed by UTF-8 name bytes. +- `read()` drains raw bytes from `pending`. +- Because records are variable-length, callers must handle partial reads. +- `HotplugHandle` in `lib.rs` should hide this by buffering partial bytes until one full record is available. + +### 9.3 Notification Model + +`Handle::HotplugEvents` participates in `fevent(EVENT_READ)` exactly like other readable handles: + +- when at least one serialized hotplug record is pending and the handle is subscribed to `EVENT_READ`, post a read event +- after a successful read drains the buffer, notification becomes edge-triggered again + +## 10. Scheme Root Enumeration + +Enumeration should be implemented with `getdents()` on `Handle::SchemeRoot`. + +Recommended behavior: + +- `scheme_root()` still creates a `Handle::SchemeRoot` +- `getdents()` emits static entries plus one entry per `devices` key +- `read()` on `SchemeRoot` stays invalid (`EBADF` or `EISDIR` are both acceptable if applied consistently) +- `openat()` continues to require a valid `SchemeRoot` dirfd + +Example visible entries after `ps2d` registers keyboard and mouse: + +```text +producer +consumer +consumer_bootlog +events +handle +handle_early +control +ps2-keyboard +ps2-mouse +``` + +This gives normal filesystem-style discovery while keeping old endpoints visible. + +## 11. `lib.rs` Public API Changes + +The public API should be extended, not replaced. + +### 11.1 Existing Types Stay + +- `ProducerHandle` +- `ConsumerHandle` +- `DisplayHandle` +- `ControlHandle` + +Their existing constructors and behavior remain unchanged. + +### 11.2 New Types + +```rust +pub struct NamedProducerHandle(File); +pub struct DeviceConsumerHandle(File); +pub struct HotplugHandle { + file: File, + partial: Vec, +} + +#[derive(Debug, Clone)] +#[repr(C)] +pub struct HotplugEventHeader { + pub kind: u32, + pub device_id: u32, + pub name_len: u32, + pub reserved: u32, +} + +#[derive(Debug, Clone)] +pub struct HotplugEvent { + pub kind: u32, + pub device_id: u32, + pub name: String, +} + +pub struct InputDeviceLister; +``` + +### 11.3 Constructors + +```rust +impl NamedProducerHandle { + pub fn new(name: &str) -> io::Result; +} + +impl DeviceConsumerHandle { + pub fn new(device_name: &str) -> io::Result; +} + +impl HotplugHandle { + pub fn new() -> io::Result; +} +``` + +Path mapping: + +- `NamedProducerHandle::new("ps2-keyboard")` → `/scheme/input/producer/ps2-keyboard` +- `DeviceConsumerHandle::new("ps2-keyboard")` → `/scheme/input/ps2-keyboard` +- `HotplugHandle::new()` → `/scheme/input/events` + +### 11.4 Read/Write Shape + +Recommended API shape: + +```rust +impl NamedProducerHandle { + pub fn write_event(&mut self, event: orbclient::Event) -> io::Result<()>; +} + +pub enum DeviceConsumerHandleEvent<'a> { + Events(&'a [Event]), +} + +impl DeviceConsumerHandle { + pub fn event_handle(&self) -> BorrowedFd<'_>; + pub fn read_events<'a>(&self, events: &'a mut [Event]) + -> io::Result>; +} + +impl HotplugHandle { + pub fn event_handle(&self) -> BorrowedFd<'_>; + pub fn read_event(&mut self) -> io::Result>; +} +``` + +`DeviceConsumerHandle` deliberately mirrors `ConsumerHandle`, but it does not need `Handoff` support because VT display handoff is unrelated to per-device streams. + +### 11.5 Device Enumeration Helper + +`InputDeviceLister` should provide a safe wrapper around scheme-root directory reads, for example: + +```rust +impl InputDeviceLister { + pub fn list() -> io::Result>; +} +``` + +Behavior: + +- read `/scheme/input/` as a directory +- drop reserved static entries +- return only currently registered device names + +This keeps callers out of scheme-internal filtering logic. + +## 12. Producer Lifecycle and Consumer Behavior + +### 12.1 Named Producer Registration + +Opening `/scheme/input/producer/{name}` is both: + +- creation of a producer handle +- registration of `{name}` as a live device + +Closing the fd unregisters the device. + +This matches current scheme style well because `inputd` already uses `on_close()` to clean up VT consumers. + +### 12.2 Device Consumer Lifetime + +Per-device consumer handles are name-based subscriptions. + +- open succeeds only while the device name is currently registered +- once open, the handle remains attached to that name +- if the producer disappears, no more events arrive for that handle +- if the same name is registered again later, the handle resumes receiving events for that name +- the hotplug stream is how clients notice that the underlying producer instance changed + +This keeps `DeviceConsumer` simple and avoids introducing a second handle teardown protocol. + +## 13. Migration Path + +### 13.1 `ps2d` + +`ps2d` is the first caller that should adopt the new API because it already has a clean split between keyboard and mouse sources. + +Recommended startup logic: + +1. Try `NamedProducerHandle::new("ps2-keyboard")` +2. Try `NamedProducerHandle::new("ps2-mouse")` +3. If both succeed, run in named mode +4. If either fails, close any partially opened named handle and fall back to one legacy `ProducerHandle::new()` + +Routing: + +- keyboard scancodes → `ps2-keyboard` +- mouse move / absolute move / button / scroll events → `ps2-mouse` + +This preserves compatibility with old `inputd` while immediately enabling per-device consumers on new `inputd`. + +### 13.2 `evdevd` + +Once the scheme exists, local `evdevd` can move from `/scheme/input/consumer` to: + +- `InputDeviceLister::list()` to discover devices +- `DeviceConsumerHandle::new(name)` for device-local streams +- `HotplugHandle::new()` to watch add/remove + +It can keep the legacy consumer path as a fallback for older systems. + +### 13.3 `usbhidd` + +`usbhidd` can remain legacy initially, then later migrate to named producers such as `usb-hid0`, `usb-hid1`, or more specific per-interface names. + +## 14. Backward Compatibility Requirements + +All of the following must continue to work unchanged: + +- `/scheme/input/producer` +- `/scheme/input/consumer` +- `/scheme/input/consumer_bootlog` +- `/scheme/input/handle/{display}` +- `/scheme/input/handle_early/{display}` +- `/scheme/input/control` +- current `ProducerHandle`, `ConsumerHandle`, `DisplayHandle`, and `ControlHandle` APIs +- current active-VT routing and graphics handoff behavior + +Compatibility rules: + +1. Old producers still emit anonymous events into the legacy stream. +2. Old consumers still receive the same event format and VT behavior. +3. New named producers additionally feed the legacy stream, so old consumers continue to see those events. +4. No caller is forced to understand hotplug or enumeration. + +## 15. Non-Goals + +This design does **not** include: + +- capability discovery (`keyboard` vs `mouse` metadata) +- kernel support or syscall ABI changes +- replacing `orbclient::Event` with a new event format +- changing VT ownership, display handoff, or control command semantics +- automatic migration of existing daemons + +## 16. Implementation Checklist + +Another developer implementing this design should be able to proceed in this order: + +1. extend `Handle` and `InputScheme` state +2. teach `openat()` to parse `producer/{name}`, `events`, and dynamic device names +3. add root `getdents()` support for `SchemeRoot` +4. refactor `write()` so producer type is detected before routing +5. fan out named-producer events to matching `DeviceConsumer` handles and the existing legacy path +6. add hotplug queue serialization helpers +7. extend `fevent()` and daemon notification loop for `DeviceConsumer` and `HotplugEvents` +8. add cleanup in `on_close()` for `NamedProducer` +9. extend `lib.rs` with the new handle types and directory lister +10. migrate `ps2d` with a named-producer-first, legacy-fallback strategy + +## 17. Final Outcome + +After this enhancement: + +- Orbital and any other legacy consumer continue to work as-is. +- `ps2d` and future drivers can publish stable device names. +- `evdevd` and similar services can subscribe to exactly one device stream. +- userspace can enumerate live input devices and react to hotplug events. + +That solves the current anonymity problem without changing the kernel or breaking the existing Redox input stack. diff --git a/local/docs/IOMMU-SPEC-REFERENCE.md b/local/docs/IOMMU-SPEC-REFERENCE.md new file mode 100644 index 00000000..c7f39266 --- /dev/null +++ b/local/docs/IOMMU-SPEC-REFERENCE.md @@ -0,0 +1,1954 @@ +# IOMMU Specification Reference — AMD-Vi & Intel VT-d + +**Purpose**: Implementation-ready hardware register and data structure reference for Red Bear OS IOMMU support. Based on AMD IOMMU Specification 48882 Rev 3.10 and Intel Virtualization Technology for Directed I/O (VT-d) Rev 5.0. + +**Status**: The `iommu` daemon now builds in-tree, but hardware validation is still missing in the AMD-first integration plan (see `AMD-FIRST-INTEGRATION.md`). This document provides the register and data-structure reference for finishing AMD-Vi and Intel VT-d bring-up. + +--- + +## Table of Contents + +1. [AMD-Vi (AMD IOMMU)](#1-amd-vi-amd-iommu) +2. [Intel VT-d](#2-intel-vt-d) +3. [Rust Struct Definitions](#3-rust-struct-definitions) + +--- + +## 1. AMD-Vi (AMD IOMMU) + +### 1.1 MMIO Register Map + +Base address obtained from ACPI IVRS table (IVHD entry `IOMMUInfo` field). + +| Offset | Name | Size | Access | Description | +|--------|------|------|--------|-------------| +| 0x0000 | DevTableBar | 64-bit | R/W | Device Table Base Address. Bits 12:51 hold physical address. Bits 0:8 = DeviceTableSize (entries = 2^(size+1), max 65536). Must be 4KiB-aligned. | +| 0x0008 | CmdBufBar | 64-bit | R/W | Command Buffer Base Address. Bits 12:51 hold physical address. Bits 0:8 = CmdBufLen (size = 2^(len+2) × 16 bytes). Must be 4KiB-aligned. | +| 0x0010 | EvtLogBar | 64-bit | R/W | Event Log Base Address. Bits 12:51 hold physical address. Bits 0:8 = EvtLogLen (size = 2^(len+2) × 16 bytes). Must be 4KiB-aligned. | +| 0x0018 | Control | 32-bit | R/W | IOMMU Control Register. See bit layout below. | +| 0x0020 | ExclusionBase | 64-bit | R/W | Exclusion Range Base Address. Physical address of excluded region start. | +| 0x0028 | ExclusionLimit | 64-bit | R/W | Exclusion Range Limit Address. Physical address of excluded region end. | +| 0x0030 | ExtendedFeature | 64-bit | RO | Extended Feature Register. Capability flags. Read to determine supported features. | +| 0x0038 | PprLogBar | 64-bit | R/W | Peripheral Page Request Log Base Address. Bits 12:51 = address, Bits 0:8 = log length. | +| 0x0030 | ExtendedFeature | 64-bit | RO | Extended Feature Register (alias for capability query). | +| 0x2000 | CmdBufHead | 64-bit | R/W | Command Buffer Head Pointer. Index into command buffer (byte offset / 16). | +| 0x2008 | CmdBufTail | 64-bit | R/W | Command Buffer Tail Pointer. Written by software to submit commands. | +| 0x2010 | EvtLogHead | 64-bit | R/W | Event Log Head Pointer. Written by software after reading events. | +| 0x2018 | EvtLogTail | 64-bit | RO | Event Log Tail Pointer. Updated by IOMMU hardware after writing event. | +| 0x2020 | Status | 32-bit | RO | IOMMU Status Register. See bit layout below. | +| 0x2028 | PprLogHead | 64-bit | R/W | PPR Log Head Pointer. | +| 0x2030 | PprLogTail | 64-bit | RO | PPR Log Tail Pointer. | + +#### Control Register (0x0018) Bit Layout + +| Bit | Name | Description | +|-----|------|-------------| +| 0 | IOMMUEnable | 0 = IOMMU translations disabled, 1 = enabled. Must be set last after all other config. | +| 1 | HTTunEn | HyperTransport Tunnel Enable. Set 0 for modern systems. | +| 2 | EventLogEn | Event Log Enable. Set 1 to enable event logging. | +| 3 | EventIntEn | Event Log Interrupt Enable. Set 1 to generate interrupts on event log overflow. | +| 4 | ComWaitIntEn | Completion Wait Interrupt Enable. | +| 5 | CmdBufEn | Command Buffer Enable. Set 1 to enable command processing. | +| 6 | PprLogEn | Peripheral Page Request Log Enable. | +| 7 | PprIntEn | PPR Log Interrupt Enable. | +| 8 | PprEn | Peripheral Page Request Processing Enable. | +| 9 | GTEn | Guest Translation Enable. | +| 10 | GAEn | Guest APIC (Advanced Programmable Interrupt Controller) Enable. | +| 12 | CRW | IOMMU Reset. Write 1 to clear errors after reset. | +| 13 | SMifEn | SMI Filter Enable. | +| 14 | SlFWEn | Self-Modify Firmware Enable. | +| 15 | SMifLogEn | SMI Filter Log Enable. | +| 16 | GAMEn_0 | Guest APIC Mode bit 0. | +| 17 | GAMEn_1 | Guest APIC Mode bit 1. | +| 18 | GAMEn_2 | Guest APIC Mode bit 2. | +| 22 | XTEn | x2APIC Enabled. | +| 23 | NXEn | No-Execute Enable. | +| 24 | IRQTableLEn | Interrupt Remap Table Length Enable. | + +#### Status Register (0x2020) Bit Layout + +| Bit | Name | Description | +|-----|------|-------------| +| 0 | IOMMURunning | 1 = IOMMU is processing commands or translations. | +| 1 | EventOverflow | 1 = Event log overflow occurred. Write 1 to clear. | +| 2 | EventLogInt | 1 = Event log interrupt pending. | +| 3 | ComWaitInt | 1 = Completion wait interrupt pending. | +| 4 | PprOverflow | 1 = PPR log overflow. | +| 5 | PprInt | 1 = PPR log interrupt pending. | +| 31 | RsvdP | Reserved (polling status bits). | + +#### Extended Feature Register (0x0030) Bit Layout + +| Bit | Name | Description | +|-----|------|-------------| +| 0 | PrefSup | Prefetch Support. | +| 1 | PPRSup | Peripheral Page Request Support. | +| 2 | XTSup | x2APIC Support. | +| 3 | NXSup | No-Execute Support. | +| 4 | GTSup | Guest Translation Support. | +| 5 | bit5 | Reserved. | +| 6 | IASup | Invalidate IOMMU All Support. | +| 7 | GASup | Guest APIC Support. | +| 8 | HESup | Hardware Error Registers Support. | +| 9 | PCSup | Performance Counters Support. | +| 12:15 | MsiNumPPR | MSI message number for PPR. | +| 27 | PASMax | Maximum PASID support. | +| 46:52 | PASMax | Physical Address Space Max (1 = 48-bit, 2 = 52-bit). | +| 57 | GISup | Global Invalidate Support. | +| 58 | HASup | Host Address Translation Size. | + +### 1.2 Device Table Entry (DTE) + +The Device Table holds up to 65536 entries indexed by BDF (Bus:Device:Function). Each entry is 256 bits (32 bytes). The table must be contiguous in physical memory. + +**Table size**: entries × 32 bytes. With 65536 entries, max 2 MiB. + +``` +DTE layout (256 bits = data[0] data[1] data[2] data[3], each u64): + +data[0] (bits 0-63): + [ 0] V — Valid. 1 = entry is valid. + [ 1] TV — Translation Valid. 1 = address translation enabled for this device. + [ 2:3] Reserved + [ 4] IW — Write permission (when Mode != 0). 1 = device may write. + [ 5] IR — Read permission (when Mode != 0). 1 = device may read. + [ 6:7] Reserved + [ 8] SE — Snoop Enable. 1 = device requests are snooped. + [ 9:11] Mode — Translation mode: + 000 = No translation (pass-through if TV=0) + 001 = 1-level page table + 010 = 2-level page table + 011 = 3-level page table + 100 = 4-level page table + 101 = 5-level page table + 110 = 6-level page table + 111 = Reserved + [12:51] PTP — Page Table Root Pointer. Physical address of top-level page table. + Must be 4KiB-aligned. Bits 0:11 of the address are assumed zero. + [52:55] GCR3Trp0 — Guest CR3 Table Root Pointer bits 12:15. + [56:58] GV — Guest Translation Valid bits. + [59] GLX — Guest Levels bit 0. + [60] GLX — Guest Levels bit 1. + [61] IR — Interrupt Remapping Enable. 1 = interrupts from this device are remapped. + [62] IW — Interrupt Write permission. 1 = device may generate interrupt writes. + [63] Reserved + +data[1] (bits 64-127): + [0:3] IntTabLen — Interrupt Remap Table Length. Number of entries = 2^(IntTabLen+1). + 0 = 2 entries, 1 = 4 entries, ..., 10 = 2048 entries, 11 = 4096 entries. + [4:5] IntCtl — Interrupt Control. 00 = abort, 01 = pass-through (no remap), + 10 = remapped, 11 = reserved. + [6:51] IRTP — Interrupt Remap Table Pointer. Physical address of interrupt + remap table. Must be 4KiB-aligned (bits 0:11 assumed zero). + [52:63] Reserved + +data[2] (bits 128-191): + [0:51] GCR3Trp1 — Guest CR3 Table Root Pointer bits 16:63. + [52:63] Reserved + +data[3] (bits 192-255): + [0:15] GCR3Trp2 — Guest CR3 Table Root Pointer bits 64:79. + [16] AttrRsvd — Reserved attribute bit. + [17] AttrU — User bit for device-specific use. + [18:20] Mode2 — Alias to Mode bits (duplicate for hardware). + [21:63] Reserved +``` + +**Key constants from Linux** (`drivers/iommu/amd/amd_iommu_types.h`): + +```c +#define DTE_FLAG_V (1ULL << 0) +#define DTE_FLAG_TV (1ULL << 1) +#define DTE_FLAG_IR (1ULL << 61) +#define DTE_FLAG_IW (1ULL << 62) +#define DTE_MODE_MASK 0x0E00ULL // bits 9:11 +#define DTE_PT_ADDR_MASK 0x0FFFFFFFFFF000ULL // bits 12:51 +#define DEV_DOMID_MASK 0x0FFFFULL // domain ID in bits 0:15 (when TV=0) +``` + +### 1.3 Interrupt Remapping Table Entry (IRTE) + +The Interrupt Remap Table is pointed to by the IRTP field in the DTE. Each entry is 128 bits (16 bytes). Length is 2^(IntTabLen+1) entries. + +``` +IRTE (128 bits = data[0] data[1], each u64): + +data[0]: + [0] RemapEn — Remap Enable. 1 = this entry is valid for remapping. + [1] SupIOPF — Suppress I/O Page Faults. 1 = suppress faults from this interrupt. + [2] IntType — Interrupt Type: + 000 = Fixed (edge or level, determined by trigger mode) + 001 = Arbitrated + 010 = SMI + 011 = NMI + 100 = INIT + 101 = EXTINT + 111 = Hardware-specific + [3:4] IntType bits continued (3-bit field uses bits 2:4) + [5] Rsvd — Reserved. + [5:7] DM — Delivery Mode. 0 = Fixed, 1 = Lowest Priority. + [8] IRrsvd — Reserved. + [9:10] GV — Guest Vector. + [11] GDstMode — Guest Destination Mode. 0 = Physical, 1 = Logical. + [12] DstMode — Destination Mode. 0 = Physical APIC ID, 1 = Logical. + [13:15] Rsvd — Reserved. + [16:31] DstID — Destination APIC ID. For x2APIC, full 32-bit ID (low 16 bits here). + [16:31] DstLo — Low 16 bits of destination APIC ID. + [32:63] Vector — Interrupt vector (0x10..0xFE). + +data[1]: + [0:31] DstHi — High 32 bits of x2APIC destination ID. Zero for xAPIC. + [32:63] Rsvd — Reserved. Must be zero. +``` + +**IRTE bit layout for x2APIC mode (when XTSup=1 in ExtendedFeature)**: + +``` +data[0]: + [0] RemapEn — 1 = valid + [1] SupIOPF — Suppress IO Page Fault + [2:4] IntType — Interrupt type (same as above) + [5:7] Rsvd + [8] DstMode — 0 = physical, 1 = logical + [9:10] Rsvd + [16:31] DstIDLo — Low 16 bits of x2APIC ID + [32:39] Vector — Interrupt vector + [40:63] Rsvd + +data[1]: + [0:31] DstIDHi — High 32 bits of x2APIC destination ID + [32:63] Rsvd +``` + +### 1.4 Command Buffer Entry + +The command buffer is a circular queue. Each entry is 128 bits (16 bytes = 4 × u32). Software writes to the tail, hardware reads from the head. Base address in CmdBufBar, head/tail pointers in CmdBufHead/CmdBufTail. + +**Buffer sizing**: 8192 bytes default (512 entries). Size = 2^(CmdBufLen+2) × 16 bytes. + +``` +Command Buffer Entry (128 bits = word[0] word[1] word[2] word[3], each u32): + +word[0]: + [0:3] Opcode — Command opcode (see below) + [4:31] Varies — Opcode-specific operands + +word[1], word[2], word[3]: + Opcode-specific payload. See each command format below. +``` + +#### COMPLETION_WAIT (Opcode 0x01) + +Used to poll for command completion. Can generate an interrupt or write a value to memory. + +``` +word[0]: [0:3]=0x01, [4]=Store (1=write to memory), [5]=Interrupt (1=generate IRQ), + [6:31] Reserved +word[1]: [0:31] Store Address low 32 bits (physical, must be 8-byte aligned) +word[2]: [0:31] Store Address high 32 bits +word[3]: [0:31] Store Data — value written to Store Address when command completes +``` + +#### INVALIDATE_DEVTAB_ENTRY (Opcode 0x02) + +Invalidates a single device table entry. Must be issued after modifying a DTE. + +``` +word[0]: [0:3]=0x02, [4:31] Reserved +word[1]: [0:15] DeviceId (BDF format: Bus[15:8] | Dev[7:3] | Func[2:0]) + [16:31] Reserved +word[2]: [0:31] Reserved +word[3]: [0:31] Reserved +``` + +#### INVALIDATE_IOMMU_PAGES (Opcode 0x03) + +Invalidates translation cache (TLB) entries for a range of pages. + +``` +word[0]: [0:3]=0x03, [4]=S (Size: 0=invalidate one page, 1=invalidate all pages for domain), + [5]=PDE (Page Directory Entry: 1=invalidate PDE cache too), + [6:31] Reserved +word[1]: [0:15] DomainId — domain to invalidate + [16:31] Reserved +word[2]: [0:51] Address — virtual address to invalidate (page-aligned). Ignored if S=1. + [52:63] Reserved +word[3]: [0:31] Reserved +``` + +#### INVALIDATE_INTERRUPT_TABLE (Opcode 0x04) + +Invalidates the interrupt remap cache for a device. + +``` +word[0]: [0:3]=0x04, [4:31] Reserved +word[1]: [0:15] DeviceId (BDF format) + [16:31] Reserved +word[2]: [0:31] Reserved +word[3]: [0:31] Reserved +``` + +#### INVALIDATE_IOMMU_ALL (Opcode 0x05) + +Invalidates all IOMMU caches (TLB, DTE, IRTE). Available when IASup=1. + +``` +word[0]: [0:3]=0x05, [4:31] Reserved +word[1]: [0:31] Reserved +word[2]: [0:31] Reserved +word[3]: [0:31] Reserved +``` + +### 1.5 Event Log Entry + +The event log is a circular queue written by the IOMMU hardware. Each entry is 128 bits (16 bytes = 4 × u32). Base address in EvtLogBar. + +**Buffer sizing**: 8192 bytes default (512 entries). Size = 2^(EvtLogLen+2) × 16 bytes. + +``` +Event Log Entry (128 bits = word[0] word[1] word[2] word[3]): + +word[0]: + [0:15] EventCode — Event type code (see below) + [16:31] EventFlags — Event-specific flags + +word[1], word[2], word[3]: + Event-specific data. See each event type below. +``` + +#### IO_PAGE_FAULT (Event Code 0x01) + +Generated when a device accesses an address that fails translation. + +``` +word[0]: [0:15]=0x01, [16] TR (Translation Response: 1=fault in translation), + [17] RZ (Read/Zero: 1=read of zero page), [18] I (Interrupt: 1=interrupt request), + [19] PE (Permission Error: 1=permission violation), [20] RW (1=write, 0=read), + [21] PR (Present: 1=PTE was present), [22] Rsvd +word[1]: [0:15] DeviceId (BDF), [16:31] Reserved or PASID +word[2]: [0:31] Fault Address low 32 bits +word[3]: [0:31] Fault Address high 32 bits +``` + +#### INVALIDATE_DEVICE_TABLE (Event Code 0x02) + +Generated when hardware detects an invalid DTE during a transaction. + +``` +word[0]: [0:15]=0x02, [16:31] Reserved +word[1]: [0:15] DeviceId (BDF), [16:31] Reserved +word[2]: [0:31] Reserved +word[3]: [0:31] Reserved +``` + +#### INVALIDATE_COMMAND (Event Code 0x03) + +Generated when an invalid command is detected in the command buffer. + +``` +word[0]: [0:15]=0x03, [16:31] Reserved +word[1]: [0:15] Reserved, [16:31] Reserved +word[2]: [0:31] Physical address of the illegal command (low) +word[3]: [0:31] Physical address of the illegal command (high) +``` + +#### COMMAND_HARDWARE_ERROR (Event Code 0x05) + +Hardware error during command processing. + +``` +word[0]: [0:15]=0x05, [16:31] Error flags +word[1]: [0:31] Error address or type +word[2]: [0:31] Error address low +word[3]: [0:31] Error address high +``` + +### 1.6 IVRS ACPI Table + +The IVRS (I/O Virtualization Reporting Structure) is the ACPI table that describes AMD IOMMU topology. Found by scanning ACPI tables with signature "IVRS" (0x56534949). + +#### IVRS Header (36 bytes) + +``` +Offset Size Field Description +0x00 4 Signature "IVRS" (0x56534949) +0x04 4 Length Total table length in bytes +0x08 1 Revision 2 = revision 2 (AMD-Vi), 3 = revision 3 +0x09 1 Checksum ACPI checksum (sum of all bytes = 0) +0x0A 6 OemId OEM identifier +0x10 8 OemTableId OEM table identifier +0x18 4 OemRevision OEM revision +0x1C 4 CreatorId ASL compiler vendor +0x20 4 CreatorRevision ASL compiler revision +0x24 4 IvInfo IOMMU Virtualization Info: + [0:7] = Virtualization Spec Revision (40 = rev 4.0) + [8:9] = EFRSup (Extended Feature Register supported) + [10:11] = Reserved + [31] = HT AtsResv (HT ATS reserved) +``` + +#### IVHD Entry (I/O Virtualization Hardware Definition) + +Describes a single IOMMU unit. There can be multiple IVHD entries for multiple IOMMUs. + +``` +Offset Size Field Description +0x00 1 Type 0x10 = IVHD type 10 (rev 2), 0x11 = IVHD type 11 (rev 3, 64-bit) +0x01 1 Flags Feature flags: + [0] = HtTunEn (HT tunnel enable) + [1] = PassPW (Pass posted writes) + [2] = ResPassPW (Reset PassPW) + [3] = Isoc (Isoc support) + [4] = IotlbSup (IOTLB support) + [5] = Coherent (Coherent IOMMU) + [6] = PrefSup (Prefetch support) + [7] = PPRSup (PPR support) +0x02 2 Length Total length of this IVHD entry including device entries +0x04 2 DeviceId BDF of the IOMMU PCI device +0x06 2 CapabilityOffset PCI capability offset for IOMMU capability block +0x08 8 IOMMUBaseAddress Physical MMIO base address of IOMMU registers + (type 10: bits 0:51 valid, type 11: full 64-bit) +0x10 2 PciSegmentGroup PCI segment group number +0x12 2 IommuInfo IOMMU Info: + [0:5] = MSI number for event log + [6:12] = Unit ID (IOMMU hardware unit ID) + [13:15] = Reserved +0x14 4 IommuEfr Extended Feature Register attributes (type 11 only) +0x18 ... DeviceEntries Variable-length device entry list follows +``` + +#### IVHD Device Entry Types + +Each device entry in an IVHD starts with a type byte followed by data. + +| Type | Name | Size | Description | +|------|------|------|-------------| +| 0x00 | IVHD_ALL | 4 | Select all devices (except those listed in other entries). Data = all zeros. | +| 0x01 | IVHD_SEL | 4 | Select a single device. Bytes 2:3 = DeviceId (BDF). Byte 4 = Data (LSA flags). | +| 0x02 | IVHD_SOR | 4 | Start of Range. Bytes 2:3 = first DeviceId in range. | +| 0x03 | IVHD_EOR | 4 | End of Range. Bytes 2:3 = last DeviceId in range. | +| 0x42 | IVHD_PAD4 | 8 | 4-byte PAD entry (reserved extension). | +| 0x43 | IVHD_PAD8 | 12 | 8-byte PAD entry (reserved extension). | +| 0x44 | IVHD_VAR | Variable | Variable-length entry. Byte 1 = length. Used for alias, extended selections. | + +#### IVHD Device Entry Data Byte + +``` +Bits of the Data byte in IVHD_SEL/IVHD_SOR: + [0] Lint0Pass — LINT0 remapping passthrough + [1] Lint1Pass — LINT1 remapping passthrough + [2] SysMgt — System Management: + 00 = No system management + 01 = System Management at request level + 10 = System Management at fault level + [3] SysMgt — (continued) + [4] NMIPass — NMI remapping passthrough + [5] ExtIntPass — External Interrupt remapping passthrough + [6] InitPass — INIT remapping passthrough + [7] Rsvd — Reserved +``` + +#### IVMD Entry (I/O Virtualization Memory Definition) + +Describes a memory region that has special IOMMU handling. Appears after IVHD entries. + +``` +Offset Size Field Description +0x00 1 Type 0x20 = IVMD type 20 (rev 2), 0x21 = IVMD type 21 (rev 3) +0x01 1 Flags Memory block flags: + [0] = Unity (untranslated/unity mapping) + [1] = Read (device may read) + [2] = Write (device may write) + [3] = ExclRange (exclusion range) +0x02 2 Length Total length of this IVMD entry (16 or 24 bytes) +0x04 2 DeviceId Start DeviceId (BDF) or 0x0000 for all devices +0x06 2 AuxData Auxiliary data (reserved in most implementations) +0x08 8 StartAddress Physical start address of the memory region (type 20: 32-bit in low bits) +0x10 8 MemoryLength Length of the memory region in bytes (type 20: 32-bit in low bits) +``` + +### 1.7 Page Table Entry (PTE) + +AMD-Vi page tables use multi-level radix tree. The number of levels is set by the DTE Mode field (1 to 6 levels). Each PTE is 64 bits. + +``` +PTE (64 bits): + [0] PR — Present. 1 = this entry maps a valid page or points to next level. + [1] U — User/Supervisor. 1 = accessible from user level. (only with NXSup) + [2] IW — Write permission. 1 = device may write to this page. + [3] IR — Read permission. 1 = device may read this page. + [4:8] Rsvd — Reserved. Must be zero. + [9:11] NextLevel — Next page table level (0=PTE/leaf, 1=PDE, 2=PDPTE, 3=PML4E, 4=PML5E). + At leaf level (PR=1, NextLevel=0): bits 12:51 = physical page frame. + At non-leaf level (PR=1, NextLevel>0): bits 12:51 = next table address. + [12:51] OutputAddr — Physical address of page frame (leaf) or next-level table (non-leaf). + Must be 4KiB-aligned (bits 0:11 assumed zero). + [51:58] Rsvd — Reserved. Must be zero. + [59] FC — Force Coherent. 1 = force coherent transactions for this page. + [60] Rsvd — Reserved. + [61] IR — Interrupt Remap (alias in page tables, platform-specific). + [62] IW — Interrupt Write (alias in page tables, platform-specific). + [63] NX — No-Execute. 1 = instruction fetches from this page are blocked (only with NXSup). +``` + +**Level-to-address-bits mapping**: + +| Levels | Address Bits | Max Physical Address | +|--------|-------------|---------------------| +| 1 | 21 | 2 MiB | +| 2 | 30 | 1 GiB | +| 3 | 39 | 512 GiB | +| 4 | 48 | 256 TiB | +| 5 | 57 | 128 PiB | +| 6 | 63 | ~8 EiB | + +**Linux page table macros** (`drivers/iommu/amd/amd_iommu_types.h`): + +```c +#define PM_LEVEL_SHIFT 9 +#define PM_LEVEL_SIZE (1UL << PM_LEVEL_SHIFT) +#define PM_LEVEL_INDEX(level, address) \ + (((address) >> (12 + (((level) - 1) * 9))) & 0x1FF) +#define PM_LEVEL_ENC(level, address) \ + ((address) | (((level) - 1) << 9) | 1ULL) // PR=1, NextLevel=level-1 +#define PM_PTE_LEVEL(pte) (((pte) >> 9) & 0x7) +``` + +### 1.8 Initialization Sequence (AMD-Vi) + +Step-by-step register programming to bring up AMD-Vi IOMMU. + +``` +Step 1: Discover IOMMU hardware + - Scan ACPI tables for IVRS signature + - Parse IVHD entries to find MMIO base address + - Read ExtendedFeature (0x0030) to determine capabilities + +Step 2: Disable IOMMU (ensure clean state) + - Control = 0x00000000 (IOMMUEnable=0, all features off) + - Wait until Status[0] (IOMMURunning) = 0 + +Step 3: Allocate and zero Device Table + - Alloc 2 MiB contiguous physical memory (65536 × 32 bytes) + - Zero all entries + - Write DevTableBar (0x0000): + Bits 0:8 = DevTableSize (0x0F for 65536 entries: 2^(0x0F+1) = 65536) + Bits 12:51 = Physical address of table + +Step 4: Allocate and zero Command Buffer + - Alloc 8192 bytes contiguous physical (512 entries × 16 bytes) + - Zero all entries + - Write CmdBufBar (0x0008): + Bits 0:8 = CmdBufLen (0x08 for 512 entries: 2^(0x08+2) = 4096 bytes... use 0x09 for 8192) + Bits 12:51 = Physical address + +Step 5: Allocate and zero Event Log + - Alloc 8192 bytes contiguous physical (512 entries × 16 bytes) + - Zero all entries + - Write EvtLogBar (0x0010): + Bits 0:8 = EvtLogLen (0x09 for 8192 bytes) + Bits 12:51 = Physical address + +Step 6: Set up exclusion range (optional) + - Write ExclusionBase (0x0020) = start of excluded physical range + - Write ExclusionLimit (0x0028) = end of excluded physical range + - Skip if no exclusion needed + +Step 7: Reset head/tail pointers + - CmdBufHead (0x2000) = 0 + - CmdBufTail (0x2008) = 0 + - EvtLogHead (0x2010) = 0 + - (EvtLogTail is RO, hardware sets it) + +Step 8: Allocate and zero Interrupt Remap Table (if IR needed) + - Alloc 4096 × 16 bytes = 64 KiB (for IntTabLen=11, max 4096 entries) + - Zero all entries + - Configure each device's DTE with IRTP pointing to this table + +Step 9: Configure DTEs for devices + - For each device that needs translation: + Set V=1, TV=1, Mode=4 (4-level), PTP=root page table address + Set IR=1, IW=1 if interrupt remapping is used + Set IntCtl=0x02 (remapped), IntTabLen, IRTP + +Step 10: Enable features in Control register + - Control = 0x00000000 | bits for enabled features: + Bit 2 (EventLogEn) = 1 + Bit 5 (CmdBufEn) = 1 + Bit 22 (XTEn) = 1 (if x2APIC supported and in use) + Bit 23 (NXEn) = 1 (if NX supported) + - DO NOT set bit 0 (IOMMUEnable) yet + +Step 11: Flush caches via command buffer + - Submit INVALIDATE_IOMMU_ALL (0x05) if supported, or: + INVALIDATE_DEVTAB_ENTRY for each modified device + INVALIDATE_INTERRUPT_TABLE for each device with IR + - Submit COMPLETION_WAIT (0x01) to synchronize + - Wait for completion + +Step 12: Enable IOMMU translations + - Set Control bit 0 (IOMMUEnable) = 1 + - Read Status to verify IOMMURunning = 1 + +Step 13: Enable interrupts (optional) + - Set Control bit 3 (EventIntEn) = 1 + - Configure MSI delivery for the IOMMU PCI device +``` + +--- + +## 2. Intel VT-d + +### 2.1 MMIO Register Map + +Base address obtained from ACPI DMAR table (DRHD entry `RegisterBase` field). + +| Offset | Name | Size | Access | Description | +|--------|------|------|--------|-------------| +| 0x00 | VER_REG | 32-bit | RO | Architecture Version. [0:7] = Minor, [8:15] = Major. | +| 0x08 | CAP_REG | 64-bit | RO | Capability Register. See bit layout below. | +| 0x10 | ECAP_REG | 64-bit | RO | Extended Capability Register. See bit layout below. | +| 0x18 | GCMD_REG | 32-bit | WO | Global Command Register. Write to request operations. | +| 0x1C | GSTS_REG | 32-bit | RO | Global Status Register. Reflects GCMD results. | +| 0x20 | RTADDR_REG | 64-bit | R/W | Root Table Address. Bit 0 = RTT (Root Table Type: 0=legacy, 1=extended). Bits 12:63 = physical address. | +| 0x28 | CCMD_REG | 64-bit | R/W | Context Command Register. For invalidating context caches. | +| 0x30 | FSTS_REG | 32-bit | RO | Fault Status Register. | +| 0x34 | FECTL_REG | 32-bit | R/W | Fault Event Control Register. | +| 0x38 | FEDATA_REG | 32-bit | R/W | Fault Event Data Register. MSI data. | +| 0x3C | FEADDR_REG | 32-bit | R/W | Fault Event Address Register. MSI address low. | +| 0x40 | FEUADDR_REG | 32-bit | R/W | Fault Event Upper Address Register. MSI address high. | +| 0x48 | AFLOG_REG | 64-bit | R/W | Advanced Fault Log Register. | +| 0x58 | PMEN_REG | 32-bit | R/W | Protected Memory Enable Register. | +| 0x5C | PLMBASE_REG | 32-bit | R/W | Protected Low Memory Base Register. | +| 0x60 | PLMLIMIT_REG | 32-bit | R/W | Protected Low Memory Limit Register. | +| 0x68 | PHMBASE_REG | 64-bit | R/W | Protected High Memory Base Register. | +| 0x70 | PHMLIMIT_REG | 64-bit | R/W | Protected High Memory Limit Register. | +| 0x78 | IQH_REG | 64-bit | RO | Invalidation Queue Head Register. | +| 0x80 | IQT_REG | 64-bit | R/W | Invalidation Queue Tail Register. | +| 0x88 | IQA_REG | 64-bit | R/W | Invalidation Queue Address Register. | +| 0x90 | ICS_REG | 32-bit | RO | Invalidation Completion Status Register. | +| 0x94 | IECTL_REG | 32-bit | R/W | Invalidation Event Control Register. | +| 0x98 | IEDATA_REG | 32-bit | R/W | Invalidation Event Data Register. | +| 0x9C | IEADDR_REG | 32-bit | R/W | Invalidation Event Address Register. | +| 0xA0 | IEUADDR_REG | 32-bit | R/W | Invalidation Event Upper Address Register. | +| 0xB0 | IRTA_REG | 64-bit | R/W | Interrupt Remapping Table Address Register. | + +#### CAP_REG (0x08) Bit Layout + +| Bit | Name | Description | +|-----|------|-------------| +| 0 | ND (bits 0:2) | Number of Domains Supported. 0=4, 1=16, 2=64, 3=256, 4=1024, 5=4K, 6=16K, 7=64K. | +| 3:7 | ZLR | Zero Length Read. 1 = supported. | +| 8 | AFL | Advanced Fault Logging. 1 = supported. | +| 9 | RWBF | Required Write-Buffer Flushing. 1 = software must flush write buffers before invalidations. | +| 10:11 | PLMR | Protected Low Memory Region. 1 = supported. | +| 12:13 | PHMR | Protected High Memory Region. 1 = supported. | +| 14 | CM | Caching Mode. 1 = IOMMU operates in caching mode (no explicit invalidation needed). | +| 15:23 | SAGAW | Supported Adjusted Guest Address Widths. Bit N set = (N+1)-level page tables supported. | +| 24:33 | MGAW | Maximum Guest Address Width. Actual address width = MGAW + 1. | +| 34:35 | MAMV | Maximum Address Mask Value. For interrupt remapping. | +| 36 | ZAM | Zero Address/Mask. For interrupt remapping. | +| 37:39 | Rsvd | Reserved. | +| 40 | FL1GP | First Level 1-GByte Page Support. | +| 41:43 | Rsvd | Reserved. | +| 44 | PSI | Page Selective Invalidation. 1 = supported. | +| 45:51 | Rsvd | Reserved. | +| 52 | SPS | Super Page Support. Bits indicate 2MiB, 1GiB, 512GiB support. | +| 52:55 | FR | Fault Recording Register count minus 1. | +| 56:60 | Rsvd | Reserved. | +| 61:63 | Rsvd | Reserved. | + +#### ECAP_REG (0x10) Bit Layout + +| Bit | Name | Description | +|-----|------|-------------| +| 0 | C | Page Request (PRI) support. | +| 1 | QI | Queued Invalidation support. 1 = IQ mechanism supported. | +| 2 | DT | Device TLB support. | +| 3 | IR | Interrupt Remapping support. 1 = supported. | +| 4 | EIM | Extended Interrupt Mode. 1 = x2APIC mode supported for IR. | +| 5:7 | Rsvd | Reserved. | +| 8 | PT | Pass Through. 1 = second-level translation bypass supported. | +| 9:17 | Rsvd | Reserved. | +| 18 | SC | Snoop Control. | +| 19:24 | Rsvd | Reserved. | +| 25:34 | IRO | IOTLB Register Offset. Offset from base for IOTLB registers. | +| 35:43 | Rsvd | Reserved. | +| 44:47 | MHMV | Maximum Handle Mask Value. | +| 48 | ECS | Extended Context Support. | +| 49 | MTS | Memory Type Support. | +| 50 | NEST | Nested Translation Support. | +| 51:63 | Rsvd | Reserved. | + +#### GCMD_REG (0x18) Bit Layout (Write-Only) + +| Bit | Name | Description | +|-----|------|-------------| +| 31 | TE | Translation Enable. Write 1 to enable/disable. | +| 30 | SRTP | Set Root Table Pointer. Write 1, hardware sets GSTS.RTPS when done. | +| 29 | SFL | Set Fault Log. Write 1 to set fault log pointer. | +| 28 | EAFL | Enable Advanced Fault Log. | +| 27 | WBF | Write Buffer Flush. Write 1, hardware sets GSTS.WBFS when done. | +| 26 | QIE | Queued Invalidation Enable. Write 1 to enable. | +| 25 | SIRTP | Set Interrupt Remap Table Pointer. Write 1, hardware sets GSTS.IRTPS. | +| 24 | CFI | Compatibility Format Interrupt. Write 1 to block compatibility interrupts. | +| 23 | IR | Interrupt Remap. Write 1 to enable interrupt remapping. | +| 0:22 | Rsvd | Reserved. Must write zero. | + +#### GSTS_REG (0x1C) Bit Layout (Read-Only) + +| Bit | Name | Description | +|-----|------|-------------| +| 31 | TES | Translation Enable Status. 1 = enabled. | +| 30 | RTPS | Root Table Pointer Status. 1 = root table pointer set. | +| 29 | FLS | Fault Log Status. | +| 28 | AFLS | Advanced Fault Log Status. | +| 27 | WBFS | Write Buffer Flush Status. 1 = flush complete. | +| 26 | QIES | Queued Invalidation Enable Status. | +| 25 | IRTPS | Interrupt Remap Table Pointer Status. | +| 24 | CFIS | Compatibility Format Interrupt Status. | +| 23 | IRES | Interrupt Remap Enable Status. | +| 0:22 | Rsvd | Reserved. | + +### 2.2 Root Table Entry + +The Root Table is pointed to by RTADDR_REG. It contains 256 entries (one per PCI bus). Each entry is 128 bits (16 bytes). Must be 4KiB-aligned. + +``` +Root Entry (128 bits = data[0] data[1], each u64): + +data[0]: + [0] P — Present. 1 = this bus has context entries. + [1:63] CTP — Context Table Pointer. Physical address of the context table + for this bus. Bits 12:63 hold address. Must be 4KiB-aligned. + +data[1]: + [0:63] Rsvd — Reserved. Must be zero. +``` + +### 2.3 Context Entry + +Each Context Table contains 256 entries (one per device:function on a bus). Each entry is 128 bits (16 bytes). + +``` +Context Entry (128 bits = data[0] data[1], each u64): + +data[0]: + [0] P — Present. 1 = entry is valid. + [1] FPD — Fault Processing Disable. 1 = faults from this device are suppressed. + [2:3] TT — Translation Type: + 00 = Legacy mode (second-level translation only) + 01 = PASID-granular translation + 10 = Pass-through (no second-level translation, bypass) + 11 = Reserved + [4:11] Rsvd — Reserved. + [12:63] SLPTPTR — Second Level Page Table Pointer. Physical address of the + second-level (guest) page table root. Must be 4KiB-aligned. + +data[1]: + [0:15] DID — Domain Identifier. Associates this device with a domain. + [16:63] Rsvd — Reserved. Must be zero. +``` + +**Extended Context Entry** (when ECS=1 in ECAP): + +``` +data[0]: + [0] P — Present + [1] FPD — Fault Processing Disable + [2:3] TT — Translation Type (same as above) + [4:11] Rsvd + [12:63] SLPTPTR — Page table pointer (same as above) + +data[1]: + [0:15] DID — Domain Identifier + [16:19] AW — Address Width. 0=3-level, 1=4-level, 2=5-level, 3=6-level. + [20:63] Rsvd — Reserved +``` + +### 2.4 DMAR ACPI Table + +The DMAR (DMA Remapping) table describes Intel VT-d IOMMU topology. Found by scanning ACPI tables with signature "DMAR" (0x52414D44). + +#### DMAR Header (48 bytes) + +``` +Offset Size Field Description +0x00 4 Signature "DMAR" (0x52414D44) +0x04 4 Length Total table length in bytes +0x08 1 Revision 1 +0x09 1 Checksum ACPI checksum (sum of all bytes = 0) +0x0A 6 OemId OEM identifier +0x10 8 OemTableId OEM table identifier +0x18 4 OemRevision OEM revision +0x1C 4 CreatorId ASL compiler vendor +0x20 4 CreatorRevision ASL compiler revision +0x24 1 HostAddressWidth DMA physical address width (e.g., 46 for 64 TiB) +0x25 1 Flags [0] = INTR_REMAP (interrupt remapping supported) + [1] = X2APIC_OPT_OUT (firmware requests no x2APIC) +0x26 6 Reserved Reserved +0x2C ... RemappingStructures Variable-length list of DRHD/RMRR/ATSR/etc entries +``` + +#### DRHD (DMA Remapping Hardware Unit Definition) + +Describes a single IOMMU unit. Multiple DRHD entries for systems with multiple IOMMUs. + +``` +Offset Size Field Description +0x00 2 Type 0x0001 = DRHD +0x02 2 Length Total length of this entry including device scope +0x04 1 Flags [0] = INCLUDE_PCI_ALL (1=this IOMMU handles all PCI devices + not covered by other non-ALL DRHD entries) +0x05 1 Reserved Reserved +0x06 2 SegmentNumber PCI Segment Group number +0x08 8 RegisterBaseAddress Physical MMIO base address of IOMMU registers +0x10 ... DeviceScope Variable-length device scope entries follow +``` + +#### DRHD Device Scope Entry + +``` +Offset Size Field Description +0x00 1 Type Device scope type: + 0x01 = PCI Endpoint Device + 0x02 = PCI SubHierarchy + 0x03 = IOAPIC + 0x04 = MSI Capable HPET + 0x05 = ACPI Name-Space Device +0x01 1 Length Total length of this scope entry +0x02 1 EnumerationId Enumeration ID (e.g., IOAPIC ID for type 0x03) +0x03 1 StartBusNumber Starting PCI bus number +0x04 ... Path PCI path entries (each 2 bytes: Device, Function) +``` + +#### RMRR (Reserved Memory Region Reporting) + +Describes memory regions that must be identity-mapped for specific devices (e.g., USB controllers, graphics). + +``` +Offset Size Field Description +0x00 2 Type 0x0002 = RMRR +0x02 2 Length Total length of this entry +0x04 2 Reserved Reserved +0x06 2 SegmentNumber PCI Segment Group +0x08 8 BaseAddress Physical start address of reserved region +0x10 8 EndAddress Physical end address of reserved region (inclusive) +0x18 ... DeviceScope Device scope entries for devices that access this region +``` + +#### Other DMAR Sub-Table Types + +| Type | Name | Description | +|------|------|-------------| +| 0x0000 | Reserved | Reserved. | +| 0x0001 | DRHD | DMA Remapping Hardware Unit Definition. | +| 0x0002 | RMRR | Reserved Memory Region Reporting. | +| 0x0003 | ATSR | Root Port ATS (Address Translation Service) Capability Reporting. | +| 0x0004 | RHSA | Remapping Hardware Static Affinity (NUMA locality). | +| 0x0005 | ANDD | ACPI Name-space Device Declaration. | + +### 2.5 Page Table Entry (Intel VT-d) + +Intel VT-d uses multi-level page tables. The number of levels depends on SAGAW in CAP_REG. Typically 3 or 4 levels. Each PTE is 64 bits. + +``` +PTE (64 bits): + [0] R — Read permission. 1 = device may read. + [1] W — Write permission. 1 = device may write. + [2:11] Rsvd — Reserved. Must be zero unless extended features. + [12:63] ADDR — Physical address. For non-leaf: next-level table address (4KiB-aligned). + For leaf: page frame address. + Mask depends on page size: + 4KiB: bits 12:63 + 2MiB: bits 21:63 (super page) + 1GiB: bits 30:63 (super page) +``` + +**Extended PTE with Supervisor bit** (when CAP_REG supports it): + +``` + [2] S — Supervisor. 1 = supervisor-mode page. + [3] AW — Access/Dirty (for first-level translation). + [4] PSE — Page Size Extension (1 = super page at this level). + [5] A — Accessed flag. + [6] D — Dirty flag. + [7:11] Rsvd — Reserved. +``` + +### 2.6 Initialization Sequence (Intel VT-d) + +Step-by-step register programming to bring up Intel VT-d. + +``` +Step 1: Discover IOMMU hardware + - Scan ACPI tables for DMAR signature + - Parse DRHD entries to find MMIO base addresses + - Read CAP_REG (0x08) for capabilities + - Read ECAP_REG (0x10) for extended capabilities + - Read VER_REG (0x00) for architecture version + +Step 2: Ensure IOMMU is disabled + - Verify GSTS_REG.TES = 0 (translation not enabled) + - If TES=1, write GCMD_REG with TE=0, wait for TES to clear + +Step 3: Allocate and zero Root Table + - Alloc 4 KiB (256 entries × 16 bytes) + - Zero all entries + - Write RTADDR_REG (0x20): + Bit 0 = 0 (legacy root table type) + Bits 12:63 = physical address + +Step 4: Set Root Table Pointer + - Write GCMD_REG bit 30 (SRTP) = 1 + - Poll GSTS_REG bit 30 (RTPS) until it reads 1 + +Step 5: Allocate and zero Context Tables (per bus) + - For each bus with devices: + Alloc 4 KiB (256 entries × 16 bytes) + Zero all entries + Set Root Entry P=1, CTP=context table address + +Step 6: Configure Context Entries + - For each device:function: + Set P=1, TT=00 (legacy), SLPTPTR=page table root, DID=domain ID + - For pass-through: Set P=1, TT=10, DID=domain ID + +Step 7: Build page tables (per domain) + - Create page table hierarchy matching SAGAW levels (typically 3 or 4) + - Map device-visible physical addresses to host physical addresses + - For identity mapping: GPA = HPA + +Step 8: Handle RMRR regions + - Identity-map all RMRR regions for their respective devices + - These regions must always be accessible to the listed devices + +Step 9: Allocate Interrupt Remap Table (if ECAP_REG.IR=1) + - Alloc table: 2^(IRTA_REG.TableSize+1) × 16 bytes + - Zero all entries + - Write IRTA_REG (0xB0): + Bits 0:6 = TableSize (e.g., 0xF = 65536 entries) + Bits 6:7 = IRTE Mode (00=remapped, 01=posted) + Bits 12:63 = Physical address + Bit 4 = EIME (Extended Interrupt Mode Enable) if x2APIC + +Step 10: Enable Interrupt Remapping + - Write GCMD_REG bit 25 (SIRTP) = 1 + - Poll GSTS_REG bit 25 (IRTPS) until 1 + - Write GCMD_REG bit 24 (CFI) = 1 to block compatibility format interrupts + - Poll GSTS_REG bit 24 (CFIS) until 1 + - Write GCMD_REG bit 23 (IR) = 1 + - Poll GSTS_REG bit 23 (IRES) until 1 + +Step 11: Invalidate caches + - If QI (Queued Invalidation) supported (ECAP_REG.QI=1): + Set up Invalidation Queue (IQA_REG) + Submit queue-based invalidation descriptors + - Else use register-based invalidation: + Write CCMD_REG for context cache invalidation + Write IOTLB registers for TLB invalidation + +Step 12: Enable translation + - Write GCMD_REG bit 31 (TE) = 1 + - Poll GSTS_REG bit 31 (TES) until 1 + +Step 13: Enable fault handling + - Program FEDATA_REG, FEADDR_REG, FEUADDR_REG for MSI delivery + - Write FECTL_REG to enable fault interrupts +``` + +--- + +## 3. Rust Struct Definitions + +These `#[repr(C, packed)]` structs can be used directly in the Red Bear OS IOMMU implementation. All bitfield access should go through helper methods (shown below) to ensure correct masking. + +### 3.1 AMD-Vi Structs + +```rust +// AMD-Vi MMIO Registers + +/// AMD-Vi IOMMU MMIO register block. +/// Base address from ACPI IVRS IVHD entry. +#[repr(C)] +pub struct AmdViMmio { + pub dev_table_bar: u64, // 0x0000 + pub cmd_buf_bar: u64, // 0x0008 + pub evt_log_bar: u64, // 0x0010 + pub control: u32, // 0x0018 + _pad0: u32, // 0x001C + pub exclusion_base: u64, // 0x0020 + pub exclusion_limit: u64, // 0x0028 + pub extended_feature: u64, // 0x0030 + pub ppr_log_bar: u64, // 0x0038 + _pad1: [u64; 0x03F0], // 0x0040..0x1FFC (padding to 0x2000) + pub cmd_buf_head: u64, // 0x2000 + pub cmd_buf_tail: u64, // 0x2008 + pub evt_log_head: u64, // 0x2010 + pub evt_log_tail: u64, // 0x2018 + pub status: u32, // 0x2020 +} +// Static assertions for offset verification +const _: () = assert!(core::mem::offset_of!(AmdViMmio, dev_table_bar) == 0x0000); +const _: () = assert!(core::mem::offset_of!(AmdViMmio, control) == 0x0018); +const _: () = assert!(core::mem::offset_of!(AmdViMmio, cmd_buf_head) == 0x2000); + +/// AMD-Vi Control Register bits. +pub mod amd_control { + pub const IOMMU_ENABLE: u32 = 1 << 0; + pub const HT_TUN_EN: u32 = 1 << 1; + pub const EVENT_LOG_EN: u32 = 1 << 2; + pub const EVENT_INT_EN: u32 = 1 << 3; + pub const COM_WAIT_INT_EN: u32 = 1 << 4; + pub const CMD_BUF_EN: u32 = 1 << 5; + pub const PPR_LOG_EN: u32 = 1 << 6; + pub const PPR_INT_EN: u32 = 1 << 7; + pub const PPR_EN: u32 = 1 << 8; + pub const GT_EN: u32 = 1 << 9; + pub const GA_EN: u32 = 1 << 10; + pub const XT_EN: u32 = 1 << 22; + pub const NX_EN: u32 = 1 << 23; +} + +/// AMD-Vi Status Register bits. +pub mod amd_status { + pub const IOMMU_RUNNING: u32 = 1 << 0; + pub const EVENT_OVERFLOW: u32 = 1 << 1; + pub const EVENT_LOG_INT: u32 = 1 << 2; + pub const COM_WAIT_INT: u32 = 1 << 3; + pub const PPR_OVERFLOW: u32 = 1 << 4; + pub const PPR_INT: u32 = 1 << 5; +} + +/// AMD-Vi Extended Feature Register bits. +pub mod amd_ext_feature { + pub const PREF_SUP: u64 = 1 << 0; + pub const PPR_SUP: u64 = 1 << 1; + pub const XT_SUP: u64 = 1 << 2; + pub const NX_SUP: u64 = 1 << 3; + pub const GT_SUP: u64 = 1 << 4; + pub const IA_SUP: u64 = 1 << 6; + pub const GA_SUP: u64 = 1 << 7; + pub const HE_SUP: u64 = 1 << 8; + pub const PC_SUP: u64 = 1 << 9; + pub const GI_SUP: u64 = 1 << 57; +} + +/// AMD-Vi Device Table Entry (256 bits = 32 bytes). +/// Index by BDF: (bus << 8) | (dev << 3) | func. +/// Table holds up to 65536 entries. +#[repr(C, packed)] +pub struct AmdDte { + pub data: [u64; 4], +} + +impl AmdDte { + /// Create a zeroed (invalid) DTE. + pub const fn zeroed() -> Self { + Self { data: [0; 4] } + } + + // data[0] accessors + + pub fn valid(&self) -> bool { + self.data[0] & (1 << 0) != 0 + } + + pub fn set_valid(&mut self, v: bool) { + if v { self.data[0] |= 1 << 0; } else { self.data[0] &= !(1 << 0); } + } + + pub fn translation_valid(&self) -> bool { + self.data[0] & (1 << 1) != 0 + } + + pub fn set_translation_valid(&mut self, v: bool) { + if v { self.data[0] |= 1 << 1; } else { self.data[0] &= !(1 << 1); } + } + + /// Translation mode (bits 9:11). 0=no translation, 4=4-level page table. + pub fn mode(&self) -> u64 { + (self.data[0] >> 9) & 0x7 + } + + pub fn set_mode(&mut self, m: u64) { + self.data[0] = (self.data[0] & !(0x7 << 9)) | ((m & 0x7) << 9); + } + + /// Page Table Root Pointer (bits 12:51 of data[0]). + /// Address must be 4KiB-aligned. + pub fn page_table_root(&self) -> u64 { + (self.data[0] >> 12) & 0x000F_FFFF_FFFF_FFFF + } + + pub fn set_page_table_root(&mut self, addr: u64) { + self.data[0] = (self.data[0] & !(0x000F_FFFF_FFFF_FFFF << 12)) + | ((addr >> 12) << 12); + } + + /// Interrupt Remapping Enable (bit 61 of data[0]). + pub fn interrupt_remap(&self) -> bool { + self.data[0] & (1 << 61) != 0 + } + + pub fn set_interrupt_remap(&mut self, v: bool) { + if v { self.data[0] |= 1 << 61; } else { self.data[0] &= !(1 << 61); } + } + + /// Interrupt Write permission (bit 62 of data[0]). + pub fn interrupt_write(&self) -> bool { + self.data[0] & (1 << 62) != 0 + } + + pub fn set_interrupt_write(&mut self, v: bool) { + if v { self.data[0] |= 1 << 62; } else { self.data[0] &= !(1 << 62); } + } + + // data[1] accessors + + /// Interrupt Remap Table Length (bits 0:3 of data[1]). + /// Number of IRTEs = 2^(len+1). + pub fn int_table_len(&self) -> u64 { + self.data[1] & 0xF + } + + pub fn set_int_table_len(&mut self, len: u64) { + self.data[1] = (self.data[1] & !0xF) | (len & 0xF); + } + + /// Interrupt Control (bits 4:5 of data[1]). + /// 00=abort, 01=pass-through, 10=remapped. + pub fn int_control(&self) -> u64 { + (self.data[1] >> 4) & 0x3 + } + + pub fn set_int_control(&mut self, ctl: u64) { + self.data[1] = (self.data[1] & !(0x3 << 4)) | ((ctl & 0x3) << 4); + } + + /// Interrupt Remap Table Pointer (bits 6:51 of data[1]). + /// Address must be 4KiB-aligned. + pub fn int_remap_table_ptr(&self) -> u64 { + (self.data[1] >> 6) & 0x000F_FFFF_FFFF_FFFF + } + + pub fn set_int_remap_table_ptr(&mut self, addr: u64) { + self.data[1] = (self.data[1] & !(0x000F_FFFF_FFFF_FFFF << 6)) + | ((addr >> 6) << 6); + } +} + +const _: () = assert!(core::mem::size_of::() == 32); + +/// AMD-Vi Interrupt Remapping Table Entry (128 bits = 16 bytes). +#[repr(C, packed)] +pub struct AmdIrte { + pub data: [u64; 2], +} + +impl AmdIrte { + pub const fn zeroed() -> Self { + Self { data: [0; 2] } + } + + /// Remap enable (bit 0 of data[0]). + pub fn remap_enabled(&self) -> bool { + self.data[0] & (1 << 0) != 0 + } + + pub fn set_remap_enabled(&mut self, v: bool) { + if v { self.data[0] |= 1 << 0; } else { self.data[0] &= !(1 << 0); } + } + + /// Suppress IO Page Fault (bit 1). + pub fn suppress_io_pf(&self) -> bool { + self.data[0] & (1 << 1) != 0 + } + + pub fn set_suppress_io_pf(&mut self, v: bool) { + if v { self.data[0] |= 1 << 1; } else { self.data[0] &= !(1 << 1); } + } + + /// Interrupt type (bits 2:4 of data[0]). + pub fn int_type(&self) -> u64 { + (self.data[0] >> 2) & 0x7 + } + + pub fn set_int_type(&mut self, t: u64) { + self.data[0] = (self.data[0] & !(0x7 << 2)) | ((t & 0x7) << 2); + } + + /// Destination mode (bit 2 of data[0], when using xAPIC logical). + /// 0=physical APIC ID, 1=logical. + pub fn dst_mode(&self) -> bool { + self.data[0] & (1 << 2) != 0 + } + + /// Destination APIC ID (bits 16:31 of data[0], low 16 bits). + /// For x2APIC, high 32 bits in data[1] bits 0:31. + pub fn destination(&self) -> u32 { + ((self.data[0] >> 16) & 0xFFFF) as u32 | ((self.data[1] & 0xFFFF_FFFF) as u32) << 16 + } + + pub fn set_destination(&mut self, apic_id: u32) { + self.data[0] = (self.data[0] & !(0xFFFF << 16)) | (((apic_id & 0xFFFF) as u64) << 16); + self.data[1] = (self.data[1] & !0xFFFF_FFFF) | ((apic_id >> 16) as u64); + } + + /// Vector (bits 32:39 of data[0], but stored in low byte of upper word). + pub fn vector(&self) -> u8 { + ((self.data[0] >> 32) & 0xFF) as u8 + } + + pub fn set_vector(&mut self, v: u8) { + self.data[0] = (self.data[0] & !(0xFF_u64 << 32)) | ((v as u64) << 32); + } +} + +const _: () = assert!(core::mem::size_of::() == 16); + +/// AMD-Vi Command Buffer Entry (128 bits = 16 bytes = 4 × u32). +#[repr(C, packed)] +pub struct AmdCmdEntry { + pub word: [u32; 4], +} + +impl AmdCmdEntry { + pub const fn zeroed() -> Self { + Self { word: [0; 4] } + } + + pub fn opcode(&self) -> u8 { + (self.word[0] & 0xF) as u8 + } + + pub fn set_opcode(&mut self, op: u8) { + self.word[0] = (self.word[0] & !0xF) | (op as u32 & 0xF); + } +} + +const _: () = assert!(core::mem::size_of::() == 16); + +/// AMD-Vi Command Opcodes. +pub mod amd_cmd_opcode { + pub const COMPLETION_WAIT: u8 = 0x01; + pub const INVALIDATE_DEVTAB_ENTRY: u8 = 0x02; + pub const INVALIDATE_IOMMU_PAGES: u8 = 0x03; + pub const INVALIDATE_INTERRUPT_TABLE: u8 = 0x04; + pub const INVALIDATE_IOMMU_ALL: u8 = 0x05; +} + +/// Build a COMPLETION_WAIT command. +pub fn amd_cmd_completion_wait(store_addr: u64, store_data: u32) -> AmdCmdEntry { + let mut cmd = AmdCmdEntry::zeroed(); + cmd.set_opcode(amd_cmd_opcode::COMPLETION_WAIT); + cmd.word[0] |= 1 << 4; // Store = 1 + cmd.word[1] = store_addr as u32; + cmd.word[2] = (store_addr >> 32) as u32; + cmd.word[3] = store_data; + cmd +} + +/// Build an INVALIDATE_DEVTAB_ENTRY command for a given BDF. +pub fn amd_cmd_invalidate_devtab(bdf: u16) -> AmdCmdEntry { + let mut cmd = AmdCmdEntry::zeroed(); + cmd.set_opcode(amd_cmd_opcode::INVALIDATE_DEVTAB_ENTRY); + cmd.word[1] = bdf as u32; + cmd +} + +/// Build an INVALIDATE_IOMMU_PAGES command. +/// If size=true, invalidates all pages for the domain (address ignored). +pub fn amd_cmd_invalidate_pages(domain_id: u16, address: u64, size: bool) -> AmdCmdEntry { + let mut cmd = AmdCmdEntry::zeroed(); + cmd.set_opcode(amd_cmd_opcode::INVALIDATE_IOMMU_PAGES); + if size { cmd.word[0] |= 1 << 4; } // S bit + cmd.word[1] = domain_id as u32; + cmd.word[2] = address as u32; + cmd.word[3] = (address >> 32) as u32; + cmd +} + +/// Build an INVALIDATE_INTERRUPT_TABLE command. +pub fn amd_cmd_invalidate_int_table(bdf: u16) -> AmdCmdEntry { + let mut cmd = AmdCmdEntry::zeroed(); + cmd.set_opcode(amd_cmd_opcode::INVALIDATE_INTERRUPT_TABLE); + cmd.word[1] = bdf as u32; + cmd +} + +/// Build an INVALIDATE_IOMMU_ALL command. +pub fn amd_cmd_invalidate_all() -> AmdCmdEntry { + let mut cmd = AmdCmdEntry::zeroed(); + cmd.set_opcode(amd_cmd_opcode::INVALIDATE_IOMMU_ALL); + cmd +} + +/// AMD-Vi Event Log Entry (128 bits = 16 bytes = 4 × u32). +#[repr(C, packed)] +pub struct AmdEvtEntry { + pub word: [u32; 4], +} + +impl AmdEvtEntry { + pub const fn zeroed() -> Self { + Self { word: [0; 4] } + } + + /// Event code (bits 0:15 of word[0]). + pub fn event_code(&self) -> u16 { + (self.word[0] & 0xFFFF) as u16 + } + + /// Device ID / BDF (bits 0:15 of word[1]). + pub fn device_id(&self) -> u16 { + (self.word[1] & 0xFFFF) as u16 + } + + /// Fault address (word[2] | word[3] << 32). + pub fn fault_address(&self) -> u64 { + self.word[2] as u64 | ((self.word[3] as u64) << 32) + } + + /// Flags from word[0] bits 16:22 (for IO_PAGE_FAULT). + pub fn fault_flags(&self) -> u16 { + ((self.word[0] >> 16) & 0x7F) as u16 + } + + /// Read/write direction from fault flags bit 4 (RW). + pub fn is_write(&self) -> bool { + self.word[0] & (1 << 20) != 0 + } + + /// Permission error from fault flags bit 3 (PE). + pub fn is_permission_error(&self) -> bool { + self.word[0] & (1 << 19) != 0 + } +} + +const _: () = assert!(core::mem::size_of::() == 16); + +/// AMD-Vi Event Codes. +pub mod amd_evt_code { + pub const ILLEGAL_DEV_TABLE_ENTRY: u16 = 0x01; + pub const IO_PAGE_FAULT: u16 = 0x02; + pub const DEV_TABLE_HW_ERROR: u16 = 0x03; + pub const PAGE_TABLE_HW_ERROR: u16 = 0x04; + pub const ILLEGAL_COMMAND: u16 = 0x05; + pub const COMMAND_HW_ERROR: u16 = 0x06; + pub const IOTLB_INV_TIMEOUT: u16 = 0x07; + pub const INVALID_DEV_REQUEST: u16 = 0x08; +} + +/// AMD-Vi Page Table Entry (64 bits). +#[repr(C, packed)] +pub struct AmdPte(pub u64); + +impl AmdPte { + /// Present bit (bit 0). + pub fn present(&self) -> bool { + self.0 & (1 << 0) != 0 + } + + pub fn set_present(&mut self, v: bool) { + if v { self.0 |= 1 << 0; } else { self.0 &= !(1 << 0); } + } + + /// Next level (bits 9:11). 0 = leaf PTE, 1-5 = pointer to next table. + pub fn next_level(&self) -> u64 { + (self.0 >> 9) & 0x7 + } + + pub fn set_next_level(&mut self, level: u64) { + self.0 = (self.0 & !(0x7 << 9)) | ((level & 0x7) << 9); + } + + /// Output address (bits 12:51). Physical frame or next-table address. + pub fn output_addr(&self) -> u64 { + self.0 & (0x000F_FFFF_FFFF_FFFF << 12) + } + + pub fn set_output_addr(&mut self, addr: u64) { + self.0 = (self.0 & !(0x000F_FFFF_FFFF_FFFF << 12)) | (addr & (0x000F_FFFF_FFFF_FFFF << 12)); + } + + /// No-execute (bit 63). Only valid when NXSup=1. + pub fn no_execute(&self) -> bool { + self.0 & (1 << 63) != 0 + } + + pub fn set_no_execute(&mut self, v: bool) { + if v { self.0 |= 1 << 63; } else { self.0 &= !(1 << 63); } + } +} + +/// Build a leaf PTE that maps addr with Read+Write permissions. +pub fn amd_pte_leaf(addr: u64) -> AmdPte { + let mut pte = AmdPte(0); + pte.set_present(true); + pte.set_next_level(0); // leaf + pte.set_output_addr(addr); + pte.0 |= (1 << 2) | (1 << 3); // IW + IR (write + read permission) + pte +} + +/// Build a non-leaf PTE that points to the next-level table at addr. +pub fn amd_pte_pointer(addr: u64, level: u64) -> AmdPte { + let mut pte = AmdPte(0); + pte.set_present(true); + pte.set_next_level(level); + pte.set_output_addr(addr); + pte +} +``` + +### 3.2 Intel VT-d Structs + +```rust +/// Intel VT-d IOMMU MMIO register block. +/// Base address from ACPI DMAR DRHD entry. +#[repr(C)] +pub struct IntelVtdMmio { + pub ver_reg: u32, // 0x00 Version + _pad0: u32, // 0x04 + pub cap_reg: u64, // 0x08 Capability + pub ecap_reg: u64, // 0x10 Extended Capability + pub gcmd_reg: u32, // 0x18 Global Command (write-only) + pub gsts_reg: u32, // 0x1C Global Status (read-only) + pub rtaddr_reg: u64, // 0x20 Root Table Address + pub ccmd_reg: u64, // 0x28 Context Command + _pad1: u64, // 0x30 + pub fsts_reg: u32, // 0x34 Fault Status + pub fectl_reg: u32, // 0x38 Fault Event Control + pub fedata_reg: u32, // 0x3C Fault Event Data + pub feaddr_reg: u32, // 0x40 Fault Event Address + pub feuaddr_reg: u32, // 0x44 Fault Event Upper Address + _pad2: u32, // 0x48 + pub aflog_reg: u64, // 0x4C Advanced Fault Log (note: spec says 0x48 for 64-bit) + _pad3: u32, // padding + pub pmen_reg: u32, // 0x64 Protected Memory Enable (spec: 0x64) + pub plmbase_reg: u32, // 0x68 Protected Low Memory Base + pub plmlimit_reg: u32, // 0x6C Protected Low Memory Limit + _pad4: u32, + pub phmbase_reg: u64, // 0x70 Protected High Memory Base + pub phmlimit_reg: u64, // 0x78 Protected High Memory Limit + pub iqh_reg: u64, // 0x80 Invalidation Queue Head + pub iqt_reg: u64, // 0x88 Invalidation Queue Tail + pub iqa_reg: u64, // 0x90 Invalidation Queue Address + pub ics_reg: u32, // 0x98 Invalidation Completion Status + _pad5: u32, + pub iectl_reg: u32, // 0xA0 Invalidation Event Control + pub iedata_reg: u32, // 0xA4 Invalidation Event Data + pub ieaddr_reg: u32, // 0xA8 Invalidation Event Address + pub ieuaddr_reg: u32, // 0xAC Invalidation Event Upper Address + _pad6: [u32; 2], // 0xB0..0xB7 (IRTA is separate below) + pub irta_reg: u64, // 0xB8 Interrupt Remapping Table Address +} +// Note: The VT-d register layout has vendor-specific gaps. For production code, +// use volatile read/write helpers with explicit offsets rather than relying +// purely on struct field offsets. The struct above serves as a reference. +// The IRTA_REG offset is 0xB8 per VT-d spec 5.0 (some earlier specs say 0xB0). + +/// Intel VT-d CAP_REG bits. +pub mod vtd_cap { + pub const ND_MASK: u64 = 0x7; + pub const ZLR: u64 = 1 << 8; + pub const AFL: u64 = 1 << 9; + pub const RWBF: u64 = 1 << 10; + pub const PLMR: u64 = 1 << 11; + pub const PHMR: u64 = 1 << 13; + pub const CM: u64 = 1 << 14; + pub const SAGAW: u64 = 0xFF << 16; + pub const SAGAW_3LVL: u64 = 1 << 18; // 3-level page tables + pub const SAGAW_4LVL: u64 = 1 << 19; // 4-level page tables + pub const SAGAW_5LVL: u64 = 1 << 20; // 5-level page tables + pub const SAGAW_6LVL: u64 = 1 << 21; // 6-level page tables + pub const MGAW_SHIFT: u64 = 24; + pub const MGAW_MASK: u64 = 0x3F << 24; +} + +/// Intel VT-d ECAP_REG bits. +pub mod vtd_ecap { + pub const C: u64 = 1 << 0; // Page Request + pub const QI: u64 = 1 << 1; // Queued Invalidation + pub const DT: u64 = 1 << 2; // Device TLB + pub const IR: u64 = 1 << 3; // Interrupt Remapping + pub const EIM: u64 = 1 << 4; // Extended Interrupt Mode (x2APIC) + pub const PT: u64 = 1 << 8; // Pass Through + pub const SC: u64 = 1 << 18; // Snoop Control + pub const IRO_SHIFT: u64 = 25; + pub const IRO_MASK: u64 = 0x3FF << 25; +} + +/// Intel VT-d GCMD_REG bits (write-only). +pub mod vtd_gcmd { + pub const TE: u32 = 1 << 31; // Translation Enable + pub const SRTP: u32 = 1 << 30; // Set Root Table Pointer + pub const SFL: u32 = 1 << 29; // Set Fault Log + pub const EAFL: u32 = 1 << 28; // Enable Advanced Fault Log + pub const WBF: u32 = 1 << 27; // Write Buffer Flush + pub const QIE: u32 = 1 << 26; // Queued Invalidation Enable + pub const SIRTP: u32 = 1 << 25; // Set Interrupt Remap Table Pointer + pub const CFI: u32 = 1 << 24; // Compatibility Format Interrupt + pub const IR: u32 = 1 << 23; // Interrupt Remap Enable +} + +/// Intel VT-d GSTS_REG bits (read-only). +pub mod vtd_gsts { + pub const TES: u32 = 1 << 31; // Translation Enable Status + pub const RTPS: u32 = 1 << 30; // Root Table Pointer Status + pub const FLS: u32 = 1 << 29; // Fault Log Status + pub const AFLS: u32 = 1 << 28; // Advanced Fault Log Status + pub const WBFS: u32 = 1 << 27; // Write Buffer Flush Status + pub const QIES: u32 = 1 << 26; // Queued Invalidation Enable Status + pub const IRTPS: u32 = 1 << 25; // Interrupt Remap Table Pointer Status + pub const CFIS: u32 = 1 << 24; // Compatibility Format Interrupt Status + pub const IRES: u32 = 1 << 23; // Interrupt Remap Enable Status +} + +/// Intel VT-d Root Table Entry (128 bits = 16 bytes). +/// 256 entries (one per PCI bus). 4KiB-aligned. +#[repr(C, packed)] +pub struct VtdRootEntry { + pub data: [u64; 2], +} + +impl VtdRootEntry { + pub const fn zeroed() -> Self { + Self { data: [0; 2] } + } + + /// Present (bit 0 of data[0]). + pub fn present(&self) -> bool { + self.data[0] & (1 << 0) != 0 + } + + pub fn set_present(&mut self, v: bool) { + if v { self.data[0] |= 1 << 0; } else { self.data[0] &= !(1 << 0); } + } + + /// Context Table Pointer (bits 12:63 of data[0]). + pub fn context_table_ptr(&self) -> u64 { + self.data[0] & !0xFFF + } + + pub fn set_context_table_ptr(&mut self, addr: u64) { + self.data[0] = (self.data[0] & 0xFFF) | (addr & !0xFFF); + } +} + +const _: () = assert!(core::mem::size_of::() == 16); + +/// Intel VT-d Context Entry (128 bits = 16 bytes). +/// 256 entries per bus (one per device:function). 4KiB-aligned table. +#[repr(C, packed)] +pub struct VtdContextEntry { + pub data: [u64; 2], +} + +impl VtdContextEntry { + pub const fn zeroed() -> Self { + Self { data: [0; 2] } + } + + /// Present (bit 0 of data[0]). + pub fn present(&self) -> bool { + self.data[0] & (1 << 0) != 0 + } + + pub fn set_present(&mut self, v: bool) { + if v { self.data[0] |= 1 << 0; } else { self.data[0] &= !(1 << 0); } + } + + /// Fault Processing Disable (bit 1 of data[0]). + pub fn fault_processing_disable(&self) -> bool { + self.data[0] & (1 << 1) != 0 + } + + pub fn set_fault_processing_disable(&mut self, v: bool) { + if v { self.data[0] |= 1 << 1; } else { self.data[0] &= !(1 << 1); } + } + + /// Translation Type (bits 2:3 of data[0]). + /// 00=legacy, 01=PASID, 10=pass-through, 11=reserved. + pub fn translation_type(&self) -> u64 { + (self.data[0] >> 2) & 0x3 + } + + pub fn set_translation_type(&mut self, tt: u64) { + self.data[0] = (self.data[0] & !(0x3 << 2)) | ((tt & 0x3) << 2); + } + + /// Second Level Page Table Pointer (bits 12:63 of data[0]). + pub fn slpt_ptr(&self) -> u64 { + self.data[0] & !0xFFF + } + + pub fn set_slpt_ptr(&mut self, addr: u64) { + self.data[0] = (self.data[0] & 0xFFF) | (addr & !0xFFF); + } + + /// Domain Identifier (bits 0:15 of data[1]). + pub fn domain_id(&self) -> u16 { + (self.data[1] & 0xFFFF) as u16 + } + + pub fn set_domain_id(&mut self, id: u16) { + self.data[1] = (self.data[1] & !0xFFFF) | (id as u64); + } +} + +const _: () = assert!(core::mem::size_of::() == 16); + +/// Intel VT-d Translation Type constants. +pub mod vtd_tt { + pub const LEGACY: u64 = 0b00; + pub const PASID: u64 = 0b01; + pub const PASS_THROUGH: u64 = 0b10; +} + +/// Intel VT-d Page Table Entry (64 bits). +#[repr(C, packed)] +pub struct VtdPte(pub u64); + +impl VtdPte { + /// Read permission (bit 0). + pub fn read(&self) -> bool { + self.0 & (1 << 0) != 0 + } + + pub fn set_read(&mut self, v: bool) { + if v { self.0 |= 1 << 0; } else { self.0 &= !(1 << 0); } + } + + /// Write permission (bit 1). + pub fn write(&self) -> bool { + self.0 & (1 << 1) != 0 + } + + pub fn set_write(&mut self, v: bool) { + if v { self.0 |= 1 << 1; } else { self.0 &= !(1 << 1); } + } + + /// Page frame or next-table address (bits 12:63). + pub fn addr(&self) -> u64 { + self.0 & !0xFFF + } + + pub fn set_addr(&mut self, a: u64) { + self.0 = (self.0 & 0xFFF) | (a & !0xFFF); + } +} + +/// Build a leaf PTE for Intel VT-d with read+write. +pub fn vtd_pte_leaf(addr: u64) -> VtdPte { + let mut pte = VtdPte(0); + pte.set_read(true); + pte.set_write(true); + pte.set_addr(addr); + pte +} + +/// Build a non-leaf PTE for Intel VT-d pointing to next-level table. +pub fn vtd_pte_pointer(addr: u64) -> VtdPte { + let mut pte = VtdPte(0); + pte.set_read(true); + pte.set_write(true); + pte.set_addr(addr); + pte +} +``` + +### 3.3 ACPI Table Structs + +```rust +/// Common ACPI table header (24 bytes). +#[repr(C, packed)] +pub struct AcpiTableHeader { + pub signature: [u8; 4], + pub length: u32, + pub revision: u8, + pub checksum: u8, + pub oem_id: [u8; 6], + pub oem_table_id: [u8; 8], + pub oem_revision: u32, + pub creator_id: [u8; 4], + pub creator_revision: u32, +} + +const _: () = assert!(core::mem::size_of::() == 36); + +/// IVRS ACPI Table Header. +#[repr(C, packed)] +pub struct IvrsTable { + pub header: AcpiTableHeader, // 36 bytes + pub iv_info: u32, // IOMMU Virtualization Info + // Followed by variable-length IVHD/IVMD entries. +} + +/// IVHD Entry (I/O Virtualization Hardware Definition). +#[repr(C, packed)] +pub struct IvhdEntry { + pub entry_type: u8, // 0x10 or 0x11 + pub flags: u8, // Feature flags + pub length: u16, // Total length including device entries + pub device_id: u16, // BDF of IOMMU PCI device + pub capability_offset: u16, // PCI capability offset + pub iommu_base_address: u64, // MMIO base address + pub pci_segment_group: u16, // PCI segment group + pub iommu_info: u16, // IOMMU info (MSI number, unit ID) + pub iommu_efr: u32, // Extended features (type 11 only) + // Followed by variable-length device entries. +} + +/// IVMD Entry (I/O Virtualization Memory Definition). +#[repr(C, packed)] +pub struct IvmdEntry { + pub entry_type: u8, // 0x20 or 0x21 + pub flags: u8, // Memory block flags + pub length: u16, // Total length + pub device_id: u16, // Start DeviceId (BDF) or 0x0000 for all + pub aux_data: u16, // Auxiliary data + pub start_address: u64, // Physical start address + pub memory_length: u64, // Length in bytes +} + +/// IVHD Device Entry (4 bytes minimum). +#[repr(C, packed)] +pub struct IvhdDeviceEntry { + pub dev_type: u8, // Device entry type (0x00..0x44) + pub data: u8, // LSA flags + pub device_id: u16, // BDF for SEL/SOR/EOR +} + +/// DMAR ACPI Table Header. +#[repr(C, packed)] +pub struct DmarTable { + pub header: AcpiTableHeader, // 36 bytes + pub host_address_width: u8, // DMA physical address width + pub flags: u8, // [0]=INTR_REMAP, [1]=X2APIC_OPT_OUT + pub reserved: [u8; 10], // Reserved + // Followed by variable-length DRHD/RMRR entries. +} + +const _: () = assert!(core::mem::size_of::() == 48); + +/// DRHD Entry (DMA Remapping Hardware Unit Definition). +#[repr(C, packed)] +pub struct DrhdEntry { + pub entry_type: u16, // 0x0001 + pub length: u16, // Total length including device scope + pub flags: u8, // [0]=INCLUDE_PCI_ALL + pub reserved: u8, // Reserved + pub segment_number: u16, // PCI segment group + pub register_base_address: u64, // Physical MMIO base address + // Followed by variable-length device scope entries. +} + +/// DRHD Device Scope Entry. +#[repr(C, packed)] +pub struct DmarDeviceScope { + pub scope_type: u8, // 0x01=PCI EP, 0x02=PCI sub-hierarchy, 0x03=IOAPIC, 0x04=HPET + pub length: u8, // Total length including path entries + pub enumeration_id: u8, // Enumeration ID (IOAPIC ID, etc.) + pub start_bus_number: u8, // Starting PCI bus number + // Followed by path entries (each 2 bytes: device, function). +} + +/// RMRR Entry (Reserved Memory Region Reporting). +#[repr(C, packed)] +pub struct RmrrEntry { + pub entry_type: u16, // 0x0002 + pub length: u16, // Total length + pub reserved: u16, // Reserved + pub segment_number: u16, // PCI segment group + pub base_address: u64, // Physical start address + pub end_address: u64, // Physical end address (inclusive) + // Followed by variable-length device scope entries. +} + +/// DMAR Sub-Table Types. +pub mod dmar_type { + pub const DRHD: u16 = 0x0001; + pub const RMRR: u16 = 0x0002; + pub const ATSR: u16 = 0x0003; + pub const RHSA: u16 = 0x0004; + pub const ANDD: u16 = 0x0005; +} + +/// DMAR Device Scope Types. +pub mod dmar_scope_type { + pub const PCI_ENDPOINT: u8 = 0x01; + pub const PCI_SUBHIERARCHY: u8 = 0x02; + pub const IOAPIC: u8 = 0x03; + pub const MSI_HPET: u8 = 0x04; + pub const ACPI_NAMESPACE: u8 = 0x05; +} +``` + +### 3.4 Utility Types + +```rust +/// BDF (Bus:Device:Function) packed as u16. +/// Format: bus[15:8] | device[7:3] | function[2:0]. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Bdf(pub u16); + +impl Bdf { + pub fn new(bus: u8, device: u8, function: u8) -> Self { + Self(((bus as u16) << 8) | ((device as u16 & 0x1F) << 3) | (function as u16 & 0x7)) + } + + pub fn bus(&self) -> u8 { + (self.0 >> 8) as u8 + } + + pub fn device(&self) -> u8 { + ((self.0 >> 3) & 0x1F) as u8 + } + + pub fn function(&self) -> u8 { + (self.0 & 0x7) as u8 + } + + /// Index into the AMD Device Table (same as raw BDF value). + pub fn dev_table_index(&self) -> usize { + self.0 as usize + } +} + +/// Domain ID. Used to group devices sharing a page table. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct DomainId(pub u16); + +/// Page table level constants. +pub mod pt_level { + /// AMD-Vi levels (Mode field in DTE). + pub const AMD_1_LEVEL: u64 = 1; + pub const AMD_2_LEVEL: u64 = 2; + pub const AMD_3_LEVEL: u64 = 3; + pub const AMD_4_LEVEL: u64 = 4; + pub const AMD_5_LEVEL: u64 = 5; + pub const AMD_6_LEVEL: u64 = 6; + + /// Intel VT-d levels (SAGAW field). + pub const VTd_3_LEVEL: u64 = 3; + pub const VTd_4_LEVEL: u64 = 4; + pub const VTd_5_LEVEL: u64 = 5; + pub const VTd_6_LEVEL: u64 = 6; +} +``` + +### 3.5 Size Constants + +```rust +/// AMD-Vi sizing constants. +pub mod amd_sizes { + /// Maximum Device Table entries. + pub const MAX_DEV_TABLE_ENTRIES: usize = 65536; + /// Device Table Entry size. + pub const DTE_SIZE: usize = 32; + /// Maximum Device Table size (65536 × 32 bytes). + pub const MAX_DEV_TABLE_SIZE: usize = MAX_DEV_TABLE_ENTRIES * DTE_SIZE; // 2 MiB + + /// Default Command Buffer entries. + pub const CMD_BUF_ENTRIES: usize = 512; + /// Command Buffer Entry size. + pub const CMD_ENTRY_SIZE: usize = 16; + /// Default Command Buffer size. + pub const CMD_BUF_SIZE: usize = CMD_BUF_ENTRIES * CMD_ENTRY_SIZE; // 8 KiB + + /// Default Event Log entries. + pub const EVT_LOG_ENTRIES: usize = 512; + /// Event Log Entry size. + pub const EVT_ENTRY_SIZE: usize = 16; + /// Default Event Log size. + pub const EVT_LOG_SIZE: usize = EVT_LOG_ENTRIES * EVT_ENTRY_SIZE; // 8 KiB + + /// IRTE size (128 bits). + pub const IRTE_SIZE: usize = 16; + /// Maximum Interrupt Remap Table entries (IntTabLen=11 → 2^12 = 4096). + pub const MAX_IRT_ENTRIES: usize = 4096; + /// Maximum Interrupt Remap Table size. + pub const MAX_IRT_SIZE: usize = MAX_IRT_ENTRIES * IRTE_SIZE; // 64 KiB + + /// Page table entry size (both AMD and Intel). + pub const PTE_SIZE: usize = 8; + /// Entries per page table page (4KiB / 8 bytes). + pub const PTES_PER_PAGE: usize = 512; +} + +/// Intel VT-d sizing constants. +pub mod vtd_sizes { + /// Root Table entries (one per PCI bus). + pub const ROOT_TABLE_ENTRIES: usize = 256; + /// Root/Context Entry size. + pub const ENTRY_SIZE: usize = 16; + /// Root Table size. + pub const ROOT_TABLE_SIZE: usize = ROOT_TABLE_ENTRIES * ENTRY_SIZE; // 4 KiB + + /// Context Table entries (one per device:function per bus). + pub const CTX_TABLE_ENTRIES: usize = 256; + /// Context Table size. + pub const CTX_TABLE_SIZE: usize = CTX_TABLE_ENTRIES * ENTRY_SIZE; // 4 KiB + + /// Page table entry size. + pub const PTE_SIZE: usize = 8; + /// Entries per page table page. + pub const PTES_PER_PAGE: usize = 512; +} + +/// PCI BDF address space: 256 buses × 32 devices × 8 functions = 65536. +pub const PCI_BDF_COUNT: usize = 256 * 32 * 8; +``` + +--- + +## Appendix: Linux Kernel Reference + +The Linux kernel IOMMU drivers are the primary reference implementation. Key files: + +| Path | Description | +|------|-------------| +| `drivers/iommu/amd/amd_iommu_types.h` | AMD-Vi type definitions, DTE/IRTE/PTE formats, register constants | +| `drivers/iommu/amd/amd_iommu.c` | AMD-Vi main driver: init, command buffer, device table management | +| `drivers/iommu/amd/init.c` | AMD-Vi initialization, IVRS parsing, early setup | +| `drivers/iommu/amd/irq.c` | AMD-Vi interrupt remapping | +| `drivers/iommu/intel/dmar.c` | Intel VT-d DMAR table parsing | +| `drivers/iommu/intel/iommu.c` | Intel VT-d main driver | +| `drivers/iommu/intel/irq_remapping.c` | Intel VT-d interrupt remapping | +| `include/linux/intel-iommu.h` | Intel VT-d register definitions, struct definitions | +| `drivers/iommu/io-pgtable.c` | Generic page table allocation | + +### Key Linux Constants for Cross-Reference + +```c +// AMD DTE bits (from amd_iommu_types.h) +#define DTE_FLAG_V (1ULL << 0) +#define DTE_FLAG_TV (1ULL << 1) +#define DTE_FLAG_IR (1ULL << 61) +#define DTE_FLAG_IW (1ULL << 62) +#define DTE_FLAG_SE (1ULL << 8) + +// AMD page table modes (DTE Mode field) +#define DTE_MODE_4LVL 4 // 4-level page tables (most common) + +// AMD command opcodes +#define CMD_COMPLETION_WAIT 0x01 +#define CMD_INVALIDATE_DEVTAB_ENTRY 0x02 +#define CMD_INVALIDATE_IOMMU_PAGES 0x03 +#define CMD_INVALIDATE_INTERRUPT_TABLE 0x04 + +// Intel DMAR flags +#define DMAR_INTR_REMAP 0x1 +#define DMAR_X2APIC_OPT_OUT 0x2 + +// Intel context entry TT (Translation Type) +#define CONTEXT_TT_MULTI_LEVEL 0 +#define CONTEXT_TT_DEV_IOTLB 1 +#define CONTEXT_TT_PASS_THROUGH 2 +``` + +--- + +*Document generated for Red Bear OS IOMMU implementation. Sources: AMD IOMMU Specification 48882 Rev 3.10, Intel VT-d Specification Rev 5.0, Linux kernel v6.x source.* diff --git a/local/docs/NETWORKING-RTL8125-NETCTL.md b/local/docs/NETWORKING-RTL8125-NETCTL.md new file mode 100644 index 00000000..27b0df5f --- /dev/null +++ b/local/docs/NETWORKING-RTL8125-NETCTL.md @@ -0,0 +1,83 @@ +# Red Bear OS Networking: RTL8125 + netctl + +## Native stack + +Red Bear uses the native Redox wired networking path already present in the base tree: + +`pcid-spawner` → native NIC daemon (`rtl8168d`, `e1000d`, `ixgbed`, `virtio-netd`) → `network.*` +scheme → `smolnetd` → `dhcpd` / `netcfg`. + +This change keeps RTL8125 in that native path instead of trying to introduce a Linux netdevice, +`sk_buff`, or NAPI compatibility layer into `linux-kpi`. + +## RTL8125 path + +- Autoload now matches `10ec:8125` in `recipes/core/base/source/drivers/net/rtl8168d/config.toml`. +- The existing Realtek driver binary remains the autoload target (`rtl8168d`). +- The daemon names RTL8125 devices distinctly in its `network.*` scheme name suffix. + +This is the narrowest viable implementation path in the current tree. It reuses the existing +userspace driver, PCI spawn, and netstack plumbing already proven for the native Realtek path. + +## relibc networking surface + +The Redox-facing libc networking surface was extended to stop reporting a fake `stub` interface: + +- `net/if.h` now exposes a real `eth0`-based view of the active interface model +- `ifaddrs.h` now returns a populated `eth0` entry +- Redox `ioctl()` now answers the common read-only `SIOCGIF*` queries used by interface-aware apps +- `netinet/in.h` now includes `in6_pktinfo` +- a minimal `resolv.h` is now generated in relibc + +This is intentionally aligned with the current single-active-interface design in `smolnetd` and +`netcfg`. + +## netctl + +Red Bear ships a Redox-native `netctl` compatibility command in `redbear-netctl`. + +### Supported profile subset + +- `Interface=eth0` +- `Connection=ethernet` +- `IP=dhcp` +- `IP=static` +- `Address=('a.b.c.d/prefix')` +- `Gateway='a.b.c.d'` +- `DNS=('a.b.c.d')` + +### Supported commands + +- `netctl list` +- `netctl status [profile]` +- `netctl start ` +- `netctl stop ` +- `netctl enable ` +- `netctl disable [profile]` +- `netctl is-enabled [profile]` +- `netctl --boot` + +Profiles live in `/etc/netctl`. Shipped examples live in `/etc/netctl/examples/`. + +### Boot integration + +Red Bear configs install `/usr/lib/init.d/12_netctl.service`, which runs: + +```text +netctl --boot +``` + +If `/etc/netctl/active` contains a profile name, that profile is applied during boot after the +base networking services have started. + +## Validation notes + +- `redbear-netctl` was type-checked and smoke-tested with a fake runtime root by exercising: + `list`, `enable`, `status`, and `start`. +- `rtl8168d` type-checks with the RTL8125 autoload configuration in place. +- relibc type-checks with the interface and header updates in place. + +## Remaining hardware validation + +This repo change set wires RTL8125 through the native path, but real hardware validation is still +required for full confidence in packet I/O on specific RTL8125 revisions. diff --git a/local/docs/QT6-PORT-STATUS.md b/local/docs/QT6-PORT-STATUS.md new file mode 100644 index 00000000..05536ea5 --- /dev/null +++ b/local/docs/QT6-PORT-STATUS.md @@ -0,0 +1,348 @@ +# Qt6 Port — Red Bear OS + +**Last updated:** 2026-04-14 +**Qt version:** 6.11.0 +**Target:** x86_64-unknown-redox (cross-compiled from Linux x86_64 host) +**Phase 1 status:** ✅ COMPLETE — Qt6 core stack + OpenGL/EGL + D-Bus + Wayland +**Phase 2 status:** ✅ COMPLETE — All 32 KF6 frameworks built +**Phase 3 status:** 🔄 IN PROGRESS — KWin + KDE Plasma build + +## Current Status Summary + +| Component | Status | Details | +|-----------|--------|---------| +| **qtbase** | ✅ | 13 libs incl. OpenGL, EGL, DBus, WaylandClient | +| **qtdeclarative** | ✅ | 11 libs, QML JIT disabled | +| **qtsvg** | ✅ | 2 libs | +| **qtwayland** | ✅ | Wayland client + compositor | +| **Mesa EGL+GBM** | ✅ | libEGL, libgbm, libGLESv2, swrast DRI | +| **libdrm** | ✅ | libdrm + libdrm_amdgpu | +| **libinput** | ✅ | 1.30.2 with comprehensive redox.patch | +| **D-Bus** | ✅ | 1.16.2, libdbus-1.so | +| **KF6 Frameworks** | ✅ 32/32 | All frameworks built | +| **KWin** | 🔄 | Recipe ready, now using real `libxcvt`, but still blocked by remaining shimmed/stubbed deps and incomplete runtime path | +| **Hardware acceleration** | ❌ | Requires kernel DMA-BUF (future work) | + +--- + +## Scope Definition + +**Phase 1 scope**: qtbase, qtdeclarative, qtsvg — the foundational Qt6 stack. +Qt6 consists of many modules — each is a separate source package. Phase 2 (qtwayland + KF6 Tier 1) +follows in the next step. + +**User-agreed scope constraints:** +- OpenGL: software/shm only, no EGL — get Qt compiling first +- Disabled features: process, sharedmemory, systemsemaphore, testlib, sql, printsupport +- Iterative approach: enable modules incrementally, re-enable disabled features later + +## Build Status + +### qtbase — Enabled Modules (7 libraries built) + +| Module | Library | Size | Description | +|--------|---------|------|-------------| +| QtCore | libQt6Core.so.6.11.0 | 13 MB | Core non-GUI: event loop, IO, threads, plugins | +| QtConcurrent | libQt6Concurrent.so.6.11.0 | 26 KB | High-level multi-threading without locks | +| QtXml | libQt6Xml.so.6.11.0 | 212 KB | XML stream reader/writer (SAX/DOM) | +| QtGui | libQt6Gui.so.6.11.0 | 12 MB | GUI infra: images, painting, text, input, windowing | +| QtWidgets | libQt6Widgets.so.6.11.0 | 9.4 MB | Widget toolkit: buttons, layouts, dialogs | +| QtWaylandClient | libQt6WaylandClient.so.6.11.0 | — | Wayland client integration | +| QtWlShellIntegration | libQt6WlShellIntegration.so.6.11.0 | — | Wayland Shell integration | + +### qtbase — Plugins (12 plugin libraries) + +| Plugin | File | Type | +|--------|------|------| +| redox | libqredox.so | QPA platform | +| offscreen | libqoffscreen.so | QPA platform | +| minimal | libqminimal.so | QPA platform | +| wayland-bsoft-integration | libqwayland-bsoft-integration.so | Wayland integration | +| gif | libqgif.so | Image format | +| ico | libqico.so | Image format | +| jpeg | libqjpeg.so | Image format | +| png | libqpng.so | Image format | +| svg | libqsvg.so | Image format | +| iconengines | libqsvgicon.so | Icon engine | +| text | libqtext.so | Text platform | +| xkb | libqxkb.so | XKB support | + +### qtdeclarative — Built Successfully (build 15) + +| Library | Description | +|---------|-------------| +| libQt6Qml.so.6.11.0 | QML core | +| libQt6QmlModels.so.6.11.0 | Models (ListModel, etc.) | +| libQt6Quick.so.6.11.0 | QtQuick UI framework | +| libQt6QmlCore.so.6.11.0 | QML internals | +| libQt6QmlCompiler.so.6.11.0 | QML JIT compiler | +| libQt6QmlWorkerScript.so.6.11.0 | Worker script runtime | +| libQt6QmlMeta.so.6.11.0 | QML meta-object | +| libQt6QmlXmlListModel.so.6.11.0 | XML ListModel | +| libQt6LabsFolderListModel.so.6.11.0 | Folder list model | +| libQt6LabsQmlModels.so.6.11.0 | Lab models | +| libQt6LabsSettings.so.6.11.0 | Settings | +| libQt6LabsSynchronizer.so.6.11.0 | Synchronizer | + +Plus: QML debug plugins, QtQuick/QML modules staged. + +**Note**: QML JIT (`QT_FEATURE_qml_jit`) does not compile for Redox — disabled. + +### qtsvg — Built Successfully + +| Component | File | +|-----------|------| +| libQt6Svg.so.6.11.0 | SVG rendering | +| libQt6SvgWidgets.so.6.11.0 | SVG widget integration | +| qsvg icon engine | libqsvgicon.so | +| qsvg image format | libqsvg.so | + +### Disabled Modules — Full Blocker Analysis + +| Module | Blocker | Root Cause | Re-enable Path | +|--------|---------|------------|----------------| +| QtNetwork | Runtime validation still pending | the relibc header/ioctl surface is now present in-tree, but downstream QtNetwork behavior still needs end-to-end validation on Redox | Validate QtNetwork against the updated relibc networking surface | +| QtOpenGL | No EGL, no GPU driver runtime validation | amdgpu/intel DRM drivers compile but haven't been validated on hardware; no Mesa EGL build | Validate GPU drivers on HW → build Mesa with EGL → enable QtOpenGL | +| QtOpenGLWidgets | Gated by `QT_FEATURE_opengl` | Same as QtOpenGL | Same as QtOpenGL | +| QtDBus | D-Bus IPC system not ported to Redox | No D-Bus daemon or libdbus on Redox | Port libdbus → enable QtDBus | +| QtSql | User-agreed scope exclusion | Not needed for initial GUI | Add sqlite/odbc recipe → enable QtSql | +| QtPrintSupport | User-agreed scope exclusion | No printing subsystem on Redox | Port cups/filters → enable QtPrintSupport | + +### Disabled Features — Full Blocker Analysis + +| Feature | CMake Flag | Blocker | Re-enable Path | +|---------|-----------|---------|----------------| +| OpenGL | `-DFEATURE_opengl=OFF` | No EGL, no GPU runtime validation | Validate GPU drivers → Mesa EGL → enable | +| EGL | `-DFEATURE_egl=OFF` | No libEGL from Mesa | Mesa EGL build → enable | +| XCB/Xlib | `-DFEATURE_xcb=OFF -DFEATURE_xlib=OFF` | No X11 on Redox | Not applicable — Redox uses Wayland | +| Vulkan | `-DFEATURE_vulkan=OFF` | No Vulkan runtime | Port Mesa Vulkan ICD → enable | +| OpenSSL | `-DFEATURE_openssl=OFF` | OpenSSL3 port in WIP but not validated | Validate openssl3 recipe → enable | +| D-Bus | `-DFEATURE_dbus=OFF` | No D-Bus on Redox | Port libdbus → enable | +| Process | `-DFEATURE_process=OFF` | relibc POSIX completeness for QProcess | Test QProcess on Redox → enable | +| Shared Memory | `-DFEATURE_sharedmemory=OFF` | `QSharedMemory` uses `shm_open()`/`shmget()` | Add `shm_open`/`shmget` to relibc | +| System Semaphore | `-DFEATURE_systemsemaphore=OFF` | `QSystemSemaphore` uses `sem_open()`/`semget()` | Add POSIX semaphores to relibc | +| qmake | `-DFEATURE_qmake=OFF` | Build tool, not needed with CMake | Enable if downstream needs qmake | +| SQL | `-DFEATURE_sql=OFF` | User-agreed scope exclusion | Add sqlite/odbc → enable | +| Print Support | `-DFEATURE_printsupport=OFF` | User-agreed scope exclusion | Port cups → enable | +| QML JIT | `-DFEATURE_qml_jit=OFF` | Does not compile for Redox | Fix in upstream or disable permanently | + +--- + +## New Discoveries (Builds 8–17) + +| # | Discovery | Fix | +|---|-----------|-----| +| 8 | qtwaylandscanner is a host tool, needs `FEATURE_qtwaylandscanner=ON` in both host and target builds | Enable feature in both cmake configs | +| 9 | wayland-scanner must be host binary — use `-DWaylandScanner_EXECUTABLE=/usr/bin/wayland-scanner` | Pass explicit path to host wayland-scanner | +| 10 | OpenGL guards needed in Wayland code (`#if QT_CONFIG(opengl)`) | Add guard in qtbase patch | +| 11 | `cmake --install` produces relocatable cmake files — replaced manual cmake copy | Use cmake install instead of manual sed | +| 12 | `QT_MKSPECS_DIR` must point to staged mkspecs — conditional in toolchain file | Add conditional logic in redox-toolchain.cmake | +| 13 | QtNetwork features leak into downstream — pass `QT_FEATURE_ssl=OFF` etc. | Explicitly disable in downstream cmake | +| 14 | SBOM generation fails — use `-DQT_GENERATE_SBOM=OFF` | Disable SBOM generation | +| 15 | Sysroot path mismatch — cookbook only symlinks bin/include/lib/share, need manual symlinks for plugins/mkspecs/metatypes/modules | Add manual symlinks in recipe | +| 16 | masm `CheckedArithmetic.h` missing `ArithmeticOperations` for LP64 | Add missing arithmetic operation to masm | +| 17 | QML JIT (`QT_FEATURE_qml_jit`) doesn't compile for Redox — disabled | Disable feature, works without JIT | +| 56 | **plasma-wayland-protocols** is a required separate package — kf6-kwayland needs PLASMA_WAYLAND_PROTOCOLS_DIR pointing to protocol XMLs | Created recipe that installs XML files + symlink for naming mismatch (org-kde-plasma-virtual-desktop.xml → plasma-virtual-desktop.xml) | +| 57 | **kf6-kcmutils** requires Qt6Quick unconditionally upstream | Strip Quick/QML/kcmshell from CMakeLists via Python-based source patching — produces libKF6KCMUtils.so + libKF6KCMUtilsCore.so (widget-only build) | +| 58 | **kf6-kwayland** fails with `get_filename_component called with incorrect number of arguments` when PLASMA_WAYLAND_PROTOCOLS_DIR is unset | Fix: create plasma-wayland-protocols package + point the cmake variable to the installed XMLs | +| 59 | **seatd** now builds as a standalone runtime package for Redox and is wired into the KDE runtime config; keep it out of KWin compile deps until DRM-lease/runtime validation exists | Runtime dependency only | + +--- + +## Build Iteration History + +| # | Issue | Fix | +|---|-------|-----| +| 1-7 | Patch format, byteswap.h, forwarding headers | Patch structure | +| 8 | qtwaylandscanner is host tool | `FEATURE_qtwaylandscanner=ON` in host+target | +| 9 | wayland-scanner must be host binary | `-DWaylandScanner_EXECUTABLE=/usr/bin/wayland-scanner` | +| 10 | OpenGL guards in Wayland code | `#if QT_CONFIG(opengl)` guard | +| 11 | cmake --install relocatable | Use cmake install over manual copy | +| 12 | QT_MKSPECS_DIR mismatch | Conditional in toolchain file | +| 13 | QtNetwork feature leak | Pass explicit QT_FEATURE_* flags | +| 14 | SBOM generation fails | `-DQT_GENERATE_SBOM=OFF` | +| 15 | Sysroot path mismatch (plugins/mkspecs/metatypes/modules) | Manual symlinks | +| 16 | masm CheckedArithmetic.h missing LP64 operation | Add ArithmeticOperations | +| 17 | QML JIT doesn't compile for Redox | Disable `QT_FEATURE_qml_jit` | +| **Phase 1** | **qtbase + qtdeclarative + qtsvg complete** | **✅ Core stack built** | + +--- + +## relibc Gaps — Complete Inventory + +### Resolved (workarounds in recipe/patch) + +| Gap | Workaround | Location | +|-----|-----------|----------| +| `sys/statfs.h` missing | Wrapper → `sys/statvfs.h` (typedef, #define) | recipe.toml heredoc | +| `ELFMAG` string missing from `elf.h` | `#define ELFMAG "\177ELF"` prepended to source | recipe.toml printf | +| `resolv.h` availability | Minimal relibc header now exists in-tree | verify downstream consumers against the generated header | +| `unlinkat()`/`linkat()` missing | Inline stubs with `AT_FDCWD` | redox.patch | +| `byteswap.h` missing | Skip include on Redox | redox.patch (brg_endian.h) | +| Float16 soft-fp (`__truncsfhf2` etc.) | Custom IEEE 754 C implementation | redox.patch (qt_float16_shims.c) | +| Half-float comparison (`__eqhf2` etc.) | Custom IEEE 754 C implementation | redox.patch (same file) | +| `openat()` not available | `#ifdef Q_OS_REDOX` guard | redox.patch (qcore_unix_p.h) | + +### Networking Surface — Now Present, Still Needs Runtime Validation + +| Gap | Impact | relibc File to Modify | +|-----|--------|----------------------| +| `resolv.h` | Present in relibc | `recipes/core/relibc/source/src/header/resolv/` | +| `in6_pktinfo` / `ipv6_mreq` | Present in relibc | `recipes/core/relibc/source/src/header/netinet_in/mod.rs` | +| `SIOCGIF*` ioctls | Present for the current Redox `eth0` model | `recipes/core/relibc/source/src/header/sys_ioctl/redox/mod.rs` | +| `::ioctl` path | Present in relibc Redox ioctl implementation | `recipes/core/relibc/source/src/header/sys_ioctl/` | +| `ifreq` / `ifconf` / `ifaddrs` | Present for the current Redox `eth0` model | `recipes/core/relibc/source/src/header/net_if/mod.rs`, `recipes/core/relibc/source/src/header/ifaddrs/mod.rs` | + +### Unresolved — Blocks Other Qt Modules/Features + +| Gap | Impact | Module Blocked | +|-----|--------|---------------| +| D-Bus IPC | QtDBus, KDE components | QtDBus | +| GPU display validation | Hardware-accelerated rendering | QtOpenGL | +| `shm_open()` / `shmget()` | Shared memory | QSharedMemory | +| `sem_open()` / `semget()` | POSIX semaphores | QSystemSemaphore | +| `fork()`/`exec()` POSIX completeness | QProcess internals | QProcess | +| Fontconfig | Advanced font selection | QtGui (bundled FreeType works for basic) | + +--- + +## Next Steps + +### Phase 2a — qtbase D-Bus Enablement (✅ COMPLETE) + +- qtbase rebuilt with `-DFEATURE_dbus=ON` in both host and target builds +- libQt6DBus.so + Qt6DBusConfig.cmake + Qt6DBus.pc staged to sysroot +- D-Bus 1.16.2 already built (24-line redox.patch for epoll + socketpair) +- Unblocks: kf6-kdbusaddons, kf6-kservice, kf6-kpackage, kf6-kglobalaccel + +### Phase 2b — qtwayland Module (🔄 Building) + +- Recipe at `recipes/wip/qt/qtwayland/recipe.toml` +- Uses redox-toolchain.cmake + host Qt build pattern +- Wayland compositor disabled, client-only build +- OpenGL guards applied for software rendering + +### Phase 2c — Input Stack (✅ COMPLETE) + +- linux-input-headers: ✅ Built — provides linux/input.h + linux/types.h + _CNT macros +- libevdev 1.13.2: ✅ Built — uinput stubs + input.h __redox__ guard +- libinput 1.30.2: ✅ Built — comprehensive redox.patch: + - SYS_pidfd_open meson guard (cc.has_header check) + - Non-udev shim (libudev stub for HAVE_UDEV=0) + - Vendored Linux input.h selection for __redox__ + - strtod_l() fallback + - timerfd fallback (tracks expiry without timerfd fd) + - Linux-only tool binaries skipped on Redox + +### Phase 3 — KF6 Frameworks (✅ ALL 32 BUILT) + +All KF6 frameworks built and staged: + +ecm, kcoreaddons, kwidgetsaddons, kconfig, ki18n, kcodecs, kguiaddons, kcolorscheme, +kauth, kwindowsystem, knotifications, kjobwidgets, kconfigwidgets, karchive, sonnet, +kcompletion, kitemviews, kitemmodels, solid, kdbusaddons, kservice, kpackage, +kcrash, ktextwidgets, kiconthemes, kglobalaccel, kdeclarative, kxmlgui, kbookmarks, +kidletime, kio, kcmutils + +Additional KDE packages: +- kdecoration ✅ BUILT (KDecoration3 window decoration library) +- kirigami ✅ STUB ONLY (dependency-resolution package, not a real runtime-ready Kirigami build) +- kf6-kwayland ✅ BUILT +- kf6-kcmutils ✅ BUILT (widget-only, Quick/QML/kcmshell stripped) +- plasma-wayland-protocols ✅ BUILT (protocol XMLs for kf6-kwayland) + +Graphics stack (PRIMARY DELIVERABLE): +- Mesa EGL+GBM ✅ BUILT (libEGL.so, libgbm.so, libGLESv2.so, swrast_dri.so) +- libdrm amdgpu ✅ BUILT (libdrm_amdgpu.so, /scheme/drm/ paths) +- Qt6 OpenGL ✅ BUILT (libQt6OpenGL.so, libQt6EglFSDeviceIntegration.so, GLES 2.0) +- D-Bus ✅ BUILT (libdbus-1.so.3.38.3, dbus-daemon) +- libinput ✅ BUILT (libinput.so.10.13.0, comprehensive redox.patch) +- libevdev ✅ BUILT (libevdev.so.2.3.0, uinput stubs) + +KWin recipe updated with 40 dependencies (all KF6 + Mesa + libdrm + libinput + qtwayland). +plasma-workspace, plasma-desktop recipes created. + +### Phase 4 — Graphics Stack (✅ COMPLETE) + +Mesa EGL+GBM+GLES2 built: +- libEGL.so (225KB) — platforms: redox, surfaceless, drm +- libgbm.so (68KB) — Generic Buffer Manager for compositor buffer allocation +- libGLESv2.so — OpenGL ES 2.0 (software via LLVMpipe) +- libGLESv1_CM.so — OpenGL ES 1.1 +- swrast_dri.so + kms_swrast_dri.so — LLVMpipe software DRI drivers +- pkgconfig: egl.pc, gbm.pc, osmesa.pc, glesv2.pc, dri.pc + +libdrm amdgpu enabled: +- libdrm_amdgpu.so (48KB) — AMD GPU DRM API +- Device paths: /scheme/drm/cardN, /scheme/drm/renderD + +Qt6 OpenGL enabled: +- libQt6OpenGL.so (716KB) — Qt OpenGL module (GLES 2.0 path) +- libQt6OpenGLWidgets.so — Qt OpenGL widgets +- libQt6EglFSDeviceIntegration.so — EGLFS platform integration +- EGLFS KMS plugin for direct DRM/KMS rendering + +### Phase 4b — Qt6 OpenGL Enablement (✅ COMPLETE) + +qtbase rebuilt with `-DFEATURE_opengl=ON -DINPUT_opengl=es2 -DFEATURE_egl=ON` +Qt cmake summary: EGL=yes, OpenGL=yes, "OpenGL ES 2.0=yes, EGLFS GBM=yes" + +### Phase 5 — KDE Plasma (🔄 IN PROGRESS) + +KDE Plasma packages built: +- kf6-kwayland ✅ BUILT +- kf6-kcmutils ✅ BUILT (widget-only, Quick/QML/kcmshell stripped) +- kirigami ✅ STUB ONLY (dependency-resolution package, not a real runtime-ready Kirigami build) +- plasma-wayland-protocols ✅ BUILT (protocol XMLs for kf6-kwayland) +- kdecoration ✅ BUILT (KDecoration3 window decoration library) + +KWin recipe updated with dependencies (all KF6 + Mesa + libdrm + libinput + qtwayland): +- All KF6 deps built (kconfigwidgets, kxmlgui, kglobalaccel, kidletime, kio, etc.) +- Mesa EGL+GBM ✅ +- libinput ✅ +- libdrm ✅ +- kf6-kwayland ✅ +- seatd builds separately (runtime dependency, not needed for compilation) + +### Phase 6 — KWin (🔄 BUILDING) + +## Dependency Graph + +``` +Phase 1 ✅ (qtbase + qtdeclarative + qtsvg) + └── Phase 2a ✅ (D-Bus daemon + qtbase D-Bus enablement) + └── Phase 2b ✅ (qtwayland built) + └── Phase 2c ✅ (libevdev + libinput built) + └── Phase 3 ✅ (KF6 — ALL 32 frameworks built) + └── Phase 4 ✅ (Mesa EGL+GBM+GLES2, Qt6 OpenGL+EGL, libdrm amdgpu) + └── Phase 5 🔄 (kdecoration ✅, kf6-kwayland ✅, kirigami stub-only, KWin still blocked on shimmed/scaffolded deps) +``` + +--- + +## Known Issues + +1. **QML JIT disabled** — `QT_FEATURE_qml_jit` does not compile for Redox. QML still works + via the interpreter path, just without JIT acceleration. Non-blocking for basic QML apps. + +2. **QtNetwork disabled** — DNS resolver and IPv6 multicast gaps in relibc. HTTP/WebSocket + unavailable until relibc networking is completed. QML network access also affected. + +3. **No GPU hardware acceleration** — Qt6 OpenGL/EGL and Mesa EGL+GBM now build, but they are still validated only on the software/LLVMpipe path. + True hardware acceleration (radeonsi or equivalent) still requires kernel DMA-BUF fd passing and real hardware validation. + +4. **relibc / graphics surface still incomplete for runtime** — the build-side `open_memstream` and Wayland-facing header export path now work, + but DMA-BUF ioctls, sync objects, and broader graphics runtime validation are still unavailable. + +5. **KDE Plasma does NOT compile or run end-to-end** — KWin, plasma-workspace, plasma-desktop recipes exist, + but are still blocked on shimmed/stubbed dependencies, runtime integration, and compositor validation. + +## Honest Status Assessment + +The Qt6/KF6 build stack is substantially further along than the earlier "~50%" estimate implied: +- Qt6, QtWayland, Mesa EGL+GBM, Qt6 OpenGL, libdrm amdgpu, and all 32 KF6 frameworks now build +- the remaining blockers are concentrated in KWin/Plasma runtime integration and in the still-shimmed or stub-only packages such as Kirigami, libepoxy, libudev, lcms2, and libdisplay-info +- hardware acceleration still requires kernel DMA-BUF work and real hardware validation +- a successful build stack is not yet the same thing as a working KDE Plasma session + +(Updated 2026-04-14 — status reconciled after relibc/libwayland bridge fixes; build-side progress is real, runtime remains incomplete) diff --git a/local/docs/REDBEAR-INFO-RUNTIME-REPORT.md b/local/docs/REDBEAR-INFO-RUNTIME-REPORT.md new file mode 100644 index 00000000..155c88e9 --- /dev/null +++ b/local/docs/REDBEAR-INFO-RUNTIME-REPORT.md @@ -0,0 +1,64 @@ +# redbear-info Runtime Report + +`redbear-info` is the canonical Red Bear OS runtime integration and debugging command. + +## Purpose + +The tool is intentionally passive. It reports what the running system can actually prove through +read-only runtime surfaces instead of flattening everything into a single “available” bit. + +It is meant to answer: + +- what Red Bear integrations are installed, +- what services or schemes are actually active, +- what integrations passed a safe read-only runtime probe, +- whether networking is configured, including IP, DNS, and default route, +- whether key hardware discovery surfaces (PCI, USB, DRM, RTL8125) are visible. + +## Output model + +Each integration is reported with one of these layered states: + +- `absent` — no artifact or runtime surface was observed +- `present` — an artifact or config exists, but there is no live runtime proof yet +- `active` — a live runtime surface exists, but the probe cannot honestly claim full working order +- `functional` — a safe read-only runtime probe succeeded +- `unobservable` — no honest runtime proof exists for a deeper claim + +This distinction matters because some Red Bear integrations compile or package cleanly before they +are hardware-validated at runtime. + +## Current sections + +`redbear-info` reports: + +- **Identity** — OS name, version, hostname +- **Networking** — stack state, connected flag, interface, MAC, IP/CIDR, DNS, default route, + active `netctl` profile, visible `network.*` schemes +- **Hardware** — PCI device count, USB controller count, DRM card count, RTL8125 PCI visibility +- **Integrations** — tools, daemons, and integration paths such as `lspci`, `lsusb`, `netctl`, + `pcid-spawner`, `smolnetd`, `firmware-loader`, `udev-shim`, `evdevd`, `redox-drm`, and the + native RTL8125 path + +## Commands + +- `redbear-info` — human-readable report +- `redbear-info --verbose` — includes evidence and claim limits +- `redbear-info --json` — structured machine-readable output +- `redbear-info --test` — suggested follow-up diagnostic commands + +## Maintenance rule + +Whenever Red Bear adds or materially changes an integration, update `redbear-info` in the same +change set. + +That includes new: + +- user-facing tools +- scheme daemons +- services +- hardware integration paths +- configuration layers that users rely on to debug a running image + +The goal is for `redbear-info` to remain the first command users run when they need to understand +the state of a Red Bear system.