Skip to content

Commit 3923e07

Browse files
author
Jonathan Woollett-Light
committed
Updated CPUID
Signed-off-by: Jonathan Woollett-Light <[email protected]>
1 parent 154bd0c commit 3923e07

35 files changed

+6935
-1679
lines changed

Cargo.lock

Lines changed: 204 additions & 28 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/arch/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ vm-fdt = "0.1.0"
1616
derive_more = { version = "0.99.17", default-features = false, features = ["from"] }
1717
thiserror = "1.0.32"
1818
bitflags = ">=1.0.4"
19+
vmm-sys-util = ">=0.8.0"
1920

2021
arch_gen = { path = "../arch_gen" }
2122
logger = { path = "../logger" }

src/cpuid/Cargo.toml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,40 @@ thiserror = "1.0.32"
1313

1414
utils = { path = "../utils"}
1515
arch = { path = "../arch" }
16+
17+
vmm-sys-util = ">=0.8.0"
18+
bit-fields = { path = "../bit-fields", features = ["serde_feature"] }
19+
phf = { version = "0.10", features = ["macros"] }
20+
serde = { version="1.0.138", features=["derive"] }
21+
log-derive = "0.4.1"
22+
log = "0.4.17"
23+
24+
arrayvec = { version="0.7.2", features=["serde"], optional=true }
25+
26+
libc = "0.2.126"
27+
# Testing template formats
28+
serde_json = "1.0.83"
29+
bincode = "1.3.3"
30+
31+
[features]
32+
default = ["static","leaf_18"]
33+
static = ["arrayvec"]
34+
leaf_18 = []
35+
# We only have hardcoded static templates and these templates include leaf 18.
36+
templates = ["static","leaf_18"]
37+
c3 = ["templates"]
38+
t2s = ["templates"]
39+
t2 = ["templates"]
40+
41+
[dev-dependencies]
42+
# # Error checking tests
43+
# libc = "0.2.126"
44+
# # Testing template formats
45+
# serde_json = "1.0.83"
46+
# bincode = "1.3.3"
47+
# Benchmarking
48+
criterion = "0.3"
49+
50+
[[bench]]
51+
name = "benchmark"
52+
harness = false

src/cpuid/benches/benchmark.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use std::convert::{From, TryFrom};
2+
3+
use cpuid::{AmdCpuid, Cpuid, IntelCpuid, RawCpuid};
4+
use criterion::{black_box, criterion_group, criterion_main, BenchmarkId, Criterion};
5+
6+
pub fn conversions(c: &mut Criterion) {
7+
let kvm = kvm_ioctls::Kvm::new().unwrap();
8+
let vm = kvm.create_vm().unwrap();
9+
let kvm_cpuid = kvm
10+
.get_supported_cpuid(kvm_bindings::KVM_MAX_CPUID_ENTRIES)
11+
.unwrap();
12+
let raw_cpuid = RawCpuid::from(kvm_cpuid.clone());
13+
let cpuid = Cpuid::try_from(raw_cpuid.clone()).unwrap();
14+
let amd_cpuid = AmdCpuid::from(raw_cpuid.clone());
15+
let intel_cpuid = IntelCpuid::from(raw_cpuid.clone());
16+
17+
c.bench_function("kvm.clone()", |b| b.iter(|| kvm_cpuid.clone()));
18+
c.bench_function("raw.clone()", |b| b.iter(|| raw_cpuid.clone()));
19+
c.bench_function("intel.clone()", |b| b.iter(|| intel_cpuid.clone()));
20+
c.bench_function("amd.clone()", |b| b.iter(|| amd_cpuid.clone()));
21+
c.bench_function("cpuid.clone()", |b| b.iter(|| cpuid.clone()));
22+
23+
c.bench_function("kvm->raw", |b| b.iter(|| RawCpuid::from(kvm_cpuid.clone())));
24+
c.bench_function("raw->kvm", |b| {
25+
b.iter(|| kvm_bindings::CpuId::from(raw_cpuid.clone()))
26+
});
27+
c.bench_function("raw->cpuid", |b| {
28+
b.iter(|| Cpuid::try_from(raw_cpuid.clone()))
29+
});
30+
c.bench_function("cpuid->raw", |b| b.iter(|| RawCpuid::from(cpuid.clone())));
31+
c.bench_function("amd->raw", |b| b.iter(|| RawCpuid::from(amd_cpuid.clone())));
32+
c.bench_function("raw->amd", |b| b.iter(|| AmdCpuid::from(raw_cpuid.clone())));
33+
c.bench_function("intel->raw", |b| {
34+
b.iter(|| RawCpuid::from(intel_cpuid.clone()))
35+
});
36+
c.bench_function("raw->intel", |b| {
37+
b.iter(|| IntelCpuid::from(raw_cpuid.clone()))
38+
});
39+
}
40+
41+
criterion_group!(benches, conversions);
42+
criterion_main!(benches);

