use std::string::String;
const CONTEXT_CONTROL_OFFSET: usize = 0x20_0000;
const CONTEXT_STRIDE: usize = 0x1000;
const CLAIM_COMPLETE_SIZE: usize = 8;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GuestPlicProfile {
pub node_path: String,
pub node_phandle: Option<u32>,
pub base: usize,
pub length: usize,
}
impl GuestPlicProfile {
pub(crate) fn validate_for_vcpus(
&self,
vcpu_count: usize,
) -> Result<(), GuestPlicProfileError> {
let contexts = vcpu_count
.max(1)
.checked_mul(2)
.ok_or(GuestPlicProfileError::ContextCountOverflow)?;
let minimum_length = contexts
.checked_mul(CONTEXT_STRIDE)
.and_then(|offset| offset.checked_add(CONTEXT_CONTROL_OFFSET))
.and_then(|offset| offset.checked_add(CLAIM_COMPLETE_SIZE))
.ok_or(GuestPlicProfileError::WindowSizeOverflow)?;
if self.length < minimum_length {
return Err(GuestPlicProfileError::WindowTooSmall {
length: self.length,
minimum: minimum_length,
});
}
Ok(())
}
}
#[derive(Clone, Debug, Eq, PartialEq, thiserror::Error)]
pub enum GuestPlicProfileError {
#[error("RISC-V PLIC context count overflows usize")]
ContextCountOverflow,
#[error("RISC-V PLIC context window size overflows usize")]
WindowSizeOverflow,
#[error("RISC-V PLIC window {length:#x} is smaller than required size {minimum:#x}")]
WindowTooSmall { length: usize, minimum: usize },
}