qemu with hax to log dma reads & writes jcs.org/2018/11/12/vfio

kvm: x86: Save/restore FPU OP, IP and DP

These FPU states are properly maintained by KVM but not yet by TCG. So
far we unconditionally set them to 0 in the guest which may cause
state corruptions, though not with modern guests.

To avoid breaking backward migration, use a conditional subsection that
is only written if any of the three fields is non-zero. The guest's
FNINIT clears them frequently, and cleared IA32_MISC_ENABLE MSR[2]
reduces the probability of non-zero values further so that this
subsection is not expected to restrict migration in any common scenario.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
Signed-off-by: Avi Kivity <avi@redhat.com>

authored by

Jan Kiszka and committed by
Avi Kivity
42cc8fa6 eb47d7c5

+42 -5
+4
target-i386/cpu.h
··· 641 641 uint16_t fpuc; 642 642 uint8_t fptags[8]; /* 0 = valid, 1 = empty */ 643 643 FPReg fpregs[8]; 644 + /* KVM-only so far */ 645 + uint16_t fpop; 646 + uint64_t fpip; 647 + uint64_t fpdp; 644 648 645 649 /* emulator internal variables */ 646 650 float_status fp_status;
+15 -5
target-i386/kvm.c
··· 753 753 fpu.fsw = env->fpus & ~(7 << 11); 754 754 fpu.fsw |= (env->fpstt & 7) << 11; 755 755 fpu.fcw = env->fpuc; 756 + fpu.last_opcode = env->fpop; 757 + fpu.last_ip = env->fpip; 758 + fpu.last_dp = env->fpdp; 756 759 for (i = 0; i < 8; ++i) { 757 760 fpu.ftwx |= (!env->fptags[i]) << i; 758 761 } ··· 778 781 #ifdef KVM_CAP_XSAVE 779 782 int i, r; 780 783 struct kvm_xsave* xsave; 781 - uint16_t cwd, swd, twd, fop; 784 + uint16_t cwd, swd, twd; 782 785 783 786 if (!kvm_has_xsave()) { 784 787 return kvm_put_fpu(env); ··· 786 789 787 790 xsave = qemu_memalign(4096, sizeof(struct kvm_xsave)); 788 791 memset(xsave, 0, sizeof(struct kvm_xsave)); 789 - cwd = swd = twd = fop = 0; 792 + cwd = swd = twd = 0; 790 793 swd = env->fpus & ~(7 << 11); 791 794 swd |= (env->fpstt & 7) << 11; 792 795 cwd = env->fpuc; ··· 794 797 twd |= (!env->fptags[i]) << i; 795 798 } 796 799 xsave->region[0] = (uint32_t)(swd << 16) + cwd; 797 - xsave->region[1] = (uint32_t)(fop << 16) + twd; 800 + xsave->region[1] = (uint32_t)(env->fpop << 16) + twd; 801 + memcpy(&xsave->region[XSAVE_CWD_RIP], &env->fpip, sizeof(env->fpip)); 802 + memcpy(&xsave->region[XSAVE_CWD_RDP], &env->fpdp, sizeof(env->fpdp)); 798 803 memcpy(&xsave->region[XSAVE_ST_SPACE], env->fpregs, 799 804 sizeof env->fpregs); 800 805 memcpy(&xsave->region[XSAVE_XMM_SPACE], env->xmm_regs, ··· 970 975 env->fpstt = (fpu.fsw >> 11) & 7; 971 976 env->fpus = fpu.fsw; 972 977 env->fpuc = fpu.fcw; 978 + env->fpop = fpu.last_opcode; 979 + env->fpip = fpu.last_ip; 980 + env->fpdp = fpu.last_dp; 973 981 for (i = 0; i < 8; ++i) { 974 982 env->fptags[i] = !((fpu.ftwx >> i) & 1); 975 983 } ··· 985 993 #ifdef KVM_CAP_XSAVE 986 994 struct kvm_xsave* xsave; 987 995 int ret, i; 988 - uint16_t cwd, swd, twd, fop; 996 + uint16_t cwd, swd, twd; 989 997 990 998 if (!kvm_has_xsave()) { 991 999 return kvm_get_fpu(env); ··· 1001 1009 cwd = (uint16_t)xsave->region[0]; 1002 1010 swd = (uint16_t)(xsave->region[0] >> 16); 1003 1011 twd = (uint16_t)xsave->region[1]; 1004 - fop = (uint16_t)(xsave->region[1] >> 16); 1012 + env->fpop = (uint16_t)(xsave->region[1] >> 16); 1005 1013 env->fpstt = (swd >> 11) & 7; 1006 1014 env->fpus = swd; 1007 1015 env->fpuc = cwd; 1008 1016 for (i = 0; i < 8; ++i) { 1009 1017 env->fptags[i] = !((twd >> i) & 1); 1010 1018 } 1019 + memcpy(&env->fpip, &xsave->region[XSAVE_CWD_RIP], sizeof(env->fpip)); 1020 + memcpy(&env->fpdp, &xsave->region[XSAVE_CWD_RDP], sizeof(env->fpdp)); 1011 1021 env->mxcsr = xsave->region[XSAVE_MXCSR]; 1012 1022 memcpy(env->fpregs, &xsave->region[XSAVE_ST_SPACE], 1013 1023 sizeof env->fpregs);
+23
target-i386/machine.c
··· 290 290 } 291 291 }; 292 292 293 + static bool fpop_ip_dp_needed(void *opaque) 294 + { 295 + CPUState *env = opaque; 296 + 297 + return env->fpop != 0 || env->fpip != 0 || env->fpdp != 0; 298 + } 299 + 300 + static const VMStateDescription vmstate_fpop_ip_dp = { 301 + .name = "cpu/fpop_ip_dp", 302 + .version_id = 1, 303 + .minimum_version_id = 1, 304 + .minimum_version_id_old = 1, 305 + .fields = (VMStateField []) { 306 + VMSTATE_UINT16_V(fpop, CPUState, 13), 307 + VMSTATE_UINT64_V(fpip, CPUState, 13), 308 + VMSTATE_UINT64_V(fpdp, CPUState, 13), 309 + VMSTATE_END_OF_LIST() 310 + } 311 + }; 312 + 293 313 static const VMStateDescription vmstate_cpu = { 294 314 .name = "cpu", 295 315 .version_id = CPU_SAVE_VERSION, ··· 397 417 { 398 418 .vmsd = &vmstate_async_pf_msr, 399 419 .needed = async_pf_msr_needed, 420 + } , { 421 + .vmsd = &vmstate_fpop_ip_dp, 422 + .needed = fpop_ip_dp_needed, 400 423 } , { 401 424 /* empty */ 402 425 }