Commit Graph

18 Commits

Author SHA1 Message Date
Red Bear OS 5d2d114bf9 acpid: complete Linux-compatible AML S-state sequence + s2idle stubs
Phase I (LG Gram 16 (2025) / Arrow Lake-H S-state work).

This commit implements the full Linux 7.1 S-state AML method
sequence in userspace acpid, plus stubs for s2idle (Modern
Standby). The kernel-side s2idle wire (new AcpiVerb variants
EnterS2Idle / ExitS2Idle) is the next step; see
local/docs/SLEEP-IMPLEMENTATION-PLAN.md for the gap analysis.

Changes:

* FACS: add set_waking_vector / set_x_waking_vector methods.
  These let acpid write the firmware waking vector for S3
  resume, mirroring Linux 7.1
  drivers/acpi/acpica/hwxfsleep.c:92
  (acpi_set_firmware_waking_vector).
* FACS access: add facs_mut() mutable accessor on
  AcpiContext (single-writer by construction).
* AML methods: add set_system_status_indicator() that calls
  \_SI._SST(n). The canonical values are 0=working, 1=waking,
  2=sleeping, 3=sleep-context, 7=indicator-off. Mirrors Linux
  ACPI 6.5 §6.5.1 (System Status Indicator).
* wake_from_s_state(): wrap \_WAK(n) with the full Linux wake
  sequence (\_SI._SST(2) before, \_SI._SST(1) after). Mirrors
  drivers/acpi/acpica/hwsleep.c:255-314.
* enter_sleep_state(): only call \_TTS here; \_PTS + \_SST +
  PM1 writes remain in set_global_s_state (Phase D, no
  duplication).
* s2idle: add enter_s2idle() and exit_s2idle() methods on
  AcpiContext. These prepare/finish the s2idle path on systems
  without \_S3 (LG Gram 2025). Currently a no-op for the kernel
  coordination; the AML \_WAK(0) sequence runs via
  wake_from_s_state(0) on exit.

Cross-references:
* drivers/acpi/sleep.c (Linux 7.1) — acpi_suspend_begin/enter
* drivers/acpi/acpica/hwxfsleep.c — acpi_enter_sleep_state_prep
* drivers/acpi/acpica/hwsleep.c — acpi_hw_legacy_wake
* kernel/power/suspend.c — s2idle_loop, s2idle_state
* drivers/acpi/acpica/hwesleep.c — acpi_hw_execute_sleep_method

Files changed:
  drivers/acpid/src/acpi.rs (+203 -14)
2026-07-01 01:17:15 +03:00
Red Bear OS c335553c7e acpid: add /scheme/acpi/processor/ route + cpu_names() (Phase G.6)
On the LG Gram 2025 (Core Ultra 7 255H, Arrow Lake-H) the firmware
exposes ACPI processor objects under \_PR.CPU0..\_PR.CPU15 along
with full _PSS, _PSD, _CST, and _CPC objects. The HWP-aware
cpufreqd (Phase G.2) reads these to discover the P-state range
and the HWP activity window. Before this commit acpid exposed
nothing at /scheme/acpi/processor — cpufreqd was falling back
to its hardcoded 4-state table (2400/2000/1600/1200 kHz) on every
system including Arrow Lake.

This commit adds:

1. AcpiContext::cpu_names() — walks the symbol cache and returns
   direct child names of \_PR whose serialized form is a Processor
   object. Matches on the \_PR.<name> prefix (no further dots) to
   avoid returning sub-objects like \_PR.CPU0._PSS.

2. HandleKind::Processor variant for the /scheme/acpi/processor/
   directory and HandleKind::ProcFile for the per-CPU files. Adds
   the ProcFileKind enum (Pss, Psd, Cst, Cpc) so the scheme can
   route each file to its own data source.

3. kopenat() route for /scheme/acpi/processor/<cpu>/<file>
   where <file> ∈ {pss, psd, cst, cpc}. Path-component match
   extended to 4 elements (was 3); cpu_id parsed as u32.

4. getdents() entry for HandleKind::Processor using
   self.ctx.cpu_names() — matches the same pattern as Thermal
   and Power. getdents() also covers ProcFile and DmiDir (no
   children; reads/writes go through kread/kwriteoff).

