Skip to content

Commit

Permalink
Merge pull request #327 from 00xc/cpu/vc-rdtsc
Browse files Browse the repository at this point in the history
cpu/vc: implement `RDTSC` and `RDSTCP` #VC handlers
  • Loading branch information
joergroedel authored Apr 26, 2024
2 parents a58ba53 + 447e578 commit 95e2039
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 143 deletions.
10 changes: 10 additions & 0 deletions kernel/src/cpu/insn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ pub enum DecodedInsn {
Outw(Operand),
Wrmsr,
Rdmsr,
Rdtsc,
Rdtscp,
}

impl DecodedInsn {
Expand All @@ -79,6 +81,8 @@ impl DecodedInsn {
Self::Outw(Operand::Imm(..)) => 3,
Self::Outl(Operand::Imm(..)) => 2,
Self::Wrmsr | Self::Rdmsr => 2,
Self::Rdtsc => 2,
Self::Rdtscp => 3,
}
}
}
Expand Down Expand Up @@ -121,7 +125,13 @@ impl Instruction {
_ => (),
},
0x0F => match self.0[1] {
0x01 => {
if self.0[2] == 0xf9 {
return Ok(DecodedInsn::Rdtscp);
}
}
0x30 => return Ok(DecodedInsn::Wrmsr),
0x31 => return Ok(DecodedInsn::Rdtsc),
0x32 => return Ok(DecodedInsn::Rdmsr),
0xA2 => return Ok(DecodedInsn::Cpuid),
_ => (),
Expand Down
2 changes: 1 addition & 1 deletion kernel/src/cpu/msr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ pub fn rdtscp() -> RdtscpOut {
let ecx: u32;

unsafe {
asm!("rdtsc",
asm!("rdtscp",
out("eax") eax,
out("ecx") ecx,
out("edx") edx,
Expand Down
26 changes: 16 additions & 10 deletions kernel/src/cpu/vc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,11 @@ use core::fmt;

pub const SVM_EXIT_EXCP_BASE: usize = 0x40;
pub const SVM_EXIT_LAST_EXCP: usize = 0x5f;
pub const SVM_EXIT_RDTSC: usize = 0x6e;
pub const SVM_EXIT_CPUID: usize = 0x72;
pub const SVM_EXIT_IOIO: usize = 0x7b;
pub const SVM_EXIT_MSR: usize = 0x7c;
pub const SVM_EXIT_RDTSCP: usize = 0x87;
pub const X86_TRAP_DB: usize = 0x01;
pub const X86_TRAP: usize = SVM_EXIT_EXCP_BASE + X86_TRAP_DB;

Expand Down Expand Up @@ -97,9 +99,10 @@ pub fn stage2_handle_vc_exception_no_ghcb(ctx: &mut X86ExceptionContext) -> Resu
pub fn stage2_handle_vc_exception(ctx: &mut X86ExceptionContext) -> Result<(), SvsmError> {
let err = ctx.error_code;

// To handle NAE events, we're supposed to reset the VALID_BITMAP field of the GHCB.
// This is currently only relevant for IOIO handling. This field is currently reset in
// the ioio_{in,ou} methods but it would be better to move the reset out of the different
// To handle NAE events, we're supposed to reset the VALID_BITMAP field of
// the GHCB. This is currently only relevant for IOIO, RDTSC and RDTSCP
// handling. This field is currently reset in the relevant GHCB methods
// but it would be better to move the reset out of the different
// handlers.
let mut ghcb = current_ghcb();

Expand All @@ -109,6 +112,8 @@ pub fn stage2_handle_vc_exception(ctx: &mut X86ExceptionContext) -> Result<(), S
(SVM_EXIT_CPUID, Some(DecodedInsn::Cpuid)) => handle_cpuid(ctx),
(SVM_EXIT_IOIO, Some(ins)) => handle_ioio(ctx, &mut ghcb, ins),
(SVM_EXIT_MSR, Some(ins)) => handle_msr(ctx, &mut ghcb, ins),
(SVM_EXIT_RDTSC, Some(DecodedInsn::Rdtsc)) => ghcb.rdtsc_regs(&mut ctx.regs),
(SVM_EXIT_RDTSCP, Some(DecodedInsn::Rdtsc)) => ghcb.rdtscp_regs(&mut ctx.regs),
_ => Err(VcError::new(ctx, VcErrorType::Unsupported).into()),
}?;

Expand All @@ -119,9 +124,10 @@ pub fn stage2_handle_vc_exception(ctx: &mut X86ExceptionContext) -> Result<(), S
pub fn handle_vc_exception(ctx: &mut X86ExceptionContext) -> Result<(), SvsmError> {
let error_code = ctx.error_code;

// To handle NAE events, we're supposed to reset the VALID_BITMAP field of the GHCB.
// This is currently only relevant for IOIO handling. This field is currently reset in
// the ioio_{in,ou} methods but it would be better to move the reset out of the different
// To handle NAE events, we're supposed to reset the VALID_BITMAP field of
// the GHCB. This is currently only relevant for IOIO, RDTSC and RDTSCP
// handling. This field is currently reset in the relevant GHCB methods
// but it would be better to move the reset out of the different
// handlers.
let mut ghcb = current_ghcb();

Expand All @@ -138,6 +144,8 @@ pub fn handle_vc_exception(ctx: &mut X86ExceptionContext) -> Result<(), SvsmErro
(SVM_EXIT_CPUID, Some(DecodedInsn::Cpuid)) => handle_cpuid(ctx),
(SVM_EXIT_IOIO, Some(ins)) => handle_ioio(ctx, &mut ghcb, ins),
(SVM_EXIT_MSR, Some(ins)) => handle_msr(ctx, &mut ghcb, ins),
(SVM_EXIT_RDTSC, Some(DecodedInsn::Rdtsc)) => ghcb.rdtsc_regs(&mut ctx.regs),
(SVM_EXIT_RDTSCP, Some(DecodedInsn::Rdtsc)) => ghcb.rdtscp_regs(&mut ctx.regs),
_ => Err(VcError::new(ctx, VcErrorType::Unsupported).into()),
}?;

Expand Down Expand Up @@ -584,8 +592,7 @@ mod tests {
}

#[test]
// #[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
#[ignore = "Currently unhandled by #VC handler"]
#[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
fn test_rdtsc() {
let mut prev: u64 = rdtsc();
for _ in 0..50 {
Expand All @@ -596,8 +603,7 @@ mod tests {
}

#[test]
// #[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
#[ignore = "Currently unhandled by #VC handler"]
#[cfg_attr(not(test_in_svsm), ignore = "Can only be run inside guest")]
fn test_rdtscp() {
let expected_pid = u32::try_from(verify_ghcb_gets_altered(|| read_msr(MSR_TSC_AUX)))
.expect("pid should be 32 bits");
Expand Down
Loading

0 comments on commit 95e2039

Please sign in to comment.