Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 59 additions & 2 deletions qemu/target/i386/misc_helper.c
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ void helper_rdtsc(CPUX86State *env)
continue;
if (!HOOK_BOUND_CHECK(hook, env->eip))
continue;

// Multiple rdtsc callbacks returning different values is undefined.
// true -> skip the rdtsc instruction
if (hook->insn == UC_X86_INS_RDTSC) {
Expand Down Expand Up @@ -275,7 +275,7 @@ void helper_rdtscp(CPUX86State *env)
continue;
if (!HOOK_BOUND_CHECK(hook, env->eip))
continue;

// Multiple rdtscp callbacks returning different values is undefined.
// true -> skip the rdtscp instruction
if (hook->insn == UC_X86_INS_RDTSCP) {
Expand Down Expand Up @@ -316,9 +316,37 @@ void helper_rdpmc(CPUX86State *env)
void helper_wrmsr(CPUX86State *env)
{
uint64_t val;
uc_engine *uc = env->uc;
struct hook *hook;
int skip_wrmsr = 0;
bool synced = false;

cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 1, GETPC());

HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN)
{
if (hook->to_delete)
continue;
if (!HOOK_BOUND_CHECK(hook, env->eip))
continue;
if (hook->insn == UC_X86_INS_WRMSR) {
uintptr_t pc = GETPC();
if (!synced && !uc->skip_sync_pc_on_exit && pc) {
cpu_restore_state(uc->cpu, pc, false);
synced = true;
}
JIT_CALLBACK_GUARD_VAR(
skip_wrmsr,
((uc_cb_insn_cpuid_t)hook->callback)(env->uc, hook->user_data));
}
if (env->uc->stop_request)
break;
}

if (skip_wrmsr)
return;

val = ((uint32_t)env->regs[R_EAX]) |
((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);

Expand Down Expand Up @@ -477,9 +505,37 @@ void helper_rdmsr(CPUX86State *env)
{
X86CPU *x86_cpu = env_archcpu(env);
uint64_t val;
uc_engine *uc = env->uc;
struct hook *hook;
int skip_rdmsr = 0;
bool synced = false;

cpu_svm_check_intercept_param(env, SVM_EXIT_MSR, 0, GETPC());

HOOK_FOREACH_VAR_DECLARE;
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN)
{
if (hook->to_delete)
continue;
if (!HOOK_BOUND_CHECK(hook, env->eip))
continue;
if (hook->insn == UC_X86_INS_RDMSR) {
uintptr_t pc = GETPC();
if (!synced && !uc->skip_sync_pc_on_exit && pc) {
cpu_restore_state(uc->cpu, pc, false);
synced = true;
}
JIT_CALLBACK_GUARD_VAR(
skip_rdmsr,
((uc_cb_insn_cpuid_t)hook->callback)(env->uc, hook->user_data));
}
if (env->uc->stop_request)
break;
}

if (skip_rdmsr)
return;

switch ((uint32_t)env->regs[R_ECX]) {
case MSR_IA32_SYSENTER_CS:
val = env->sysenter_cs;
Expand Down Expand Up @@ -628,6 +684,7 @@ void helper_rdmsr(CPUX86State *env)
env->regs[R_EDX] = (uint32_t)(val >> 32);
}


static void do_pause(X86CPU *cpu)
{
CPUState *cs = CPU(cpu);
Expand Down
6 changes: 3 additions & 3 deletions qemu/target/i386/unicorn.c
Original file line number Diff line number Diff line change
Expand Up @@ -2023,12 +2023,12 @@ static bool x86_stop_interrupt(struct uc_struct *uc, int intno)

static bool x86_insn_hook_validate(uint32_t insn_enum)
{
// for x86 we can only hook IN, OUT, SYSCALL, SYSENTER, CPUID, RDTSC, and
// RDTSCP
// for x86 we can only hook IN, OUT, SYSCALL, SYSENTER, CPUID, RDTSC, RDTSCP, RDMSR and WRMSR
if (insn_enum != UC_X86_INS_IN && insn_enum != UC_X86_INS_OUT &&
insn_enum != UC_X86_INS_SYSCALL && insn_enum != UC_X86_INS_SYSENTER &&
insn_enum != UC_X86_INS_CPUID && insn_enum != UC_X86_INS_RDTSC &&
insn_enum != UC_X86_INS_RDTSCP) {
insn_enum != UC_X86_INS_RDTSCP && insn_enum != UC_X86_INS_RDMSR &&
insn_enum != UC_X86_INS_WRMSR) {
return false;
}
return true;
Expand Down
76 changes: 76 additions & 0 deletions tests/unit/test_x86.c
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,80 @@ static void test_x86_hook_insn_rdtscp(void)
OK(uc_close(uc));
}

static int test_x86_hook_insn_wrmsr_cb(uc_engine *uc, void *user_data)
{
*(int *)user_data = 1;
return 0;
}

static void test_x86_hook_insn_wrmsr(void)
{
/* WRMSR (0f 30) */
char code[] = "\x0F\x30";
int fired = 0;

uc_engine *uc;
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof code - 1);

uint64_t rcx = 0x174; /* MSR_IA32_SYSENTER_CS */
uint64_t rax = 0x10;
uint64_t rdx = 0;
OK(uc_reg_write(uc, UC_X86_REG_RCX, &rcx));
OK(uc_reg_write(uc, UC_X86_REG_RAX, &rax));
OK(uc_reg_write(uc, UC_X86_REG_RDX, &rdx));

uc_hook hook;
OK(uc_hook_add(uc, &hook, UC_HOOK_INSN, test_x86_hook_insn_wrmsr_cb,
&fired, 1, 0, UC_X86_INS_WRMSR));

OK(uc_emu_start(uc, code_start, code_start + sizeof code - 1, 0, 0));

OK(uc_hook_del(uc, hook));
TEST_CHECK(fired == 1);
OK(uc_close(uc));
}

static int test_x86_hook_insn_rdmsr_cb(uc_engine *uc, void *user_data)
{
uint64_t eax = 0xDEAD;
uint64_t edx = 0xBEEF;
OK(uc_reg_write(uc, UC_X86_REG_RAX, &eax));
OK(uc_reg_write(uc, UC_X86_REG_RDX, &edx));
*(int *)user_data = 1;
return 1; /* skip underlying rdmsr */
}

static void test_x86_hook_insn_rdmsr(void)
{
/* RDMSR (0f 32) */
char code[] = "\x0F\x32";
int fired = 0;

uc_engine *uc;
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof code - 1);

uint64_t rcx = 0x174; /* MSR_IA32_SYSENTER_CS */
OK(uc_reg_write(uc, UC_X86_REG_RCX, &rcx));

uc_hook hook;
OK(uc_hook_add(uc, &hook, UC_HOOK_INSN, test_x86_hook_insn_rdmsr_cb,
&fired, 1, 0, UC_X86_INS_RDMSR));

OK(uc_emu_start(uc, code_start, code_start + sizeof code - 1, 0, 0));

OK(uc_hook_del(uc, hook));
TEST_CHECK(fired == 1);

uint64_t eax = 0;
uint64_t edx = 0;
OK(uc_reg_read(uc, UC_X86_REG_RAX, &eax));
OK(uc_reg_read(uc, UC_X86_REG_RDX, &edx));
TEST_CHECK(eax == 0xDEAD);
TEST_CHECK(edx == 0xBEEF);

OK(uc_close(uc));
}

static void test_x86_dr7()
{
uc_engine *uc;
Expand Down Expand Up @@ -2262,6 +2336,8 @@ TEST_LIST = {
{"test_x86_ro_segfault", test_x86_ro_segfault},
{"test_x86_hook_insn_rdtsc", test_x86_hook_insn_rdtsc},
{"test_x86_hook_insn_rdtscp", test_x86_hook_insn_rdtscp},
{"test_x86_hook_insn_wrmsr", test_x86_hook_insn_wrmsr},
{"test_x86_hook_insn_rdmsr", test_x86_hook_insn_rdmsr},
{"test_x86_dr7", test_x86_dr7},
{"test_x86_hook_block", test_x86_hook_block},
{"test_x86_mem_hooks_pc_guarantee", test_x86_mem_hooks_pc_guarantee},
Expand Down
Loading