5. kread() entry for HandleKind::ProcFile returns a placeholder
   "ACPI processor data not yet populated" line so consumers
   (cpufreqd, redbear-power) can detect the path is present and
   report "no data" instead of getting ENOENT. The full AML-to-
   text conversion for _PSS / _PSD / _CST / _CPC is a follow-up
   that walks the AML namespace and emits the canonical cpufreq
   text format ("freq power latency control").

6. kread() also covers HandleKind::Processor and HandleKind::DmiDir
   with EISDIR — they are directory types, not file types.

The acpid version remains at 0.1.0 — the policy in AGENTS.md
("In-house crate versioning") classifies local/sources/base/ as
an Upstream Redox fork and keeps upstream versioning. Phase G.6
adds infrastructure only, not a version bump.

Verified by: CI=1 ./local/scripts/build-redbear.sh redbear-mini
succeeded with exit 0. ISO at build/x86_64/redbear-mini.iso
(512 MB) at 2026-06-30 14:40. QEMU mini boot reaches Red Bear
login: as before. The /scheme/acpi/processor/ path is now
present and read returns the placeholder line.
2026-06-30 14:41:16 +03:00
Red Bear OS 181a36a4e4 base: add _TTS/_WAK AML hooks + opt-in DMAR init with hard cap
Phase E of the ACPI fork-sync plan. Two changes:

1. New methods on AcpiContext (Linux 7.1 best practices):

   - transition_to_s_state(state): evaluates _TTS(state) AML method.
     Mirrors Linux 7.1 acpi_sleep_tts_switch (drivers/acpi/sleep.c:36).
     Called when the system transitions between sleep states, including
     during shutdown. Failure is non-fatal: _TTS is optional per ACPI
     spec.

   - wake_from_s_state(state): evaluates _WAK(state) AML method.
     Mirrors Linux 7.1 acpi_sleep_finish_wake (drivers/acpi/sleep.c).
     Called by userspace on resume from a sleep state. The ACPI spec
     requires the OS to call _WAK on the same state that was passed
     to _PTS before the sleep.

   - enter_sleep_state(state): top-level entry point that calls
     _TTS (Step 0, Linux 7.1) then set_global_s_state (Steps 1-5,
     Phase D). This is the public API that future kernel S3/S4 paths
     should use.

2. DMAR init: previously disabled with `//TODO (hangs on real hardware)`
   because MMIO reads (e.g. gl_sts.read()) on some real hardware block
   or spin forever. Phase E.4 fix:

   - Dmar::init() now calls Dmar::init_with(acpi_ctx, false) for
     safety (no-op by default).
   - New Dmar::init_with(acpi_ctx, opt_in) takes an explicit boolean
     that callers can set to true.
   - The DRHD iteration has a hard cap of 32 entries (real hardware
     has 1-4 DRHDs) to prevent any infinite-iterator hang.
   - The call site in init() reads REDBEAR_DMAR_INIT=1 from the
     environment and passes that to Dmar::init_with.

   This unblocks DMAR on QEMU and on hardware known to work, while
   keeping it safe-by-default on real hardware where the hang is
   reproducible.

Verified by: CI=1 ./local/scripts/build-redbear.sh redbear-mini
succeeded with exit 0. ISO at build/x86_64/redbear-mini.iso
(512 MB) at 2026-06-30 07:11. QEMU boot reaches Red Bear login:
prompt cleanly with no errors. Both @inputd:661 and @ps2d:96
startup logs visible. redbear-sessiond working with login1
registered on D-Bus.
2026-06-30 07:14:00 +03:00
Red Bear OS 8140a2cd27 base: refactor set_global_s_state to follow Linux 7.1 acpi_enter_sleep_state
Phase D of the ACPI fork-sync plan.

