Skip to content

Commit

Permalink
add rdtsc/rdtscp opcode emulation
Browse files Browse the repository at this point in the history
This might be useful in cases where it's desired to catch rdtsc/rdtscp begin executed only in user-mode.

Disabling rdtsc/rdstcp for user-mode is achieved by setting cr4_t::timestamp_disable flag (it might be needed to set correct value to the shadow CR4 due to patch-guard).

Note: this commit temporarily disables VMWARE_WORKAROUND, until correct solution is implemented.
  • Loading branch information
wbenny committed Aug 1, 2019
1 parent 7167324 commit d30f38b
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 7 deletions.
7 changes: 7 additions & 0 deletions src/hvpp/hvpp/vcpu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ vcpu_t::vcpu_t(vmexit_handler& handler) noexcept
, ept_count_{}
, ept_index_{}

//
// Initialize timestamp-counter members.
//
, tsc_entry_{}
, tsc_delta_previous_{}
, tsc_delta_sum_{}

//
// Well, this is also not necessary.
// This member is reset to "false" on each VM-exit in entry_host() method.
Expand Down
71 changes: 64 additions & 7 deletions src/hvpp/hvpp/vmexit/vmexit_passthrough.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ namespace detail
static constexpr uint8_t opcode[] = { 0x48, 0x0f, 0x07 };
return memcmp(address, opcode, sizeof(opcode)) == 0;
}

static bool is_rdtsc_instruction(const void* address) noexcept
{
static constexpr uint8_t opcode[] = { 0x0f, 0x31 };
return memcmp(address, opcode, sizeof(opcode)) == 0;
}

static bool is_rdtscp_instruction(const void* address) noexcept
{
static constexpr uint8_t opcode[] = { 0x0f, 0x01, 0xf9 };
return memcmp(address, opcode, sizeof(opcode)) == 0;
}
}

void vmexit_passthrough_handler::setup(vcpu_t& vp) noexcept
Expand Down Expand Up @@ -1124,21 +1136,56 @@ void vmexit_passthrough_handler::handle_interrupt(vcpu_t& vp) noexcept

case exception_vector::general_protection:
{
//
// 3 bytes are enough to hold either `rdtsc' or `rdtscp'
// instruction opcode.
//
uint8_t buffer[3];

#ifdef HVPP_ENABLE_VMWARE_WORKAROUND
auto instruction_length = static_cast<size_t>(vp.exit_instruction_length());
auto read_size = std::max(instruction_length, sizeof(buffer));

if (auto err_va = vp.guest_read_memory(vp.context().rip, buffer, read_size))
{
hvpp_trace("handle_interrupt (general_protection) - read_guest_memory(%p, %u) failed, injecting #PF",
vp.context().rip,
instruction_length);

write<cr2_t>({ err_va.value() });
vp.interrupt_inject(interrupt::page_fault);
vp.suppress_rip_adjust();

return;
}

//
// VMWare I/O backdoor (port 0x5658/0x5659) workaround.
// Compare copied memory to `rdtsc' & `rdtscp' instructions.
//
cr3_guard _{ vp.guest_cr3() };

vmx::exit_qualification_io_instruction_t exit_qualification;
if (try_decode_io_instruction(vp.context(), exit_qualification))
if (detail::is_rdtsc_instruction(buffer))
{
handle_emulate_rdtsc(vp);
return;
}
else if (detail::is_rdtscp_instruction(buffer))
{
ia32_asm_io_with_context(exit_qualification, vp.context());
handle_emulate_rdtscp(vp);
return;
}

#ifdef HVPP_ENABLE_VMWARE_WORKAROUND

// //
// // VMWare I/O backdoor (port 0x5658/0x5659) workaround.
// //
// cr3_guard _{ vp.guest_cr3() };
//
// vmx::exit_qualification_io_instruction_t exit_qualification;
// if (try_decode_io_instruction(vp.context(), exit_qualification))
// {
// ia32_asm_io_with_context(exit_qualification, vp.context());
// return;
// }

#endif

break;
Expand Down Expand Up @@ -1323,4 +1370,14 @@ void vmexit_passthrough_handler::handle_emulate_sysret(vcpu_t& vp) noexcept
vp.guest_ss(ss);
}

void vmexit_passthrough_handler::handle_emulate_rdtsc(vcpu_t& vp) noexcept
{
handle_execute_rdtsc(vp);
}

void vmexit_passthrough_handler::handle_emulate_rdtscp(vcpu_t& vp) noexcept
{
handle_execute_rdtscp(vp);
}

}
2 changes: 2 additions & 0 deletions src/hvpp/hvpp/vmexit/vmexit_passthrough.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ class vmexit_passthrough_handler

virtual void handle_emulate_syscall(vcpu_t& vp) noexcept;
virtual void handle_emulate_sysret(vcpu_t& vp) noexcept;
virtual void handle_emulate_rdtsc(vcpu_t& vp) noexcept;
virtual void handle_emulate_rdtscp(vcpu_t& vp) noexcept;
};

}

0 comments on commit d30f38b

Please sign in to comment.