From 0a3799eadac6ad335551d4fb30328a9e6c802e8e Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 19:14:33 -0300 Subject: [PATCH] FPU control word and tags --- bindings/python/unicorn/x86_const.py | 4 ++- include/unicorn/x86.h | 3 +- qemu/target-i386/unicorn.c | 52 +++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index a0cf0abc..8f93c0e0 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -248,7 +248,9 @@ UC_X86_REG_IDTR = 242 UC_X86_REG_GDTR = 243 UC_X86_REG_LDTR = 244 UC_X86_REG_TR = 245 -UC_X86_REG_ENDING = 246 +UC_X86_REG_FPTAGS = 246 +UC_X86_REG_FPCW = 247 +UC_X86_REG_ENDING = 248 # X86 instructions diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 51401eba..88559730 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -73,7 +73,8 @@ typedef enum uc_x86_reg { UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D, UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, - UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, + UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, + UC_X86_REG_FPTAG, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 3ab525c3..4b285f93 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -152,10 +152,42 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_FPSW: { uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; - fpus = fpus & ~(7<<11); - fpus |= (X86_CPU(uc, mycpu)->env.fpstt&7)<<11; + fpus = fpus & ~0x3800; + fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + break; + 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 (X86_CPU(uc, mycpu)->env.fptags[i]) { + fptag |= 3; + } else { + tmp.d = X86_CPU(uc, mycpu)->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; + } break; } @@ -606,10 +638,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_FPSW: { uint16_t fpus = *(uint16_t*) value; - X86_CPU(uc, mycpu)->env.fpus = fpus; - X86_CPU(uc, mycpu)->env.fpstt = (fpus>>11)&7; + X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800; + X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7; } break; + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + break; + case UC_X86_REG_FPTAG: + { + int i; + uint16_t fptag = *(uint16_t*) value; + for (i = 0; i < 8; i++) { + X86_CPU(uc, mycpu)->env.fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } + } } switch(uc->mode) {