Files
unicorn/qemu/target/i386/unicorn.c
Takacs, Philipp 901034577a i386 call internal helper on special porpese register write
Some registers writes have side effects. i.e. write to cr3 flush the tlb,
if the PG bit is set.
2023-03-28 13:50:11 +02:00

1670 lines
53 KiB
C

/* Unicorn Emulator Engine */
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
#include "uc_priv.h"
#include "sysemu/cpus.h"
#include "cpu.h"
#include "unicorn_common.h"
#include <unicorn/x86.h> /* needed for uc_x86_mmr */
#include "unicorn.h"
#define FPST(n) (env->fpregs[(env->fpstt + (n)) & 7].d)
#define X86_NON_CS_FLAGS (DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK)
static void load_seg_16_helper(CPUX86State *env, int seg, uint32_t selector)
{
cpu_x86_load_seg_cache(env, seg, selector, (selector << 4), 0xffff,
X86_NON_CS_FLAGS);
}
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f);
floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper);
extern void helper_wrmsr(CPUX86State *env);
extern void helper_rdmsr(CPUX86State *env);
static void x86_set_pc(struct uc_struct *uc, uint64_t address)
{
if (uc->mode == UC_MODE_16) {
int16_t cs = (uint16_t)X86_CPU(uc->cpu)->env.segs[R_CS].selector;
((CPUX86State *)uc->cpu->env_ptr)->eip = address - cs * 16;
} else
((CPUX86State *)uc->cpu->env_ptr)->eip = address;
}
static uint64_t x86_get_pc(struct uc_struct *uc)
{
if (uc->mode == UC_MODE_16) {
return X86_CPU(uc->cpu)->env.segs[R_CS].selector * 16 +
((CPUX86State *)uc->cpu->env_ptr)->eip;
} else {
return ((CPUX86State *)uc->cpu->env_ptr)->eip;
}
}
static void x86_release(void *ctx)
{
int i;
TCGContext *tcg_ctx = (TCGContext *)ctx;
X86CPU *cpu = (X86CPU *)tcg_ctx->uc->cpu;
CPUTLBDesc *d = cpu->neg.tlb.d;
CPUTLBDescFast *f = cpu->neg.tlb.f;
CPUTLBDesc *desc;
CPUTLBDescFast *fast;
X86CPUClass *xcc = X86_CPU_GET_CLASS(cpu);
release_common(ctx);
for (i = 0; i < NB_MMU_MODES; i++) {
desc = &(d[i]);
fast = &(f[i]);
g_free(desc->iotlb);
g_free(fast->table);
}
free(xcc->model);
}
void x86_reg_reset(struct uc_struct *uc)
{
CPUArchState *env = uc->cpu->env_ptr;
memset(env->regs, 0, sizeof(env->regs));
memset(env->segs, 0, sizeof(env->segs));
memset(env->cr, 0, sizeof(env->cr));
memset(&env->ldt, 0, sizeof(env->ldt));
memset(&env->gdt, 0, sizeof(env->gdt));
memset(&env->tr, 0, sizeof(env->tr));
memset(&env->idt, 0, sizeof(env->idt));
env->eip = 0;
cpu_load_eflags(env, 0, -1);
env->cc_op = CC_OP_EFLAGS;
env->fpstt = 0; /* top of stack index */
env->fpus = 0;
env->fpuc = 0;
memset(env->fptags, 0, sizeof(env->fptags)); /* 0 = valid, 1 = empty */
env->mxcsr = 0;
memset(env->xmm_regs, 0, sizeof(env->xmm_regs));
memset(&env->xmm_t0, 0, sizeof(env->xmm_t0));
memset(&env->mmx_t0, 0, sizeof(env->mmx_t0));
memset(env->ymmh_regs, 0, sizeof(env->ymmh_regs));
memset(env->opmask_regs, 0, sizeof(env->opmask_regs));
memset(env->zmmh_regs, 0, sizeof(env->zmmh_regs));
/* sysenter registers */
env->sysenter_cs = 0;
env->sysenter_esp = 0;
env->sysenter_eip = 0;
env->efer = 0;
env->star = 0;
env->vm_hsave = 0;
env->tsc = 0;
env->tsc_adjust = 0;
env->tsc_deadline = 0;
env->mcg_status = 0;
env->msr_ia32_misc_enable = 0;
env->msr_ia32_feature_control = 0;
env->msr_fixed_ctr_ctrl = 0;
env->msr_global_ctrl = 0;
env->msr_global_status = 0;
env->msr_global_ovf_ctrl = 0;
memset(env->msr_fixed_counters, 0, sizeof(env->msr_fixed_counters));
memset(env->msr_gp_counters, 0, sizeof(env->msr_gp_counters));
memset(env->msr_gp_evtsel, 0, sizeof(env->msr_gp_evtsel));
#ifdef TARGET_X86_64
memset(env->hi16_zmm_regs, 0, sizeof(env->hi16_zmm_regs));
env->lstar = 0;
env->cstar = 0;
env->fmask = 0;
env->kernelgsbase = 0;
#endif
// TODO: reset other registers in CPUX86State qemu/target-i386/cpu.h
// properly initialize internal setup for each mode
switch (uc->mode) {
default:
break;
case UC_MODE_16:
env->hflags = 0;
env->cr[0] = 0;
// undo the damage done by the memset of env->segs above
// for R_CS, not quite the same as x86_cpu_reset
cpu_x86_load_seg_cache(env, R_CS, 0, 0, 0xffff,
DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
DESC_R_MASK | DESC_A_MASK);
// remainder yields same state as x86_cpu_reset
load_seg_16_helper(env, R_DS, 0);
load_seg_16_helper(env, R_ES, 0);
load_seg_16_helper(env, R_SS, 0);
load_seg_16_helper(env, R_FS, 0);
load_seg_16_helper(env, R_GS, 0);
break;
case UC_MODE_32:
env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_OSFXSR_MASK;
cpu_x86_update_cr0(env, CR0_PE_MASK); // protected mode
break;
case UC_MODE_64:
env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK |
HF_LMA_MASK | HF_OSFXSR_MASK;
env->hflags &= ~(HF_ADDSEG_MASK);
env->efer |= MSR_EFER_LMA | MSR_EFER_LME; // extended mode activated
cpu_x86_update_cr0(env, CR0_PE_MASK); // protected mode
/* If we are operating in 64bit mode then add the Long Mode flag
* to the CPUID feature flag
*/
env->features[FEAT_8000_0001_EDX] |= CPUID_EXT2_LM;
break;
}
}
static int x86_msr_read(CPUX86State *env, uc_x86_msr *msr)
{
uint64_t ecx = env->regs[R_ECX];
uint64_t eax = env->regs[R_EAX];
uint64_t edx = env->regs[R_EDX];
env->regs[R_ECX] = msr->rid;
helper_rdmsr(env);
msr->value = ((uint32_t)env->regs[R_EAX]) |
((uint64_t)((uint32_t)env->regs[R_EDX]) << 32);
env->regs[R_EAX] = eax;
env->regs[R_ECX] = ecx;
env->regs[R_EDX] = edx;
/* The implementation doesn't throw exception or return an error if there is
* one, so we will return 0. */
return 0;
}
static int x86_msr_write(CPUX86State *env, uc_x86_msr *msr)
{
uint64_t ecx = env->regs[R_ECX];
uint64_t eax = env->regs[R_EAX];
uint64_t edx = env->regs[R_EDX];
env->regs[R_ECX] = msr->rid;
env->regs[R_EAX] = (unsigned int)msr->value;
env->regs[R_EDX] = (unsigned int)(msr->value >> 32);
helper_wrmsr(env);
env->regs[R_ECX] = ecx;
env->regs[R_EAX] = eax;
env->regs[R_EDX] = edx;
/* The implementation doesn't throw exception or return an error if there is
* one, so we will return 0. */
return 0;
}
static void reg_read(CPUX86State *env, unsigned int regid, void *value,
uc_mode mode)
{
switch (regid) {
default:
break;
case UC_X86_REG_FP0:
case UC_X86_REG_FP1:
case UC_X86_REG_FP2:
case UC_X86_REG_FP3:
case UC_X86_REG_FP4:
case UC_X86_REG_FP5:
case UC_X86_REG_FP6:
case UC_X86_REG_FP7: {
floatx80 reg = env->fpregs[regid - UC_X86_REG_FP0].d;
cpu_get_fp80(value, (uint16_t *)((char *)value + sizeof(uint64_t)),
reg);
}
return;
case UC_X86_REG_FPSW: {
uint16_t fpus = env->fpus;
fpus = fpus & ~0x3800;
fpus |= (env->fpstt & 0x7) << 11;
*(uint16_t *)value = fpus;
}
return;
case UC_X86_REG_FPCW:
*(uint16_t *)value = env->fpuc;
return;
case UC_X86_REG_FPTAG: {
#define EXPD(fp) (fp.l.upper & 0x7fff)
#define MANTD(fp) (fp.l.lower)
#define MAXEXPD 0x7fff
int fptag, exp, i;
uint64_t mant;
CPU_LDoubleU tmp;
fptag = 0;
for (i = 7; i >= 0; i--) {
fptag <<= 2;
if (env->fptags[i]) {
fptag |= 3;
} else {
tmp.d = env->fpregs[i].d;
exp = EXPD(tmp);
mant = MANTD(tmp);
if (exp == 0 && mant == 0) {
/* zero */
fptag |= 1;
} else if (exp == 0 || exp == MAXEXPD ||
(mant & (1LL << 63)) == 0) {
/* NaNs, infinity, denormal */
fptag |= 2;
}
}
}
*(uint16_t *)value = fptag;
}
return;
case UC_X86_REG_XMM0:
case UC_X86_REG_XMM1:
case UC_X86_REG_XMM2:
case UC_X86_REG_XMM3:
case UC_X86_REG_XMM4:
case UC_X86_REG_XMM5:
case UC_X86_REG_XMM6:
case UC_X86_REG_XMM7: {
float64 *dst = (float64 *)value;
ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
dst[0] = reg->ZMM_Q(0);
dst[1] = reg->ZMM_Q(1);
return;
}
case UC_X86_REG_ST0:
case UC_X86_REG_ST1:
case UC_X86_REG_ST2:
case UC_X86_REG_ST3:
case UC_X86_REG_ST4:
case UC_X86_REG_ST5:
case UC_X86_REG_ST6:
case UC_X86_REG_ST7: {
// value must be big enough to keep 80 bits (10 bytes)
memcpy(value, &FPST(regid - UC_X86_REG_ST0), 10);
return;
}
case UC_X86_REG_YMM0:
case UC_X86_REG_YMM1:
case UC_X86_REG_YMM2:
case UC_X86_REG_YMM3:
case UC_X86_REG_YMM4:
case UC_X86_REG_YMM5:
case UC_X86_REG_YMM6:
case UC_X86_REG_YMM7:
case UC_X86_REG_YMM8:
case UC_X86_REG_YMM9:
case UC_X86_REG_YMM10:
case UC_X86_REG_YMM11:
case UC_X86_REG_YMM12:
case UC_X86_REG_YMM13:
case UC_X86_REG_YMM14:
case UC_X86_REG_YMM15: {
float64 *dst = (float64 *)value;
ZMMReg *lo_reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
dst[0] = lo_reg->ZMM_Q(0);
dst[1] = lo_reg->ZMM_Q(1);
dst[2] = hi_reg->_d[0];
dst[3] = hi_reg->_d[1];
return;
}
case UC_X86_REG_FIP:
*(uint64_t *)value = env->fpip;
return;
case UC_X86_REG_FCS:
*(uint16_t *)value = env->fpcs;
return;
case UC_X86_REG_FDP:
*(uint64_t *)value = env->fpdp;
return;
case UC_X86_REG_FDS:
*(uint16_t *)value = env->fpds;
return;
case UC_X86_REG_FOP:
*(uint16_t *)value = env->fpop;
return;
}
switch (mode) {
default:
break;
case UC_MODE_16:
switch (regid) {
default:
break;
case UC_X86_REG_ES:
*(int16_t *)value = env->segs[R_ES].selector;
return;
case UC_X86_REG_SS:
*(int16_t *)value = env->segs[R_SS].selector;
return;
case UC_X86_REG_DS:
*(int16_t *)value = env->segs[R_DS].selector;
return;
case UC_X86_REG_FS:
*(int16_t *)value = env->segs[R_FS].selector;
return;
case UC_X86_REG_GS:
*(int16_t *)value = env->segs[R_GS].selector;
return;
case UC_X86_REG_FS_BASE:
*(uint32_t *)value = (uint32_t)env->segs[R_FS].base;
return;
}
// fall-thru
case UC_MODE_32:
switch (regid) {
default:
break;
case UC_X86_REG_CR0:
case UC_X86_REG_CR1:
case UC_X86_REG_CR2:
case UC_X86_REG_CR3:
case UC_X86_REG_CR4:
*(int32_t *)value = env->cr[regid - UC_X86_REG_CR0];
break;
case UC_X86_REG_DR0:
case UC_X86_REG_DR1:
case UC_X86_REG_DR2:
case UC_X86_REG_DR3:
case UC_X86_REG_DR4:
case UC_X86_REG_DR5:
case UC_X86_REG_DR6:
case UC_X86_REG_DR7:
*(int32_t *)value = env->dr[regid - UC_X86_REG_DR0];
break;
case UC_X86_REG_FLAGS:
*(int16_t *)value = cpu_compute_eflags(env);
break;
case UC_X86_REG_EFLAGS:
*(int32_t *)value = cpu_compute_eflags(env);
break;
case UC_X86_REG_EAX:
*(int32_t *)value = env->regs[R_EAX];
break;
case UC_X86_REG_AX:
*(int16_t *)value = READ_WORD(env->regs[R_EAX]);
break;
case UC_X86_REG_AH:
*(int8_t *)value = READ_BYTE_H(env->regs[R_EAX]);
break;
case UC_X86_REG_AL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_EAX]);
break;
case UC_X86_REG_EBX:
*(int32_t *)value = env->regs[R_EBX];
break;
case UC_X86_REG_BX:
*(int16_t *)value = READ_WORD(env->regs[R_EBX]);
break;
case UC_X86_REG_BH:
*(int8_t *)value = READ_BYTE_H(env->regs[R_EBX]);
break;
case UC_X86_REG_BL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_EBX]);
break;
case UC_X86_REG_ECX:
*(int32_t *)value = env->regs[R_ECX];
break;
case UC_X86_REG_CX:
*(int16_t *)value = READ_WORD(env->regs[R_ECX]);
break;
case UC_X86_REG_CH:
*(int8_t *)value = READ_BYTE_H(env->regs[R_ECX]);
break;
case UC_X86_REG_CL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_ECX]);
break;
case UC_X86_REG_EDX:
*(int32_t *)value = env->regs[R_EDX];
break;
case UC_X86_REG_DX:
*(int16_t *)value = READ_WORD(env->regs[R_EDX]);
break;
case UC_X86_REG_DH:
*(int8_t *)value = READ_BYTE_H(env->regs[R_EDX]);
break;
case UC_X86_REG_DL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_EDX]);
break;
case UC_X86_REG_ESP:
*(int32_t *)value = env->regs[R_ESP];
break;
case UC_X86_REG_SP:
*(int16_t *)value = READ_WORD(env->regs[R_ESP]);
break;
case UC_X86_REG_EBP:
*(int32_t *)value = env->regs[R_EBP];
break;
case UC_X86_REG_BP:
*(int16_t *)value = READ_WORD(env->regs[R_EBP]);
break;
case UC_X86_REG_ESI:
*(int32_t *)value = env->regs[R_ESI];
break;
case UC_X86_REG_SI:
*(int16_t *)value = READ_WORD(env->regs[R_ESI]);
break;
case UC_X86_REG_EDI:
*(int32_t *)value = env->regs[R_EDI];
break;
case UC_X86_REG_DI:
*(int16_t *)value = READ_WORD(env->regs[R_EDI]);
break;
case UC_X86_REG_EIP:
*(int32_t *)value = env->eip;
break;
case UC_X86_REG_IP:
*(int16_t *)value = READ_WORD(env->eip);
break;
case UC_X86_REG_CS:
*(int16_t *)value = (uint16_t)env->segs[R_CS].selector;
break;
case UC_X86_REG_DS:
*(int16_t *)value = (uint16_t)env->segs[R_DS].selector;
break;
case UC_X86_REG_SS:
*(int16_t *)value = (uint16_t)env->segs[R_SS].selector;
break;
case UC_X86_REG_ES:
*(int16_t *)value = (uint16_t)env->segs[R_ES].selector;
break;
case UC_X86_REG_FS:
*(int16_t *)value = (uint16_t)env->segs[R_FS].selector;
break;
case UC_X86_REG_GS:
*(int16_t *)value = (uint16_t)env->segs[R_GS].selector;
break;
case UC_X86_REG_IDTR:
((uc_x86_mmr *)value)->limit = (uint16_t)env->idt.limit;
((uc_x86_mmr *)value)->base = (uint32_t)env->idt.base;
break;
case UC_X86_REG_GDTR:
((uc_x86_mmr *)value)->limit = (uint16_t)env->gdt.limit;
((uc_x86_mmr *)value)->base = (uint32_t)env->gdt.base;
break;
case UC_X86_REG_LDTR:
((uc_x86_mmr *)value)->limit = env->ldt.limit;
((uc_x86_mmr *)value)->base = (uint32_t)env->ldt.base;
((uc_x86_mmr *)value)->selector = (uint16_t)env->ldt.selector;
((uc_x86_mmr *)value)->flags = env->ldt.flags;
break;
case UC_X86_REG_TR:
((uc_x86_mmr *)value)->limit = env->tr.limit;
((uc_x86_mmr *)value)->base = (uint32_t)env->tr.base;
((uc_x86_mmr *)value)->selector = (uint16_t)env->tr.selector;
((uc_x86_mmr *)value)->flags = env->tr.flags;
break;
case UC_X86_REG_MSR:
x86_msr_read(env, (uc_x86_msr *)value);
break;
case UC_X86_REG_MXCSR:
*(uint32_t *)value = env->mxcsr;
break;
case UC_X86_REG_FS_BASE:
*(uint32_t *)value = (uint32_t)env->segs[R_FS].base;
break;
}
break;
#ifdef TARGET_X86_64
case UC_MODE_64:
switch (regid) {
default:
break;
case UC_X86_REG_CR0:
case UC_X86_REG_CR1:
case UC_X86_REG_CR2:
case UC_X86_REG_CR3:
case UC_X86_REG_CR4:
*(int64_t *)value = env->cr[regid - UC_X86_REG_CR0];
break;
case UC_X86_REG_DR0:
case UC_X86_REG_DR1:
case UC_X86_REG_DR2:
case UC_X86_REG_DR3:
case UC_X86_REG_DR4:
case UC_X86_REG_DR5:
case UC_X86_REG_DR6:
case UC_X86_REG_DR7:
*(int64_t *)value = env->dr[regid - UC_X86_REG_DR0];
break;
case UC_X86_REG_FLAGS:
*(int16_t *)value = cpu_compute_eflags(env);
break;
case UC_X86_REG_EFLAGS:
*(int32_t *)value = cpu_compute_eflags(env);
break;
case UC_X86_REG_RFLAGS:
*(int64_t *)value = cpu_compute_eflags(env);
break;
case UC_X86_REG_RAX:
*(uint64_t *)value = env->regs[R_EAX];
break;
case UC_X86_REG_EAX:
*(int32_t *)value = READ_DWORD(env->regs[R_EAX]);
break;
case UC_X86_REG_AX:
*(int16_t *)value = READ_WORD(env->regs[R_EAX]);
break;
case UC_X86_REG_AH:
*(int8_t *)value = READ_BYTE_H(env->regs[R_EAX]);
break;
case UC_X86_REG_AL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_EAX]);
break;
case UC_X86_REG_RBX:
*(uint64_t *)value = env->regs[R_EBX];
break;
case UC_X86_REG_EBX:
*(int32_t *)value = READ_DWORD(env->regs[R_EBX]);
break;
case UC_X86_REG_BX:
*(int16_t *)value = READ_WORD(env->regs[R_EBX]);
break;
case UC_X86_REG_BH:
*(int8_t *)value = READ_BYTE_H(env->regs[R_EBX]);
break;
case UC_X86_REG_BL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_EBX]);
break;
case UC_X86_REG_RCX:
*(uint64_t *)value = env->regs[R_ECX];
break;
case UC_X86_REG_ECX:
*(int32_t *)value = READ_DWORD(env->regs[R_ECX]);
break;
case UC_X86_REG_CX:
*(int16_t *)value = READ_WORD(env->regs[R_ECX]);
break;
case UC_X86_REG_CH:
*(int8_t *)value = READ_BYTE_H(env->regs[R_ECX]);
break;
case UC_X86_REG_CL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_ECX]);
break;
case UC_X86_REG_RDX:
*(uint64_t *)value = env->regs[R_EDX];
break;
case UC_X86_REG_EDX:
*(int32_t *)value = READ_DWORD(env->regs[R_EDX]);
break;
case UC_X86_REG_DX:
*(int16_t *)value = READ_WORD(env->regs[R_EDX]);
break;
case UC_X86_REG_DH:
*(int8_t *)value = READ_BYTE_H(env->regs[R_EDX]);
break;
case UC_X86_REG_DL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_EDX]);
break;
case UC_X86_REG_RSP:
*(uint64_t *)value = env->regs[R_ESP];
break;
case UC_X86_REG_ESP:
*(int32_t *)value = READ_DWORD(env->regs[R_ESP]);
break;
case UC_X86_REG_SP:
*(int16_t *)value = READ_WORD(env->regs[R_ESP]);
break;
case UC_X86_REG_SPL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_ESP]);
break;
case UC_X86_REG_RBP:
*(uint64_t *)value = env->regs[R_EBP];
break;
case UC_X86_REG_EBP:
*(int32_t *)value = READ_DWORD(env->regs[R_EBP]);
break;
case UC_X86_REG_BP:
*(int16_t *)value = READ_WORD(env->regs[R_EBP]);
break;
case UC_X86_REG_BPL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_EBP]);
break;
case UC_X86_REG_RSI:
*(uint64_t *)value = env->regs[R_ESI];
break;
case UC_X86_REG_ESI:
*(int32_t *)value = READ_DWORD(env->regs[R_ESI]);
break;
case UC_X86_REG_SI:
*(int16_t *)value = READ_WORD(env->regs[R_ESI]);
break;
case UC_X86_REG_SIL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_ESI]);
break;
case UC_X86_REG_RDI:
*(uint64_t *)value = env->regs[R_EDI];
break;
case UC_X86_REG_EDI:
*(int32_t *)value = READ_DWORD(env->regs[R_EDI]);
break;
case UC_X86_REG_DI:
*(int16_t *)value = READ_WORD(env->regs[R_EDI]);
break;
case UC_X86_REG_DIL:
*(int8_t *)value = READ_BYTE_L(env->regs[R_EDI]);
break;
case UC_X86_REG_RIP:
*(uint64_t *)value = env->eip;
break;
case UC_X86_REG_EIP:
*(int32_t *)value = READ_DWORD(env->eip);
break;
case UC_X86_REG_IP:
*(int16_t *)value = READ_WORD(env->eip);
break;
case UC_X86_REG_CS:
*(int16_t *)value = (uint16_t)env->segs[R_CS].selector;
break;
case UC_X86_REG_DS:
*(int16_t *)value = (uint16_t)env->segs[R_DS].selector;
break;
case UC_X86_REG_SS:
*(int16_t *)value = (uint16_t)env->segs[R_SS].selector;
break;
case UC_X86_REG_ES:
*(int16_t *)value = (uint16_t)env->segs[R_ES].selector;
break;
case UC_X86_REG_FS:
*(int16_t *)value = (uint16_t)env->segs[R_FS].selector;
break;
case UC_X86_REG_GS:
*(int16_t *)value = (uint16_t)env->segs[R_GS].selector;
break;
case UC_X86_REG_R8:
*(int64_t *)value = READ_QWORD(env->regs[8]);
break;
case UC_X86_REG_R8D:
*(int32_t *)value = READ_DWORD(env->regs[8]);
break;
case UC_X86_REG_R8W:
*(int16_t *)value = READ_WORD(env->regs[8]);
break;
case UC_X86_REG_R8B:
*(int8_t *)value = READ_BYTE_L(env->regs[8]);
break;
case UC_X86_REG_R9:
*(int64_t *)value = READ_QWORD(env->regs[9]);
break;
case UC_X86_REG_R9D:
*(int32_t *)value = READ_DWORD(env->regs[9]);
break;
case UC_X86_REG_R9W:
*(int16_t *)value = READ_WORD(env->regs[9]);
break;
case UC_X86_REG_R9B:
*(int8_t *)value = READ_BYTE_L(env->regs[9]);
break;
case UC_X86_REG_R10:
*(int64_t *)value = READ_QWORD(env->regs[10]);
break;
case UC_X86_REG_R10D:
*(int32_t *)value = READ_DWORD(env->regs[10]);
break;
case UC_X86_REG_R10W:
*(int16_t *)value = READ_WORD(env->regs[10]);
break;
case UC_X86_REG_R10B:
*(int8_t *)value = READ_BYTE_L(env->regs[10]);
break;
case UC_X86_REG_R11:
*(int64_t *)value = READ_QWORD(env->regs[11]);
break;
case UC_X86_REG_R11D:
*(int32_t *)value = READ_DWORD(env->regs[11]);
break;
case UC_X86_REG_R11W:
*(int16_t *)value = READ_WORD(env->regs[11]);
break;
case UC_X86_REG_R11B:
*(int8_t *)value = READ_BYTE_L(env->regs[11]);
break;
case UC_X86_REG_R12:
*(int64_t *)value = READ_QWORD(env->regs[12]);
break;
case UC_X86_REG_R12D:
*(int32_t *)value = READ_DWORD(env->regs[12]);
break;
case UC_X86_REG_R12W:
*(int16_t *)value = READ_WORD(env->regs[12]);
break;
case UC_X86_REG_R12B:
*(int8_t *)value = READ_BYTE_L(env->regs[12]);
break;
case UC_X86_REG_R13:
*(int64_t *)value = READ_QWORD(env->regs[13]);
break;
case UC_X86_REG_R13D:
*(int32_t *)value = READ_DWORD(env->regs[13]);
break;
case UC_X86_REG_R13W:
*(int16_t *)value = READ_WORD(env->regs[13]);
break;
case UC_X86_REG_R13B:
*(int8_t *)value = READ_BYTE_L(env->regs[13]);
break;
case UC_X86_REG_R14:
*(int64_t *)value = READ_QWORD(env->regs[14]);
break;
case UC_X86_REG_R14D:
*(int32_t *)value = READ_DWORD(env->regs[14]);
break;
case UC_X86_REG_R14W:
*(int16_t *)value = READ_WORD(env->regs[14]);
break;
case UC_X86_REG_R14B:
*(int8_t *)value = READ_BYTE_L(env->regs[14]);
break;
case UC_X86_REG_R15:
*(int64_t *)value = READ_QWORD(env->regs[15]);
break;
case UC_X86_REG_R15D:
*(int32_t *)value = READ_DWORD(env->regs[15]);
break;
case UC_X86_REG_R15W:
*(int16_t *)value = READ_WORD(env->regs[15]);
break;
case UC_X86_REG_R15B:
*(int8_t *)value = READ_BYTE_L(env->regs[15]);
break;
case UC_X86_REG_IDTR:
((uc_x86_mmr *)value)->limit = (uint16_t)env->idt.limit;
((uc_x86_mmr *)value)->base = env->idt.base;
break;
case UC_X86_REG_GDTR:
((uc_x86_mmr *)value)->limit = (uint16_t)env->gdt.limit;
((uc_x86_mmr *)value)->base = env->gdt.base;
break;
case UC_X86_REG_LDTR:
((uc_x86_mmr *)value)->limit = env->ldt.limit;
((uc_x86_mmr *)value)->base = env->ldt.base;
((uc_x86_mmr *)value)->selector = (uint16_t)env->ldt.selector;
((uc_x86_mmr *)value)->flags = env->ldt.flags;
break;
case UC_X86_REG_TR:
((uc_x86_mmr *)value)->limit = env->tr.limit;
((uc_x86_mmr *)value)->base = env->tr.base;
((uc_x86_mmr *)value)->selector = (uint16_t)env->tr.selector;
((uc_x86_mmr *)value)->flags = env->tr.flags;
break;
case UC_X86_REG_MSR:
x86_msr_read(env, (uc_x86_msr *)value);
break;
case UC_X86_REG_MXCSR:
*(uint32_t *)value = env->mxcsr;
break;
case UC_X86_REG_XMM8:
case UC_X86_REG_XMM9:
case UC_X86_REG_XMM10:
case UC_X86_REG_XMM11:
case UC_X86_REG_XMM12:
case UC_X86_REG_XMM13:
case UC_X86_REG_XMM14:
case UC_X86_REG_XMM15: {
float64 *dst = (float64 *)value;
ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
dst[0] = reg->ZMM_Q(0);
dst[1] = reg->ZMM_Q(1);
break;
}
case UC_X86_REG_FS_BASE:
*(uint64_t *)value = (uint64_t)env->segs[R_FS].base;
break;
case UC_X86_REG_GS_BASE:
*(uint64_t *)value = (uint64_t)env->segs[R_GS].base;
break;
}
break;
#endif
}
return;
}
static int reg_write(CPUX86State *env, unsigned int regid, const void *value,
uc_mode mode)
{
int ret;
switch (regid) {
default:
break;
case UC_X86_REG_FP0:
case UC_X86_REG_FP1:
case UC_X86_REG_FP2:
case UC_X86_REG_FP3:
case UC_X86_REG_FP4:
case UC_X86_REG_FP5:
case UC_X86_REG_FP6:
case UC_X86_REG_FP7: {
uint64_t mant = *(uint64_t *)value;
uint16_t upper = *(uint16_t *)((char *)value + sizeof(uint64_t));
env->fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper);
}
return 0;
case UC_X86_REG_FPSW: {
uint16_t fpus = *(uint16_t *)value;
env->fpus = fpus & ~0x3800;
env->fpstt = (fpus >> 11) & 0x7;
}
return 0;
case UC_X86_REG_FPCW:
cpu_set_fpuc(env, *(uint16_t *)value);
return 0;
case UC_X86_REG_FPTAG: {
int i;
uint16_t fptag = *(uint16_t *)value;
for (i = 0; i < 8; i++) {
env->fptags[i] = ((fptag & 3) == 3);
fptag >>= 2;
}
return 0;
} break;
case UC_X86_REG_XMM0:
case UC_X86_REG_XMM1:
case UC_X86_REG_XMM2:
case UC_X86_REG_XMM3:
case UC_X86_REG_XMM4:
case UC_X86_REG_XMM5:
case UC_X86_REG_XMM6:
case UC_X86_REG_XMM7: {
float64 *src = (float64 *)value;
ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
reg->ZMM_Q(0) = src[0];
reg->ZMM_Q(1) = src[1];
return 0;
}
case UC_X86_REG_ST0:
case UC_X86_REG_ST1:
case UC_X86_REG_ST2:
case UC_X86_REG_ST3:
case UC_X86_REG_ST4:
case UC_X86_REG_ST5:
case UC_X86_REG_ST6:
case UC_X86_REG_ST7: {
// value must be big enough to keep 80 bits (10 bytes)
memcpy(&FPST(regid - UC_X86_REG_ST0), value, 10);
return 0;
}
case UC_X86_REG_YMM0:
case UC_X86_REG_YMM1:
case UC_X86_REG_YMM2:
case UC_X86_REG_YMM3:
case UC_X86_REG_YMM4:
case UC_X86_REG_YMM5:
case UC_X86_REG_YMM6:
case UC_X86_REG_YMM7:
case UC_X86_REG_YMM8:
case UC_X86_REG_YMM9:
case UC_X86_REG_YMM10:
case UC_X86_REG_YMM11:
case UC_X86_REG_YMM12:
case UC_X86_REG_YMM13:
case UC_X86_REG_YMM14:
case UC_X86_REG_YMM15: {
float64 *src = (float64 *)value;
ZMMReg *lo_reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
lo_reg->ZMM_Q(0) = src[0];
lo_reg->ZMM_Q(1) = src[1];
// YMM is not supported by QEMU at all
// As of qemu 5.0.1, ymmh_regs is nowhere used.
hi_reg->_d[0] = src[2];
hi_reg->_d[1] = src[3];
return 0;
}
case UC_X86_REG_FIP:
env->fpip = *(uint64_t *)value;
return 0;
case UC_X86_REG_FCS:
env->fpcs = *(uint16_t *)value;
return 0;
case UC_X86_REG_FDP:
env->fpdp = *(uint64_t *)value;
return 0;
case UC_X86_REG_FDS:
env->fpds = *(uint16_t *)value;
return 0;
case UC_X86_REG_FOP:
env->fpop = *(uint16_t *)value;
return 0;
}
switch (mode) {
default:
break;
case UC_MODE_16:
switch (regid) {
default:
break;
case UC_X86_REG_ES:
load_seg_16_helper(env, R_ES, *(uint16_t *)value);
return 0;
case UC_X86_REG_SS:
load_seg_16_helper(env, R_SS, *(uint16_t *)value);
return 0;
case UC_X86_REG_DS:
load_seg_16_helper(env, R_DS, *(uint16_t *)value);
return 0;
case UC_X86_REG_FS:
load_seg_16_helper(env, R_FS, *(uint16_t *)value);
return 0;
case UC_X86_REG_GS:
load_seg_16_helper(env, R_GS, *(uint16_t *)value);
return 0;
}
// fall-thru
case UC_MODE_32:
switch (regid) {
default:
break;
case UC_X86_REG_CR0:
cpu_x86_update_cr0(env, *(uint32_t *)value);
goto write_cr;
case UC_X86_REG_CR1:
case UC_X86_REG_CR2:
case UC_X86_REG_CR3:
cpu_x86_update_cr3(env, *(uint32_t *)value);
goto write_cr;
case UC_X86_REG_CR4:
cpu_x86_update_cr4(env, *(uint32_t *)value);
write_cr:
env->cr[regid - UC_X86_REG_CR0] = *(uint32_t *)value;
break;
case UC_X86_REG_DR0:
case UC_X86_REG_DR1:
case UC_X86_REG_DR2:
case UC_X86_REG_DR3:
case UC_X86_REG_DR4:
case UC_X86_REG_DR5:
case UC_X86_REG_DR6:
case UC_X86_REG_DR7:
env->dr[regid - UC_X86_REG_DR0] = *(uint32_t *)value;
break;
case UC_X86_REG_FLAGS:
cpu_load_eflags(env, *(uint16_t *)value, -1);
break;
case UC_X86_REG_EFLAGS:
cpu_load_eflags(env, *(uint32_t *)value, -1);
break;
case UC_X86_REG_EAX:
env->regs[R_EAX] = *(uint32_t *)value;
break;
case UC_X86_REG_AX:
WRITE_WORD(env->regs[R_EAX], *(uint16_t *)value);
break;
case UC_X86_REG_AH:
WRITE_BYTE_H(env->regs[R_EAX], *(uint8_t *)value);
break;
case UC_X86_REG_AL:
WRITE_BYTE_L(env->regs[R_EAX], *(uint8_t *)value);
break;
case UC_X86_REG_EBX:
env->regs[R_EBX] = *(uint32_t *)value;
break;
case UC_X86_REG_BX:
WRITE_WORD(env->regs[R_EBX], *(uint16_t *)value);
break;
case UC_X86_REG_BH:
WRITE_BYTE_H(env->regs[R_EBX], *(uint8_t *)value);
break;
case UC_X86_REG_BL:
WRITE_BYTE_L(env->regs[R_EBX], *(uint8_t *)value);
break;
case UC_X86_REG_ECX:
env->regs[R_ECX] = *(uint32_t *)value;
break;
case UC_X86_REG_CX:
WRITE_WORD(env->regs[R_ECX], *(uint16_t *)value);
break;
case UC_X86_REG_CH:
WRITE_BYTE_H(env->regs[R_ECX], *(uint8_t *)value);
break;
case UC_X86_REG_CL:
WRITE_BYTE_L(env->regs[R_ECX], *(uint8_t *)value);
break;
case UC_X86_REG_EDX:
env->regs[R_EDX] = *(uint32_t *)value;
break;
case UC_X86_REG_DX:
WRITE_WORD(env->regs[R_EDX], *(uint16_t *)value);
break;
case UC_X86_REG_DH:
WRITE_BYTE_H(env->regs[R_EDX], *(uint8_t *)value);
break;
case UC_X86_REG_DL:
WRITE_BYTE_L(env->regs[R_EDX], *(uint8_t *)value);
break;
case UC_X86_REG_ESP:
env->regs[R_ESP] = *(uint32_t *)value;
break;
case UC_X86_REG_SP:
WRITE_WORD(env->regs[R_ESP], *(uint16_t *)value);
break;
case UC_X86_REG_EBP:
env->regs[R_EBP] = *(uint32_t *)value;
break;
case UC_X86_REG_BP:
WRITE_WORD(env->regs[R_EBP], *(uint16_t *)value);
break;
case UC_X86_REG_ESI:
env->regs[R_ESI] = *(uint32_t *)value;
break;
case UC_X86_REG_SI:
WRITE_WORD(env->regs[R_ESI], *(uint16_t *)value);
break;
case UC_X86_REG_EDI:
env->regs[R_EDI] = *(uint32_t *)value;
break;
case UC_X86_REG_DI:
WRITE_WORD(env->regs[R_EDI], *(uint16_t *)value);
break;
case UC_X86_REG_EIP:
env->eip = *(uint32_t *)value;
break;
case UC_X86_REG_IP:
env->eip = *(uint16_t *)value;
break;
case UC_X86_REG_CS:
ret = uc_check_cpu_x86_load_seg(env, R_CS, *(uint16_t *)value);
if (ret) {
return ret;
}
cpu_x86_load_seg(env, R_CS, *(uint16_t *)value);
break;
case UC_X86_REG_DS:
ret = uc_check_cpu_x86_load_seg(env, R_DS, *(uint16_t *)value);
if (ret) {
return ret;
}
cpu_x86_load_seg(env, R_DS, *(uint16_t *)value);
break;
case UC_X86_REG_SS:
ret = uc_check_cpu_x86_load_seg(env, R_SS, *(uint16_t *)value);
if (ret) {
return ret;
}
cpu_x86_load_seg(env, R_SS, *(uint16_t *)value);
break;
case UC_X86_REG_ES:
ret = uc_check_cpu_x86_load_seg(env, R_ES, *(uint16_t *)value);
if (ret) {
return ret;
}
cpu_x86_load_seg(env, R_ES, *(uint16_t *)value);
break;
case UC_X86_REG_FS:
ret = uc_check_cpu_x86_load_seg(env, R_FS, *(uint16_t *)value);
if (ret) {
return ret;
}
cpu_x86_load_seg(env, R_FS, *(uint16_t *)value);
break;
case UC_X86_REG_GS:
ret = uc_check_cpu_x86_load_seg(env, R_GS, *(uint16_t *)value);
if (ret) {
return ret;
}
cpu_x86_load_seg(env, R_GS, *(uint16_t *)value);
break;
case UC_X86_REG_IDTR:
env->idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit;
env->idt.base = (uint32_t)((uc_x86_mmr *)value)->base;
break;
case UC_X86_REG_GDTR:
env->gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit;
env->gdt.base = (uint32_t)((uc_x86_mmr *)value)->base;
break;
case UC_X86_REG_LDTR:
env->ldt.limit = ((uc_x86_mmr *)value)->limit;
env->ldt.base = (uint32_t)((uc_x86_mmr *)value)->base;
env->ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector;
env->ldt.flags = ((uc_x86_mmr *)value)->flags;
break;
case UC_X86_REG_TR:
env->tr.limit = ((uc_x86_mmr *)value)->limit;
env->tr.base = (uint32_t)((uc_x86_mmr *)value)->base;
env->tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector;
env->tr.flags = ((uc_x86_mmr *)value)->flags;
break;
case UC_X86_REG_MSR:
x86_msr_write(env, (uc_x86_msr *)value);
break;
case UC_X86_REG_MXCSR:
cpu_set_mxcsr(env, *(uint32_t *)value);
break;
/*
// Don't think base registers are a "thing" on x86
case UC_X86_REG_FS_BASE:
env->segs[R_FS].base = *(uint32_t *)value;
continue;
case UC_X86_REG_GS_BASE:
env->segs[R_GS].base = *(uint32_t *)value;
continue;
*/
}
break;
#ifdef TARGET_X86_64
case UC_MODE_64:
switch (regid) {
default:
break;
case UC_X86_REG_CR0:
cpu_x86_update_cr0(env, *(uint32_t *) value);
goto write_cr64;
case UC_X86_REG_CR1:
case UC_X86_REG_CR2:
case UC_X86_REG_CR3:
cpu_x86_update_cr3(env, *(uint32_t *) value);
goto write_cr64;
case UC_X86_REG_CR4:
cpu_x86_update_cr4(env, *(uint32_t *) value);
write_cr64:
env->cr[regid - UC_X86_REG_CR0] = *(uint64_t *)value;
break;
case UC_X86_REG_DR0:
case UC_X86_REG_DR1:
case UC_X86_REG_DR2:
case UC_X86_REG_DR3:
case UC_X86_REG_DR4:
case UC_X86_REG_DR5:
case UC_X86_REG_DR6:
case UC_X86_REG_DR7:
env->dr[regid - UC_X86_REG_DR0] = *(uint64_t *)value;
break;
case UC_X86_REG_FLAGS:
cpu_load_eflags(env, *(uint16_t *)value, -1);
break;
case UC_X86_REG_EFLAGS:
cpu_load_eflags(env, *(uint32_t *)value, -1);
break;
case UC_X86_REG_RFLAGS:
cpu_load_eflags(env, *(uint64_t *)value, -1);
break;
case UC_X86_REG_RAX:
env->regs[R_EAX] = *(uint64_t *)value;
break;
case UC_X86_REG_EAX:
WRITE_DWORD(env->regs[R_EAX], *(uint32_t *)value);
break;
case UC_X86_REG_AX:
WRITE_WORD(env->regs[R_EAX], *(uint16_t *)value);
break;
case UC_X86_REG_AH:
WRITE_BYTE_H(env->regs[R_EAX], *(uint8_t *)value);
break;
case UC_X86_REG_AL:
WRITE_BYTE_L(env->regs[R_EAX], *(uint8_t *)value);
break;
case UC_X86_REG_RBX:
env->regs[R_EBX] = *(uint64_t *)value;
break;
case UC_X86_REG_EBX:
WRITE_DWORD(env->regs[R_EBX], *(uint32_t *)value);
break;
case UC_X86_REG_BX:
WRITE_WORD(env->regs[R_EBX], *(uint16_t *)value);
break;
case UC_X86_REG_BH:
WRITE_BYTE_H(env->regs[R_EBX], *(uint8_t *)value);
break;
case UC_X86_REG_BL:
WRITE_BYTE_L(env->regs[R_EBX], *(uint8_t *)value);
break;
case UC_X86_REG_RCX:
env->regs[R_ECX] = *(uint64_t *)value;
break;
case UC_X86_REG_ECX:
WRITE_DWORD(env->regs[R_ECX], *(uint32_t *)value);
break;
case UC_X86_REG_CX:
WRITE_WORD(env->regs[R_ECX], *(uint16_t *)value);
break;
case UC_X86_REG_CH:
WRITE_BYTE_H(env->regs[R_ECX], *(uint8_t *)value);
break;
case UC_X86_REG_CL:
WRITE_BYTE_L(env->regs[R_ECX], *(uint8_t *)value);
break;
case UC_X86_REG_RDX:
env->regs[R_EDX] = *(uint64_t *)value;
break;
case UC_X86_REG_EDX:
WRITE_DWORD(env->regs[R_EDX], *(uint32_t *)value);
break;
case UC_X86_REG_DX:
WRITE_WORD(env->regs[R_EDX], *(uint16_t *)value);
break;
case UC_X86_REG_DH:
WRITE_BYTE_H(env->regs[R_EDX], *(uint8_t *)value);
break;
case UC_X86_REG_DL:
WRITE_BYTE_L(env->regs[R_EDX], *(uint8_t *)value);
break;
case UC_X86_REG_RSP:
env->regs[R_ESP] = *(uint64_t *)value;
break;
case UC_X86_REG_ESP:
WRITE_DWORD(env->regs[R_ESP], *(uint32_t *)value);
break;
case UC_X86_REG_SP:
WRITE_WORD(env->regs[R_ESP], *(uint16_t *)value);
break;
case UC_X86_REG_SPL:
WRITE_BYTE_L(env->regs[R_ESP], *(uint8_t *)value);
break;
case UC_X86_REG_RBP:
env->regs[R_EBP] = *(uint64_t *)value;
break;
case UC_X86_REG_EBP:
WRITE_DWORD(env->regs[R_EBP], *(uint32_t *)value);
break;
case UC_X86_REG_BP:
WRITE_WORD(env->regs[R_EBP], *(uint16_t *)value);
break;
case UC_X86_REG_BPL:
WRITE_BYTE_L(env->regs[R_EBP], *(uint8_t *)value);
break;
case UC_X86_REG_RSI:
env->regs[R_ESI] = *(uint64_t *)value;
break;
case UC_X86_REG_ESI:
WRITE_DWORD(env->regs[R_ESI], *(uint32_t *)value);
break;
case UC_X86_REG_SI:
WRITE_WORD(env->regs[R_ESI], *(uint16_t *)value);
break;
case UC_X86_REG_SIL:
WRITE_BYTE_L(env->regs[R_ESI], *(uint8_t *)value);
break;
case UC_X86_REG_RDI:
env->regs[R_EDI] = *(uint64_t *)value;
break;
case UC_X86_REG_EDI:
WRITE_DWORD(env->regs[R_EDI], *(uint32_t *)value);
break;
case UC_X86_REG_DI:
WRITE_WORD(env->regs[R_EDI], *(uint16_t *)value);
break;
case UC_X86_REG_DIL:
WRITE_BYTE_L(env->regs[R_EDI], *(uint8_t *)value);
break;
case UC_X86_REG_RIP:
env->eip = *(uint64_t *)value;
break;
case UC_X86_REG_EIP:
env->eip = *(uint32_t *)value;
break;
case UC_X86_REG_IP:
WRITE_WORD(env->eip, *(uint16_t *)value);
break;
case UC_X86_REG_CS:
env->segs[R_CS].selector = *(uint16_t *)value;
break;
case UC_X86_REG_DS:
env->segs[R_DS].selector = *(uint16_t *)value;
break;
case UC_X86_REG_SS:
env->segs[R_SS].selector = *(uint16_t *)value;
break;
case UC_X86_REG_ES:
env->segs[R_ES].selector = *(uint16_t *)value;
break;
case UC_X86_REG_FS:
ret = uc_check_cpu_x86_load_seg(env, R_FS, *(uint16_t *)value);
if (ret) {
return ret;
}
cpu_x86_load_seg(env, R_FS, *(uint16_t *)value);
break;
case UC_X86_REG_GS:
ret = uc_check_cpu_x86_load_seg(env, R_GS, *(uint16_t *)value);
if (ret) {
return ret;
}
cpu_x86_load_seg(env, R_GS, *(uint16_t *)value);
break;
case UC_X86_REG_R8:
env->regs[8] = *(uint64_t *)value;
break;
case UC_X86_REG_R8D:
WRITE_DWORD(env->regs[8], *(uint32_t *)value);
break;
case UC_X86_REG_R8W:
WRITE_WORD(env->regs[8], *(uint16_t *)value);
break;
case UC_X86_REG_R8B:
WRITE_BYTE_L(env->regs[8], *(uint8_t *)value);
break;
case UC_X86_REG_R9:
env->regs[9] = *(uint64_t *)value;
break;
case UC_X86_REG_R9D:
WRITE_DWORD(env->regs[9], *(uint32_t *)value);
break;
case UC_X86_REG_R9W:
WRITE_WORD(env->regs[9], *(uint16_t *)value);
break;
case UC_X86_REG_R9B:
WRITE_BYTE_L(env->regs[9], *(uint8_t *)value);
break;
case UC_X86_REG_R10:
env->regs[10] = *(uint64_t *)value;
break;
case UC_X86_REG_R10D:
WRITE_DWORD(env->regs[10], *(uint32_t *)value);
break;
case UC_X86_REG_R10W:
WRITE_WORD(env->regs[10], *(uint16_t *)value);
break;
case UC_X86_REG_R10B:
WRITE_BYTE_L(env->regs[10], *(uint8_t *)value);
break;
case UC_X86_REG_R11:
env->regs[11] = *(uint64_t *)value;
break;
case UC_X86_REG_R11D:
WRITE_DWORD(env->regs[11], *(uint32_t *)value);
break;
case UC_X86_REG_R11W:
WRITE_WORD(env->regs[11], *(uint16_t *)value);
break;
case UC_X86_REG_R11B:
WRITE_BYTE_L(env->regs[11], *(uint8_t *)value);
break;
case UC_X86_REG_R12:
env->regs[12] = *(uint64_t *)value;
break;
case UC_X86_REG_R12D:
WRITE_DWORD(env->regs[12], *(uint32_t *)value);
break;
case UC_X86_REG_R12W:
WRITE_WORD(env->regs[12], *(uint16_t *)value);
break;
case UC_X86_REG_R12B:
WRITE_BYTE_L(env->regs[12], *(uint8_t *)value);
break;
case UC_X86_REG_R13:
env->regs[13] = *(uint64_t *)value;
break;
case UC_X86_REG_R13D:
WRITE_DWORD(env->regs[13], *(uint32_t *)value);
break;
case UC_X86_REG_R13W:
WRITE_WORD(env->regs[13], *(uint16_t *)value);
break;
case UC_X86_REG_R13B:
WRITE_BYTE_L(env->regs[13], *(uint8_t *)value);
break;
case UC_X86_REG_R14:
env->regs[14] = *(uint64_t *)value;
break;
case UC_X86_REG_R14D:
WRITE_DWORD(env->regs[14], *(uint32_t *)value);
break;
case UC_X86_REG_R14W:
WRITE_WORD(env->regs[14], *(uint16_t *)value);
break;
case UC_X86_REG_R14B:
WRITE_BYTE_L(env->regs[14], *(uint8_t *)value);
break;
case UC_X86_REG_R15:
env->regs[15] = *(uint64_t *)value;
break;
case UC_X86_REG_R15D:
WRITE_DWORD(env->regs[15], *(uint32_t *)value);
break;
case UC_X86_REG_R15W:
WRITE_WORD(env->regs[15], *(uint16_t *)value);
break;
case UC_X86_REG_R15B:
WRITE_BYTE_L(env->regs[15], *(uint8_t *)value);
break;
case UC_X86_REG_IDTR:
env->idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit;
env->idt.base = ((uc_x86_mmr *)value)->base;
break;
case UC_X86_REG_GDTR:
env->gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit;
env->gdt.base = ((uc_x86_mmr *)value)->base;
break;
case UC_X86_REG_LDTR:
env->ldt.limit = ((uc_x86_mmr *)value)->limit;
env->ldt.base = ((uc_x86_mmr *)value)->base;
env->ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector;
env->ldt.flags = ((uc_x86_mmr *)value)->flags;
break;
case UC_X86_REG_TR:
env->tr.limit = ((uc_x86_mmr *)value)->limit;
env->tr.base = ((uc_x86_mmr *)value)->base;
env->tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector;
env->tr.flags = ((uc_x86_mmr *)value)->flags;
break;
case UC_X86_REG_MSR:
x86_msr_write(env, (uc_x86_msr *)value);
break;
case UC_X86_REG_MXCSR:
cpu_set_mxcsr(env, *(uint32_t *)value);
break;
case UC_X86_REG_XMM8:
case UC_X86_REG_XMM9:
case UC_X86_REG_XMM10:
case UC_X86_REG_XMM11:
case UC_X86_REG_XMM12:
case UC_X86_REG_XMM13:
case UC_X86_REG_XMM14:
case UC_X86_REG_XMM15: {
float64 *src = (float64 *)value;
ZMMReg *reg = (ZMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
reg->ZMM_Q(0) = src[0];
reg->ZMM_Q(1) = src[1];
break;
}
case UC_X86_REG_FS_BASE:
env->segs[R_FS].base = *(uint64_t *)value;
return 0;
case UC_X86_REG_GS_BASE:
env->segs[R_GS].base = *(uint64_t *)value;
return 0;
}
break;
#endif
}
return 0;
}
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
int count)
{
CPUX86State *env = &(X86_CPU(uc->cpu)->env);
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_read(env, regid, value, uc->mode);
}
return 0;
}
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
int count)
{
CPUX86State *env = &(X86_CPU(uc->cpu)->env);
int i;
int ret;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
ret = reg_write(env, regid, value, uc->mode);
if (ret) {
return ret;
}
switch (uc->mode) {
default:
break;
case UC_MODE_32:
switch (regid) {
default:
break;
case UC_X86_REG_EIP:
case UC_X86_REG_IP:
// force to quit execution and flush TB
uc->quit_request = true;
break_translation_loop(uc);
break;
}
#ifdef TARGET_X86_64
case UC_MODE_64:
switch (regid) {
default:
break;
case UC_X86_REG_RIP:
case UC_X86_REG_EIP:
case UC_X86_REG_IP:
// force to quit execution and flush TB
uc->quit_request = true;
break_translation_loop(uc);
break;
}
#endif
}
}
return 0;
}
DEFAULT_VISIBILITY
int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs,
void **vals, int count)
{
CPUX86State *env = (CPUX86State *)ctx->data;
int i;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
void *value = vals[i];
reg_read(env, regid, value, ctx->mode);
}
return 0;
}
DEFAULT_VISIBILITY
int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs,
void *const *vals, int count)
{
CPUX86State *env = (CPUX86State *)ctx->data;
int i;
int ret;
for (i = 0; i < count; i++) {
unsigned int regid = regs[i];
const void *value = vals[i];
ret = reg_write(env, regid, value, ctx->mode);
if (ret) {
return ret;
}
}
return 0;
}
static bool x86_stop_interrupt(struct uc_struct *uc, int intno)
{
switch (intno) {
default:
return false;
case EXCP06_ILLOP:
return true;
}
}
static bool x86_insn_hook_validate(uint32_t insn_enum)
{
// for x86 we can only hook IN, OUT, and SYSCALL
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) {
return false;
}
return true;
}
static bool x86_opcode_hook_invalidate(uint32_t op, uint32_t flags)
{
if (op != UC_TCG_OP_SUB) {
return false;
}
switch (op) {
case UC_TCG_OP_SUB:
if ((flags & UC_TCG_OP_FLAG_CMP) && (flags & UC_TCG_OP_FLAG_DIRECT)) {
return false;
}
break;
default:
return false;
}
return true;
}
static int x86_cpus_init(struct uc_struct *uc, const char *cpu_model)
{
X86CPU *cpu;
cpu = cpu_x86_init(uc);
if (cpu == NULL) {
return -1;
}
return 0;
}
DEFAULT_VISIBILITY
void x86_uc_init(struct uc_struct *uc)
{
uc->reg_read = x86_reg_read;
uc->reg_write = x86_reg_write;
uc->reg_reset = x86_reg_reset;
uc->release = x86_release;
uc->set_pc = x86_set_pc;
uc->get_pc = x86_get_pc;
uc->stop_interrupt = x86_stop_interrupt;
uc->insn_hook_validate = x86_insn_hook_validate;
uc->opcode_hook_invalidate = x86_opcode_hook_invalidate;
uc->cpus_init = x86_cpus_init;
uc->cpu_context_size = offsetof(CPUX86State, retaddr);
uc_common_init(uc);
}
/* vim: set ts=4 sts=4 sw=4 et: */