From 56be23ce6e56b13d7aed192536817ee039a3bb71 Mon Sep 17 00:00:00 2001 From: Admin Pupkin Date: Wed, 20 May 2026 13:38:53 +0300 Subject: [PATCH] kernel: Add sys:msr scheme for userspace MSR read/write Expose MSR access via /scheme/sys/msr// for root only. Required for cpufreqd P-state control and thermal sensor drivers. --- local/patches/kernel/P23-sys-msr-scheme.patch | 87 +++++++++++++++++++ recipes/core/kernel/recipe.toml | 2 + 2 files changed, 89 insertions(+) create mode 100644 local/patches/kernel/P23-sys-msr-scheme.patch diff --git a/local/patches/kernel/P23-sys-msr-scheme.patch b/local/patches/kernel/P23-sys-msr-scheme.patch new file mode 100644 index 0000000000..1eb1ac784e --- /dev/null +++ b/local/patches/kernel/P23-sys-msr-scheme.patch @@ -0,0 +1,87 @@ +diff --git a/src/scheme/sys/mod.rs b/src/scheme/sys/mod.rs +index 8f26187a..9eb35644 100644 +--- a/src/scheme/sys/mod.rs ++++ b/src/scheme/sys/mod.rs +@@ -47,0 +48,5 @@ enum Handle { ++ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ Msr { ++ cpu: usize, ++ msr: u32, ++ }, +@@ -135,0 +141,22 @@ impl KernelScheme for SysScheme { ++ } else if path.starts_with("msr/") { ++ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ { ++ if ctx.uid != 0 { ++ return Err(Error::new(EPERM)); ++ } ++ let rest = &path[4..]; ++ let mut parts = rest.split('/'); ++ let cpu_str = parts.next().ok_or(Error::new(EINVAL))?; ++ let msr_str = parts.next().ok_or(Error::new(EINVAL))?; ++ if parts.next().is_some() { ++ return Err(Error::new(EINVAL)); ++ } ++ let cpu: usize = cpu_str.parse().map_err(|_| Error::new(EINVAL))?; ++ let msr: u32 = u32::from_str_radix(msr_str, 16).map_err(|_| Error::new(EINVAL))?; ++ let id = HANDLES.write(token.token()).insert(Handle::Msr { cpu, msr }); ++ Ok(OpenResult::SchemeLocal(id, InternalFlags::POSITIONED)) ++ } ++ #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] ++ { ++ Err(Error::new(ENOENT)) ++ } +@@ -162,0 +190,2 @@ impl KernelScheme for SysScheme { ++ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ Handle::Msr { .. } => return Ok(0), +@@ -190,0 +220,10 @@ impl KernelScheme for SysScheme { ++ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ Handle::Msr { cpu, msr } => { ++ const FIRST: &[u8] = b"sys:msr/"; ++ let mut bytes_read = buf.copy_common_bytes_from_slice(FIRST)?; ++ let suffix = format!("{}/{:x}", cpu, msr); ++ if let Some(remaining) = buf.advance(FIRST.len()) { ++ bytes_read += remaining.copy_common_bytes_from_slice(suffix.as_bytes())?; ++ } ++ return Ok(bytes_read); ++ } +@@ -217,0 +257,9 @@ impl KernelScheme for SysScheme { ++ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ Handle::Msr { cpu, msr } => { ++ if *cpu != crate::cpu_id().get() as usize { ++ return Err(Error::new(EINVAL)); ++ } ++ let val = unsafe { x86::msr::rdmsr(*msr) }; ++ let data = format!("{:016x}\n", val).into_bytes(); ++ return buffer.copy_common_bytes_from_slice(&data[pos..]); ++ } +@@ -255,0 +304,12 @@ impl KernelScheme for SysScheme { ++ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ Handle::Msr { cpu, msr } => { ++ if *cpu != crate::cpu_id().get() as usize { ++ return Err(Error::new(EINVAL)); ++ } ++ let mut intermediate = [0_u8; 32]; ++ let len = buffer.copy_common_bytes_to_slice(&mut intermediate)?; ++ let val_str = core::str::from_utf8(&intermediate[..len]).map_err(|_| Error::new(EINVAL))?; ++ let val = u64::from_str_radix(val_str.trim(), 16).map_err(|_| Error::new(EINVAL))?; ++ unsafe { x86::msr::wrmsr(*msr, val); } ++ return Ok(len); ++ } +@@ -272 +332,2 @@ impl KernelScheme for SysScheme { +- Handle::Resource { .. } => Err(Error::new(ENOTDIR)), ++ Handle::Resource { .. } ++ | Handle::Msr { .. } => Err(Error::new(ENOTDIR)), +@@ -295,0 +357,12 @@ impl KernelScheme for SysScheme { ++ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] ++ Handle::Msr { .. } => { ++ let stat = Stat { ++ st_mode: 0o600 | MODE_FILE, ++ st_uid: 0, ++ st_gid: 0, ++ st_size: 0, ++ ..Default::default() ++ }; ++ buf.copy_exactly(&stat)?; ++ return Ok(()); ++ } diff --git a/recipes/core/kernel/recipe.toml b/recipes/core/kernel/recipe.toml index a5a1d976e5..8ba614270c 100644 --- a/recipes/core/kernel/recipe.toml +++ b/recipes/core/kernel/recipe.toml @@ -43,6 +43,8 @@ patches = [ # LocalX2Apic entries (QEMU, some BIOS), fall back to processing LocalApic # entries with zero-extended IDs using x2APIC 64-bit ICR format "../../../local/patches/kernel/P22-x2apic-madt-fallback.patch", + # P23: sys:msr scheme — kernel MSR read/write via /scheme/sys/msr// + "../../../local/patches/kernel/P23-sys-msr-scheme.patch", ] [build]