src/cpuid/src/amd/mod.rs

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
2+
// SPDX-License-Identifier: Apache-2.0
3+
#![warn(clippy::pedantic)]
4+
5+
use std::cmp::{Ord, Ordering, PartialOrd};
6+
use std::convert::TryInto;
7+
8+
use log_derive::{logfn, logfn_inputs};
9+
use serde::{Deserialize, Serialize};
10+
11+
use super::{FixedString, RawCpuid};
12+
13+
/// A structure containing the information as described in the AMD CPUID specification as described
14+
/// in
15+
/// [AMD64 Architecture Programmer’s Manual Volume 3: General-Purpose and System Instructions](https://www.amd.com/system/files/TechDocs/24594.pdf)
16+
/// .
17+
///
18+
/// # Notes
19+
///
20+
/// We not do not currently check AMD features on snapshot restore.
21+
#[allow(clippy::unsafe_derive_deserialize, clippy::module_name_repetitions)]
22+
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
23+
#[repr(C)]
24+
pub struct AmdCpuid(pub RawCpuid);
25+
26+
// TODO: Replace checking of CPUID avaiblity with `x86` and `x86_64` check and
27+
// [`std::arch_x86_64::has_cpuid()`] when this is stabilized. CPUID is supported when:
28+
// - We are on an x86 archtecture with `see` enabled and `sgx disabled`.
29+
// - We are on an x86_64 architecture with `sgx` disabled
30+
#[cfg(any(
31+
all(target_arch = "x86", target_feature = "sse", not(target_env = "sgx")),
32+
all(target_arch = "x86_64", not(target_env = "sgx"))
33+
))]
34+
impl AmdCpuid {
35+
/// Alias for [`AmdCpuid::default`]
36+
#[must_use]
37+
pub fn new() -> Self {
38+
Self(RawCpuid::new())
39+
}
40+
}
41+
impl AmdCpuid {
42+
/// Returns the CPUID manufacturers ID. E.g. `GenuineIntel` or `AuthenticAMD`.
43+
///
44+
/// # Panics
45+
///
46+
/// When the underlying [`RawCpuid`] has no entry for leaf 0.
47+
#[must_use]
48+
pub fn manufacturer_id(&self) -> FixedString<12> {
49+
let leaf = self.0.get(0, 0).unwrap();
50+
let manufacturer_str: [u8; 12] = [
51+
leaf.ebx.to_ne_bytes(),
52+
leaf.edx.to_ne_bytes(),
53+
leaf.ecx.to_ne_bytes(),
54+
]
55+
.concat()
56+
.try_into()
57+
.unwrap();
58+
FixedString(manufacturer_str)
59+
}
60+
}
61+
impl PartialOrd for AmdCpuid {
62+
fn partial_cmp(&self, _other: &Self) -> Option<Ordering> {
63+
Some(Ordering::Equal)
64+
}
65+
}
66+
impl Default for AmdCpuid {
67+
/// Constructs new `Cpuid` via [`core::arch::x86_64::__cpuid_count`].
68+
///
69+
/// # Note
70+
///
71+
/// As we do not currently support the AMD CPUID specification this constructs an empty
72+
/// [`RawCpuid`].
73+
fn default() -> Self {
74+
Self(RawCpuid::new())
75+
}
76+
}
77+
impl Ord for AmdCpuid {
78+
/// Checks if `self` is a able to support `other`.
79+
///
80+
/// Checks if a process from an environment with cpuid `other` could be continued in the
81+
/// environment with the cpuid `self`.
82+
#[logfn(Trace)]
83+
#[logfn_inputs(Info)]
84+
fn cmp(&self, other: &Self) -> Ordering {
85+
self.partial_cmp(&other).unwrap()
86+
}
87+
}
88+
impl From<RawCpuid> for AmdCpuid {
89+
fn from(raw_cpuid: RawCpuid) -> Self {
90+
Self(raw_cpuid)
91+
}
92+
}
93+
impl From<AmdCpuid> for RawCpuid {
94+
fn from(amd_cpuid: AmdCpuid) -> Self {
95+
amd_cpuid.0
96+
}
97+
}

src/cpuid/src/bit_helper.rs

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
// SPDX-License-Identifier: Apache-2.0
3-
4-
#![macro_use]
3+
use std::convert::TryFrom;
54

