mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
arch: FeatureMsrAdjustment type
We introduce a type analogous to CpuidOutputRegisterAdjustment, but for feature MSRs. Signed-off-by: Oliver Anderson <oliver.anderson@cyberus-technology.de> On-behalf-of: SAP oliver.anderson@sap.com
This commit is contained in:
committed by
Rob Bradford
parent
37aa545c2a
commit
26305445b6
@@ -3,9 +3,14 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
use hypervisor::arch::x86::MsrEntry;
|
||||
use log::{debug, error};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::x86_64::helpers::{deserialize_u32_hex, serialize_u32_hex};
|
||||
use crate::x86_64::Error;
|
||||
use crate::x86_64::helpers::{
|
||||
deserialize_u32_hex, deserialize_u64_hex, serialize_u32_hex, serialize_u64_hex,
|
||||
};
|
||||
|
||||
/// The register address of an MSR
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
@@ -16,3 +21,71 @@ pub struct RegisterAddress(
|
||||
)]
|
||||
pub u32,
|
||||
);
|
||||
|
||||
/// Used to adjust the value of a Feature MSR.
|
||||
///
|
||||
/// Instances of this struct typically adjust MSR values according to the
|
||||
/// following formula: `msr_value = (self.mask & msr_value) | self.replacements`.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
|
||||
pub struct FeatureMsrAdjustment {
|
||||
/// Packs values to be placed into the given feature MSR value.
|
||||
#[serde(
|
||||
serialize_with = "serialize_u64_hex",
|
||||
deserialize_with = "deserialize_u64_hex"
|
||||
)]
|
||||
pub replacements: u64,
|
||||
|
||||
/// Used to zero out the area `replacements` occupy. This mask is not necessarily !replacements, as replacements
|
||||
/// may pack values of different types that occupy varying ranges of bits.
|
||||
///
|
||||
/// Bit ranges within a feature MSR value that are **not** supposed to be replaced/overwritten should be set in
|
||||
/// this mask.
|
||||
#[serde(
|
||||
serialize_with = "serialize_u64_hex",
|
||||
deserialize_with = "deserialize_u64_hex"
|
||||
)]
|
||||
pub mask: u64,
|
||||
}
|
||||
|
||||
impl FeatureMsrAdjustment {
|
||||
/// Adjusts the given `feature_msrs` according to `adjustments`.
|
||||
///
|
||||
/// An error is returned if there exists an MSR register address in
|
||||
/// `adjustments` without a matching entry in `feature_msrs`.
|
||||
pub(super) fn adjust_feature_msrs(
|
||||
feature_msrs: &[MsrEntry],
|
||||
adjustments: &[(RegisterAddress, FeatureMsrAdjustment)],
|
||||
) -> Result<Vec<MsrEntry>, Error> {
|
||||
let mut missing_msr = false;
|
||||
let mut output_feature_msrs = Vec::with_capacity(adjustments.len());
|
||||
for (reg_address, adjustment) in adjustments {
|
||||
let Some(entry) = feature_msrs
|
||||
.iter()
|
||||
.find(|entry| entry.index == reg_address.0)
|
||||
else {
|
||||
missing_msr = true;
|
||||
error!(
|
||||
"Did not find feature based MSR entry for MSR {:#x}",
|
||||
reg_address.0
|
||||
);
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut entry = *entry;
|
||||
let data = entry.data;
|
||||
entry.data = (adjustment.mask & data) | adjustment.replacements;
|
||||
|
||||
debug!(
|
||||
"Prepared adjusted MSR feature: register address={:#x} value={:#x}, previous value={data:#x}",
|
||||
entry.index, entry.data
|
||||
);
|
||||
output_feature_msrs.push(entry);
|
||||
}
|
||||
|
||||
if missing_msr {
|
||||
Err(Error::CpuProfileMissingMsr)
|
||||
} else {
|
||||
Ok(output_feature_msrs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,6 +170,13 @@ pub enum Error {
|
||||
)]
|
||||
MissingExpectedCpuidEntry(#[source] MissingCpuidEntriesError),
|
||||
|
||||
/// Error when trying to apply a CPU profile because a necessary MSR was not found.
|
||||
///
|
||||
/// We encourage functions returning this variant to log all missing MSRs for debugging
|
||||
/// purposes.
|
||||
#[error("The selected CPU profile cannot be utilized because a necessary MSR was not found")]
|
||||
CpuProfileMissingMsr,
|
||||
|
||||
// Error writing EBDA address
|
||||
#[error("Error writing EBDA address")]
|
||||
EbdaSetup(#[source] vm_memory::GuestMemoryError),
|
||||
|
||||
Reference in New Issue
Block a user