diff --git a/qemu/target/i386/misc_helper.c b/qemu/target/i386/misc_helper.c index d46953a4..f9924368 100644 --- a/qemu/target/i386/misc_helper.c +++ b/qemu/target/i386/misc_helper.c @@ -105,6 +105,7 @@ void helper_into(CPUX86State *env, int next_eip_addend) void helper_cpuid(CPUX86State *env) { uint32_t eax, ebx, ecx, edx; + struct hook *hook; cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC()); @@ -114,6 +115,21 @@ void helper_cpuid(CPUX86State *env) env->regs[R_EBX] = ebx; env->regs[R_ECX] = ecx; env->regs[R_EDX] = edx; + + // Unicorn: call registered CPUID hooks + 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_CPUID) + ((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data); + + // the last callback may already asked to stop emulation + if (env->uc->stop_request) + break; + } } target_ulong helper_read_crN(CPUX86State *env, int reg) diff --git a/qemu/target/i386/unicorn.c b/qemu/target/i386/unicorn.c index 7b66800f..eef1e471 100644 --- a/qemu/target/i386/unicorn.c +++ b/qemu/target/i386/unicorn.c @@ -1564,7 +1564,8 @@ static bool x86_insn_hook_validate(uint32_t insn_enum) 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_SYSENTER + && insn_enum != UC_X86_INS_CPUID) { return false; } return true; diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index 86a3c182..17d346ef 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -525,6 +525,31 @@ static void test_x86_sysenter() { OK(uc_close(uc)); } +static void test_x86_hook_cpuid_callback(uc_engine* uc, void* data) { + int reg = 7; + + OK(uc_reg_write(uc, UC_X86_REG_EAX, ®)); +} + +static void test_x86_hook_cpuid() { + uc_engine* uc; + char code[] = "\x40\x0F\xA2"; // INC EAX; CPUID + uc_hook h; + int reg; + + uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1); + + OK(uc_hook_add(uc, &h, UC_HOOK_INSN, test_x86_hook_cpuid_callback, NULL, 1, 0, UC_X86_INS_CPUID)); + + OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0)); + + OK(uc_reg_read(uc, UC_X86_REG_EAX, ®)); + + TEST_CHECK(reg == 7); + + OK(uc_close(uc)); +} + TEST_LIST = { { "test_x86_in", test_x86_in }, { "test_x86_out", test_x86_out }, @@ -545,5 +570,6 @@ TEST_LIST = { { "test_x86_smc_xor", test_x86_smc_xor}, { "test_x86_mmio_uc_mem_rw", test_x86_mmio_uc_mem_rw}, { "test_x86_sysenter", test_x86_sysenter}, + { "test_x86_hook_cpuid", test_x86_hook_cpuid}, { NULL, NULL } }; \ No newline at end of file