fix: commit remaining dirty files + phase4-5 checker updates
Wave C background task output: status doc + checker enhancements
This commit is contained in:
@@ -2,9 +2,16 @@
|
||||
|
||||
**Last updated:** 2026-04-29
|
||||
**Canonical plan:** `local/docs/CONSOLE-TO-KDE-DESKTOP-PLAN.md` (v3.0)
|
||||
**Boot improvement plan:** `local/docs/BOOT-PROCESS-IMPROVEMENT-PLAN.md` (v1.0)
|
||||
**Boot improvement plan:** `local/docs/BOOT-PROCESS-IMPROVEMENT-PLAN.md` (v1.1)
|
||||
**Source archival policy:** `local/docs/SOURCE-ARCHIVAL-POLICY.md` (v1.0)
|
||||
|
||||
## Recent Changes (2026-04-29, Wave C)
|
||||
|
||||
- **Validation infrastructure consistency refresh**:
|
||||
- `redbear-phase4-kde-check` now detects resolved KF6 shared-library version suffixes in addition to checking library presence, session entry points, and KDE runtime markers.
|
||||
- `redbear-phase5-gpu-check` now detects GPU PCI vendor/device identity from `/scheme/pci` before reporting firmware / Mesa / DRM preflight state.
|
||||
- `redbear-boot-check` now provides a bounded boot-surface checker for greeter-facing service ordering, DRM readiness, compositor socket creation, and greeter hello-protocol health.
|
||||
|
||||
## Recent Changes (2026-04-29, Wave 7)
|
||||
|
||||
- **KF6 surface made more honest for Phase 3/4**:
|
||||
@@ -160,8 +167,9 @@ greeter/auth/session-launch stack on the `redbear-full` desktop path.
|
||||
| `kwin` | **stub** | cmake configs + wrapper scripts that delegate to redbear-compositor |
|
||||
| `test-phase4-runtime.sh` | **exists** | Phase 4 KDE Plasma preflight harness (guest + QEMU modes) |
|
||||
| `test-phase5-gpu-runtime.sh` | **exists** | Phase 5 hardware GPU preflight harness (guest + QEMU modes) |
|
||||
| `redbear-phase4-kde-check` | **builds** | Phase 4 KDE preflight: KF6 libraries, plasma binaries, session entry points, kirigami status |
|
||||
| `redbear-phase5-gpu-check` | **builds** | Phase 5 GPU preflight: DRM device, GPU firmware, Mesa DRI drivers, display modes |
|
||||
| `redbear-phase4-kde-check` | **builds** | Phase 4 KDE preflight: KF6 libraries plus resolved KF6 version suffixes, plasma binaries, session entry points, and kirigami status |
|
||||
| `redbear-phase5-gpu-check` | **builds** | Phase 5 GPU preflight: DRM device, GPU PCI vendor/device detection, GPU firmware, Mesa DRI drivers, and display modes |
|
||||
| `redbear-boot-check` | **builds** | Boot-surface preflight: `pcid-spawner`→greeter ordering contract, DRM device readiness, compositor socket creation, and greeter hello-protocol health |
|
||||
| | | |
|
||||
| **Phase 5 (Hardware GPU) — driver scaffold** | | |
|
||||
| `redox-drm` | **builds** | DRM scheme daemon with Intel Gen8-Gen12 + AMD device support and quirk tables; no hardware validation |
|
||||
|
||||
@@ -24,6 +24,16 @@ const REDBEAR_KDE_SESSION_ENV_FILE: &str = "redbear-kde-session.env";
|
||||
const REDBEAR_KDE_SESSION_READY_FILE: &str = "redbear-kde-session.ready";
|
||||
#[cfg(target_os = "redox")]
|
||||
const REDBEAR_KDE_SESSION_PANEL_READY_FILE: &str = "redbear-kde-session.panel-ready";
|
||||
#[cfg(target_os = "redox")]
|
||||
const KEY_KF6_LIBRARIES: &[&str] = &[
|
||||
"/usr/lib/libKF6CoreAddons.so",
|
||||
"/usr/lib/libKF6ConfigCore.so",
|
||||
"/usr/lib/libKF6I18n.so",
|
||||
"/usr/lib/libKF6WindowSystem.so",
|
||||
"/usr/lib/libKF6Notifications.so",
|
||||
"/usr/lib/libKF6Service.so",
|
||||
"/usr/lib/libKF6WaylandClient.so",
|
||||
];
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
@@ -141,6 +151,7 @@ impl Report {
|
||||
struct JsonReport {
|
||||
overall_success: bool,
|
||||
kf6_libs_present: bool,
|
||||
kf6_library_versions: bool,
|
||||
plasma_binaries_present: bool,
|
||||
session_entry: bool,
|
||||
session_environment: bool,
|
||||
@@ -164,6 +175,7 @@ impl Report {
|
||||
let report = JsonReport {
|
||||
overall_success: !self.any_failed(),
|
||||
kf6_libs_present: self.check_passed("KF6_LIBRARIES"),
|
||||
kf6_library_versions: self.check_passed("KF6_LIBRARY_VERSIONS"),
|
||||
plasma_binaries_present: self.check_passed("PLASMA_BINARIES"),
|
||||
session_entry: self.check_passed("SESSION_ENTRY"),
|
||||
session_environment: self.check_passed("SESSION_ENVIRONMENT"),
|
||||
@@ -207,19 +219,10 @@ fn parse_args() -> Result<bool, String> {
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn check_kf6_libraries() -> Check {
|
||||
let key_libs = [
|
||||
"/usr/lib/libKF6CoreAddons.so",
|
||||
"/usr/lib/libKF6ConfigCore.so",
|
||||
"/usr/lib/libKF6I18n.so",
|
||||
"/usr/lib/libKF6WindowSystem.so",
|
||||
"/usr/lib/libKF6Notifications.so",
|
||||
"/usr/lib/libKF6Service.so",
|
||||
"/usr/lib/libKF6WaylandClient.so",
|
||||
];
|
||||
let mut found = 0usize;
|
||||
let mut missing = Vec::new();
|
||||
|
||||
for lib in key_libs {
|
||||
for lib in KEY_KF6_LIBRARIES {
|
||||
if Path::new(lib).exists() {
|
||||
found += 1;
|
||||
} else {
|
||||
@@ -231,7 +234,7 @@ fn check_kf6_libraries() -> Check {
|
||||
if missing.is_empty() {
|
||||
Check::pass(
|
||||
"KF6_LIBRARIES",
|
||||
format!("{found}/{} key KF6 libraries found", key_libs.len()),
|
||||
format!("{found}/{} key KF6 libraries found", KEY_KF6_LIBRARIES.len()),
|
||||
)
|
||||
} else {
|
||||
let preview = missing
|
||||
@@ -242,17 +245,93 @@ fn check_kf6_libraries() -> Check {
|
||||
.join(", ");
|
||||
Check::pass(
|
||||
"KF6_LIBRARIES",
|
||||
format!("{found}/{} found, missing: {preview}", key_libs.len()),
|
||||
format!("{found}/{} found, missing: {preview}", KEY_KF6_LIBRARIES.len()),
|
||||
)
|
||||
}
|
||||
} else {
|
||||
Check::fail(
|
||||
"KF6_LIBRARIES",
|
||||
format!("only {found}/{} key KF6 libraries found", key_libs.len()),
|
||||
format!(
|
||||
"only {found}/{} key KF6 libraries found",
|
||||
KEY_KF6_LIBRARIES.len()
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn library_display_name(path: &str) -> &str {
|
||||
path.rsplit('/').next().unwrap_or(path)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn detect_shared_library_version(path: &Path) -> Result<String, String> {
|
||||
let resolved = fs::canonicalize(path)
|
||||
.map_err(|err| format!("failed to resolve {}: {err}", path.display()))?;
|
||||
let file_name = resolved
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.ok_or_else(|| format!("failed to read resolved file name for {}", path.display()))?;
|
||||
|
||||
file_name
|
||||
.rsplit_once(".so.")
|
||||
.map(|(_, version)| version.to_string())
|
||||
.ok_or_else(|| {
|
||||
format!(
|
||||
"resolved library {} does not contain a version suffix",
|
||||
resolved.display()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn check_kf6_library_versions() -> Check {
|
||||
let mut versions = BTreeMap::<String, Vec<String>>::new();
|
||||
let mut unresolved = Vec::new();
|
||||
|
||||
for lib in KEY_KF6_LIBRARIES {
|
||||
let lib_path = Path::new(lib);
|
||||
if !lib_path.exists() {
|
||||
continue;
|
||||
}
|
||||
|
||||
match detect_shared_library_version(lib_path) {
|
||||
Ok(version) => versions
|
||||
.entry(version)
|
||||
.or_default()
|
||||
.push(library_display_name(lib).to_string()),
|
||||
Err(err) => unresolved.push(err),
|
||||
}
|
||||
}
|
||||
|
||||
let detected = versions.values().map(Vec::len).sum::<usize>();
|
||||
if detected >= 6 {
|
||||
let mut detail_parts = versions
|
||||
.iter()
|
||||
.map(|(version, libs)| format!("{version} [{}]", libs.join(", ")))
|
||||
.collect::<Vec<_>>();
|
||||
if !unresolved.is_empty() {
|
||||
detail_parts.push(format!("unresolved: {}", unresolved.join("; ")));
|
||||
}
|
||||
|
||||
Check::pass(
|
||||
"KF6_LIBRARY_VERSIONS",
|
||||
format!(
|
||||
"detected version suffixes for {detected}/{} key KF6 libraries: {}",
|
||||
KEY_KF6_LIBRARIES.len(),
|
||||
detail_parts.join(" | ")
|
||||
),
|
||||
)
|
||||
} else {
|
||||
let detail = if unresolved.is_empty() {
|
||||
String::from("no versioned KF6 libraries could be resolved")
|
||||
} else {
|
||||
unresolved.join("; ")
|
||||
};
|
||||
Check::fail("KF6_LIBRARY_VERSIONS", detail)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn check_plasma_binaries() -> Check {
|
||||
let required = [
|
||||
@@ -631,6 +710,7 @@ fn run() -> Result<(), String> {
|
||||
let mut report = Report::new(json_mode);
|
||||
|
||||
report.add(check_kf6_libraries());
|
||||
report.add(check_kf6_library_versions());
|
||||
report.add(check_plasma_binaries());
|
||||
report.add(check_session_entry());
|
||||
report.add(check_session_environment());
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
|
||||
use std::process;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
use redbear_hwutils::{PciLocation, lookup_pci_device_name, lookup_pci_vendor_name, parse_pci_location};
|
||||
#[cfg(target_os = "redox")]
|
||||
use redox_driver_sys::pci::parse_device_info_from_config_space;
|
||||
|
||||
const PROGRAM: &str = "redbear-phase5-gpu-check";
|
||||
const USAGE: &str = "Usage: redbear-phase5-gpu-check [--json]\n\n\
|
||||
Phase 5 hardware GPU preflight check. Validates DRM device registration,\n\
|
||||
@@ -120,6 +125,7 @@ impl Report {
|
||||
#[derive(serde::Serialize)]
|
||||
struct JsonReport {
|
||||
drm_device: bool,
|
||||
gpu_pci_vendor: bool,
|
||||
gpu_firmware: bool,
|
||||
mesa_dri: bool,
|
||||
display_modes: bool,
|
||||
@@ -138,6 +144,11 @@ impl Report {
|
||||
.iter()
|
||||
.find(|c| c.name == "GPU_FIRMWARE")
|
||||
.map_or(false, |c| c.result == CheckResult::Pass);
|
||||
let pci_vendor = self
|
||||
.checks
|
||||
.iter()
|
||||
.find(|c| c.name == "GPU_PCI_VENDOR")
|
||||
.map_or(false, |c| c.result == CheckResult::Pass);
|
||||
let mesa = self
|
||||
.checks
|
||||
.iter()
|
||||
@@ -176,6 +187,7 @@ impl Report {
|
||||
std::io::stdout(),
|
||||
&JsonReport {
|
||||
drm_device: drm,
|
||||
gpu_pci_vendor: pci_vendor,
|
||||
gpu_firmware: firmware,
|
||||
mesa_dri: mesa,
|
||||
display_modes: modes,
|
||||
@@ -256,6 +268,101 @@ fn check_drm_device() -> Check {
|
||||
Check::fail("DRM_DEVICE", "no DRM device found at /scheme/drm/card0")
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
#[derive(Clone, Debug)]
|
||||
struct GpuPciDevice {
|
||||
location: PciLocation,
|
||||
vendor_id: u16,
|
||||
device_id: u16,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn collect_gpu_pci_devices() -> Result<Vec<GpuPciDevice>, String> {
|
||||
let entries = std::fs::read_dir("/scheme/pci")
|
||||
.map_err(|err| format!("failed to read /scheme/pci: {err}"))?;
|
||||
let mut devices = Vec::new();
|
||||
|
||||
for entry in entries.flatten() {
|
||||
let file_name = entry.file_name();
|
||||
let Some(file_name) = file_name.to_str() else {
|
||||
continue;
|
||||
};
|
||||
let Some(location) = parse_pci_location(file_name) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let config_path = format!("{}/config", location.scheme_path());
|
||||
let config = match std::fs::read(&config_path) {
|
||||
Ok(config) => config,
|
||||
Err(_) => continue,
|
||||
};
|
||||
if config.len() < 64 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let Some(info) = parse_device_info_from_config_space(
|
||||
redox_driver_sys::pci::PciLocation {
|
||||
segment: location.segment,
|
||||
bus: location.bus,
|
||||
device: location.device,
|
||||
function: location.function,
|
||||
},
|
||||
&config,
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if info.class_code != 0x03 {
|
||||
continue;
|
||||
}
|
||||
|
||||
devices.push(GpuPciDevice {
|
||||
location,
|
||||
vendor_id: info.vendor_id,
|
||||
device_id: info.device_id,
|
||||
});
|
||||
}
|
||||
|
||||
devices.sort_by_key(|device| device.location);
|
||||
Ok(devices)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn format_gpu_pci_device(device: &GpuPciDevice) -> String {
|
||||
let vendor = lookup_pci_vendor_name(device.vendor_id)
|
||||
.unwrap_or_else(|| format!("vendor {:04x}", device.vendor_id));
|
||||
let device_name = lookup_pci_device_name(device.vendor_id, device.device_id)
|
||||
.unwrap_or_else(|| format!("device {:04x}", device.device_id));
|
||||
|
||||
format!(
|
||||
"{} {} ({})",
|
||||
device.location, vendor, device_name
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn check_gpu_pci_vendor() -> Check {
|
||||
match collect_gpu_pci_devices() {
|
||||
Ok(devices) if devices.is_empty() => Check::fail(
|
||||
"GPU_PCI_VENDOR",
|
||||
"no display-class PCI device found under /scheme/pci",
|
||||
),
|
||||
Ok(devices) => {
|
||||
let preview = devices
|
||||
.iter()
|
||||
.take(3)
|
||||
.map(format_gpu_pci_device)
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
Check::pass(
|
||||
"GPU_PCI_VENDOR",
|
||||
&format!("detected {} GPU PCI device(s): {preview}", devices.len()),
|
||||
)
|
||||
}
|
||||
Err(err) => Check::fail("GPU_PCI_VENDOR", &err),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
fn check_gpu_firmware() -> Check {
|
||||
let firmware_dirs = ["/lib/firmware/amdgpu", "/lib/firmware/i915"];
|
||||
@@ -509,6 +616,7 @@ fn check_cs_ioctl_protocol() -> Check {
|
||||
fn check_hardware_rendering_ready(report: &Report) -> Check {
|
||||
let required = [
|
||||
"DRM_DEVICE",
|
||||
"GPU_PCI_VENDOR",
|
||||
"GPU_FIRMWARE",
|
||||
"MESA_DRI",
|
||||
"DISPLAY_MODES",
|
||||
@@ -557,6 +665,7 @@ fn run() -> Result<(), String> {
|
||||
let json_mode = parse_args()?;
|
||||
let mut report = Report::new(json_mode);
|
||||
report.add(check_drm_device());
|
||||
report.add(check_gpu_pci_vendor());
|
||||
report.add(check_gpu_firmware());
|
||||
report.add(check_mesa_dri_hardware());
|
||||
report.add(check_display_modes());
|
||||
|
||||
Reference in New Issue
Block a user