65
/// Structure representing a range of bits in a number.
76
///
@@ -15,14 +14,16 @@
1514
/// lsb_index: 3,
1615
/// };
1716
/// ```
18-
/// The BitRange specified above will represent the following part of the number 72:
17+
/// The `BitRange` specified above will represent the following part of the number 72:
18+
/// ```text
1919
/// +-------------------------------------+---+---+---+---+---+---+---+---+---+---+
2020
/// | Base 2 Representation of the number | 0 | 0 | 0 | 1 | 0 | 0 | 1 | 0 | 0 | 0 |
2121
/// +-------------------------------------+---+---+---+---+---+---+---+---+---+---+
2222
/// | bits indexes | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
2323
/// +-------------------------------------+---+---+---+---+---+---+---+---+---+---+
2424
/// | BitRange | | | * | * | * | * | * | | | |
2525
/// +-------------------------------------+---+---+---+---+---+---+---+---+---+---+
26+
/// ```
2627
pub struct BitRange {
2728
/// most significant bit index
2829
pub msb_index: u32,
@@ -55,7 +56,7 @@ pub trait BitRangeExt<T> {
5556
/// ```
5657
fn get_mask(&self) -> T;
5758

58-
/// Checks if the current BitRange is valid for type `T`.
59+
/// Checks if the current [`BitRange`] is valid for type `T`.
5960
fn is_valid(&self) -> bool;
6061

6162
/// Asserts if `self.is_valid()` returns true.
@@ -70,23 +71,15 @@ impl BitRangeExt<u32> for BitRange {
7071
fn get_mask(&self) -> u32 {
7172
self.check();
7273

73-
((((1_u64) << (self.msb_index - self.lsb_index + 1)) - 1) << self.lsb_index) as u32
74+
u32::try_from((((1_u64) << (self.msb_index - self.lsb_index + 1)) - 1) << self.lsb_index)
75+
.unwrap()
7476
}
7577

7678
fn is_valid(&self) -> bool {
7779
self.msb_index >= self.lsb_index && self.msb_index <= MAX_U32_BIT_INDEX
7880
}
7981
}
8082

81-
macro_rules! bit_range {
82-
($msb_index:expr, $lsb_index:expr) => {
83-
BitRange {
84-
msb_index: $msb_index,
85-
lsb_index: $lsb_index,
86-
}
87-
};
88-
}
89-
9083
/// Trait containing helper methods for bit operations.
9184
pub trait BitHelper {
9285
/// Reads the value of the bit at position `pos`

src/cpuid/src/brand_string.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ impl BrandString {
8080
///
8181
/// For other CPUs, we'll just expose an empty string.
8282
///
83-
/// This is safe because we know BRAND_STRING_INTEL and BRAND_STRING_AMD to hold valid data
83+
/// This is safe because we know `BRAND_STRING_INTEL` and `BRAND_STRING_AMD` to hold valid data
8484
/// (allowed length and holding only valid ASCII chars).
8585
pub fn from_vendor_id(vendor_id: &[u8; 12]) -> BrandString {
8686
match vendor_id {
@@ -139,6 +139,7 @@ impl BrandString {
139139
/// Returns the given register value for the given CPUID leaf.
140140
///
141141
/// `leaf` must be between 0x80000002 and 0x80000004.
142+
#[cfg(test)]
142143
#[inline]
143144
pub fn get_reg_for_leaf(&self, leaf: u32, reg: Reg) -> u32 {
144145
// It's ok not to validate parameters here, leaf and reg should
@@ -164,14 +165,17 @@ impl BrandString {
164165
// This is actually safe, because self.reg_buf has a fixed, known size,
165166
// and also there's no risk of misalignment, since we're downgrading
166167
// alignment constraints from dword to byte.
167-
unsafe { slice::from_raw_parts(self.reg_buf.as_ptr() as *const u8, Self::REG_BUF_SIZE * 4) }
168+
unsafe { slice::from_raw_parts(self.reg_buf.as_ptr().cast::<u8>(), Self::REG_BUF_SIZE * 4) }
168169
}
169170

170171
/// Gets a mutable `u8` slice view into the brand string buffer.
171172
#[inline]
172173
fn as_bytes_mut(&mut self) -> &mut [u8] {
173174
unsafe {
174-
slice::from_raw_parts_mut(self.reg_buf.as_mut_ptr() as *mut u8, Self::REG_BUF_SIZE * 4)
175+
slice::from_raw_parts_mut(
176+
self.reg_buf.as_mut_ptr().cast::<u8>(),
177+
Self::REG_BUF_SIZE * 4,
178+
)
175179
}
176180
}
177181

0 commit comments

Comments
 (0)