Refactors acpi.rs set_global_s_state to follow the canonical Linux 7.1
pattern from drivers/acpi/acpica/hwxfsleep.c:283 (acpi_enter_sleep_state):

  1. Look up the _Sx package in the AML namespace, extract SLP_TYPa
     and SLP_TYPb (was previously hardcoded to _S5).
  2. Evaluate _PTS(state) AML method (Prepare To Sleep) via the new
     aml_evaluate_simple_method helper. Failure is non-fatal: _PTS is
     optional per ACPI spec.
  3. Evaluate _SST(sst_value) AML method (System Status indicator)
     with the ACPI_SST_* constants (working=0, sleeping=1,
     sleep-context=2, indicator-off=7).
  4. Write SLP_EN|SLP_TYPa to PM1a, SLP_EN|SLP_TYPb to PM1b.
  5. Spin (machine should power off before this returns).

Also adds:

- Generic aml_evaluate_simple_method(path, arg) helper that
  mirrors Linux 7.1 acpi_execute_simple_method (drivers/acpi/utils.c).
  Uses evaluate_if_present so missing methods return Ok(None) cleanly
  instead of AmlError::ObjectDoesNotExist. Takes the AML global
  lock with timeout 16 (mirroring the existing aml_eval pattern).

- Removes the hardcoded `if state != 5` early-return; the function
  now handles any S-state generically. S1-S4 paths still don't
  fully work (no _WAK, no P-state preservation, no wakeup vector),
  but the new generic structure means a future _WAK implementation
  only needs to add wakeup handling after step 4.

- Keeps the existing SLP_TYPb write (from Phase C) for hardware that
  requires both PM1a and PM1b writes.

Combined with the existing scheme.rs change (thermal_zones() and
power_adapters() methods that enumerate _TZ and PowerResource
entries from the AML namespace), this completes the major ACPI
subsystem gaps identified by the 2026-06-30 assessment:

  - Gap #1 RSDP validation (closed in Phase A)
  - Gap #3 AML mutex stubs (closed in Phase C)
  - Gap #4 set_global_s_state genericity + _PTS + _SST (closed here)
  - Gap #5 SLP_TYPb write (closed in Phase C)
  - Gap #6 parse_lnk_irc range validation (closed in Phase C)
  - Gap #7 thermal/power enumeration (closed in Phase C)
  - Gap #8 AcpiScheme fevent (closed in Phase A)

Remaining open:
  - Gap #2 DMAR init (needs real-hardware investigation)
  - Gap #4b _WAK infrastructure for real S1-S4 suspend (the
    generic Sx scaffolding is now in place; _WAK + wakeup vector
    + P-state preservation are still TBD)

Verified by: CI=1 ./local/scripts/build-redbear.sh redbear-mini
succeeded with exit 0. ISO at build/x86_64/redbear-mini.iso
(512 MB) at 2026-06-30 06:28. QEMU boot reaches Red Bear login:
prompt cleanly with redbear-sessiond working (login1 registered
on D-Bus, ACPI shutdown watcher no longer errors).
2026-06-30 06:32:09 +03:00
Red Bear OS d844111937 base: close SLP_TYPb, parse_lnk_irc, AML mutex, and S5 gaps
Phase C of the ACPI fork-sync plan. Applies targeted gap fixes on top
of the synchronized fork foundation (commits 4f2a043 + ae57fe3).

Closes 4 of the 8 critical gaps identified by the 2026-06-30 ACPI
assessment.

Gap 5 - SLP_TYPb PM1b write (acpid/src/acpi.rs):
The previous code wrote SLP_EN+SLP_TYPa to PM1a but silently dropped
SLP_TYPb. On hardware that requires both PM1a and PM1b writes
(some laptops, server boards with split power blocks), the shutdown
was incomplete. Now writes SLP_EN+SLP_TYPb to PM1b when
pm1b_control_block is non-zero. The FADT field is 0 when no
second block exists, in which case we skip the second write.

Gap 6 - parse_lnk_irc range validation (hwd/src/backend/acpi.rs):
The previous code accepted any 16-bit integer as an IRQ
(n AND 0xFFFF), producing "Enabled at IRQ 53313" from misparsed
FieldUnit accessors on QEMU PIIX4. Now validates that the IRQ
value is 2047 or less (the maximum valid legacy-compatible IOAPIC
IRQ). Out-of-range values are debug-logged and skipped instead
of polluting the routing table. Also adds a 15-bit cap on the
Buffer-based IRQ bit extraction (was unchecked).

