Skip to content

Commit

Permalink
cpuid: Entries can now be retreived from kvm
Browse files Browse the repository at this point in the history
These represent what a guest VM can see for features.
  • Loading branch information
andrewjj20 committed Jan 9, 2023
1 parent ebaaab4 commit efb0984
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 13 deletions.
32 changes: 32 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ structopt = "0.3"
serde = { version = "1.0", features = ["derive"] }
serde_yaml = "0.8"
enum_dispatch = "0.3.8"
kvm-ioctls = { version = "0.12.0", optional = true }
kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"], optional = true }

[features]
default = ["use_msr"]
default = ["use_msr", "kvm"]
use_msr = []
kvm = [ "dep:kvm-ioctls", "dep:kvm-bindings" ]
43 changes: 34 additions & 9 deletions src/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,23 @@
use super::facts::{self, GenericFact};
use super::{
bitfield::{self, Facter},
cpuid, is_empty_leaf,
is_empty_leaf,
};
use core::arch::x86_64::CpuidResult;
use enum_dispatch::enum_dispatch;
use serde::{Deserialize, Serialize};
use std::fmt;
use std::ops::Fn;
use std::string;
use std::vec::Vec;

#[enum_dispatch]
pub trait DisplayLeaf {
fn scan_sub_leaves(&self, leaf: u32) -> Vec<CpuidResult>;
fn scan_sub_leaves<CPUIDFunc: Fn(u32, u32) -> CpuidResult>(
&self,
leaf: u32,
cpuid: CPUIDFunc,
) -> Vec<CpuidResult>;
fn display_leaf(
&self,
leaf: &[CpuidResult],
Expand Down Expand Up @@ -48,7 +53,11 @@ impl StartLeaf {
}

impl DisplayLeaf for StartLeaf {
fn scan_sub_leaves(&self, leaf: u32) -> Vec<CpuidResult> {
fn scan_sub_leaves<CPUIDFunc: Fn(u32, u32) -> CpuidResult>(
&self,
leaf: u32,
cpuid: CPUIDFunc,
) -> Vec<CpuidResult> {
vec![cpuid(leaf, 0)]
}
fn display_leaf(
Expand Down Expand Up @@ -104,7 +113,11 @@ impl StringLeaf {
}

impl DisplayLeaf for StringLeaf {
fn scan_sub_leaves(&self, leaf: u32) -> Vec<CpuidResult> {
fn scan_sub_leaves<CPUIDFunc: Fn(u32, u32) -> CpuidResult>(
&self,
leaf: u32,
cpuid: CPUIDFunc,
) -> Vec<CpuidResult> {
let cpuid = cpuid(leaf, 0);
if !is_empty_leaf(&cpuid) {
vec![cpuid]
Expand Down Expand Up @@ -159,7 +172,11 @@ impl BitFieldLeaf {
}

impl DisplayLeaf for BitFieldLeaf {
fn scan_sub_leaves(&self, leaf: u32) -> Vec<CpuidResult> {
fn scan_sub_leaves<CPUIDFunc: Fn(u32, u32) -> CpuidResult>(
&self,
leaf: u32,
cpuid: CPUIDFunc,
) -> Vec<CpuidResult> {
let cpuid = cpuid(leaf, 0);
if !is_empty_leaf(&cpuid) {
vec![cpuid]
Expand Down Expand Up @@ -232,8 +249,12 @@ impl LeafDesc {
&self.data_type
}

pub fn bind_leaf(&self, leaf: u32) -> Option<BoundLeaf> {
let sub_leaves = self.scan_sub_leaves(leaf);
pub fn bind_leaf<CPUIDFunc: Fn(u32, u32) -> CpuidResult>(
&self,
leaf: u32,
cpuid: CPUIDFunc,
) -> Option<BoundLeaf> {
let sub_leaves = self.scan_sub_leaves(leaf, cpuid);
if !sub_leaves.is_empty() {
Some(BoundLeaf {
desc: self,
Expand All @@ -246,8 +267,12 @@ impl LeafDesc {
}

impl DisplayLeaf for LeafDesc {
fn scan_sub_leaves(&self, leaf: u32) -> Vec<CpuidResult> {
self.data_type.scan_sub_leaves(leaf)
fn scan_sub_leaves<CPUIDFunc: Fn(u32, u32) -> CpuidResult>(
&self,
leaf: u32,
cpuid: CPUIDFunc,
) -> Vec<CpuidResult> {
self.data_type.scan_sub_leaves(leaf, cpuid)
}
fn display_leaf(
&self,
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl std::fmt::Display for CpuidError {

impl std::error::Error for CpuidError {}

fn cpuid(leaf: u32, sub_leaf: u32) -> CpuidResult {
pub fn cpuid(leaf: u32, sub_leaf: u32) -> CpuidResult {
unsafe { __cpuid_count(leaf, sub_leaf) }
}

Expand Down
50 changes: 48 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,57 @@ impl Command for Disp {
} else {
println!("CPUID:");
for (leaf, desc) in &config.cpuids {
if let Some(bound) = desc.bind_leaf(*leaf) {
if let Some(bound) = desc.bind_leaf(*leaf, cpuid) {
println!("{:#010x}: {}", leaf, bound);
}
}

#[cfg(all(target_os = "linux", feature = "kvm"))]
{
use kvm_bindings::{KVM_CPUID_FLAG_SIGNIFCANT_INDEX, KVM_MAX_CPUID_ENTRIES};
use kvm_ioctls::Kvm;
println!("KVM-CPUID:");
let kvm = Kvm::new().expect("Unable to open KVM");
let cpuid_fam = kvm
.get_supported_cpuid(KVM_MAX_CPUID_ENTRIES)
.expect("Unable to retreive cpuid entries");
let cpuid_entries = cpuid_fam.as_slice();
for (leaf, desc) in &config.cpuids {
use core::arch::x86_64::CpuidResult;
if let Some(bound) = desc.bind_leaf(*leaf, |leaf, subleaf| {
cpuid_entries
.iter()
.find_map(|entry| {
if entry.function == leaf {
if (subleaf == 0
&& (entry.flags & KVM_CPUID_FLAG_SIGNIFCANT_INDEX) == 0)
|| (subleaf == entry.index)
{
Some(CpuidResult {
eax: entry.eax,
ebx: entry.ebx,
ecx: entry.ecx,
edx: entry.edx,
})
} else {
None
}
} else {
None
}
})
.unwrap_or(CpuidResult {
eax: 0,
ebx: 0,
ecx: 0,
edx: 0,
})
}) {
println!("{:#010x}: {}", leaf, bound);
}
}
}

if MSRDesc::is_availible() {
println!("MSRS:");
for msr in &config.msrs {
Expand All @@ -73,7 +119,7 @@ fn collect_facts(config: &Definition) -> Result<Vec<YAMLFact>, Box<dyn std::erro
let mut ret: Vec<YAMLFact> = config
.cpuids
.iter()
.filter_map(|(leaf, desc)| desc.bind_leaf(*leaf))
.filter_map(|(leaf, desc)| desc.bind_leaf(*leaf, cpuid))
.flat_map(|bound| bound.get_facts().into_iter())
.map(|mut fact| {
fact.add_path("cpuid");
Expand Down

0 comments on commit efb0984

Please sign in to comment.