142a623c7SBlue Swirl /* 242a623c7SBlue Swirl * User emulator execution 342a623c7SBlue Swirl * 442a623c7SBlue Swirl * Copyright (c) 2003-2005 Fabrice Bellard 542a623c7SBlue Swirl * 642a623c7SBlue Swirl * This library is free software; you can redistribute it and/or 742a623c7SBlue Swirl * modify it under the terms of the GNU Lesser General Public 842a623c7SBlue Swirl * License as published by the Free Software Foundation; either 9fb0343d5SThomas Huth * version 2.1 of the License, or (at your option) any later version. 1042a623c7SBlue Swirl * 1142a623c7SBlue Swirl * This library is distributed in the hope that it will be useful, 1242a623c7SBlue Swirl * but WITHOUT ANY WARRANTY; without even the implied warranty of 1342a623c7SBlue Swirl * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1442a623c7SBlue Swirl * Lesser General Public License for more details. 1542a623c7SBlue Swirl * 1642a623c7SBlue Swirl * You should have received a copy of the GNU Lesser General Public 1742a623c7SBlue Swirl * License along with this library; if not, see <http://www.gnu.org/licenses/>. 1842a623c7SBlue Swirl */ 19d38ea87aSPeter Maydell #include "qemu/osdep.h" 2078271684SClaudio Fontana #include "hw/core/tcg-cpu-ops.h" 2176cad711SPaolo Bonzini #include "disas/disas.h" 2263c91552SPaolo Bonzini #include "exec/exec-all.h" 23dcb32f1dSPhilippe Mathieu-Daudé #include "tcg/tcg.h" 24023b0ae3SPeter Maydell #include "qemu/bitops.h" 25f08b6170SPaolo Bonzini #include "exec/cpu_ldst.h" 263b9bd3f4SPaolo Bonzini #include "exec/translate-all.h" 27a411d296SPhilippe Mathieu-Daudé #include "exec/helper-proto.h" 28e6cd4bb5SRichard Henderson #include "qemu/atomic128.h" 29243af022SPaolo Bonzini #include "trace/trace-root.h" 3037e891e3SRichard Henderson #include "tcg/tcg-ldst.h" 310583f775SRichard Henderson #include "internal.h" 3242a623c7SBlue Swirl 33ec603b55SRichard Henderson __thread uintptr_t helper_retaddr; 34ec603b55SRichard Henderson 3542a623c7SBlue Swirl //#define DEBUG_SIGNAL 3642a623c7SBlue Swirl 370fdbb7d2SRichard Henderson /* 380fdbb7d2SRichard Henderson * Adjust the pc to pass to cpu_restore_state; return the memop type. 390fdbb7d2SRichard Henderson */ 400fdbb7d2SRichard Henderson MMUAccessType adjust_signal_pc(uintptr_t *pc, bool is_write) 4142a623c7SBlue Swirl { 4252ba13f0SRichard Henderson switch (helper_retaddr) { 4352ba13f0SRichard Henderson default: 4452ba13f0SRichard Henderson /* 4552ba13f0SRichard Henderson * Fault during host memory operation within a helper function. 4652ba13f0SRichard Henderson * The helper's host return address, saved here, gives us a 4752ba13f0SRichard Henderson * pointer into the generated code that will unwind to the 4852ba13f0SRichard Henderson * correct guest pc. 49ec603b55SRichard Henderson */ 500fdbb7d2SRichard Henderson *pc = helper_retaddr; 5152ba13f0SRichard Henderson break; 5252ba13f0SRichard Henderson 5352ba13f0SRichard Henderson case 0: 5452ba13f0SRichard Henderson /* 5552ba13f0SRichard Henderson * Fault during host memory operation within generated code. 5652ba13f0SRichard Henderson * (Or, a unrelated bug within qemu, but we can't tell from here). 5752ba13f0SRichard Henderson * 5852ba13f0SRichard Henderson * We take the host pc from the signal frame. However, we cannot 5952ba13f0SRichard Henderson * use that value directly. Within cpu_restore_state_from_tb, we 6052ba13f0SRichard Henderson * assume PC comes from GETPC(), as used by the helper functions, 6152ba13f0SRichard Henderson * so we adjust the address by -GETPC_ADJ to form an address that 62e3a6e0daSzhaolichang * is within the call insn, so that the address does not accidentally 6352ba13f0SRichard Henderson * match the beginning of the next guest insn. However, when the 6452ba13f0SRichard Henderson * pc comes from the signal frame it points to the actual faulting 6552ba13f0SRichard Henderson * host memory insn and not the return from a call insn. 6652ba13f0SRichard Henderson * 6752ba13f0SRichard Henderson * Therefore, adjust to compensate for what will be done later 6852ba13f0SRichard Henderson * by cpu_restore_state_from_tb. 6952ba13f0SRichard Henderson */ 700fdbb7d2SRichard Henderson *pc += GETPC_ADJ; 7152ba13f0SRichard Henderson break; 7252ba13f0SRichard Henderson 7352ba13f0SRichard Henderson case 1: 7452ba13f0SRichard Henderson /* 7552ba13f0SRichard Henderson * Fault during host read for translation, or loosely, "execution". 7652ba13f0SRichard Henderson * 7752ba13f0SRichard Henderson * The guest pc is already pointing to the start of the TB for which 7852ba13f0SRichard Henderson * code is being generated. If the guest translator manages the 7952ba13f0SRichard Henderson * page crossings correctly, this is exactly the correct address 8052ba13f0SRichard Henderson * (and if the translator doesn't handle page boundaries correctly 8152ba13f0SRichard Henderson * there's little we can do about that here). Therefore, do not 8252ba13f0SRichard Henderson * trigger the unwinder. 8352ba13f0SRichard Henderson * 8452ba13f0SRichard Henderson * Like tb_gen_code, release the memory lock before cpu_loop_exit. 8552ba13f0SRichard Henderson */ 8652ba13f0SRichard Henderson mmap_unlock(); 870fdbb7d2SRichard Henderson *pc = 0; 880fdbb7d2SRichard Henderson return MMU_INST_FETCH; 89ec603b55SRichard Henderson } 90ec603b55SRichard Henderson 910fdbb7d2SRichard Henderson return is_write ? MMU_DATA_STORE : MMU_DATA_LOAD; 920fdbb7d2SRichard Henderson } 930fdbb7d2SRichard Henderson 945e38ba7dSRichard Henderson /** 955e38ba7dSRichard Henderson * handle_sigsegv_accerr_write: 965e38ba7dSRichard Henderson * @cpu: the cpu context 975e38ba7dSRichard Henderson * @old_set: the sigset_t from the signal ucontext_t 985e38ba7dSRichard Henderson * @host_pc: the host pc, adjusted for the signal 995e38ba7dSRichard Henderson * @guest_addr: the guest address of the fault 1005e38ba7dSRichard Henderson * 1015e38ba7dSRichard Henderson * Return true if the write fault has been handled, and should be re-tried. 1025e38ba7dSRichard Henderson * 1035e38ba7dSRichard Henderson * Note that it is important that we don't call page_unprotect() unless 104*9323e79fSPeter Maydell * this is really a "write to nonwritable page" fault, because 1055e38ba7dSRichard Henderson * page_unprotect() assumes that if it is called for an access to 106*9323e79fSPeter Maydell * a page that's writable this means we had two threads racing and 107*9323e79fSPeter Maydell * another thread got there first and already made the page writable; 1085e38ba7dSRichard Henderson * so we will retry the access. If we were to call page_unprotect() 1095e38ba7dSRichard Henderson * for some other kind of fault that should really be passed to the 1105e38ba7dSRichard Henderson * guest, we'd end up in an infinite loop of retrying the faulting access. 1115e38ba7dSRichard Henderson */ 1125e38ba7dSRichard Henderson bool handle_sigsegv_accerr_write(CPUState *cpu, sigset_t *old_set, 1135e38ba7dSRichard Henderson uintptr_t host_pc, abi_ptr guest_addr) 1145e38ba7dSRichard Henderson { 1155e38ba7dSRichard Henderson switch (page_unprotect(guest_addr, host_pc)) { 1165e38ba7dSRichard Henderson case 0: 1175e38ba7dSRichard Henderson /* 1185e38ba7dSRichard Henderson * Fault not caused by a page marked unwritable to protect 1195e38ba7dSRichard Henderson * cached translations, must be the guest binary's problem. 1205e38ba7dSRichard Henderson */ 1215e38ba7dSRichard Henderson return false; 1225e38ba7dSRichard Henderson case 1: 1235e38ba7dSRichard Henderson /* 1245e38ba7dSRichard Henderson * Fault caused by protection of cached translation; TBs 1255e38ba7dSRichard Henderson * invalidated, so resume execution. 1265e38ba7dSRichard Henderson */ 1275e38ba7dSRichard Henderson return true; 1285e38ba7dSRichard Henderson case 2: 1295e38ba7dSRichard Henderson /* 1305e38ba7dSRichard Henderson * Fault caused by protection of cached translation, and the 1315e38ba7dSRichard Henderson * currently executing TB was modified and must be exited immediately. 1325e38ba7dSRichard Henderson */ 133940b3090SRichard Henderson sigprocmask(SIG_SETMASK, old_set, NULL); 134940b3090SRichard Henderson cpu_loop_exit_noexc(cpu); 1355e38ba7dSRichard Henderson /* NORETURN */ 1365e38ba7dSRichard Henderson default: 1375e38ba7dSRichard Henderson g_assert_not_reached(); 1385e38ba7dSRichard Henderson } 1395e38ba7dSRichard Henderson } 1405e38ba7dSRichard Henderson 141069cfe77SRichard Henderson static int probe_access_internal(CPUArchState *env, target_ulong addr, 142069cfe77SRichard Henderson int fault_size, MMUAccessType access_type, 143069cfe77SRichard Henderson bool nonfault, uintptr_t ra) 14459e96ac6SDavid Hildenbrand { 14572d2bbf9SRichard Henderson int acc_flag; 14672d2bbf9SRichard Henderson bool maperr; 147c25c283dSDavid Hildenbrand 148c25c283dSDavid Hildenbrand switch (access_type) { 149c25c283dSDavid Hildenbrand case MMU_DATA_STORE: 15072d2bbf9SRichard Henderson acc_flag = PAGE_WRITE_ORG; 151c25c283dSDavid Hildenbrand break; 152c25c283dSDavid Hildenbrand case MMU_DATA_LOAD: 15372d2bbf9SRichard Henderson acc_flag = PAGE_READ; 154c25c283dSDavid Hildenbrand break; 155c25c283dSDavid Hildenbrand case MMU_INST_FETCH: 15672d2bbf9SRichard Henderson acc_flag = PAGE_EXEC; 157c25c283dSDavid Hildenbrand break; 158c25c283dSDavid Hildenbrand default: 159c25c283dSDavid Hildenbrand g_assert_not_reached(); 160c25c283dSDavid Hildenbrand } 161c25c283dSDavid Hildenbrand 16272d2bbf9SRichard Henderson if (guest_addr_valid_untagged(addr)) { 16372d2bbf9SRichard Henderson int page_flags = page_get_flags(addr); 16472d2bbf9SRichard Henderson if (page_flags & acc_flag) { 16572d2bbf9SRichard Henderson return 0; /* success */ 16672d2bbf9SRichard Henderson } 16772d2bbf9SRichard Henderson maperr = !(page_flags & PAGE_VALID); 16872d2bbf9SRichard Henderson } else { 16972d2bbf9SRichard Henderson maperr = true; 17072d2bbf9SRichard Henderson } 17172d2bbf9SRichard Henderson 172069cfe77SRichard Henderson if (nonfault) { 173069cfe77SRichard Henderson return TLB_INVALID_MASK; 17459e96ac6SDavid Hildenbrand } 17572d2bbf9SRichard Henderson 17672d2bbf9SRichard Henderson cpu_loop_exit_sigsegv(env_cpu(env), addr, access_type, maperr, ra); 177069cfe77SRichard Henderson } 178069cfe77SRichard Henderson 179069cfe77SRichard Henderson int probe_access_flags(CPUArchState *env, target_ulong addr, 180069cfe77SRichard Henderson MMUAccessType access_type, int mmu_idx, 181069cfe77SRichard Henderson bool nonfault, void **phost, uintptr_t ra) 182069cfe77SRichard Henderson { 183069cfe77SRichard Henderson int flags; 184069cfe77SRichard Henderson 185069cfe77SRichard Henderson flags = probe_access_internal(env, addr, 0, access_type, nonfault, ra); 1863e8f1628SRichard Henderson *phost = flags ? NULL : g2h(env_cpu(env), addr); 187069cfe77SRichard Henderson return flags; 188069cfe77SRichard Henderson } 189069cfe77SRichard Henderson 190069cfe77SRichard Henderson void *probe_access(CPUArchState *env, target_ulong addr, int size, 191069cfe77SRichard Henderson MMUAccessType access_type, int mmu_idx, uintptr_t ra) 192069cfe77SRichard Henderson { 193069cfe77SRichard Henderson int flags; 194069cfe77SRichard Henderson 195069cfe77SRichard Henderson g_assert(-(addr | TARGET_PAGE_MASK) >= size); 196069cfe77SRichard Henderson flags = probe_access_internal(env, addr, size, access_type, false, ra); 197069cfe77SRichard Henderson g_assert(flags == 0); 198fef39ccdSDavid Hildenbrand 1993e8f1628SRichard Henderson return size ? g2h(env_cpu(env), addr) : NULL; 20059e96ac6SDavid Hildenbrand } 20159e96ac6SDavid Hildenbrand 202a411d296SPhilippe Mathieu-Daudé /* The softmmu versions of these helpers are in cputlb.c. */ 203a411d296SPhilippe Mathieu-Daudé 204f83bcecbSRichard Henderson /* 205f83bcecbSRichard Henderson * Verify that we have passed the correct MemOp to the correct function. 206f83bcecbSRichard Henderson * 207f83bcecbSRichard Henderson * We could present one function to target code, and dispatch based on 208f83bcecbSRichard Henderson * the MemOp, but so far we have worked hard to avoid an indirect function 209f83bcecbSRichard Henderson * call along the memory path. 210f83bcecbSRichard Henderson */ 211f83bcecbSRichard Henderson static void validate_memop(MemOpIdx oi, MemOp expected) 212ed4cfbcdSRichard Henderson { 213f83bcecbSRichard Henderson #ifdef CONFIG_DEBUG_TCG 214f83bcecbSRichard Henderson MemOp have = get_memop(oi) & (MO_SIZE | MO_BSWAP); 215f83bcecbSRichard Henderson assert(have == expected); 216f83bcecbSRichard Henderson #endif 217f83bcecbSRichard Henderson } 218ed4cfbcdSRichard Henderson 21937e891e3SRichard Henderson void helper_unaligned_ld(CPUArchState *env, target_ulong addr) 22037e891e3SRichard Henderson { 22137e891e3SRichard Henderson cpu_loop_exit_sigbus(env_cpu(env), addr, MMU_DATA_LOAD, GETPC()); 22237e891e3SRichard Henderson } 22337e891e3SRichard Henderson 22437e891e3SRichard Henderson void helper_unaligned_st(CPUArchState *env, target_ulong addr) 22537e891e3SRichard Henderson { 22637e891e3SRichard Henderson cpu_loop_exit_sigbus(env_cpu(env), addr, MMU_DATA_STORE, GETPC()); 22737e891e3SRichard Henderson } 22837e891e3SRichard Henderson 229f83bcecbSRichard Henderson static void *cpu_mmu_lookup(CPUArchState *env, target_ulong addr, 230f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra, MMUAccessType type) 231f83bcecbSRichard Henderson { 2329395cd0aSRichard Henderson MemOp mop = get_memop(oi); 2339395cd0aSRichard Henderson int a_bits = get_alignment_bits(mop); 234f83bcecbSRichard Henderson void *ret; 235f83bcecbSRichard Henderson 2369395cd0aSRichard Henderson /* Enforce guest required alignment. */ 2379395cd0aSRichard Henderson if (unlikely(addr & ((1 << a_bits) - 1))) { 2389395cd0aSRichard Henderson cpu_loop_exit_sigbus(env_cpu(env), addr, type, ra); 2399395cd0aSRichard Henderson } 240f83bcecbSRichard Henderson 241f83bcecbSRichard Henderson ret = g2h(env_cpu(env), addr); 242f83bcecbSRichard Henderson set_helper_retaddr(ra); 243ed4cfbcdSRichard Henderson return ret; 244ed4cfbcdSRichard Henderson } 245ed4cfbcdSRichard Henderson 246f83bcecbSRichard Henderson uint8_t cpu_ldb_mmu(CPUArchState *env, abi_ptr addr, 247f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 248ed4cfbcdSRichard Henderson { 249f83bcecbSRichard Henderson void *haddr; 250f83bcecbSRichard Henderson uint8_t ret; 251ed4cfbcdSRichard Henderson 252f83bcecbSRichard Henderson validate_memop(oi, MO_UB); 253f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); 254f83bcecbSRichard Henderson ret = ldub_p(haddr); 255f83bcecbSRichard Henderson clear_helper_retaddr(); 256f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); 257ed4cfbcdSRichard Henderson return ret; 258ed4cfbcdSRichard Henderson } 259ed4cfbcdSRichard Henderson 260f83bcecbSRichard Henderson uint16_t cpu_ldw_be_mmu(CPUArchState *env, abi_ptr addr, 261f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 262ed4cfbcdSRichard Henderson { 263f83bcecbSRichard Henderson void *haddr; 264f83bcecbSRichard Henderson uint16_t ret; 265ed4cfbcdSRichard Henderson 266f83bcecbSRichard Henderson validate_memop(oi, MO_BEUW); 267f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); 268f83bcecbSRichard Henderson ret = lduw_be_p(haddr); 269f83bcecbSRichard Henderson clear_helper_retaddr(); 270f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); 271ed4cfbcdSRichard Henderson return ret; 272ed4cfbcdSRichard Henderson } 273ed4cfbcdSRichard Henderson 274f83bcecbSRichard Henderson uint32_t cpu_ldl_be_mmu(CPUArchState *env, abi_ptr addr, 275f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 276ed4cfbcdSRichard Henderson { 277f83bcecbSRichard Henderson void *haddr; 278f83bcecbSRichard Henderson uint32_t ret; 279f83bcecbSRichard Henderson 280f83bcecbSRichard Henderson validate_memop(oi, MO_BEUL); 281f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); 282f83bcecbSRichard Henderson ret = ldl_be_p(haddr); 283f83bcecbSRichard Henderson clear_helper_retaddr(); 284f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); 285f83bcecbSRichard Henderson return ret; 286f83bcecbSRichard Henderson } 287f83bcecbSRichard Henderson 288f83bcecbSRichard Henderson uint64_t cpu_ldq_be_mmu(CPUArchState *env, abi_ptr addr, 289f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 290f83bcecbSRichard Henderson { 291f83bcecbSRichard Henderson void *haddr; 292ed4cfbcdSRichard Henderson uint64_t ret; 293ed4cfbcdSRichard Henderson 294fc313c64SFrédéric Pétrot validate_memop(oi, MO_BEUQ); 295f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); 296f83bcecbSRichard Henderson ret = ldq_be_p(haddr); 297f83bcecbSRichard Henderson clear_helper_retaddr(); 298f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); 299b9e60257SRichard Henderson return ret; 300b9e60257SRichard Henderson } 301b9e60257SRichard Henderson 302f83bcecbSRichard Henderson uint16_t cpu_ldw_le_mmu(CPUArchState *env, abi_ptr addr, 303f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 304b9e60257SRichard Henderson { 305f83bcecbSRichard Henderson void *haddr; 306f83bcecbSRichard Henderson uint16_t ret; 307f83bcecbSRichard Henderson 308f83bcecbSRichard Henderson validate_memop(oi, MO_LEUW); 309f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); 310f83bcecbSRichard Henderson ret = lduw_le_p(haddr); 311f83bcecbSRichard Henderson clear_helper_retaddr(); 312f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); 313f83bcecbSRichard Henderson return ret; 314f83bcecbSRichard Henderson } 315f83bcecbSRichard Henderson 316f83bcecbSRichard Henderson uint32_t cpu_ldl_le_mmu(CPUArchState *env, abi_ptr addr, 317f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 318f83bcecbSRichard Henderson { 319f83bcecbSRichard Henderson void *haddr; 320b9e60257SRichard Henderson uint32_t ret; 321b9e60257SRichard Henderson 322f83bcecbSRichard Henderson validate_memop(oi, MO_LEUL); 323f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); 324f83bcecbSRichard Henderson ret = ldl_le_p(haddr); 325f83bcecbSRichard Henderson clear_helper_retaddr(); 326f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); 327b9e60257SRichard Henderson return ret; 328b9e60257SRichard Henderson } 329b9e60257SRichard Henderson 330f83bcecbSRichard Henderson uint64_t cpu_ldq_le_mmu(CPUArchState *env, abi_ptr addr, 331f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 332b9e60257SRichard Henderson { 333f83bcecbSRichard Henderson void *haddr; 334b9e60257SRichard Henderson uint64_t ret; 335b9e60257SRichard Henderson 336fc313c64SFrédéric Pétrot validate_memop(oi, MO_LEUQ); 337f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_LOAD); 338f83bcecbSRichard Henderson ret = ldq_le_p(haddr); 339f83bcecbSRichard Henderson clear_helper_retaddr(); 340f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_R); 341ed4cfbcdSRichard Henderson return ret; 342ed4cfbcdSRichard Henderson } 343ed4cfbcdSRichard Henderson 344f83bcecbSRichard Henderson void cpu_stb_mmu(CPUArchState *env, abi_ptr addr, uint8_t val, 345f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 346ed4cfbcdSRichard Henderson { 347f83bcecbSRichard Henderson void *haddr; 348ed4cfbcdSRichard Henderson 349f83bcecbSRichard Henderson validate_memop(oi, MO_UB); 350f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); 351f83bcecbSRichard Henderson stb_p(haddr, val); 352ed4cfbcdSRichard Henderson clear_helper_retaddr(); 353f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); 354ed4cfbcdSRichard Henderson } 355ed4cfbcdSRichard Henderson 356f83bcecbSRichard Henderson void cpu_stw_be_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, 357f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 358ed4cfbcdSRichard Henderson { 359f83bcecbSRichard Henderson void *haddr; 360ed4cfbcdSRichard Henderson 361f83bcecbSRichard Henderson validate_memop(oi, MO_BEUW); 362f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); 363f83bcecbSRichard Henderson stw_be_p(haddr, val); 364ed4cfbcdSRichard Henderson clear_helper_retaddr(); 365f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); 366ed4cfbcdSRichard Henderson } 367ed4cfbcdSRichard Henderson 368f83bcecbSRichard Henderson void cpu_stl_be_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, 369f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 370ed4cfbcdSRichard Henderson { 371f83bcecbSRichard Henderson void *haddr; 372ed4cfbcdSRichard Henderson 373f83bcecbSRichard Henderson validate_memop(oi, MO_BEUL); 374f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); 375f83bcecbSRichard Henderson stl_be_p(haddr, val); 376ed4cfbcdSRichard Henderson clear_helper_retaddr(); 377f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); 378ed4cfbcdSRichard Henderson } 379ed4cfbcdSRichard Henderson 380f83bcecbSRichard Henderson void cpu_stq_be_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, 381f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 382ed4cfbcdSRichard Henderson { 383f83bcecbSRichard Henderson void *haddr; 384ed4cfbcdSRichard Henderson 385fc313c64SFrédéric Pétrot validate_memop(oi, MO_BEUQ); 386f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); 387f83bcecbSRichard Henderson stq_be_p(haddr, val); 388b9e60257SRichard Henderson clear_helper_retaddr(); 389f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); 390b9e60257SRichard Henderson } 391b9e60257SRichard Henderson 392f83bcecbSRichard Henderson void cpu_stw_le_mmu(CPUArchState *env, abi_ptr addr, uint16_t val, 393f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 394b9e60257SRichard Henderson { 395f83bcecbSRichard Henderson void *haddr; 396b9e60257SRichard Henderson 397f83bcecbSRichard Henderson validate_memop(oi, MO_LEUW); 398f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); 399f83bcecbSRichard Henderson stw_le_p(haddr, val); 400b9e60257SRichard Henderson clear_helper_retaddr(); 401f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); 402b9e60257SRichard Henderson } 403b9e60257SRichard Henderson 404f83bcecbSRichard Henderson void cpu_stl_le_mmu(CPUArchState *env, abi_ptr addr, uint32_t val, 405f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 406b9e60257SRichard Henderson { 407f83bcecbSRichard Henderson void *haddr; 408b9e60257SRichard Henderson 409f83bcecbSRichard Henderson validate_memop(oi, MO_LEUL); 410f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); 411f83bcecbSRichard Henderson stl_le_p(haddr, val); 412b9e60257SRichard Henderson clear_helper_retaddr(); 413f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); 414b9e60257SRichard Henderson } 415b9e60257SRichard Henderson 416f83bcecbSRichard Henderson void cpu_stq_le_mmu(CPUArchState *env, abi_ptr addr, uint64_t val, 417f83bcecbSRichard Henderson MemOpIdx oi, uintptr_t ra) 418b9e60257SRichard Henderson { 419f83bcecbSRichard Henderson void *haddr; 420b9e60257SRichard Henderson 421fc313c64SFrédéric Pétrot validate_memop(oi, MO_LEUQ); 422f83bcecbSRichard Henderson haddr = cpu_mmu_lookup(env, addr, oi, ra, MMU_DATA_STORE); 423f83bcecbSRichard Henderson stq_le_p(haddr, val); 424ed4cfbcdSRichard Henderson clear_helper_retaddr(); 425f83bcecbSRichard Henderson qemu_plugin_vcpu_mem_cb(env_cpu(env), addr, oi, QEMU_PLUGIN_MEM_W); 426ed4cfbcdSRichard Henderson } 427ed4cfbcdSRichard Henderson 428ed4cfbcdSRichard Henderson uint32_t cpu_ldub_code(CPUArchState *env, abi_ptr ptr) 429ed4cfbcdSRichard Henderson { 430ed4cfbcdSRichard Henderson uint32_t ret; 431ed4cfbcdSRichard Henderson 432ed4cfbcdSRichard Henderson set_helper_retaddr(1); 4333e8f1628SRichard Henderson ret = ldub_p(g2h_untagged(ptr)); 434ed4cfbcdSRichard Henderson clear_helper_retaddr(); 435ed4cfbcdSRichard Henderson return ret; 436ed4cfbcdSRichard Henderson } 437ed4cfbcdSRichard Henderson 438ed4cfbcdSRichard Henderson uint32_t cpu_lduw_code(CPUArchState *env, abi_ptr ptr) 439ed4cfbcdSRichard Henderson { 440ed4cfbcdSRichard Henderson uint32_t ret; 441ed4cfbcdSRichard Henderson 442ed4cfbcdSRichard Henderson set_helper_retaddr(1); 4433e8f1628SRichard Henderson ret = lduw_p(g2h_untagged(ptr)); 444ed4cfbcdSRichard Henderson clear_helper_retaddr(); 445ed4cfbcdSRichard Henderson return ret; 446ed4cfbcdSRichard Henderson } 447ed4cfbcdSRichard Henderson 448ed4cfbcdSRichard Henderson uint32_t cpu_ldl_code(CPUArchState *env, abi_ptr ptr) 449ed4cfbcdSRichard Henderson { 450ed4cfbcdSRichard Henderson uint32_t ret; 451ed4cfbcdSRichard Henderson 452ed4cfbcdSRichard Henderson set_helper_retaddr(1); 4533e8f1628SRichard Henderson ret = ldl_p(g2h_untagged(ptr)); 454ed4cfbcdSRichard Henderson clear_helper_retaddr(); 455ed4cfbcdSRichard Henderson return ret; 456ed4cfbcdSRichard Henderson } 457ed4cfbcdSRichard Henderson 458ed4cfbcdSRichard Henderson uint64_t cpu_ldq_code(CPUArchState *env, abi_ptr ptr) 459ed4cfbcdSRichard Henderson { 460ed4cfbcdSRichard Henderson uint64_t ret; 461ed4cfbcdSRichard Henderson 462ed4cfbcdSRichard Henderson set_helper_retaddr(1); 4633e8f1628SRichard Henderson ret = ldq_p(g2h_untagged(ptr)); 464ed4cfbcdSRichard Henderson clear_helper_retaddr(); 465ed4cfbcdSRichard Henderson return ret; 466ed4cfbcdSRichard Henderson } 467ed4cfbcdSRichard Henderson 468f83bcecbSRichard Henderson #include "ldst_common.c.inc" 469f83bcecbSRichard Henderson 470a754f7f3SRichard Henderson /* 471a754f7f3SRichard Henderson * Do not allow unaligned operations to proceed. Return the host address. 472a754f7f3SRichard Henderson * 473a754f7f3SRichard Henderson * @prot may be PAGE_READ, PAGE_WRITE, or PAGE_READ|PAGE_WRITE. 474a754f7f3SRichard Henderson */ 475a411d296SPhilippe Mathieu-Daudé static void *atomic_mmu_lookup(CPUArchState *env, target_ulong addr, 4769002ffcbSRichard Henderson MemOpIdx oi, int size, int prot, 477a754f7f3SRichard Henderson uintptr_t retaddr) 478a411d296SPhilippe Mathieu-Daudé { 479fce3f474SRichard Henderson MemOp mop = get_memop(oi); 480fce3f474SRichard Henderson int a_bits = get_alignment_bits(mop); 481fce3f474SRichard Henderson void *ret; 482fce3f474SRichard Henderson 483fce3f474SRichard Henderson /* Enforce guest required alignment. */ 484fce3f474SRichard Henderson if (unlikely(addr & ((1 << a_bits) - 1))) { 485fce3f474SRichard Henderson MMUAccessType t = prot == PAGE_READ ? MMU_DATA_LOAD : MMU_DATA_STORE; 486fce3f474SRichard Henderson cpu_loop_exit_sigbus(env_cpu(env), addr, t, retaddr); 487fce3f474SRichard Henderson } 488fce3f474SRichard Henderson 489a411d296SPhilippe Mathieu-Daudé /* Enforce qemu required alignment. */ 490a411d296SPhilippe Mathieu-Daudé if (unlikely(addr & (size - 1))) { 49129a0af61SRichard Henderson cpu_loop_exit_atomic(env_cpu(env), retaddr); 492a411d296SPhilippe Mathieu-Daudé } 493fce3f474SRichard Henderson 494fce3f474SRichard Henderson ret = g2h(env_cpu(env), addr); 49508b97f7fSRichard Henderson set_helper_retaddr(retaddr); 49608b97f7fSRichard Henderson return ret; 497a411d296SPhilippe Mathieu-Daudé } 498a411d296SPhilippe Mathieu-Daudé 499be9568b4SRichard Henderson #include "atomic_common.c.inc" 500be9568b4SRichard Henderson 501be9568b4SRichard Henderson /* 502be9568b4SRichard Henderson * First set of functions passes in OI and RETADDR. 503be9568b4SRichard Henderson * This makes them callable from other helpers. 504be9568b4SRichard Henderson */ 505be9568b4SRichard Henderson 506be9568b4SRichard Henderson #define ATOMIC_NAME(X) \ 507be9568b4SRichard Henderson glue(glue(glue(cpu_atomic_ ## X, SUFFIX), END), _mmu) 50808b97f7fSRichard Henderson #define ATOMIC_MMU_CLEANUP do { clear_helper_retaddr(); } while (0) 509a411d296SPhilippe Mathieu-Daudé 510a411d296SPhilippe Mathieu-Daudé #define DATA_SIZE 1 511a411d296SPhilippe Mathieu-Daudé #include "atomic_template.h" 512a411d296SPhilippe Mathieu-Daudé 513a411d296SPhilippe Mathieu-Daudé #define DATA_SIZE 2 514a411d296SPhilippe Mathieu-Daudé #include "atomic_template.h" 515a411d296SPhilippe Mathieu-Daudé 516a411d296SPhilippe Mathieu-Daudé #define DATA_SIZE 4 517a411d296SPhilippe Mathieu-Daudé #include "atomic_template.h" 518a411d296SPhilippe Mathieu-Daudé 519a411d296SPhilippe Mathieu-Daudé #ifdef CONFIG_ATOMIC64 520a411d296SPhilippe Mathieu-Daudé #define DATA_SIZE 8 521a411d296SPhilippe Mathieu-Daudé #include "atomic_template.h" 522a411d296SPhilippe Mathieu-Daudé #endif 523a411d296SPhilippe Mathieu-Daudé 524e6cd4bb5SRichard Henderson #if HAVE_ATOMIC128 || HAVE_CMPXCHG128 525be9568b4SRichard Henderson #define DATA_SIZE 16 526be9568b4SRichard Henderson #include "atomic_template.h" 527be9568b4SRichard Henderson #endif 528