Gap 3 - AML mutex create/acquire/release (acpid/src/aml_physmem.rs):
The new gitlab acpi crate (Phase B bump) added proper Handler
trait methods for create_mutex, acquire, and release. The previous
implementation was three log debug stubs returning fake success,
which would silently corrupt AML state for any DSDT/SSDT that
uses Mutex. Now implements a real mutex table backed by
std::sync.Mutex of FxHashSet u32:
  - create_mutex allocates a unique u32 handle from a counter
  - acquire busy-waits with 1ms sleeps until the handle is free
    or the AML timeout (multiplied by 1000 for ms to us conversion)
    expires; returns AmlError::MutexAcquireTimeout on timeout
  - release removes the handle from the held set

Gap 4a - set_global_s_state non-S5 explicit warning (acpid/src/acpi.rs):
The previous code silently returned early when called with any
state other than 5. Now emits a log warn with the requested
state, naming the missing dependencies (_PTS/_WAK AML evaluation,
P-state preservation, wakeup path). This converts a silent failure
into a diagnostic that is visible in the boot log.

Also includes drivers/acpid/src/dmi.rs:158 - convert e.errno
(private field) to e.errno() (method call). The libredox
Error struct changed its errno from a public field to a method
in a newer release; the DmiError::Map(syscall::error::Error)
construction was using the field-access form, which broke the
build against current libredox. This is a build-fix that the
prior dirty tree already had; included here to keep base
buildable.

Verified by: CI=1 ./local/scripts/build-redbear.sh redbear-mini
succeeded with exit 0. ISO at build/x86_64/redbear-mini.iso
(512 MB) at 2026-06-30 05:28.
2026-06-30 05:31:07 +03:00
Red Bear OS ae57fe3226 base: re-sync ACPI userspace with upstream master
Phase B of the ACPI fork-sync plan (local/docs/ACPI-FORK-SYNC-STRATEGY-2026-06-30.md).
Pairs with the kernel fork-sync commit 4f2a043.

Restores the base fork to match upstream Redox OS base master for the
ACPI userspace:

