use std::{
convert::From,
fs::{File, OpenOptions},
io::{Read, Seek, SeekFrom},
os::unix::fs::FileExt,
path::Path,
};
#[derive(Debug)]
pub enum MsrError {
IoError(std::io::Error),
MissingKernelModule,
UnknownError,
}
impl std::error::Error for MsrError {}
impl std::fmt::Display for MsrError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
MsrError::IoError(io_error) => write!(f, "IoError Encountered: {io_error}"),
MsrError::MissingKernelModule => write!(f, "MSR Kernel Module not loaded!"),
MsrError::UnknownError => write!(f, "An unknown error was encountered!"),
}
}
}
impl From<std::io::Error> for MsrError {
fn from(value: std::io::Error) -> Self {
Self::IoError(value)
}
}
type Result<T> = std::result::Result<T, MsrError>;
pub struct Msr {
pub reg: u32,
fh: File,
buffer: [u8; 8],
}
impl Msr {
pub fn new(reg: u32, cpu: u16) -> Result<Self> {
let cpu_msr_path: String = format!("/dev/cpu/{cpu}/msr");
if !Path::new(&cpu_msr_path).exists() {
return Err(MsrError::MissingKernelModule);
}
Ok(Self {
reg,
fh: OpenOptions::new()
.read(true)
.write(true)
.open(cpu_msr_path)?,
buffer: [0; 8],
})
}
pub fn read_value(&mut self) -> u64 {
u64::from_ne_bytes(self.buffer)
}
pub fn set_value(&mut self, value: u64) {
self.buffer = value.to_ne_bytes();
}
}
pub trait Accessor {
fn read(&mut self) -> Result<u64>;
fn write(&self) -> Result<()>;
}
impl Accessor for Msr {
fn read(&mut self) -> Result<u64> {
self.fh.seek(SeekFrom::Start(self.reg.into()))?;
self.fh.read_exact(&mut self.buffer)?;
Ok(self.read_value())
}
fn write(&self) -> Result<()> {
self.fh.write_all_at(&self.buffer, self.reg.into())?;
Ok(())
}
}