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

tcg/svm: use host cr4 during NPT page table walk

During a page table walk of TCG+SVM the code in target/i386/excp_helper.c
get_hphys() uses the cr4 register of the guest instead of the hypervisor
to check for the PSE bit. In the test case we have, the guest have not
enabled (yet) the PSE bit and so the page table walk results in a wrong
host physical address resolution and wrong content read by the guest.

Attached patch is against 4.2.1, but works also on 3.1.0. It fixes the
issue for our automated testcase, which is a 32bit hypervisor w/o PAE
support running a guest VM with tcg+svm.

The test worked beforehand up to qemu 2.12, started to fail with qemu 3.0
and later. The added TCG/SVM NPT commit seems to introduce the regression.

In case someone want to try to reproduce it, the iso is at [0], the good
case is [1] and the failing case is [2]. The used commandline is:

qemu-system-i386 -no-kvm -nographic -cpu phenom -m 512 -machine q35 -cdrom seoul-vmm-test.iso

[0] https://depot.genode.org/alex-ab/images/seoul-vmm-test.iso
[1] https://depot.genode.org/alex-ab/images/seoul-vmm-good.txt
[2] https://depot.genode.org/alex-ab/images/seoul-vmm-bad.txt

Signed-off-by: Alexander Boettcher <alexander.boettcher@genode-labs.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Alexander Boettcher and committed by
Paolo Bonzini
a2d57703 45db94cc

+9 -3
+2 -2
target/i386/excp_helper.c
··· 262 262 } 263 263 ptep = pde | PG_NX_MASK; 264 264 265 - /* if PSE bit is set, then we use a 4MB page */ 266 - if ((pde & PG_PSE_MASK) && (env->cr[4] & CR4_PSE_MASK)) { 265 + /* if host cr4 PSE bit is set, then we use a 4MB page */ 266 + if ((pde & PG_PSE_MASK) && (env->nested_pg_mode & SVM_NPT_PSE)) { 267 267 page_size = 4096 * 1024; 268 268 pte_addr = pde_addr; 269 269
+1
target/i386/svm.h
··· 135 135 #define SVM_NPT_PAE (1 << 0) 136 136 #define SVM_NPT_LMA (1 << 1) 137 137 #define SVM_NPT_NXE (1 << 2) 138 + #define SVM_NPT_PSE (1 << 3) 138 139 139 140 #define SVM_NPTEXIT_P (1ULL << 0) 140 141 #define SVM_NPTEXIT_RW (1ULL << 1)
+6 -1
target/i386/svm_helper.c
··· 209 209 210 210 nested_ctl = x86_ldq_phys(cs, env->vm_vmcb + offsetof(struct vmcb, 211 211 control.nested_ctl)); 212 + 213 + env->nested_pg_mode = 0; 214 + 212 215 if (nested_ctl & SVM_NPT_ENABLED) { 213 216 env->nested_cr3 = x86_ldq_phys(cs, 214 217 env->vm_vmcb + offsetof(struct vmcb, 215 218 control.nested_cr3)); 216 219 env->hflags2 |= HF2_NPT_MASK; 217 220 218 - env->nested_pg_mode = 0; 219 221 if (env->cr[4] & CR4_PAE_MASK) { 220 222 env->nested_pg_mode |= SVM_NPT_PAE; 223 + } 224 + if (env->cr[4] & CR4_PSE_MASK) { 225 + env->nested_pg_mode |= SVM_NPT_PSE; 221 226 } 222 227 if (env->hflags & HF_LMA_MASK) { 223 228 env->nested_pg_mode |= SVM_NPT_LMA;