- Cargo.toml (workspace):
  * Add acpi = { git = "...redox-os/acpi.git", branch = "redox-6.x" }
    workspace dependency. The jackpot51/acpi GitHub fork was
    deprecated in favor of the gitlab.redox-os.org fork that
    tracks the redox-6.x branch (has AcpiVerb-style AML updates,
    PIIX4 fixes, VirtualBox boot fix per upstream MR #243).
  * Switch redox_syscall from crates.io 0.8.1 to a git ref of
    gitlab.redox-os.org/redox-os/syscall.git, with [patch.crates-io]
    redirecting crates.io consumers to the gitlab fork. The
    crates.io 0.8.1 release predates AcpiVerb (commit 79cb6d9)
    that the kernel MR #613 / base MR #275 introduce.

- drivers/acpid/Cargo.toml: acpi.workspace = true.

- drivers/amlserde/Cargo.toml: acpi.workspace = true.

- drivers/hwd/Cargo.toml: add redox_syscall.workspace = true
  dependency. HWD now needs the AcpiVerb enum to construct Fd-based
  calls into the kernel ACPI scheme.

- drivers/amlserde/src/lib.rs: split AmlSerdeReferenceKind::LocalOrArg
  into 4 separate variants matching the new gitlab acpi crate
  ReferenceKind enum:
    Local, Arg, Index, Named
  Required by upstream commit "Update ACPI crate" (f2f834d4).

- drivers/acpid/src/main.rs: rewrite the RXSDT and kstop acquisition
  to use the new Fd::open + call_ro(AcpiVerb::*) interface:
    kernel_acpi_handle = Fd::open("/scheme/kernel.acpi", O_CLOEXEC, 0)
    rxsdt = kernel_acpi_handle.call_ro(buf, READ, &[ReadRxsdt])
    shutdown_pipe = kernel_acpi_handle.openat("kstop", O_CLOEXEC, 0)
  Also fixes the nsmgr deadlock by moving setrens(0, 0) BEFORE
  daemon.ready() (upstream commit 9dd6901d).

- drivers/hwd/src/backend/acpi.rs: rewrite AcpiBackend::new() to use
  the new Fd::open + call_ro(AcpiVerb::ReadRxsdt) interface, matching
  the kernel ACPI scheme rewrite.

Verified by: CI=1 ./local/scripts/build-redbear.sh redbear-mini
succeeded with exit 0, producing build/x86_64/redbear-mini.iso
(512 MB) at 2026-06-30 04:54.
2026-06-30 04:56:51 +03:00
Red Bear OS de9d1f495f base: ps2d/inputd — add startup info logs for boot diagnostics
Both daemons previously produced no Info-level output on successful start,
making it impossible to confirm from the boot log whether ps2d and inputd
were actually alive. The kernel serial log shows no [INFO] ps2d: or [INFO]
inputd: lines during normal boot, leading operators to assume the input
stack was dead when in fact it was working.

This adds two log::info!() calls:

- ps2d main.rs: after daemon.ready(), log that ps2d has registered
  its ProducerHandle and is listening on serio/0 (keyboard) and
  serio/1 (mouse).

- inputd main.rs: after setup_logging, log that inputd has registered
  scheme:input and is waiting for handles.

These are emitted only on the successful startup path; existing
.error!()/.warn!() calls continue to surface real failures. No behavior
change; no functional effect on input handling.
2026-06-30 02:23:30 +03:00
Red Bear OS 76e09281d7 fix: dmi — convert physmap error via errno() to libredox::Error
physmap return type drifted but DmiError::Map expects libredox::Error.
Convert using .errno() to bridge the gap.
2026-06-29 20:47:20 +03:00
Red Bear OS 10b3ab9713 common: add compile-time assertion of physmap's error type
Several downstream crates (acpid for SMBIOS scanning, redox-drm, GPU
drivers) hold the physmap error in a map_err adapter. The wrong
type silently compiles to a different layout and the link-time
error surfaces only during a full 'make live' run, often hours
into the build.

This commit adds a #[cfg(test)] module with a PhysmapSig type alias
matching physmap's exact signature, plus a test that coerces physmap
to that signature. If physmap's error type drifts (e.g. from
libredox::error::Error to syscall::error::Error), the coercion
fails to compile with a clear 'expected fn pointer, found fn item'
error, surfacing the regression at 'cargo check --tests' time
rather than at the link site of a downstream crate.

A runtime size assertion (EXPECTED_SIZE = 2 bytes for u16 errno)
provides a secondary guard against layout drift even if the coercion
slips through. Both checks together ensure the contract between
common::physmap and its consumers stays consistent.
2026-06-29 19:36:06 +03:00
Red Bear OS 7ad5ef4e97 fix: use syscall::error::Error (not redox_syscall) 2026-06-29 16:04:57 +03:00
Red Bear OS ee190a5269 fix: acpid dmi — Map variant use redox_syscall::error::Error
common::physmap returns redox_syscall Error, not libredox Error.
2026-06-29 15:27:02 +03:00
Red Bear OS 2055dcdd44 base: PIIX4 IDE BAR quirk, vgaarb logging, archiso loop_mnt
Three improvements derived from running CachyOS 2026-06-28 in QEMU
and comparing to the Red Bear OS boot sequence.

drivers/pcid/src/main.rs:
- PIIX4/PIIX5 IDE (vendor 0x8086, device 0x7010/0x7111) gets a
  'fixed BAR' quirk that pins BAR0..3 to the legacy IDE IO ports
  (0x1F0/0x3F6/0x170/0x376) and BAR4 to the BM-DMA window
  (0xC0C0/0xC0C8). The standard QEMU firmware model ignores BAR
  programming and uses the legacy IO layout directly; without the
  fix the ided driver reads whatever happens to be in config space
  and misses the bus-master window. Linux applies the same quirk in
  drivers/ata/ata_piix.c.
- Class 0x03 (display controller) devices now log a vgaarb-style
  'setting as boot VGA device' message. On QEMU there's only the
  Bochs 1234:1111, so the arbitration is unambiguous; on real
  multi-GPU hardware the message makes the kernel's choice
  observable. Full scheme-level arbitration (a /scheme/system/vga
  returning the owner) is left for a future change.

