diff --git a/local/recipes/system/cpufreqd/source/src/main.rs b/local/recipes/system/cpufreqd/source/src/main.rs index 42d1b5fba3..6830a88ac7 100644 --- a/local/recipes/system/cpufreqd/source/src/main.rs +++ b/local/recipes/system/cpufreqd/source/src/main.rs @@ -333,28 +333,72 @@ fn write_scheme_state(governor: Governor, cpus: &[CpuInfo]) { } fn detect_virtualization() -> bool { - // Detect a hypervisor / VM by reading DMI strings. On QEMU the - // sys_vendor is "QEMU" or "KVM" or similar; on real hardware - // (e.g. LG Gram 2025) it's "LG Electronics" or "Intel Corporation". - // Returning true here means: "the cpufreqd governor's P-state - // writes are not going to take effect because the emulator - // doesn't model IA32_PERF_STATUS / IA32_PERF_CTL." - if let Ok(s) = fs::read_to_string("/sys/class/dmi/id/sys_vendor") { + // Detect a hypervisor / VM before applying P-state changes. + // + // Two signals are checked: + // + // 1. DMI strings at the Redox-correct path /scheme/acpi/dmi/ + // (NOT /sys/class/dmi/id/ — that is the Linux path). + // The Redox acpid exposes SMBIOS fields there. On QEMU with + // OVMF the strings are "QEMU", "KVM", or similar; on real + // hardware (e.g. LG Gram 2025) they are the OEM strings + // ("LG Electronics", "16Z90TR"). When SMBIOS is absent (the + // Redox acpid log line "SMBIOS: no entry point found" can + // happen on some QEMU configurations), the read returns Err + // and we fall through to the CPUID check. + // + // 2. The CPUID hypervisor-present bit (leaf 1, ECX bit 31) read + // via inline assembly. This is the canonical x86 VM-detection + // signal — it works regardless of whether SMBIOS is exposed. + // On QEMU/KVM/VMware/VirtualBox/Hyper-V/Xen the bit is set; + // on bare metal it is clear. The pattern mirrors + // redbear-power/src/cpuid.rs:168 which already uses this bit. + // + // When either signal says "virtualized", cpufreqd is constructed + // with read_only = true and apply_pstate short-circuits at the + // top: load is still tracked, governor choice is still logged, + // but no MSR writes fire. On real hardware the writes go to the + // kernel scheme (/scheme/sys/msr/{cpu}/0x{msr_hex}) and the + // governor progresses through P-states normally. + if let Ok(s) = fs::read_to_string("/scheme/acpi/dmi/sys_vendor") { let s = s.to_ascii_lowercase(); if s.contains("qemu") || s.contains("kvm") || s.contains("vmware") || s.contains("virtualbox") || s.contains("hyper-v") || s.contains("xen") + || s.contains("microsoft corporation") || s.contains("amazon") { return true; } } - if let Ok(s) = fs::read_to_string("/sys/class/dmi/id/product_name") { + if let Ok(s) = fs::read_to_string("/scheme/acpi/dmi/product_name") { let s = s.to_ascii_lowercase(); if s.contains("virtual") || s.contains("kvm") || s.contains("qemu") { return true; } } - // No /sys/class/dmi on this system (Redox bare metal) — assume - // real hardware. cpufreqd's P-state writes are meaningful. + // SMBIOS absent or uninformative: fall back to the CPUID + // hypervisor-present bit. Inline assembly because the Redox + // kernel does not expose raw CPUID leaves via a scheme. + if cpuid_hypervisor_bit() { + return true; + } + // No SMBIOS, no CPUID bit: assume real hardware. cpufreqd's + // P-state writes through /scheme/sys/msr/{cpu}/0x{msr_hex} + // are meaningful. + false +} + +#[cfg(target_arch = "x86_64")] +fn cpuid_hypervisor_bit() -> bool { + // CPUID leaf 1, subleaf 0, ECX bit 31 — the standard x86 + // hypervisor-present bit. Returns true when running under + // any hypervisor that advertises itself (QEMU/KVM, VMware, + // VirtualBox, Hyper-V, Xen, bhyve, etc.). + let cpuid = unsafe { core::arch::x86_64::__cpuid_count(1, 0) }; + (cpuid.ecx & (1 << 31)) != 0 +} + +#[cfg(not(target_arch = "x86_64"))] +fn cpuid_hypervisor_bit() -> bool { false } diff --git a/local/sources/kernel b/local/sources/kernel index a8042049ce..c231262700 160000 --- a/local/sources/kernel +++ b/local/sources/kernel @@ -1 +1 @@ -Subproject commit a8042049ce0c5388039e8f24442e2ec8cd6e0537 +Subproject commit c231262700bfe5dd68c6afa54cc87f3c3f98a53c