-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- split cpu_leaf into separate files for each leaf - move leaf handlers into cpu_leaf - test leaf handlers individually - move all the templates into a folder Signed-off-by: Serban Iorga <seriorga@amazon.com>
- Loading branch information
Serban Iorga
committed
Feb 21, 2019
1 parent
f68a218
commit 82d2d56
Showing
31 changed files
with
1,116 additions
and
1,482 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
use super::registers::*; | ||
use bit_helper::BitHelper; | ||
use cpu_leaf::*; | ||
use kvm_bindings::kvm_cpuid_entry2; | ||
|
||
// CPUID bits in ebx, ecx, and edx. | ||
const EBX_CLFLUSH_CACHELINE: u32 = 8; | ||
|
||
/// Sets leaf 01H EBX[23-16]. | ||
/// | ||
/// The maximum number of addressable logical CPUs is computed as the closest power of 2 | ||
/// higher or equal to the CPU count configured by the user. | ||
pub fn get_max_addressable_lprocessors(cpu_count: u8) -> Result<u8, Error> { | ||
let mut max_addressable_lcpu = (cpu_count as f64).log2().ceil(); | ||
max_addressable_lcpu = (2 as f64).powf(max_addressable_lcpu); | ||
// check that this number is still an u8 | ||
if max_addressable_lcpu > u8::max_value().into() { | ||
return Err(Error::VcpuCountOverflow); | ||
} | ||
Ok(max_addressable_lcpu as u8) | ||
} | ||
|
||
pub struct Engine { | ||
pub cpu_id: u8, | ||
pub cpu_count: u8, | ||
} | ||
|
||
impl LeafEngine for Engine { | ||
fn get_leaf_engine_id(&self) -> String { | ||
"leaf_0x1".to_string() | ||
} | ||
|
||
fn process(&self, entry: &mut kvm_cpuid_entry2) -> Result<(), Error> { | ||
let max_addr_cpu = get_max_addressable_lprocessors(self.cpu_count)? as u32; | ||
|
||
// X86 hypervisor feature | ||
entry | ||
.ecx | ||
.write_bit(ecx::TSC_DEADLINE_TIMER_BITINDEX, true) | ||
.write_bit(ecx::HYPERVISOR_BITINDEX, true); | ||
|
||
entry | ||
.ebx | ||
.write_bits_in_range(&ebx::APICID_BITRANGE, self.cpu_id as u32) | ||
.write_bits_in_range(&ebx::CLFLUSH_SIZE_BITRANGE, EBX_CLFLUSH_CACHELINE) | ||
.write_bits_in_range(&ebx::CPU_COUNT_BITRANGE, max_addr_cpu); | ||
|
||
// A value of 1 for HTT indicates the value in CPUID.1.EBX[23:16] | ||
// (the Maximum number of addressable IDs for logical processors in this package) | ||
// is valid for the package | ||
entry.edx.write_bit(edx::HTT, self.cpu_count > 1); | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use super::*; | ||
use kvm_bindings::kvm_cpuid_entry2; | ||
|
||
#[test] | ||
fn test_get_max_addressable_lprocessors() { | ||
assert_eq!(get_max_addressable_lprocessors(1).unwrap(), 1); | ||
assert_eq!(get_max_addressable_lprocessors(2).unwrap(), 2); | ||
assert_eq!(get_max_addressable_lprocessors(4).unwrap(), 4); | ||
assert_eq!(get_max_addressable_lprocessors(6).unwrap(), 8); | ||
assert!(get_max_addressable_lprocessors(u8::max_value()).is_err()); | ||
} | ||
|
||
fn test_process(cpu_count: u8, expected_htt: bool) { | ||
let engine: Engine = Engine { | ||
cpu_id: 0, | ||
cpu_count: cpu_count, | ||
}; | ||
|
||
let mut entry = &mut kvm_cpuid_entry2 { | ||
function: 0x1, | ||
index: 0, | ||
flags: 0, | ||
eax: 0, | ||
ebx: 0, | ||
ecx: 0, | ||
edx: 0, | ||
padding: [0, 0, 0], | ||
}; | ||
|
||
assert!(engine.process(&mut entry).is_ok()); | ||
|
||
assert!(entry.ecx.read_bit(ecx::TSC_DEADLINE_TIMER_BITINDEX)); | ||
assert!(entry.ecx.read_bit(ecx::HYPERVISOR_BITINDEX)); | ||
|
||
assert!(entry.ebx.read_bits_in_range(&ebx::APICID_BITRANGE) == engine.cpu_id as u32); | ||
assert!(entry.ebx.read_bits_in_range(&ebx::CLFLUSH_SIZE_BITRANGE) == EBX_CLFLUSH_CACHELINE); | ||
assert!( | ||
entry.ebx.read_bits_in_range(&ebx::CPU_COUNT_BITRANGE) | ||
== get_max_addressable_lprocessors(engine.cpu_count).unwrap() as u32 | ||
); | ||
assert!(entry.edx.read_bit(edx::HTT) == expected_htt) | ||
} | ||
|
||
#[test] | ||
fn test_1vcpu() { | ||
test_process(1, false); | ||
} | ||
|
||
#[test] | ||
fn test_2vcpu() { | ||
test_process(2, true); | ||
} | ||
} |
Oops, something went wrong.