-
Notifications
You must be signed in to change notification settings - Fork 1.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix AMD boot freeze #1015
Fix AMD boot freeze #1015
Conversation
2af8500
to
e8e5bfd
Compare
cpuid/src/common.rs
Outdated
use kvm::CpuId; | ||
use kvm_bindings::kvm_cpuid_entry2; | ||
|
||
const INTEL: &[u8; 12] = b"GenuineIntel"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: I would prefix these two with VENDOR_ID_* so we have a better understanding of what are we using them for.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
cpuid/src/common.rs
Outdated
const INTEL: &[u8; 12] = b"GenuineIntel"; | ||
const AMD: &[u8; 12] = b"AuthenticAMD"; | ||
|
||
const EXT_FUNCTION: u32 = 0x80000000; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is HIGHEST_EXTENDED_FUNCTION
. We should name constants here as close as possible to the names that they have in the Intel/AMD manual so it is easier to correlate the code with the software development manuals.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
cpuid/src/common.rs
Outdated
} | ||
|
||
// this is safe because the host supports the `cpuid` instruction | ||
let max_function = unsafe { __get_cpuid_max(function & EXT_FUNCTION).0 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am wondering if instead of always querying the maximum cpuid leaf supported, we can instead save the max_function
somewhere and then just do the comparison from the following line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't know if it's worth it. This is really fast. The entire call to filter_cpuid takes less then 15 microseconds
cpuid/src/common.rs
Outdated
} | ||
|
||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
fn get_cpuid(function: u32, count: u32) -> Result<CpuidResult, Error> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: In Intel terminology I believe count
is actually sub_leaf
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
cpuid/src/common.rs
Outdated
|
||
#[test] | ||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] | ||
fn get_cpu_id_test() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please prefix test function with the word test
so it is easier to mentally separate the tests from the helper functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
cpuid/src/common.rs
Outdated
@@ -16,32 +16,28 @@ use std::arch::x86::__cpuid_count; | |||
#[cfg(target_arch = "x86_64")] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's no other reason. I squashed the commits.
cpuid/src/cpu_leaf.rs
Outdated
@@ -3,6 +3,8 @@ | |||
|
|||
// Basic CPUID Information | |||
pub mod leaf_0x1 { | |||
pub const FUNCTION: u32 = 0x1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know leaf
and function
are used interchangeably everywhere, but to not confuse people that look at this code for the first time, I would say to stick with only one name: either leaf or function.
If we want to still call them leaves, than we can rename FUNCTION
to LEAF_NR
. What do you say?
P.S. Nice improvement from having the values of the leaves hardcoded.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
cpuid/src/lib.rs
Outdated
let cpuid_transformer: &dyn CpuidTransformer = match &vendor_id { | ||
INTEL => &intel::IntelCpuidTransformer {}, | ||
AMD => &amd::AmdCpuidTransformer {}, | ||
_ => &other::OtherCpuidTransformer {}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of having OtherCpuidTransformer
? When we add a new platform shouldn't we just add the corresponding transformer and not have a generic one here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I removed it
@@ -66,7 +69,23 @@ pub enum Error { | |||
VcpuCountOverflow, | |||
/// The max size has been exceeded | |||
SizeLimitExceeded, | |||
/// A call to an internal helper method failed | |||
InternalError(super::common::Error), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: use super::common and then just write common::Error here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I do this there will be conflicts between the Error defined here and common::Error. I will have to use self::Error instead of Error. I would keep it as it is
37a38dc
to
7b86f2e
Compare
@andreeaflorescu I adressed all the comments. Please take another look. |
cpuid/src/cpu_leaf.rs
Outdated
@@ -3,6 +3,8 @@ | |||
|
|||
// Basic CPUID Information | |||
pub mod leaf_0x1 { | |||
pub const LEAF_NR: u32 = 0x1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: "nr" is not short for number. I suggest either "num" or "no".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -63,19 +65,41 @@ pub mod leaf_0x1 { | |||
} | |||
} | |||
|
|||
// Deterministic Cache Parameters Leaf | |||
pub mod leaf_0x4 { | |||
pub mod leaf_cache_parameters { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't this node have a leaf number const as well?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this is in fact a sub-leaf of the 0x4 leaf.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not an actual leaf. Since 0x4 and 0x8000_001d are very similar, but not completely the same (see ox4 - page 32 and 0x8000_001d - page 76 ), I created this "parent leaf" in order to hold the common properties. 0x4 and 0x8000_001d inherit these common properties, and then add their specific ones.
} | ||
|
||
let cpuid2 = CpuId::from_entries(&entries); | ||
*cpuid = cpuid2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function completely replaces the cpuid
struct with a new copy, which is not something the caller might expect. I.e. if, in the future, we decide to extend the CpuId
struct to hold more data, that data would be lost upon returning from this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created #1019 in order to address this issue. I would like to tackle it later with lower priority. Also see here: #1015 (comment)
) -> Result<(), Error> { | ||
Ok(()) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find this two-step logic (pre-process entry list + transform individual entries) a bit difficult to follow.
Why not have a single transforming / filtering trait, that ingests a CpuId
struct and outputs a "fixed" CpuId
? Then, different vendors / templates / whatever else might affect cpuid, could provide an implementation for that trait, and we could chain these transformations together, to produce the final emulated cpuid.
I.e. the flow I'm imagining looks something like this:
vcpu::configure()
...
vendor_filter <- pick_vendor_filter_based_on_host_cpu()
template_filter <- pick_template_filter_based_on_microvm_config()
emulated_cpuid <-
template_filter.apply(
vendor_filter.apply(
get_emulated_cpuid_from_kvm()
)
)
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In general I agree with having a single transforming / filtering trait, that ingests a CpuId struct and outputs a "fixed" CpuId. It seems like a more consistent approach, but I'm not sure it would be that easy. There are more things to take into account here. Like the fact that certain templates can be applied only to certain vendors. For example C3 can only be applied to Intel. I would like to dive deeper into it and take my time on implementing this. Also, since I have limited access to AMD hardware I would need this PR merged as soon as possible in order to continue the work on CPU feature masking for AMD.
So is it ok if I create another issue for this and address it probably next week ? We should also update the CPU templates in order to use the BitRange structure, I can do that as part of the same issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay, then. We can take it offline and discuss this approach - I can't see many issues arising.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I created #1025
copied from firecracker-microvm#882 Signed-off-by: Serban Iorga <[email protected]>
Signed-off-by: Serban Iorga <[email protected]>
Signed-off-by: Serban Iorga <[email protected]>
Signed-off-by: Serban Iorga <[email protected]>
7b86f2e
to
be42217
Compare
@dhrgit I answered to all the comments. Please take another look. |
Issue #, if available: #815
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.