-
Notifications
You must be signed in to change notification settings - Fork 133
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
add flush_broadcast
and tlbsync
functions
#403
Conversation
src/instructions/tlb.rs
Outdated
|
||
/// Invalidates TLB entry(s) with Broadcast. | ||
/// | ||
/// # Safety | ||
/// | ||
/// This function is unsafe as it requires CPUID.(EAX=8000_0008H, ECX=0H):EBX.INVLPGB | ||
/// to be 1 and count to be less than or equal to CPUID.(EAX=8000_0008H, ECX=0H):EDX[0..=15]. | ||
#[inline] | ||
pub unsafe fn flush_broadcast<S>( | ||
va_and_count: Option<(Page<S>, u16)>, | ||
pcid: Option<Pcid>, | ||
asid: Option<u16>, | ||
include_global: bool, | ||
final_translation_only: bool, | ||
include_nested_translations: bool, | ||
) where | ||
S: NotGiantPageSize, |
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.
Do we want to use the builder pattern for this? There are an awful lot of parameters and this doesn't seem very future proof in case AMD adds more options.
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 agree that we want some sort of builder or #[non_exhaustive]
struct to be used for this.
A builder pattern would also better reflect:
- What reasonable defaults should be
- What parameters are optional
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 can also be used to make some parameters unsafe.
If count is greater than the CPUID value (0x80000008_EDX[15:0]), you can issue the instruction in a loop and then perform a single TLBSYNC. |
Ah, good to know, I was wondering about that, thank you! I don't think we want to execute cpuid inside that function to figure out how often we have to loop though: There is precedence for relying on the caller to ensure an instruction is valid to execute (e.g. see |
Yes, you definitely don't want to be executing CPUID each time. In an SEV-SNP VM it will generate a #VC exception, which will then use the CPUID page to satisfy the instruction without exiting to the hypervisor, at least. I haven't looked closely at the crate, is there any way to set/save some kind of initialization state that can be referenced? |
We do something kind of like that for the x86_64/src/instructions/random.rs Lines 3 to 19 in 642956d
For |
Implementing the loop for this turns out to be less trivial than I initially thought. Two things I'm not completely certain about:
|
fam19h/model11h is Genoa. Yes, theoretically, the CPUID could report 0 for the maximum count, in which case you would only be able to do a single page at a time (#GP if the ECX[15:0] > maximum page count supported).
I believe that the address would not be canonicalized, and would then just be a miss in the TLB since no addresses would match. |
Also, for the ASID related instructions, it seems like we would want some sort of common |
AFAICT the reason that we have a With that said I'm not sure what size the ASID type should be and how we should enforce the limit given by the CPUID function. Perhaps we should start keeping these limits in global variables so that we can properly enforce them without executing |
8f3a412
to
5e5e328
Compare
This allows us to these functions internally without requiring the nightly `step_trait` feature.
5e5e328
to
bae6119
Compare
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.
Thanks a lot for tackling this! I left some superficial comments on the API. I didn't have time to look through the flush_broadcast
implementation, but the rest looks good to me.
This avoids any confusion between the trait methods and inherent methods.
This works for all methods except `pages` which changes the type.
flush_broadcast
can be used to broadcast TLB flushes to all CPU cores andtlbsync
can be used to wait for those flushes to be done.