Better design of cpuid instruction hook
This commit is contained in:
parent
dfb14e971f
commit
7bb756249a
|
@ -75,6 +75,14 @@ typedef struct uc_x86_msr {
|
||||||
// @user_data: user data passed to tracing APIs.
|
// @user_data: user data passed to tracing APIs.
|
||||||
typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data);
|
typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data);
|
||||||
|
|
||||||
|
// Callback function for tracing cpuid (for uc_hook_intr())
|
||||||
|
// @user_data: user data passed to tracing APIs.
|
||||||
|
//
|
||||||
|
// @return: true indicates the callback overwrites the cpuid instruction while
|
||||||
|
// false
|
||||||
|
// indicates cpuid instruction will still be executed.
|
||||||
|
typedef int (*uc_cb_insn_cpuid_t)(struct uc_struct *uc, void *user_data);
|
||||||
|
|
||||||
//> X86 registers
|
//> X86 registers
|
||||||
typedef enum uc_x86_reg {
|
typedef enum uc_x86_reg {
|
||||||
UC_X86_REG_INVALID = 0,
|
UC_X86_REG_INVALID = 0,
|
||||||
|
|
|
@ -106,16 +106,10 @@ void helper_cpuid(CPUX86State *env)
|
||||||
{
|
{
|
||||||
uint32_t eax, ebx, ecx, edx;
|
uint32_t eax, ebx, ecx, edx;
|
||||||
struct hook *hook;
|
struct hook *hook;
|
||||||
|
int skip_cpuid = 0;
|
||||||
|
|
||||||
cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
|
cpu_svm_check_intercept_param(env, SVM_EXIT_CPUID, 0, GETPC());
|
||||||
|
|
||||||
cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
|
|
||||||
&eax, &ebx, &ecx, &edx);
|
|
||||||
env->regs[R_EAX] = eax;
|
|
||||||
env->regs[R_EBX] = ebx;
|
|
||||||
env->regs[R_ECX] = ecx;
|
|
||||||
env->regs[R_EDX] = edx;
|
|
||||||
|
|
||||||
// Unicorn: call registered CPUID hooks
|
// Unicorn: call registered CPUID hooks
|
||||||
HOOK_FOREACH_VAR_DECLARE;
|
HOOK_FOREACH_VAR_DECLARE;
|
||||||
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) {
|
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) {
|
||||||
|
@ -123,13 +117,26 @@ void helper_cpuid(CPUX86State *env)
|
||||||
continue;
|
continue;
|
||||||
if (!HOOK_BOUND_CHECK(hook, env->eip))
|
if (!HOOK_BOUND_CHECK(hook, env->eip))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
// Multiple cpuid callbacks returning different values is undefined.
|
||||||
|
// true -> skip the cpuid instruction
|
||||||
if (hook->insn == UC_X86_INS_CPUID)
|
if (hook->insn == UC_X86_INS_CPUID)
|
||||||
((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data);
|
skip_cpuid = ((uc_cb_insn_cpuid_t)hook->callback)(env->uc, hook->user_data);
|
||||||
|
|
||||||
// the last callback may already asked to stop emulation
|
// the last callback may already asked to stop emulation
|
||||||
if (env->uc->stop_request)
|
if (env->uc->stop_request)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!skip_cpuid) {
|
||||||
|
cpu_x86_cpuid(env, (uint32_t)env->regs[R_EAX], (uint32_t)env->regs[R_ECX],
|
||||||
|
&eax, &ebx, &ecx, &edx);
|
||||||
|
env->regs[R_EAX] = eax;
|
||||||
|
env->regs[R_EBX] = ebx;
|
||||||
|
env->regs[R_ECX] = ecx;
|
||||||
|
env->regs[R_EDX] = edx;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
target_ulong helper_read_crN(CPUX86State *env, int reg)
|
target_ulong helper_read_crN(CPUX86State *env, int reg)
|
||||||
|
|
|
@ -601,11 +601,14 @@ static void test_x86_sysenter()
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_hook_cpuid_callback(uc_engine *uc, void *data)
|
static int test_x86_hook_cpuid_callback(uc_engine *uc, void *data)
|
||||||
{
|
{
|
||||||
int reg = 7;
|
int reg = 7;
|
||||||
|
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_EAX, ®));
|
OK(uc_reg_write(uc, UC_X86_REG_EAX, ®));
|
||||||
|
|
||||||
|
// Overwrite the cpuid instruction.
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_hook_cpuid()
|
static void test_x86_hook_cpuid()
|
||||||
|
|
Loading…
Reference in New Issue