diff --git a/include/exec/cpu_ldst.h b/include/exec/cpu_ldst.h
index 1673287..64fe806 100644
--- a/include/exec/cpu_ldst.h
+++ b/include/exec/cpu_ldst.h
@@ -307,37 +307,40 @@ uint64_t helper_ldq_cmmu(CPUArchState *env, target_ulong addr, int mmu_idx);
 #undef MEMSUFFIX
 #undef SOFTMMU_CODE_ACCESS
 
-/**
- * tlb_vaddr_to_host:
- * @env: CPUArchState
- * @addr: guest virtual address to look up
- * @access_type: 0 for read, 1 for write, 2 for execute
- * @mmu_idx: MMU index to use for lookup
- *
- * Look up the specified guest virtual index in the TCG softmmu TLB.
- * If the TLB contains a host virtual address suitable for direct RAM
- * access, then return it. Otherwise (TLB miss, TLB entry is for an
- * I/O access, etc) return NULL.
- *
- * This is the equivalent of the initial fast-path code used by
- * TCG backends for guest load and store accesses.
- */
-static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
-                                      int access_type, int mmu_idx)
+#endif /* defined(CONFIG_USER_ONLY) */
+
+
+
+#if defined(CONFIG_USER_ONLY)
+static inline void *tlb_vaddr_to_host_common(CPUArchState *env,
+                                             target_ulong addr,
+                                             int access_type, int mmu_idx,
+                                             uintptr_t retaddr, bool fill)
+{
+    return g2h(vaddr);
+}
+#else
+static inline void *tlb_vaddr_to_host_common(CPUArchState *env,
+                                             target_ulong addr,
+                                             int access_type, int mmu_idx,
+                                             uintptr_t retaddr, bool fill)
 {
     int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
-    CPUTLBEntry *tlbentry = &env->tlb_table[mmu_idx][index];
+    CPUTLBEntry *tlbentry;
     target_ulong tlb_addr;
     uintptr_t haddr;
 
+again:
+    tlbentry = &env->tlb_table[mmu_idx][index];
+
     switch (access_type) {
-    case 0:
+    case MMU_DATA_LOAD:
         tlb_addr = tlbentry->addr_read;
         break;
-    case 1:
+    case MMU_DATA_STORE:
         tlb_addr = tlbentry->addr_write;
         break;
-    case 2:
+    case MMU_INST_FETCH:
         tlb_addr = tlbentry->addr_code;
         break;
     default:
@@ -347,10 +350,14 @@ static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
     if ((addr & TARGET_PAGE_MASK)
         != (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
         /* TLB entry is for a different page */
+        if (fill) {
+            tlb_fill(ENV_GET_CPU(env), addr, access_type, mmu_idx, retaddr);
+            goto again;
+        }
         return NULL;
     }
 
-    if (tlb_addr & ~TARGET_PAGE_MASK) {
+    if (tlb_addr & TLB_MMIO) {
         /* IO access */
         return NULL;
     }
@@ -358,7 +365,54 @@ static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
     haddr = addr + env->tlb_table[mmu_idx][index].addend;
     return (void *)haddr;
 }
+#endif
 
-#endif /* defined(CONFIG_USER_ONLY) */
+/**
+ * tlb_vaddr_to_host:
+ * @env: CPUArchState
+ * @addr: guest virtual address to look up
+ * @access_type: MMU_DATA_LOAD for read, MMU_DATA_STORE for write,
+ *               MMU_INST_FETCH for execute
+ * @mmu_idx: MMU index to use for lookup
+ *
+ * Look up the specified guest virtual index in the TCG softmmu TLB.
+ * If the TLB contains a host virtual address suitable for direct RAM
+ * access, then return it. Otherwise (TLB miss, TLB entry is for an
+ * I/O access, etc) return NULL.
+ *
+ * This is the equivalent of the initial fast-path code used by
+ * TCG backends for guest load and store accesses.
+ */
+static inline void *tlb_vaddr_to_host(CPUArchState *env, target_ulong addr,
+                                      int access_type, int mmu_idx)
+{
+    return tlb_vaddr_to_host_common(env, addr, access_type,
+                                    mmu_idx, 0, false);
+}
+
+/**
+ * tlb_vaddr_to_host_fill:
+ * @env: CPUArchState
+ * @addr: guest virtual address to look up
+ * @access_type: MMU_DATA_LOAD for read, MMU_DATA_STORE for write,
+ *               MMU_INST_FETCH for execute
+ * @mmu_idx: MMU index to use for lookup
+ * @retaddr: address returned by GETPC() when called from a helper or 0
+ *
+ * Look up the specified guest virtual index in the TCG softmmu TLB.
+ * If the TLB contains a host virtual address suitable for direct RAM
+ * access, then return it. In case of a TLB miss, it trigger an exception.
+ * Otherwise (TLB entry is for an I/O access, etc), it returns NULL.
+ *
+ * It is the responsability of the caller to ensure endian conversion, that
+ * page boundaries are not crossed and that access alignement is correct.
+ */
+static inline void *tlb_vaddr_to_host_fill(CPUArchState *env, target_ulong addr,
+                                           int access_type, int mmu_idx,
+                                           uintptr_t retaddr)
+{
+    return tlb_vaddr_to_host_common(env, addr, access_type,
+                                    mmu_idx, retaddr, true);
+}
 
 #endif /* CPU_LDST_H */
