Files
RedBear-OS/local/docs/QUIRKS-SYSTEM.md
T
vasilito ef3dd8b1fd docs: Linux 7.0 → 7.1 reference across all active docs
Update all active (non-archived) doc references from Linux 7.0 to
Linux 7.1.  The reference tree at local/reference/linux-7.1/ already
exists; the docs were lagging behind.

Files touched:
  AGENTS.md — reference path and git fetch command
  CHANGELOG.md — device ID source note
  local/docs/IMPLEMENTATION-MASTER-PLAN.md — source-of-truth path x2
  local/docs/CPU-DMA-IRQ-MSI-SCHEDULER-FIX-PLAN.md — source-of-truth
  local/docs/DRM-MODERNIZATION-EXECUTION-PLAN.md — quirk extraction note
  local/docs/QUIRKS-AUDIT.md — storage quirk table note
  local/docs/QUIRKS-SYSTEM.md — storage quirk mining note

Archived docs (local/docs/archived/*) are preserved as-is — they
represent historical state and are not the planning authority.
2026-07-07 01:32:36 +03:00

474 lines
18 KiB
Markdown

# Red Bear OS Hardware Quirks System
## Overview
Red Bear OS implements a data-driven hardware quirks system inspired by Linux's
PCI/USB/DMI quirk infrastructure, adapted for Redox's microkernel/userspace-driver
architecture.
Quirks handle known hardware defects that cannot be fixed by correct driver code
alone. They override default driver behavior for specific devices, revisions, or
entire system models.
For the current follow-up cleanup and integration roadmap, see
`local/docs/QUIRKS-IMPROVEMENT-PLAN.md`.
## Architecture
```
Driver probes device
└─ PciDeviceInfo::quirks()
├─ Layer 1: Compiled-in table (pci_table.rs, usb_table.rs)
├─ Layer 2: TOML files from /etc/quirks.d/*.toml
└─ Layer 3: DMI-based system rules
└─ Returns: PciQuirkFlags (bitwise OR of all matching entries)
```
All matching entries accumulate via bitwise OR, so broad rules (e.g., "all AMD GPUs
need firmware") and narrow rules (e.g., "this specific revision has broken MSI-X")
compose naturally.
## Quirk Sources
### 1. Compiled-in Tables
Location: `local/recipes/drivers/redox-driver-sys/source/src/quirks/`
Critical quirks that must be available before the root filesystem is mounted.
Defined as `const` arrays in Rust:
- `pci_table.rs``PCI_QUIRK_TABLE: &[PciQuirkEntry]`
- `usb_table.rs``USB_QUIRK_TABLE: &[UsbQuirkEntry]`
Each entry specifies:
- Vendor/device/subsystem match fields (0xFFFF = wildcard)
- Revision range (lo..hi inclusive)
- Class code mask and match value
- `PciQuirkFlags` bitmask
### 2. TOML Quirk Files
Location: `/etc/quirks.d/*.toml` (shipped by the `redbear-quirks` package)
Extensible at runtime without recompiling drivers. Format:
```toml
[[pci_quirk]]
vendor = 0x1002
device = 0x73BF
flags = ["need_firmware", "no_d3cold"]
[[pci_quirk]]
vendor = 0x10EC
device = 0x8125
flags = ["no_aspm"]
[[usb_quirk]]
vendor = 0x0A12
flags = ["bad_descriptor", "no_set_config"]
```
Files are loaded alphabetically from `/etc/quirks.d/`. Recommended naming:
`00-core.toml`, `10-gpu.toml`, `20-usb.toml`, `30-net.toml`, `40-storage.toml`,
`50-system.toml`.
Runtime TOML loading now also supports `[[dmi_system_quirk]]` entries. Those
entries are applied when `acpid` is running and serving live DMI data from
`/scheme/acpi/dmi`.
### 3. DMI-Based System Quirks
Match by SMBIOS fields (sys_vendor, board_name, product_name) to apply
system-wide quirk overrides. Eight compiled-in rules exist for known systems,
and `/etc/quirks.d/*.toml` can now add `[[dmi_system_quirk]]` rules with
`match.*` keys plus optional `pci_vendor` / `pci_device` selectors. Runtime use
now reads live SMBIOS strings from `acpid` via `/scheme/acpi/dmi`.
## Available Quirk Flags
### ACPI Quirks (AcpiQuirkFlags)
Defined in `quirks/mod.rs`. Used by `acpid` and the kernel ACPI scheme to
override ACPI table processing.
| Flag | Bit | Meaning |
|------|-----|---------|
| `SUPPRESS_IVRS` | 15 | Skip IVRS (AMD-Vi IOMMU) ACPI table — use when IOMMU is broken or unwanted |
### PCI Quirks (PciQuirkFlags)
| Flag | Meaning |
|------|---------|
| `NO_MSI` | MSI capability broken; use MSI-X or legacy |
| `NO_MSIX` | MSI-X capability broken; use MSI or legacy |
| `FORCE_LEGACY_IRQ` | Must use INTx interrupts |
| `NO_PM` | Disable all power management |
| `NO_D3COLD` | Cannot recover from D3cold power state |
| `NO_ASPM` | Active State Power Management broken |
| `NEED_IOMMU` | Requires IOMMU isolation |
| `NO_IOMMU` | Must NOT be behind IOMMU |
| `DMA_32BIT_ONLY` | Only supports 32-bit DMA |
| `RESIZE_BAR` | BAR sizing reports incorrectly |
| `DISABLE_BAR_SIZING` | Use firmware BAR values as-is |
| `NEED_FIRMWARE` | Requires firmware files to initialize |
| `DISABLE_ACCEL` | Disable hardware acceleration |
| `FORCE_VRAM_ONLY` | No GTT/system memory fallback |
| `NO_USB3` | Force USB 2.0 mode |
| `RESET_DELAY_MS` | Needs extra post-reset delay |
| `NO_STRING_FETCH` | Do not fetch string descriptors |
| `BAD_EEPROM` | EEPROM unreliable; use hardcoded values |
| `BUS_MASTER_DELAY` | Needs delay after bus-master enable |
| `WRONG_CLASS` | Reports incorrect class code |
| `BROKEN_BRIDGE` | PCI bridge forwarding bug |
| `NO_RESOURCE_RELOC` | Do not relocate PCI resources |
### USB Quirks (UsbQuirkFlags)
| Flag | Meaning |
|------|---------|
| `NO_STRING_FETCH` | Do not fetch string descriptors |
| `RESET_DELAY` | Needs extra reset delay |
| `NO_USB3` | Disable USB 3.x |
| `NO_SET_CONFIG` | Cannot handle SetConfiguration |
| `NO_SUSPEND` | Broken suspend/resume |
| `NEED_RESET` | Needs reset after probe |
| `BAD_DESCRIPTOR` | Wrong descriptor sizes |
| `NO_LPM` | Disable Link Power Management |
| `NO_U1U2` | Disable U1/U2 link transitions |
## Driver Integration
### For Rust Drivers (using redox-driver-sys)
```rust
use redox_driver_sys::quirks::PciQuirkFlags;
fn probe(info: &PciDeviceInfo) {
let quirks = info.quirks();
if quirks.contains(PciQuirkFlags::NO_MSIX) {
// Skip MSI-X, try MSI or legacy
}
if quirks.contains(PciQuirkFlags::NEED_FIRMWARE) {
// Load firmware before initializing device
}
if quirks.contains(PciQuirkFlags::DISABLE_ACCEL) {
// Skip hardware probe, let software renderer take over
return Err(DriverError::QuirkDisabled);
}
}
```
### For C Drivers (using linux-kpi)
The `linux-kpi` crate exposes two FFI functions for C drivers to query quirks:
```c
#include <linux/pci.h>
// After pci_enable_device() in your probe callback:
static int my_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
u64 quirks = pci_get_quirk_flags(dev);
if (quirks & PCI_QUIRK_NO_MSIX) {
// Skip MSI-X, fall back to MSI or legacy IRQ
}
if (pci_has_quirk(dev, PCI_QUIRK_NEED_FIRMWARE)) {
// Load firmware before initializing hardware
}
}
```
The amdgpu Redox glue/runtime path is now the first in-tree production C consumer
of this interface: it queries `pci_get_quirk_flags()` during AMD DC init, logs the
resulting IRQ expectations, and treats `PCI_QUIRK_NEED_FIRMWARE` as a hard failure
instead of a warn-and-continue path when that quirk is active.
### For USB Storage Drivers (usbscsid)
The USB SCSI driver (`drivers/storage/usbscsid`) carries its own self-contained quirk
module (`src/quirks.rs`) that reads `[[usb_storage_quirk]]` entries from `/etc/quirks.d/*.toml`.
It does not depend on `redox-driver-sys` — the quirk lookup is inline.
At daemon startup, `usbscsid` extracts vendor/product IDs from the USB device descriptor
and looks up matching quirks from both the compiled-in table and TOML files. The resulting
`UsbStorageQuirkFlags` propagate to both the BOT transport and the SCSI command layer.
Active behavioral flags and their injection points:
| Flag | Layer | Effect |
|------|-------|--------|
| `IGNORE_RESIDUE` | BOT (`bot.rs`) | Suppresses CSW data_residue; avoids false short-transfer errors |
| `FIX_CAPACITY` | SCSI (`scsi/mod.rs`) | Subtracts 1 from READ CAPACITY(10) block count |
| `SINGLE_LUN` | BOT (`bot.rs`) | Enforces LUN=0 in CBW |
| `MAX_SECTORS_64` | SCSI (`scsi/mod.rs`) | Clamps transfer_len to 64 sectors per command |
| `INITIAL_READ10` | SCSI (`scsi/mod.rs`) | Uses READ(10)/WRITE(10) instead of READ(16)/WRITE(16) |
TOML format for storage quirks:
```toml
[[usb_storage_quirk]]
vendor = 0x03EB
product = 0x2002
revision = "0100-0100"
manufacturer = "ATMEL"
description = "SND1 Storage"
flags = ["ignore_residue"]
```
The full 214-entry table lives in `quirks.d/30-storage.toml`, mined from Linux 7.1's
`drivers/usb/storage/unusual_devs.h`.
Available C quirk flag macros (defined in `linux/pci.h`):
| Macro | Bit | Meaning |
|-------|-----|---------|
| `PCI_QUIRK_NO_MSI` | 0 | MSI interrupts broken |
| `PCI_QUIRK_NO_MSIX` | 1 | MSI-X interrupts broken |
| `PCI_QUIRK_FORCE_LEGACY` | 2 | Must use legacy INTx |
| `PCI_QUIRK_NO_PM` | 3 | Power management broken |
| `PCI_QUIRK_NO_D3COLD` | 4 | D3cold state broken |
| `PCI_QUIRK_NO_ASPM` | 5 | ASPM broken |
| `PCI_QUIRK_NEED_IOMMU` | 6 | Requires IOMMU |
| `PCI_QUIRK_DMA_32BIT_ONLY` | 8 | DMA limited to 32-bit |
| `PCI_QUIRK_NEED_FIRMWARE` | 11 | Requires firmware load |
| `PCI_QUIRK_DISABLE_ACCEL` | 12 | Disable hardware acceleration |
## Adding New Quirks
### To the compiled-in table
Edit `local/recipes/drivers/redox-driver-sys/source/src/quirks/pci_table.rs`:
```rust
const F_MY_FLAGS: PciQuirkFlags = PciQuirkFlags::from_bits_truncate(
PciQuirkFlags::NEED_FIRMWARE.bits() | PciQuirkFlags::NO_ASPM.bits(),
);
PciQuirkEntry {
vendor: 0xVENDOR,
device: 0xDEVICE,
flags: F_MY_FLAGS,
..PciQuirkEntry::WILDCARD
},
```
### To a TOML file
Create or edit a file in `local/recipes/system/redbear-quirks/source/quirks.d/`:
```toml
[[pci_quirk]]
vendor = 0xVENDOR
device = 0xDEVICE
flags = ["need_firmware", "no_aspm"]
[[usb_quirk]]
vendor = 0xVENDOR
product = 0xPRODUCT
flags = ["no_lpm", "need_reset"]
[[usb_storage_quirk]]
vendor = 0xVENDOR
product = 0xPRODUCT
flags = ["ignore_residue", "fix_capacity"]
[[dmi_system_quirk]]
pci_vendor = 0xVENDOR
flags = ["disable_accel"]
match.sys_vendor = "Example Vendor"
match.product_name = "Example Model"
[[acpi_table_quirk]]
signature = "DMAR"
match.sys_vendor = "Example Vendor"
match.product_name = "Example Model"
```
### Choosing where to add
- **Compiled-in**: Boot-critical quirks, anything needed before root mount
- **TOML**: Everything else — easier to update, no recompilation needed
- **DMI rule**: System-specific workarounds that apply to specific laptop models
## File Layout
```
local/recipes/drivers/redox-driver-sys/source/src/quirks/
├── mod.rs # Public API: lookup_pci_quirks(), PciQuirkFlags, PciQuirkEntry
├── pci_table.rs # Compiled-in PCI quirk table
├── usb_table.rs # Compiled-in USB quirk table
├── dmi.rs # DMI/SMBIOS matching and system-level quirk rules
└── toml_loader.rs # /etc/quirks.d/*.toml parser
local/recipes/system/redbear-quirks/
├── recipe.toml # Custom build: copies TOML files to /etc/quirks.d/
└── source/quirks.d/
├── 00-core.toml
├── 10-gpu.toml
├── 20-usb.toml
├── 30-net.toml
├── 40-storage.toml
└── 50-system.toml
```
## Relationship to Linux Quirks
| Linux Pattern | Red Bear Equivalent |
|---------------|-------------------|
| `DECLARE_PCI_FIXUP_HEADER(v, d, fn)` | `PciQuirkEntry { vendor: v, device: d, flags: ... }` |
| `pci_dev->dev_flags \|= PCI_DEV_FLAGS_NO_BUS_RESET` | No direct equivalent — future flag candidate |
| `USB_QUIRK_STRING_FETCH` | `UsbQuirkFlags::NO_STRING_FETCH` |
| `DMI_MATCH(DMI_SYS_VENDOR, "Lenovo")` | `DmiMatchRule { sys_vendor: Some("Lenovo") }` |
| `acpi_black_listed()` | `[[acpi_table_quirk]] signature = "...."` with skip semantics in `acpid` |
## Extended Types
Beyond quirk flags, `redox-driver-sys` provides several supporting types for
driver configuration access, panel orientation, and platform-level DMI rules.
### DrmPanelOrientation
Defined in `quirks/mod.rs`. Represents the physical orientation of a DRM panel,
used by display drivers to apply correct rotation.
```rust
pub enum DrmPanelOrientation {
Normal,
LeftSideUp, // 90° clockwise
UpsideDown, // 180°
RightSideUp, // 270° clockwise
}
```
Loaded via `load_drm_panel_orientation()` in `quirks/dmi.rs`. Currently returns
`Normal` by default. The `PANEL_ORIENTATION_TABLE` (compiled-in) is empty and
can be populated with DMI-match entries for tablets/convertibles that have
non-standard panel mounting.
### Platform DMI Quirks
Defined in `quirks/dmi.rs`. System-wide quirks keyed by DMI/SMBIOS match rules
that affect platform-level behavior (not tied to a specific PCI device).
```rust
pub struct PlatformDmiQuirkRule {
pub sys_vendor: Option<String>,
pub board_name: Option<String>,
pub product_name: Option<String>,
pub subsystem: PlatformSubsystem,
pub value: String,
}
pub enum PlatformSubsystem {
Acpi, // ACPI table processing behavior
Pci, // PCI bus behavior
Drm, // DRM/display behavior
}
```
Loaded via `load_platform_dmi_quirks()` which reads from the compiled-in
`PLATFORM_QUIRK_TABLE` and returns matching rules. Currently the table is empty.
### PCI Config Space Access (ConfigAccess)
Defined in `pci.rs`. Supports two PCI configuration space access methods:
```rust
pub enum ConfigAccess {
File(File), // /scheme/pci/<bdf> — modern Redox path
IoPorts, // Legacy 0xCF8/0xCFC I/O port access
}
```
`PciDevice::open()` uses `File` mode by default. `PciDevice::open_io_ports()`
creates a `PciDevice` with `IoPorts` mode for systems where the PCI scheme
is unavailable or for early-boot PCI access.
I/O port address calculation: `0x80000000 | bus<<16 | device<<11 | function<<8 | (offset & 0xFC)`.
All `read8`/`read16`/`read32`/`write8`/`write16`/`write32` methods dispatch
on the `ConfigAccess` variant.
## Testing
Run quirks unit tests:
```bash
cd local/recipes/drivers/redox-driver-sys/source
cargo test
```
## Implementation Status
| Phase | Component | Status |
|-------|-----------|--------|
| Q1 | Core types (PciQuirkFlags, PciQuirkEntry, UsbQuirkFlags) | ✅ Done |
| Q1 | Compiled-in PCI/USB quirk tables | ✅ Done |
| Q1 | Lookup API (quirks(), has_quirk()) | ✅ Done |
| Q1 | Subsystem (subvendor/subdevice) fields | ✅ Done — compiled and TOML PCI matching both apply subsystem selectors |
| Q2 | TOML loader for /etc/quirks.d/ | ✅ Done |
| Q2 | redbear-quirks data package | ✅ Done |
| Q3 | redox-drm integration (MSI-X/MSI/legacy + DISABLE_ACCEL) | ✅ Done |
| Q3 | xhcid PCI controller quirks (interrupt + reset delay) | ✅ Done |
| Q3 | xhcid USB device quirks (descriptor/configuration/BOS handling) | ✅ Done |
| Q3 | pcid-spawner quirk passthrough | ✅ Done |
| Q3 | linux-kpi quirk flag bridge | ✅ Done |
| Q3 | amdgpu linux-kpi quirk consumption | ✅ Done |
| Q3 | redbear-info --quirks display | ✅ Done |
| Q4 | DMI/SMBIOS compiled-in rules | ✅ Done — 8 system rules (const table) |
| Q4 | DMI/SMBIOS TOML runtime loading | ✅ Done — `dmi_system_quirk` uses live `/scheme/acpi/dmi` data from `acpid` |
| Q4 | ACPI table blacklist/override | ✅ Done — `acpid` applies `[[acpi_table_quirk]]` skip rules during table load |
| Q5 | lspci quirk display | ✅ Done — shows active quirks per device |
| Q5 | lsusb quirk display | ✅ Done — shows active quirks per device |
| Q5 | Linux quirk extraction tool | ✅ Script exists — PCI mode uses heuristic name matching, USB mode works for table entries |
| Q6 | DrmPanelOrientation + load_drm_panel_orientation() | ✅ Done — enum + DMI loader (table empty, returns Normal) |
| Q6 | Platform DMI quirks (PlatformDmiQuirkRule, PlatformSubsystem) | ✅ Done — types + loader (table empty) |
| Q6 | ACPI SUPPRESS_IVRS flag | ✅ Done — bit 15 in AcpiQuirkFlags |
| Q6 | PciDevice::open_io_ports() + ConfigAccess enum | ✅ Done — legacy I/O port PCI config access |
Quirk flags span data definition, infrastructure wiring, and driver consumption.
Most flags are defined but not yet consumed at runtime — the tables below show
the honest breakdown.
**Flags consumed by drivers (runtime checks in production code):**
- redox-drm: `NO_MSIX`, `NO_MSI`, `FORCE_LEGACY_IRQ`, `DISABLE_ACCEL` (interrupt setup + driver probe)
- xhcid: `RESET_DELAY_MS`, `NO_MSI`, `NO_MSIX`, `FORCE_LEGACY_IRQ` (interrupt selection + port reset delay)
- xhcid (USB device path): `NO_STRING_FETCH`, `BAD_DESCRIPTOR`, `RESET_DELAY`, `HUB_SLOW_RESET`, `NO_BOS`, `SHORT_SET_ADDR_TIMEOUT`, `FORCE_ONE_CONFIG`, `HONOR_BNUMINTERFACES`, `DELAY_CTRL_MSG`, `NO_SET_CONFIG`, `NO_SET_INTF`, `NEED_RESET`, `NO_SUSPEND` (enumeration/configuration/BOS/runtime recovery plus suspend gating)
- amdgpu: startup firmware requirement enforced at the Rust DRM boundary, with real quirk-aware runtime logging for `NO_ASPM`, `NEED_IOMMU`, `NO_MSI`, `NO_MSIX`
**Infrastructure (data flows, reporting, and partial integration):**
- pcid-spawner: computes `PCI_QUIRK_FLAGS` by calling the canonical `redox-driver-sys` lookup on synthesized `PciDeviceInfo`, then passes the env var onward
- linux-kpi: `pci_get_quirk_flags()` / `pci_has_quirk()` C FFI is available for C drivers and is now consumed by the Red Bear amdgpu path
- redbear-info: `--quirks` reads `/etc/quirks.d/*.toml` and reports configured PCI/USB/DMI entries
- lspci: shows active quirk flags per PCI device (via redox-driver-sys lookup)
- lsusb: shows active quirk flags per USB device (via redox-driver-sys lookup)
- DMI compiled-in rules: 8 entries match systems by vendor/product/board (served through `acpid` at `/scheme/acpi/dmi`)
**Observed/logged but not yet strongly enforced in runtime policy:**
- xhcid `NO_SUSPEND` is now enforced and `usbhubd` mirrors USB 2 hub-port suspend state into child xhcid devices, but suspend policy origination and USB 3 link-state coordination are still pending in the broader hub/power-management layer
- `NO_ASPM`, `NEED_IOMMU`, `NO_MSI`, `NO_MSIX` in the amdgpu path are surfaced in quirk-aware logs before broader driver policy exists.
**Defined but not yet consumed by any real driver path:**
- `NO_PM`, `NO_D3COLD`, `DMA_32BIT_ONLY`, `BUS_MASTER_DELAY`, `NO_IOMMU`, etc.
`firmware-loader` itself does not interpret `NEED_FIRMWARE`; that policy is now enforced at the Rust-side DRM startup boundary instead.
Active Red Bear images that include `redbear-device-services` already ship the upstream
`redbear-firmware` bundle into `/lib/firmware`. The bounded Intel DMC work therefore selects and
requires the right startup blobs from that shipped firmware set, rather than depending on the user
to fetch firmware at runtime.
For early xhcid timing quirks, `[[usb_quirk]]` entries may also carry `port = "1.2.3"` selectors.
Those selectors are used only for pre-descriptor timing flags (`RESET_DELAY`, `HUB_SLOW_RESET`,
`SHORT_SET_ADDR_TIMEOUT`) where vendor/product IDs are not yet available.
**Remaining infrastructure work:**
- none in the current quirks scope
`pcid-spawner` now brokers quirks through the canonical `redox-driver-sys` lookup instead of carrying a separate in-tree PCI quirk engine.