1 /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 /* Access guest memory in blocks. */ 3 4 #include "qemu/osdep.h" 5 #include "cpu.h" 6 #include "exec/cpu_ldst.h" 7 #include "exec/exec-all.h" 8 #include "access.h" 9 10 11 void access_prepare_mmu(X86Access *ret, CPUX86State *env, 12 vaddr vaddr, unsigned size, 13 MMUAccessType type, int mmu_idx, uintptr_t ra) 14 { 15 int size1, size2; 16 void *haddr1, *haddr2; 17 18 assert(size > 0 && size <= TARGET_PAGE_SIZE); 19 20 size1 = MIN(size, -(vaddr | TARGET_PAGE_MASK)), 21 size2 = size - size1; 22 23 memset(ret, 0, sizeof(*ret)); 24 ret->vaddr = vaddr; 25 ret->size = size; 26 ret->size1 = size1; 27 ret->mmu_idx = mmu_idx; 28 ret->env = env; 29 ret->ra = ra; 30 31 haddr1 = probe_access(env, vaddr, size1, type, mmu_idx, ra); 32 ret->haddr1 = haddr1; 33 34 if (unlikely(size2)) { 35 haddr2 = probe_access(env, vaddr + size1, size2, type, mmu_idx, ra); 36 if (haddr2 == haddr1 + size1) { 37 ret->size1 = size; 38 } else { 39 #ifdef CONFIG_USER_ONLY 40 g_assert_not_reached(); 41 #else 42 ret->haddr2 = haddr2; 43 #endif 44 } 45 } 46 } 47 48 void access_prepare(X86Access *ret, CPUX86State *env, vaddr vaddr, 49 unsigned size, MMUAccessType type, uintptr_t ra) 50 { 51 int mmu_idx = cpu_mmu_index(env_cpu(env), false); 52 access_prepare_mmu(ret, env, vaddr, size, type, mmu_idx, ra); 53 } 54 55 static void *access_ptr(X86Access *ac, vaddr addr, unsigned len) 56 { 57 vaddr offset = addr - ac->vaddr; 58 59 assert(addr >= ac->vaddr); 60 61 #ifdef CONFIG_USER_ONLY 62 assert(offset <= ac->size1 - len); 63 return ac->haddr1 + offset; 64 #else 65 if (likely(offset <= ac->size1 - len)) { 66 return ac->haddr1 + offset; 67 } 68 assert(offset <= ac->size - len); 69 /* 70 * If the address is not naturally aligned, it might span both pages. 71 * Only return ac->haddr2 if the area is entirely within the second page, 72 * otherwise fall back to slow accesses. 73 */ 74 if (likely(offset >= ac->size1)) { 75 return ac->haddr2 + (offset - ac->size1); 76 } 77 return NULL; 78 #endif 79 } 80 81 #ifdef CONFIG_USER_ONLY 82 # define test_ptr(p) true 83 #else 84 # define test_ptr(p) likely(p) 85 #endif 86 87 uint8_t access_ldb(X86Access *ac, vaddr addr) 88 { 89 void *p = access_ptr(ac, addr, sizeof(uint8_t)); 90 91 if (test_ptr(p)) { 92 return ldub_p(p); 93 } 94 return cpu_ldub_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra); 95 } 96 97 uint16_t access_ldw(X86Access *ac, vaddr addr) 98 { 99 void *p = access_ptr(ac, addr, sizeof(uint16_t)); 100 101 if (test_ptr(p)) { 102 return lduw_le_p(p); 103 } 104 return cpu_lduw_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra); 105 } 106 107 uint32_t access_ldl(X86Access *ac, vaddr addr) 108 { 109 void *p = access_ptr(ac, addr, sizeof(uint32_t)); 110 111 if (test_ptr(p)) { 112 return ldl_le_p(p); 113 } 114 return cpu_ldl_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra); 115 } 116 117 uint64_t access_ldq(X86Access *ac, vaddr addr) 118 { 119 void *p = access_ptr(ac, addr, sizeof(uint64_t)); 120 121 if (test_ptr(p)) { 122 return ldq_le_p(p); 123 } 124 return cpu_ldq_le_mmuidx_ra(ac->env, addr, ac->mmu_idx, ac->ra); 125 } 126 127 void access_stb(X86Access *ac, vaddr addr, uint8_t val) 128 { 129 void *p = access_ptr(ac, addr, sizeof(uint8_t)); 130 131 if (test_ptr(p)) { 132 stb_p(p, val); 133 } else { 134 cpu_stb_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra); 135 } 136 } 137 138 void access_stw(X86Access *ac, vaddr addr, uint16_t val) 139 { 140 void *p = access_ptr(ac, addr, sizeof(uint16_t)); 141 142 if (test_ptr(p)) { 143 stw_le_p(p, val); 144 } else { 145 cpu_stw_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra); 146 } 147 } 148 149 void access_stl(X86Access *ac, vaddr addr, uint32_t val) 150 { 151 void *p = access_ptr(ac, addr, sizeof(uint32_t)); 152 153 if (test_ptr(p)) { 154 stl_le_p(p, val); 155 } else { 156 cpu_stl_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra); 157 } 158 } 159 160 void access_stq(X86Access *ac, vaddr addr, uint64_t val) 161 { 162 void *p = access_ptr(ac, addr, sizeof(uint64_t)); 163 164 if (test_ptr(p)) { 165 stq_le_p(p, val); 166 } else { 167 cpu_stq_le_mmuidx_ra(ac->env, addr, val, ac->mmu_idx, ac->ra); 168 } 169 } 170