Merge tag 'pull-loongarch-20241016' of https://gitlab.com/gaosong/qemu into staging
[qemu/armbru.git] / target / ppc / mmu-hash32.c
blob44b16142ab8d5c2aa491099db73efd16158e0159
1 /*
2 * PowerPC MMU, TLB and BAT emulation helpers for QEMU.
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 * Copyright (c) 2013 David Gibson, IBM Corporation
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 #include "qemu/osdep.h"
22 #include "cpu.h"
23 #include "exec/exec-all.h"
24 #include "exec/page-protection.h"
25 #include "sysemu/kvm.h"
26 #include "kvm_ppc.h"
27 #include "internal.h"
28 #include "mmu-hash32.h"
29 #include "mmu-books.h"
30 #include "exec/log.h"
32 /* #define DEBUG_BATS */
34 #ifdef DEBUG_BATS
35 # define LOG_BATS(...) qemu_log_mask(CPU_LOG_MMU, __VA_ARGS__)
36 #else
37 # define LOG_BATS(...) do { } while (0)
38 #endif
40 static target_ulong hash32_bat_size(int mmu_idx,
41 target_ulong batu, target_ulong batl)
43 if ((mmuidx_pr(mmu_idx) && !(batu & BATU32_VP))
44 || (!mmuidx_pr(mmu_idx) && !(batu & BATU32_VS))) {
45 return 0;
48 return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
51 static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
52 MMUAccessType access_type, int *prot,
53 int mmu_idx)
55 CPUPPCState *env = &cpu->env;
56 target_ulong *BATlt, *BATut;
57 bool ifetch = access_type == MMU_INST_FETCH;
58 int i;
60 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
61 ifetch ? 'I' : 'D', ea);
62 if (ifetch) {
63 BATlt = env->IBAT[1];
64 BATut = env->IBAT[0];
65 } else {
66 BATlt = env->DBAT[1];
67 BATut = env->DBAT[0];
69 for (i = 0; i < env->nb_BATs; i++) {
70 target_ulong batu = BATut[i];
71 target_ulong batl = BATlt[i];
72 target_ulong mask;
74 mask = hash32_bat_size(mmu_idx, batu, batl);
75 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
76 " BATl " TARGET_FMT_lx "\n", __func__,
77 ifetch ? 'I' : 'D', i, ea, batu, batl);
79 if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
80 hwaddr raddr = (batl & mask) | (ea & ~mask);
82 *prot = ppc_hash32_bat_prot(batu, batl);
84 return raddr & TARGET_PAGE_MASK;
88 /* No hit */
89 #if defined(DEBUG_BATS)
90 if (qemu_log_enabled()) {
91 target_ulong *BATu, *BATl;
92 target_ulong BEPIl, BEPIu, bl;
94 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
95 for (i = 0; i < 4; i++) {
96 BATu = &BATut[i];
97 BATl = &BATlt[i];
98 BEPIu = *BATu & BATU32_BEPIU;
99 BEPIl = *BATu & BATU32_BEPIL;
100 bl = (*BATu & 0x00001FFC) << 15;
101 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
102 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
103 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
104 __func__, ifetch ? 'I' : 'D', i, ea,
105 *BATu, *BATl, BEPIu, BEPIl, bl);
108 #endif
110 return -1;
113 static bool ppc_hash32_direct_store(PowerPCCPU *cpu, target_ulong sr,
114 target_ulong eaddr,
115 MMUAccessType access_type,
116 hwaddr *raddr, int *prot, int mmu_idx,
117 bool guest_visible)
119 CPUState *cs = CPU(cpu);
120 CPUPPCState *env = &cpu->env;
122 qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
124 if (access_type == MMU_INST_FETCH) {
125 /* No code fetch is allowed in direct-store areas */
126 if (guest_visible) {
127 cs->exception_index = POWERPC_EXCP_ISI;
128 env->error_code = 0x10000000;
130 return false;
134 * From ppc_cpu_get_phys_page_debug, env->access_type is not set.
135 * Assume ACCESS_INT for that case.
137 switch (guest_visible ? env->access_type : ACCESS_INT) {
138 case ACCESS_INT:
139 /* Integer load/store : only access allowed */
140 break;
141 case ACCESS_FLOAT:
142 /* Floating point load/store */
143 cs->exception_index = POWERPC_EXCP_ALIGN;
144 env->error_code = POWERPC_EXCP_ALIGN_FP;
145 env->spr[SPR_DAR] = eaddr;
146 return false;
147 case ACCESS_RES:
148 /* lwarx, ldarx or srwcx. */
149 env->error_code = 0;
150 env->spr[SPR_DAR] = eaddr;
151 if (access_type == MMU_DATA_STORE) {
152 env->spr[SPR_DSISR] = 0x06000000;
153 } else {
154 env->spr[SPR_DSISR] = 0x04000000;
156 return false;
157 case ACCESS_CACHE:
159 * dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi
161 * Should make the instruction do no-op. As it already do
162 * no-op, it's quite easy :-)
164 *raddr = eaddr;
165 return true;
166 case ACCESS_EXT:
167 /* eciwx or ecowx */
168 cs->exception_index = POWERPC_EXCP_DSI;
169 env->error_code = 0;
170 env->spr[SPR_DAR] = eaddr;
171 if (access_type == MMU_DATA_STORE) {
172 env->spr[SPR_DSISR] = 0x06100000;
173 } else {
174 env->spr[SPR_DSISR] = 0x04100000;
176 return false;
177 default:
178 cpu_abort(cs, "ERROR: insn should not need address translation\n");
181 if (ppc_hash32_key(mmuidx_pr(mmu_idx), sr)) {
182 *prot = PAGE_READ | PAGE_WRITE;
183 } else {
184 *prot = PAGE_READ;
186 if (check_prot_access_type(*prot, access_type)) {
187 *raddr = eaddr;
188 return true;
191 if (guest_visible) {
192 cs->exception_index = POWERPC_EXCP_DSI;
193 env->error_code = 0;
194 env->spr[SPR_DAR] = eaddr;
195 if (access_type == MMU_DATA_STORE) {
196 env->spr[SPR_DSISR] = 0x0a000000;
197 } else {
198 env->spr[SPR_DSISR] = 0x08000000;
201 return false;
204 static hwaddr ppc_hash32_pteg_search(PowerPCCPU *cpu, hwaddr pteg_off,
205 bool secondary, target_ulong ptem,
206 ppc_hash_pte32_t *pte)
208 hwaddr pte_offset = pteg_off;
209 target_ulong pte0, pte1;
210 int i;
212 for (i = 0; i < HPTES_PER_GROUP; i++) {
213 pte0 = ppc_hash32_load_hpte0(cpu, pte_offset);
215 * pte0 contains the valid bit and must be read before pte1,
216 * otherwise we might see an old pte1 with a new valid bit and
217 * thus an inconsistent hpte value
219 smp_rmb();
220 pte1 = ppc_hash32_load_hpte1(cpu, pte_offset);
222 if ((pte0 & HPTE32_V_VALID)
223 && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
224 && HPTE32_V_COMPARE(pte0, ptem)) {
225 pte->pte0 = pte0;
226 pte->pte1 = pte1;
227 return pte_offset;
230 pte_offset += HASH_PTE_SIZE_32;
233 return -1;
236 static void ppc_hash32_set_r(PowerPCCPU *cpu, hwaddr pte_offset, uint32_t pte1)
238 target_ulong base = ppc_hash32_hpt_base(cpu);
239 hwaddr offset = pte_offset + 6;
241 /* The HW performs a non-atomic byte update */
242 stb_phys(CPU(cpu)->as, base + offset, ((pte1 >> 8) & 0xff) | 0x01);
245 static void ppc_hash32_set_c(PowerPCCPU *cpu, hwaddr pte_offset, uint64_t pte1)
247 target_ulong base = ppc_hash32_hpt_base(cpu);
248 hwaddr offset = pte_offset + 7;
250 /* The HW performs a non-atomic byte update */
251 stb_phys(CPU(cpu)->as, base + offset, (pte1 & 0xff) | 0x80);
254 static hwaddr ppc_hash32_htab_lookup(PowerPCCPU *cpu,
255 target_ulong sr, target_ulong eaddr,
256 ppc_hash_pte32_t *pte)
258 hwaddr pteg_off, pte_offset;
259 hwaddr hash;
260 uint32_t vsid, pgidx, ptem;
262 vsid = sr & SR32_VSID;
263 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
264 hash = vsid ^ pgidx;
265 ptem = (vsid << 7) | (pgidx >> 10);
267 /* Page address translation */
268 qemu_log_mask(CPU_LOG_MMU, "htab_base " HWADDR_FMT_plx
269 " htab_mask " HWADDR_FMT_plx
270 " hash " HWADDR_FMT_plx "\n",
271 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu), hash);
273 /* Primary PTEG lookup */
274 qemu_log_mask(CPU_LOG_MMU, "0 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
275 " vsid=%" PRIx32 " ptem=%" PRIx32
276 " hash=" HWADDR_FMT_plx "\n",
277 ppc_hash32_hpt_base(cpu), ppc_hash32_hpt_mask(cpu),
278 vsid, ptem, hash);
279 pteg_off = get_pteg_offset32(cpu, hash);
280 pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 0, ptem, pte);
281 if (pte_offset == -1) {
282 /* Secondary PTEG lookup */
283 qemu_log_mask(CPU_LOG_MMU, "1 htab=" HWADDR_FMT_plx "/" HWADDR_FMT_plx
284 " vsid=%" PRIx32 " api=%" PRIx32
285 " hash=" HWADDR_FMT_plx "\n", ppc_hash32_hpt_base(cpu),
286 ppc_hash32_hpt_mask(cpu), vsid, ptem, ~hash);
287 pteg_off = get_pteg_offset32(cpu, ~hash);
288 pte_offset = ppc_hash32_pteg_search(cpu, pteg_off, 1, ptem, pte);
291 return pte_offset;
294 bool ppc_hash32_xlate(PowerPCCPU *cpu, vaddr eaddr, MMUAccessType access_type,
295 hwaddr *raddrp, int *psizep, int *protp, int mmu_idx,
296 bool guest_visible)
298 CPUState *cs = CPU(cpu);
299 CPUPPCState *env = &cpu->env;
300 target_ulong sr;
301 hwaddr pte_offset, raddr;
302 ppc_hash_pte32_t pte;
303 bool key;
304 int prot;
306 /* There are no hash32 large pages. */
307 *psizep = TARGET_PAGE_BITS;
309 /* 1. Handle real mode accesses */
310 if (mmuidx_real(mmu_idx)) {
311 /* Translation is off */
312 *raddrp = eaddr;
313 *protp = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
314 return true;
317 /* 2. Check Block Address Translation entries (BATs) */
318 if (env->nb_BATs != 0) {
319 raddr = ppc_hash32_bat_lookup(cpu, eaddr, access_type, protp, mmu_idx);
320 if (raddr != -1) {
321 if (!check_prot_access_type(*protp, access_type)) {
322 if (guest_visible) {
323 if (access_type == MMU_INST_FETCH) {
324 cs->exception_index = POWERPC_EXCP_ISI;
325 env->error_code = 0x08000000;
326 } else {
327 cs->exception_index = POWERPC_EXCP_DSI;
328 env->error_code = 0;
329 env->spr[SPR_DAR] = eaddr;
330 if (access_type == MMU_DATA_STORE) {
331 env->spr[SPR_DSISR] = 0x0a000000;
332 } else {
333 env->spr[SPR_DSISR] = 0x08000000;
337 return false;
339 *raddrp = raddr;
340 return true;
344 /* 3. Look up the Segment Register */
345 sr = env->sr[eaddr >> 28];
347 /* 4. Handle direct store segments */
348 if (sr & SR32_T) {
349 return ppc_hash32_direct_store(cpu, sr, eaddr, access_type,
350 raddrp, protp, mmu_idx, guest_visible);
353 /* 5. Check for segment level no-execute violation */
354 if (access_type == MMU_INST_FETCH && (sr & SR32_NX)) {
355 if (guest_visible) {
356 cs->exception_index = POWERPC_EXCP_ISI;
357 env->error_code = 0x10000000;
359 return false;
362 /* 6. Locate the PTE in the hash table */
363 pte_offset = ppc_hash32_htab_lookup(cpu, sr, eaddr, &pte);
364 if (pte_offset == -1) {
365 if (guest_visible) {
366 if (access_type == MMU_INST_FETCH) {
367 cs->exception_index = POWERPC_EXCP_ISI;
368 env->error_code = 0x40000000;
369 } else {
370 cs->exception_index = POWERPC_EXCP_DSI;
371 env->error_code = 0;
372 env->spr[SPR_DAR] = eaddr;
373 if (access_type == MMU_DATA_STORE) {
374 env->spr[SPR_DSISR] = 0x42000000;
375 } else {
376 env->spr[SPR_DSISR] = 0x40000000;
380 return false;
382 qemu_log_mask(CPU_LOG_MMU,
383 "found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
385 /* 7. Check access permissions */
386 key = ppc_hash32_key(mmuidx_pr(mmu_idx), sr);
387 prot = ppc_hash32_prot(key, pte.pte1 & HPTE32_R_PP, sr & SR32_NX);
389 if (!check_prot_access_type(prot, access_type)) {
390 /* Access right violation */
391 qemu_log_mask(CPU_LOG_MMU, "PTE access rejected\n");
392 if (guest_visible) {
393 if (access_type == MMU_INST_FETCH) {
394 cs->exception_index = POWERPC_EXCP_ISI;
395 env->error_code = 0x08000000;
396 } else {
397 cs->exception_index = POWERPC_EXCP_DSI;
398 env->error_code = 0;
399 env->spr[SPR_DAR] = eaddr;
400 if (access_type == MMU_DATA_STORE) {
401 env->spr[SPR_DSISR] = 0x0a000000;
402 } else {
403 env->spr[SPR_DSISR] = 0x08000000;
407 return false;
410 qemu_log_mask(CPU_LOG_MMU, "PTE access granted !\n");
412 /* 8. Update PTE referenced and changed bits if necessary */
414 if (!(pte.pte1 & HPTE32_R_R)) {
415 ppc_hash32_set_r(cpu, pte_offset, pte.pte1);
417 if (!(pte.pte1 & HPTE32_R_C)) {
418 if (access_type == MMU_DATA_STORE) {
419 ppc_hash32_set_c(cpu, pte_offset, pte.pte1);
420 } else {
422 * Treat the page as read-only for now, so that a later write
423 * will pass through this function again to set the C bit
425 prot &= ~PAGE_WRITE;
428 *protp = prot;
430 /* 9. Determine the real address from the PTE */
431 *raddrp = pte.pte1 & HPTE32_R_RPN;
432 *raddrp &= TARGET_PAGE_MASK;
433 *raddrp |= eaddr & ~TARGET_PAGE_MASK;
434 return true;