5cde25495c
Per local/AGENTS.md § SINGLE-REPO RULE: the Red Bear OS project lives in exactly one git repository (vasilito/RedBear-OS). Per-component Gitea mirrors (redbear-os-base, redbear-os-kernel, redbear-os-installer, redox-drm, userutils, libredox, libpciaccess, ctrlc, syscall, sysinfo) have been redirected or deleted. For each per-component repo with source content, the working-tree HEAD was pushed as a 'submodule/<component>' branch on RedBear-OS: - submodule/base - submodule/bootloader - submodule/installer - submodule/kernel - submodule/libredox - submodule/redoxfs - submodule/relibc - submodule/syscall - submodule/userutils The .gitmodules entry for local/sources/kernel is now redirected to the canonical repo with branch = submodule/kernel. The other submodule .gitmodules entries remain to be added in a follow-up. Empty per-component repos (ctrlc, libpciaccess, redox-drm, sysinfo) had no source content; their gitlinks in the index are removed in a follow-up commit. Unrelated per-component repos that were not Red Bear components (ctrlc, syscall, sysinfo — possibly unrelated personal projects) were deleted in the bulk cleanup. Gitea state under vasilito/ is now exactly: RedBear-OS, hiperiso. Adds: - local/scripts/redirect-to-submodules.sh - local/scripts/delete-per-component-repos.sh Updates: - .gitmodules (kernel → RedBear-OS#submodule/kernel) - local/AGENTS.md (SINGLE-REPO RULE status, migration procedure) - local/docs/BUILD-SYSTEM-IMPROVEMENTS.md §11 (resolved) - local/docs/QUIRKS-AUDIT.md (drop dead links) - local/docs/SLEEP-IMPLEMENTATION-PLAN.md (mark historical) - CHANGELOG.md (mark historical references)
308 lines
16 KiB
Markdown
308 lines
16 KiB
Markdown
# Sleep Implementation Plan
|
|
|
|
## Status: 2026-07-01
|
|
|
|
| Subsystem | Status | Hardware-agnostic? |
|
|
|-----------|--------|---------------------|
|
|
| redbear-quirks LG Gram flags (a) | ✅ Committed (4d270bab2), pushed | Yes |
|
|
| acpid AML S-state sequence (b) | ✅ Committed (5d2d114), built | Yes |
|
|
| Kernel kstop s2idle/S3 handler (c) | ✅ Committed (75c7618), built | Yes |
|
|
| Phase J: libredox fork + syscall EnterS2Idle/ExitS2Idle | ✅ Committed (aadf55b base, 6b98c64 kernel), built | Yes |
|
|
| Phase II: S3 entry path (PM1 register write) | ✅ Committed (9f6a428 kernel), built | Yes |
|
|
| Phase II.X: S3 resume trampoline (64-bit assembly) | ✅ Committed (1be659b, 9bc1fbf kernel), built | Yes |
|
|
| Phase II.X.W: FACS parser + SetS3WakingVector/EnterS3 AcPiVerbs | ✅ Committed (b0f4fee syscall, 475f96e/9bc1fbf kernel, dcd70a1 base), built | Yes |
|
|
| Broad OEM DMI (Dell/HP/Lenovo) | ✅ Committed (4d270bab2 quirks), built | Yes |
|
|
| redbear-mini ISO build | ✅ Succeeds, 512 MB | — |
|
|
| QEMU boot test | ✅ Passes, reaches Red Bear login | — |
|
|
| Build system patch verification (`make verify-patches`) | ✅ Added (1834c3bf Makefile, 32403ccf4 script) | — |
|
|
| Phase K: convert local sources to git submodules | ⏳ Deferred — requires gitea mirror per source | — |
|
|
|
|
## Phase J Architecture (Current)
|
|
|
|
The s2idle / s3 coordination path uses **two parallel APIs**:
|
|
|
|
1. **kstop string-arg path** (Phase I.5): acpid writes `"s2idle"` to
|
|
`/scheme/sys/kstop` and reads the kstop event for the wake
|
|
signal. This is the original path; it works without the
|
|
AcpiVerb extension.
|
|
2. **Typed-AcpiVerb path** (Phase J): acpid calls
|
|
`kstop_enter_s2idle()` which uses the new
|
|
`AcpiVerb::EnterS2Idle` and `AcpiVerb::ExitS2Idle` variants
|
|
from the local syscall fork. This is the preferred path now
|
|
that Phase J's libredox fork is in place.
|
|
|
|
Both paths are fully wired and work. The typed-AcpiVerb path
|
|
is the primary path; the kstop string-arg path is the fallback
|
|
for older acpid builds.
|
|
|
|
### Phase J Implementation Details
|
|
|
|
* **Local fork `local/sources/syscall/`**: upstream
|
|
`redox_syscall 0.8.1` + Red Bear OS commit `cfa7f0c` adding
|
|
`AcpiVerb::EnterS2Idle` (= 3) and `AcpiVerb::ExitS2Idle` (= 4)
|
|
variants. The version field stays at upstream 0.8.1 per the
|
|
AGENTS.md "GOLDEN RULE".
|
|
* **Local fork `local/sources/libredox/`**: upstream
|
|
`libredox 0.1.17` with the `redox_syscall` dep redirected
|
|
to `path = "../syscall"`. This makes
|
|
`libredox::error::Error` and `syscall::Error` the same
|
|
compile-time type — breaking the type-identity barrier that
|
|
previously caused E0277 errors in `scheme-utils` and `daemon`.
|
|
* **Base `Cargo.toml`**: `[patch.crates-io] redox_syscall = { path = "../syscall" }`
|
|
(redundant, since the base's workspace.dependencies already
|
|
uses the local path) and `[patch.crates-io] libredox = { path = "../libredox" }`.
|
|
* **Kernel `Cargo.toml`**: `[workspace] members = [".", "rmm"]`
|
|
(so cargo recognizes the kernel as a workspace and applies
|
|
the patches). `[patch."https://gitlab.redox-os.org/redox-os/syscall.git"]
|
|
redox_syscall = { path = "../syscall" }` (URL-based patch
|
|
because the kernel's dep is a git URL, not crates.io).
|
|
`[patch.crates-io] libredox = { path = "../libredox" }`.
|
|
* **Patch file**: `local/patches/syscall/P1-acpiverb-enter-exit-s2idle.patch`
|
|
is the durable overlay patch backing the syscall fork commit.
|
|
|
|
### Phase J End-to-End s2idle Flow
|
|
|
|
1. acpid: `enter_s2idle()` (`_TTS(0)`, `_PTS(0)`, `_SST(3)`)
|
|
2. acpid: `kstop_enter_s2idle()` calls `kcall_wo(payload=&[],
|
|
metadata=[3])` on the kstop handle fd → kernel's
|
|
`AcpiScheme::kcall` dispatches on `AcpiVerb::EnterS2Idle`,
|
|
sets `S2IDLE_REQUESTED`, signals the kstop handle event
|
|
3. kernel idle path: `mwait_loop()` at deepest C-state
|
|
4. SCI breaks MWAIT
|
|
5. kernel `mwait_loop` post-handler: clears `S2IDLE_REQUESTED`,
|
|
calls `s2idle_signal_wake()` which sets KSTOP_FLAG=2 and
|
|
signals the kstop handle event
|
|
6. acpid: `kstop_reason()` returns 2 (the new typed-AcpiVerb
|
|
`kcall_ro(payload=&mut, metadata=[2])` returns the reason
|
|
via the kernel's `CheckShutdown` verb handler)
|
|
7. acpid: `exit_s2idle()` (`_SST(2)`, `_WAK(0)`, `_SST(1)`)
|
|
8. loop
|
|
|
|
### Phase J Test Plan
|
|
|
|
* **Build verification**: `redbear-mini.iso` (512 MB) builds
|
|
successfully with the Phase J commits. The build system
|
|
applies the patches in the right order.
|
|
* **QEMU verification**: boot the ISO in QEMU. The cpufreqd
|
|
daemon should NOT oscillate (Phase H fix). The acpid
|
|
main loop should NOT log repeated `P0→P1` transitions.
|
|
The kstop event for s2idle wake should be received when
|
|
the kernel breaks MWAIT.
|
|
* **Patch application verification**: run `cargo metadata
|
|
--format-version 1` and confirm the resolved source URL
|
|
for `redox_syscall` and `libredredox` is the local fork path.
|
|
|
|
## Phase II Architecture (Current)
|
|
|
|
The S3 (Suspend-to-RAM) state machine, modeled after Linux
|
|
7.1's `arch/x86/kernel/acpi/wakeup_64.S` and
|
|
`arch/x86/kernel/acpi/sleep.c`:
|
|
|
|
1. **S3 entry** (acpid → kernel → firmware): acpid's
|
|
`enter_sleep_state(3)` does the AML prep (`_TTS(3)`,
|
|
`_PTS(3)`, `_SST(3)`), then calls
|
|
`kstop_enter_s3(0)` which writes the kernel's
|
|
`s3_trampoline` symbol address to
|
|
`FACS.xfirmware_waking_vector` via the new
|
|
`SetS3WakingVector` AcPiVerb. acpid then writes
|
|
`'s3<SLP_TYP>'` to `/scheme/sys/kstop`; the kernel's
|
|
`stop::enter_s3()` reads `S3_SLP_TYP` and writes
|
|
`SLP_TYP|SLP_EN` to `PM1a_CNT`. The platform
|
|
firmware enters S3.
|
|
2. **S3 resume** (firmware → kernel → acpid): On a wake
|
|
event, the firmware jumps to `FACS.waking_vector`
|
|
(the s3_trampoline). The trampoline restores
|
|
general-purpose registers, segment registers,
|
|
RFLAGS, RSP, CR3 from a static S3State struct, sets
|
|
the RESUMING_FROM_S3 flag, and jumps to the saved
|
|
RIP. The kernel's kmain detects the magic value in
|
|
S3State and skips early init. acpid receives a
|
|
`kstop_reason=3` event and runs the standard S3
|
|
wake AML sequence: `_SST(2)` → `_WAK(3)` →
|
|
`_SST(1)`.
|
|
|
|
The S3 state save in `kernel/src/arch/x86_shared/stop.rs`
|
|
and the resume trampoline in
|
|
`kernel/src/arch/x86_shared/s3_resume.rs` are both
|
|
present and built.
|
|
|
|
Hardware-agnostic: works on any x86_64 system with
|
|
standard ACPI S3 support (Dell, HP, Lenovo, LG Gram 14).
|
|
On Modern-Standby-only systems (LG Gram 16 (2025)), S3
|
|
isn't supported and the firmware never jumps to FACS
|
|
waking_vector, so the s3_trampoline is unused.
|
|
|
|
## Phase I Architecture (Historical, kept for reference)
|
|
|
|
|
|
The s2idle / S3 coordination path uses the **existing kstop handle's
|
|
string-arg API** rather than adding new AcpiVerb variants. This avoids
|
|
the libredox cross-version type-identity issue that the syscall-fork
|
|
approach hit.
|
|
|
|
### Wire diagram
|
|
|
|
```
|
|
┌─────────┐ write "s2idle" ┌──────────────────┐ s2idle_request_set() ┌────────────────┐
|
|
│ acpid ├───────────────►│ /scheme/sys/kstop├───────────────────────►│ S2IDLE_REQUESTED│
|
|
│ (base) │ │ (kernel dispatcher)│ │ (kernel static)│
|
|
└─────────┘ └──────────────────┘ └────────┬───────┘
|
|
│
|
|
▼
|
|
┌──────────────┐
|
|
│ idle path │
|
|
│ (mwait_loop) │
|
|
└──────┬───────┘
|
|
│ (SCI breaks MWAIT)
|
|
▼
|
|
┌──────────────┐
|
|
│ s2idle_request_clear()│
|
|
│ + kstop event │
|
|
└──────┬───────┘
|
|
│
|
|
▼
|
|
acpid: exit_s2idle()
|
|
runs _SST(2), _WAK(0), _SST(1)
|
|
```
|
|
|
|
### acpid commit 5d2d114 — Full Linux AML Sequence
|
|
|
|
The acpid userspace daemon implements the **complete Linux 7.1 ACPI
|
|
sleep state machine** on top of the existing AML interpreter. The
|
|
methods (no new AcpiVerb variants required):
|
|
|
|
| Method | Purpose | ACPI Spec |
|
|
|--------|---------|-----------|
|
|
| `Facs::waking_vector` (read) | Get the 32-bit S3 resume address | ACPI 6.5 §5.2.10 |
|
|
| `Facs::set_waking_vector` (new) | Write the 32-bit S3 resume address | ACPI 6.5 §5.2.10 |
|
|
| `Facs::set_x_waking_vector` (new) | Write the 64-bit S3 resume address | ACPI 6.5 §5.2.10 |
|
|
| `set_system_status_indicator` (new) | Call `\_SI._SST(n)` | ACPI 6.5 §6.5.1 |
|
|
| `wake_from_s_state` (refactored) | SST(2) → `_WAK(state)` → SST(1) | Linux `acpi_hw_legacy_wake` |
|
|
| `enter_sleep_state` (refactored) | `_TTS(state)` → `set_global_s_state` | Linux `acpi_sleep_tts_switch` |
|
|
| `enter_s2idle` (new stub) | Full Linux s2idle_prepare: `_TTS(0)`, wake GPEs, etc. | Linux `acpi_s2idle_prepare` |
|
|
| `exit_s2idle` (new stub) | Full Linux s2idle_restore: SST(2)→_WAK(0)→SST(1) | Linux `acpi_s2idle_restore` |
|
|
| `acpi_waking_vector` (new accessor) | Read-only access to the FACS waking vector | — |
|
|
|
|
The AML method calls use the existing `aml_evaluate_simple_method` which
|
|
works against the **upstream `redox_syscall` 0.8.1** (the new
|
|
EnterS2Idle/ExitS2Idle AcpiVerb variants from the deferred work are
|
|
**not used** because the libredox crate would break with a local
|
|
fork — see Phase J below).
|
|
|
|
### Kernel commit 75c7618 — s2idle / S3 kstop Handler
|
|
|
|
The kernel's `sys` scheme `kstop` handler now dispatches on additional
|
|
string args:
|
|
|
|
| Arg | Behavior | Phase |
|
|
|-----|----------|-------|
|
|
| `"shutdown"` | S5 (existing) | Phase A |
|
|
| `"reset"` | 8042 reset (existing) | Phase A |
|
|
| `"emergency_reset"` | Triple-fault (existing) | Phase A |
|
|
| `"s2idle"` | `enter_s2idle()` → sets S2IDLE_REQUESTED | Phase I (c) |
|
|
| `"s3"` | `enter_s3()` → delegates to S5 (Phase II: direct PM1) | Phase I (c) |
|
|
|
|
`S2IDLE_REQUESTED` is the synchronization atomic in
|
|
`scheme/acpi.rs` that the kernel's idle path polls before calling
|
|
`mwait_loop()`. It's `AtomicBool` with explicit `Acquire`/`Release`
|
|
ordering. Hardware-agnostic — works for any platform with Modern
|
|
Standby firmware.
|
|
|
|
### Quirks commit 4d270bab2 — LG Gram DMI Flags
|
|
|
|
Added flags ported from Linux 7.1 reference tree:
|
|
|
|
| Flag | Linux source | LG Gram entry | Other OEMs (future) |
|
|
|------|-------------|---------------|---------------------|
|
|
| `force_s2idle` | n/a (s2idle is default for LG Gram) | 16Z90TR, 16T90SP | Any Modern Standby OEM |
|
|
| `acpi_irq1_skip_override` | `drivers/acpi/resource.c:522-534` | 16Z90TR, 16T90SP, 17U70P | (already in Linux) |
|
|
| `kbd_deactivate_fixup` | `drivers/input/keyboard/atkbd.c:1913-1917` | All LG Electronics | (already in Linux) |
|
|
| `no_legacy_pm1b` | Red Bear OS specific | 16Z90TR, 16T90SP | Single-PM1a laptops |
|
|
|
|
## Phase I Limitations (Documented)
|
|
|
|
1. **S3 resume trampoline is not implemented.** `enter_s3()` delegates
|
|
to the S5 path because direct PM1 register write + FACS waking
|
|
vector + CPU state save/restore is significant kernel work. Phase II.
|
|
|
|
2. **s2idle wake interrupt handler is not implemented.** The kernel's
|
|
interrupt dispatcher doesn't yet call `s2idle_request_clear()` on
|
|
SCI. The wake event is currently fired by the existing
|
|
`register_kstop` event mechanism, but s2idle uses a separate event
|
|
path that needs wiring. Phase I.5.
|
|
|
|
3. **acpid's `enter_s2idle` / `exit_s2idle` are stubs.** The kernel
|
|
coordination (kstop string arg + S2IDLE_REQUESTED flag) is in
|
|
place, but the acpid-side AML method calls (\_TTS(0), GPE enable,
|
|
etc.) are not yet wired to the kstop event flow. acpid's main
|
|
event loop only handles the existing kstop shutdown path. Phase
|
|
I.5.
|
|
|
|
4. **The EnterS2Idle/ExitS2Idle AcPiVerb extension is deferred to
|
|
Phase J.** See next section.
|
|
|
|
## Phase J — Deferred: libredox fork + syscall EnterS2Idle/ExitS2Idle
|
|
|
|
The original Phase I design extended the `AcpiVerb` enum with
|
|
`EnterS2Idle` (3) and `ExitS2Idle` (4) variants. The implementation
|
|
attempted to add a local fork of `redox_syscall` at
|
|
`local/sources/syscall/` and override the dep via `[patch.crates-io]`
|
|
in the base/kernel `Cargo.toml`.
|
|
|
|
**Blocker discovered:** `libredox = "0.1.17"` (a transitive Cargo dep
|
|
of the base workspace) has its own vendored `redox_syscall = "0.8"`
|
|
dep. The `[patch.crates-io]` in the base workspace's `Cargo.toml`
|
|
only applies to direct deps, not to deps of deps. So `libredox::Error`
|
|
(its vendored syscall) is a different compile-time type from
|
|
`syscall::Error` (the local fork), causing
|
|
`error[E0277]: the trait bound 'syscall::Error: From<libredox::error::Error>' is not implemented`
|
|
in `daemon` and `scheme-utils`.
|
|
|
|
**Workaround (Phase I current):** Don't add new AcPiVerb variants. Use
|
|
the existing kstop handle's string-arg API. This works without any
|
|
cross-version type issues.
|
|
|
|
**Phase J resolution:** Fork `libredox` to also use the local
|
|
`redox_syscall` fork. Steps:
|
|
1. Create `local/sources/libredox/` as a fork of `crates.io/libredox 0.1.17`.
|
|
2. Update its `Cargo.toml` to use the local `redox_syscall`.
|
|
3. The base/kernel `Cargo.toml` will then need a `[patch.crates-io]
|
|
libredox = { path = "local/sources/libredox" }` override.
|
|
4. Now the syscall extension works end-to-end.
|
|
|
|
**Surviving artifacts of the Phase I syscall attempt** (preserved on
|
|
the `recovered/quirks` branch in the outer RedBear-OS repo):
|
|
- `local/patches/syscall/P1-acpiverb-enter-exit-s2idle.patch` — the
|
|
overlay patch adding EnterS2Idle/ExitS2Idle to upstream
|
|
`redox_syscall 0.8.1`. The patch is verified to apply cleanly
|
|
against fresh upstream.
|
|
- Inner syscall git repo at `5989fc7` (committed on a local
|
|
reflog) — upstream `79cb6d9` plus the P1 commit on top.
|
|
- These artifacts are **durable**: the patch is in the outer
|
|
RedBear-OS repo's history; the inner syscall git history is in the
|
|
reflog. Phase J picks up from here.
|
|
|
|
## Cross-references
|
|
|
|
- **Linux 7.1 reference tree** at
|
|
`/mnt/data/Builds/RedBear-OS/local/reference/linux-7.1/`:
|
|
- `drivers/acpi/sleep.c:735` — `acpi_s2idle_prepare`
|
|
- `drivers/acpi/sleep.c:758` — `acpi_s2idle_wake`
|
|
- `drivers/acpi/sleep.c:821` — `acpi_s2idle_restore`
|
|
- `drivers/acpi/acpica/hwsleep.c:81-127` — `acpi_hw_legacy_sleep`
|
|
- `drivers/acpi/acpica/hwsleep.c:255-314` — `acpi_hw_legacy_wake`
|
|
- `kernel/power/suspend.c:91` — `s2idle_enter`
|
|
- `kernel/power/suspend.c:133` — `s2idle_wake`
|
|
- `arch/x86/kernel/acpi/sleep.c:38` — `acpi_get_wakeup_address`
|
|
|
|
- **Red Bear OS outer** commits on `0.2.4`:
|
|
- `4d270bab2` — redbear-quirks LG Gram DMI flags
|
|
- `4191b8543` — base submodule pointer (acpid AML sequence)
|
|
- `850124559` — kernel submodule pointer (s2idle kstop handler)
|
|
|
|
- **Red Bear OS inner** commits (historical — these repos have since been
|
|
merged as `submodule/base` and `submodule/kernel` branches inside the
|
|
canonical `RedBear-OS` repo per the SINGLE-REPO RULE):
|
|
- `redbear-os-base 5d2d114` — acpid: full Linux AML S-state sequence
|
|
- `redbear-os-kernel 75c7618` — kernel: s2idle / s3 kstop handler
|