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

tcg: Record code_gen_buffer address for user-only memory helpers

When we handle a signal from a fault within a user-only memory helper,
we cannot cpu_restore_state with the PC found within the signal frame.
Use a TLS variable, helper_retaddr, to record the unwind start point
to find the faulting guest insn.

Tested-by: Alex Bennée <alex.bennee@linaro.org>
Reviewed-by: Alex Bennée <alex.bennee@linaro.org>
Reported-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

+87 -20
+25 -7
accel/tcg/atomic_template.h
··· 62 62 ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 63 63 { 64 64 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 65 - return atomic_cmpxchg__nocheck(haddr, cmpv, newv); 65 + DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, cmpv, newv); 66 + ATOMIC_MMU_CLEANUP; 67 + return ret; 66 68 } 67 69 68 70 #if DATA_SIZE >= 16 ··· 70 72 { 71 73 DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 72 74 __atomic_load(haddr, &val, __ATOMIC_RELAXED); 75 + ATOMIC_MMU_CLEANUP; 73 76 return val; 74 77 } 75 78 ··· 78 81 { 79 82 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 80 83 __atomic_store(haddr, &val, __ATOMIC_RELAXED); 84 + ATOMIC_MMU_CLEANUP; 81 85 } 82 86 #else 83 87 ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 84 88 ABI_TYPE val EXTRA_ARGS) 85 89 { 86 90 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 87 - return atomic_xchg__nocheck(haddr, val); 91 + DATA_TYPE ret = atomic_xchg__nocheck(haddr, val); 92 + ATOMIC_MMU_CLEANUP; 93 + return ret; 88 94 } 89 95 90 96 #define GEN_ATOMIC_HELPER(X) \ ··· 92 98 ABI_TYPE val EXTRA_ARGS) \ 93 99 { \ 94 100 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 95 - return atomic_##X(haddr, val); \ 96 - } \ 101 + DATA_TYPE ret = atomic_##X(haddr, val); \ 102 + ATOMIC_MMU_CLEANUP; \ 103 + return ret; \ 104 + } 97 105 98 106 GEN_ATOMIC_HELPER(fetch_add) 99 107 GEN_ATOMIC_HELPER(fetch_and) ··· 123 131 ABI_TYPE cmpv, ABI_TYPE newv EXTRA_ARGS) 124 132 { 125 133 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 126 - return BSWAP(atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv))); 134 + DATA_TYPE ret = atomic_cmpxchg__nocheck(haddr, BSWAP(cmpv), BSWAP(newv)); 135 + ATOMIC_MMU_CLEANUP; 136 + return BSWAP(ret); 127 137 } 128 138 129 139 #if DATA_SIZE >= 16 ··· 131 141 { 132 142 DATA_TYPE val, *haddr = ATOMIC_MMU_LOOKUP; 133 143 __atomic_load(haddr, &val, __ATOMIC_RELAXED); 144 + ATOMIC_MMU_CLEANUP; 134 145 return BSWAP(val); 135 146 } 136 147 ··· 140 151 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 141 152 val = BSWAP(val); 142 153 __atomic_store(haddr, &val, __ATOMIC_RELAXED); 154 + ATOMIC_MMU_CLEANUP; 143 155 } 144 156 #else 145 157 ABI_TYPE ATOMIC_NAME(xchg)(CPUArchState *env, target_ulong addr, 146 158 ABI_TYPE val EXTRA_ARGS) 147 159 { 148 160 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; 149 - return BSWAP(atomic_xchg__nocheck(haddr, BSWAP(val))); 161 + ABI_TYPE ret = atomic_xchg__nocheck(haddr, BSWAP(val)); 162 + ATOMIC_MMU_CLEANUP; 163 + return BSWAP(ret); 150 164 } 151 165 152 166 #define GEN_ATOMIC_HELPER(X) \ ··· 154 168 ABI_TYPE val EXTRA_ARGS) \ 155 169 { \ 156 170 DATA_TYPE *haddr = ATOMIC_MMU_LOOKUP; \ 157 - return BSWAP(atomic_##X(haddr, BSWAP(val))); \ 171 + DATA_TYPE ret = atomic_##X(haddr, BSWAP(val)); \ 172 + ATOMIC_MMU_CLEANUP; \ 173 + return BSWAP(ret); \ 158 174 } 159 175 160 176 GEN_ATOMIC_HELPER(fetch_and) ··· 180 196 sto = BSWAP(ret + val); 181 197 ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); 182 198 if (ldn == ldo) { 199 + ATOMIC_MMU_CLEANUP; 183 200 return ret; 184 201 } 185 202 ldo = ldn; ··· 198 215 sto = BSWAP(ret); 199 216 ldn = atomic_cmpxchg__nocheck(haddr, ldo, sto); 200 217 if (ldn == ldo) { 218 + ATOMIC_MMU_CLEANUP; 201 219 return ret; 202 220 } 203 221 ldo = ldn;
+1
accel/tcg/cputlb.c
··· 1041 1041 #define ATOMIC_NAME(X) \ 1042 1042 HELPER(glue(glue(glue(atomic_ ## X, SUFFIX), END), _mmu)) 1043 1043 #define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, oi, retaddr) 1044 + #define ATOMIC_MMU_CLEANUP do { } while (0) 1044 1045 1045 1046 #define DATA_SIZE 1 1046 1047 #include "atomic_template.h"
+47 -11
accel/tcg/user-exec.c
··· 39 39 #include <sys/ucontext.h> 40 40 #endif 41 41 42 + __thread uintptr_t helper_retaddr; 43 + 42 44 //#define DEBUG_SIGNAL 43 45 44 46 /* exit the current TB from a signal handler. The host registers are ··· 62 64 CPUClass *cc; 63 65 int ret; 64 66 67 + /* We must handle PC addresses from two different sources: 68 + * a call return address and a signal frame address. 69 + * 70 + * Within cpu_restore_state_from_tb we assume the former and adjust 71 + * the address by -GETPC_ADJ so that the address is within the call 72 + * insn so that addr does not accidentally match the beginning of the 73 + * next guest insn. 74 + * 75 + * However, when the PC comes from the signal frame, it points to 76 + * the actual faulting host insn and not a call insn. Subtracting 77 + * GETPC_ADJ in that case may accidentally match the previous guest insn. 78 + * 79 + * So for the later case, adjust forward to compensate for what 80 + * will be done later by cpu_restore_state_from_tb. 81 + */ 82 + if (helper_retaddr) { 83 + pc = helper_retaddr; 84 + } else { 85 + pc += GETPC_ADJ; 86 + } 87 + 65 88 /* For synchronous signals we expect to be coming from the vCPU 66 89 * thread (so current_cpu should be valid) and either from running 67 90 * code or during translation which can fault as we cross pages. ··· 84 107 switch (page_unprotect(h2g(address), pc)) { 85 108 case 0: 86 109 /* Fault not caused by a page marked unwritable to protect 87 - * cached translations, must be the guest binary's problem 110 + * cached translations, must be the guest binary's problem. 88 111 */ 89 112 break; 90 113 case 1: 91 114 /* Fault caused by protection of cached translation; TBs 92 - * invalidated, so resume execution 115 + * invalidated, so resume execution. Retain helper_retaddr 116 + * for a possible second fault. 93 117 */ 94 118 return 1; 95 119 case 2: 96 120 /* Fault caused by protection of cached translation, and the 97 121 * currently executing TB was modified and must be exited 98 - * immediately. 122 + * immediately. Clear helper_retaddr for next execution. 99 123 */ 124 + helper_retaddr = 0; 100 125 cpu_exit_tb_from_sighandler(cpu, old_set); 101 - g_assert_not_reached(); 126 + /* NORETURN */ 127 + 102 128 default: 103 129 g_assert_not_reached(); 104 130 } ··· 112 138 /* see if it is an MMU fault */ 113 139 g_assert(cc->handle_mmu_fault); 114 140 ret = cc->handle_mmu_fault(cpu, address, is_write, MMU_USER_IDX); 141 + 142 + if (ret == 0) { 143 + /* The MMU fault was handled without causing real CPU fault. 144 + * Retain helper_retaddr for a possible second fault. 145 + */ 146 + return 1; 147 + } 148 + 149 + /* All other paths lead to cpu_exit; clear helper_retaddr 150 + * for next execution. 151 + */ 152 + helper_retaddr = 0; 153 + 115 154 if (ret < 0) { 116 155 return 0; /* not an MMU fault */ 117 156 } 118 - if (ret == 0) { 119 - return 1; /* the MMU fault was handled without causing real CPU fault */ 120 - } 121 157 122 - /* Now we have a real cpu fault. Since this is the exact location of 123 - * the exception, we must undo the adjustment done by cpu_restore_state 124 - * for handling call return addresses. */ 125 - cpu_restore_state(cpu, pc + GETPC_ADJ); 158 + /* Now we have a real cpu fault. */ 159 + cpu_restore_state(cpu, pc); 126 160 127 161 sigprocmask(SIG_SETMASK, old_set, NULL); 128 162 cpu_loop_exit(cpu); ··· 585 619 if (unlikely(addr & (size - 1))) { 586 620 cpu_loop_exit_atomic(ENV_GET_CPU(env), retaddr); 587 621 } 622 + helper_retaddr = retaddr; 588 623 return g2h(addr); 589 624 } 590 625 591 626 /* Macro to call the above, with local variables from the use context. */ 592 627 #define ATOMIC_MMU_LOOKUP atomic_mmu_lookup(env, addr, DATA_SIZE, GETPC()) 628 + #define ATOMIC_MMU_CLEANUP do { helper_retaddr = 0; } while (0) 593 629 594 630 #define ATOMIC_NAME(X) HELPER(glue(glue(atomic_ ## X, SUFFIX), END)) 595 631 #define EXTRA_ARGS
+2
include/exec/cpu_ldst.h
··· 76 76 77 77 #if defined(CONFIG_USER_ONLY) 78 78 79 + extern __thread uintptr_t helper_retaddr; 80 + 79 81 /* In user-only mode we provide only the _code and _data accessors. */ 80 82 81 83 #define MEMSUFFIX _data
+12 -2
include/exec/cpu_ldst_useronly_template.h
··· 73 73 target_ulong ptr, 74 74 uintptr_t retaddr) 75 75 { 76 - return glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(env, ptr); 76 + RES_TYPE ret; 77 + helper_retaddr = retaddr; 78 + ret = glue(glue(cpu_ld, USUFFIX), MEMSUFFIX)(env, ptr); 79 + helper_retaddr = 0; 80 + return ret; 77 81 } 78 82 79 83 #if DATA_SIZE <= 2 ··· 93 97 target_ulong ptr, 94 98 uintptr_t retaddr) 95 99 { 96 - return glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(env, ptr); 100 + int ret; 101 + helper_retaddr = retaddr; 102 + ret = glue(glue(cpu_lds, SUFFIX), MEMSUFFIX)(env, ptr); 103 + helper_retaddr = 0; 104 + return ret; 97 105 } 98 106 #endif 99 107 ··· 116 124 RES_TYPE v, 117 125 uintptr_t retaddr) 118 126 { 127 + helper_retaddr = retaddr; 119 128 glue(glue(cpu_st, SUFFIX), MEMSUFFIX)(env, ptr, v); 129 + helper_retaddr = 0; 120 130 } 121 131 #endif 122 132