56be23ce6e
Expose MSR access via /scheme/sys/msr/<cpu>/<msr> for root only. Required for cpufreqd P-state control and thermal sensor drivers.
88 lines
4.2 KiB
Diff
88 lines
4.2 KiB
Diff
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(());
|
|
+ }
|