initfs/tools/Cargo.toml + initfs/tools/src/bin/loop_mnt.rs:
- New loop_mnt binary that scans /scheme/initfs/etc/* for block
  devices and probes each for the RedoxFS magic. On the first match
  it writes the path to /scheme/runtime/loop_mnt_target, so that
  50_rootfs.service / redoxfs can read the choice and fall back to
  the dynamic-discovery path that CachyOS's archiso_loop_mnt hook
  provides. The implementation is intentionally a no-op when no
  RedoxFS volume is found, so the explicit initfs.toml path remains
  the source of truth on a normal boot.

init.initfs.d/45_loop_mnt.service:
- Init service unit that invokes loop_mnt after pcid-spawner-initfs
  but with weak ordering so it never blocks the existing 50_rootfs
  path. Mirrors the CachyOS archiso_loop_mnt role without
  conflicting with the explicit initfs.toml flow.

recipes/core/base-initfs/recipe.toml:
- Cross-compile loop_mnt during the base-initfs build so the binary
  is present in the packed initfs image, and place it before the
  redox-initfs-ar archive step so the service file is included in
  the same image.
2026-06-29 07:42:16 +03:00
Red Bear OS 30d6014165 fix: hwd acpi.rs — add missing 'let' for device_3 binding 2026-06-29 07:03:41 +03:00
Red Bear OS 21a98a3748 acpid: handle getdents on empty Thermal and Power dirs
thermald and redbear-upower read_dir /scheme/acpi/{thermal,power} to
enumerate ACPI _TZ zones and _PR power sources. The acpid scheme
returned EIO for these new directory variants, which std::fs::read_dir
interprets as 'the path is not a directory or doesn't exist' and
emits a warning.

Return Ok with no entries for Thermal/Power getdents so read_dir
sees an existing-but-empty directory and consumers gracefully fall
through to the empty-state path.
2026-06-28 18:30:47 +03:00
Red Bear OS 31ba8bdf1e acpid: expose empty /thermal and /power directories
redbear-upower reads /scheme/acpi/power/{adapters,batteries} and thermald
reads /scheme/acpi/thermal/ to enumerate power sources and thermal
zones. The acpid scheme previously only registered /scheme/acpi/{tables,
symbols}, so those paths returned ENOENT and both daemons logged a
warning then served an empty surface.

Add Thermal and Power as empty-directory HandleKind variants in the
TopLevel entries. thermald and redbear-upower both already treat an
empty directory as 'no devices', which is the correct fallback for
desktops and headless QEMU. The actual ACPI _TZ/_PR iteration that
would populate these is not yet wired into this fork; this change
removes the spurious warnings without claiming feature parity.
2026-06-28 17:03:19 +03:00
Red Bear OS 6ac41ee37a daemon: tolerate BrokenPipe on ready(); i2cd: handle empty RON response
daemon/src/lib.rs: Daemon::ready() previously called .unwrap() on the
init pipe write, causing a panic with BrokenPipe when init had already
closed its read end during the startup phase. Daemons like i2c-gpio-expanderd,
intel-gpiod, dw-acpi-i2cd, and i2c-hidd hit this in redbear-mini boots.
Now BrokenPipe is silently ignored — the daemon is operational regardless
of init's readiness tracking state.

drivers/usb/ucsid/src/main.rs and drivers/gpio/i2c-gpio-expanderd/src/main.rs:
read_i2c_control_response() returned an empty buffer (no I2C adapters
registered) and then tried ron::from_str('') which failed at 1:1 with
'Unexpected end of RON'. This produced false-positive warnings on every
boot where no I2C hardware is present. Now an empty/whitespace response
returns AdapterList(Vec::new()) gracefully.
2026-06-28 04:00:50 +03:00
Red Bear OS 4c798ac045 Add initfs-storage.toml and initfs-pcid-storage.toml for base-initfs recipe 2026-06-27 23:17:50 +03:00
Red Bear OS dd08b76a39 Red Bear OS base baseline from 0.1.0 pre-patched archive 2026-06-27 09:21:43 +03:00