]> git.proxmox.com Git - qemu.git/blame - target-ppc/mmu-hash32.c
mmu-hash*: Fold pte_check*() logic into caller
[qemu.git] / target-ppc / mmu-hash32.c
CommitLineData
9d7c3f4a
DG
1/*
2 * PowerPC MMU, TLB and BAT emulation helpers for QEMU.
3 *
4 * Copyright (c) 2003-2007 Jocelyn Mayer
5 * Copyright (c) 2013 David Gibson, IBM Corporation
6 *
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 of the License, or (at your option) any later version.
11 *
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.
16 *
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/>.
19 */
20
21#include "cpu.h"
22#include "helper.h"
23#include "sysemu/kvm.h"
24#include "kvm_ppc.h"
25#include "mmu-hash32.h"
26
27//#define DEBUG_MMU
98132796 28//#define DEBUG_BAT
9d7c3f4a
DG
29
30#ifdef DEBUG_MMU
31# define LOG_MMU(...) qemu_log(__VA_ARGS__)
32# define LOG_MMU_STATE(env) log_cpu_state((env), 0)
33#else
34# define LOG_MMU(...) do { } while (0)
35# define LOG_MMU_STATE(...) do { } while (0)
36#endif
37
98132796
DG
38#ifdef DEBUG_BATS
39# define LOG_BATS(...) qemu_log(__VA_ARGS__)
40#else
41# define LOG_BATS(...) do { } while (0)
42#endif
43
5dc68eb0
DG
44struct mmu_ctx_hash32 {
45 hwaddr raddr; /* Real address */
5dc68eb0 46 int prot; /* Protection bits */
5dc68eb0
DG
47 int key; /* Access key */
48 int nx; /* Non-execute area */
49};
50
496272a7
DG
51static int ppc_hash32_pp_check(int key, int pp, int nx)
52{
53 int access;
54
55 /* Compute access rights */
56 access = 0;
57 if (key == 0) {
58 switch (pp) {
59 case 0x0:
60 case 0x1:
61 case 0x2:
62 access |= PAGE_WRITE;
63 /* No break here */
64 case 0x3:
65 access |= PAGE_READ;
66 break;
67 }
68 } else {
69 switch (pp) {
70 case 0x0:
71 access = 0;
72 break;
73 case 0x1:
74 case 0x3:
75 access = PAGE_READ;
76 break;
77 case 0x2:
78 access = PAGE_READ | PAGE_WRITE;
79 break;
80 }
81 }
82 if (nx == 0) {
83 access |= PAGE_EXEC;
84 }
85
86 return access;
87}
88
91cda45b 89static int ppc_hash32_check_prot(int prot, int rwx)
496272a7
DG
90{
91 int ret;
92
91cda45b 93 if (rwx == 2) {
496272a7
DG
94 if (prot & PAGE_EXEC) {
95 ret = 0;
96 } else {
97 ret = -2;
98 }
91cda45b 99 } else if (rwx) {
496272a7
DG
100 if (prot & PAGE_WRITE) {
101 ret = 0;
102 } else {
103 ret = -2;
104 }
105 } else {
106 if (prot & PAGE_READ) {
107 ret = 0;
108 } else {
109 ret = -2;
110 }
111 }
112
113 return ret;
114}
115
98132796
DG
116/* Perform BAT hit & translation */
117static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp,
118 int *validp, int *protp, target_ulong *BATu,
119 target_ulong *BATl)
120{
121 target_ulong bl;
122 int pp, valid, prot;
123
d5aea6f3 124 bl = (*BATu & BATU32_BL) << 15;
98132796
DG
125 valid = 0;
126 prot = 0;
d5aea6f3
DG
127 if (((msr_pr == 0) && (*BATu & BATU32_VS)) ||
128 ((msr_pr != 0) && (*BATu & BATU32_VP))) {
98132796 129 valid = 1;
d5aea6f3 130 pp = *BATl & BATL32_PP;
98132796
DG
131 if (pp != 0) {
132 prot = PAGE_READ | PAGE_EXEC;
133 if (pp == 0x2) {
134 prot |= PAGE_WRITE;
135 }
136 }
137 }
138 *blp = bl;
139 *validp = valid;
140 *protp = prot;
141}
142
143static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
144 int *validp, int *protp,
145 target_ulong *BATu, target_ulong *BATl)
146{
147 target_ulong bl;
148 int key, pp, valid, prot;
149
d5aea6f3 150 bl = (*BATl & BATL32_601_BL) << 17;
98132796 151 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
d5aea6f3 152 (uint8_t)(*BATl & BATL32_601_BL), bl, ~bl);
98132796 153 prot = 0;
d5aea6f3 154 valid = !!(*BATl & BATL32_601_V);
98132796 155 if (valid) {
d5aea6f3 156 pp = *BATu & BATU32_601_PP;
98132796 157 if (msr_pr == 0) {
d5aea6f3 158 key = !!(*BATu & BATU32_601_KS);
98132796 159 } else {
d5aea6f3 160 key = !!(*BATu & BATU32_601_KP);
98132796
DG
161 }
162 prot = ppc_hash32_pp_check(key, pp, 0);
163 }
164 *blp = bl;
165 *validp = valid;
166 *protp = prot;
167}
168
5dc68eb0 169static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
91cda45b 170 target_ulong virtual, int rwx)
98132796
DG
171{
172 target_ulong *BATlt, *BATut, *BATu, *BATl;
173 target_ulong BEPIl, BEPIu, bl;
174 int i, valid, prot;
175 int ret = -1;
176
177 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
91cda45b
DG
178 rwx == 2 ? 'I' : 'D', virtual);
179 if (rwx == 2) {
98132796
DG
180 BATlt = env->IBAT[1];
181 BATut = env->IBAT[0];
91cda45b 182 } else {
98132796
DG
183 BATlt = env->DBAT[1];
184 BATut = env->DBAT[0];
98132796
DG
185 }
186 for (i = 0; i < env->nb_BATs; i++) {
187 BATu = &BATut[i];
188 BATl = &BATlt[i];
d5aea6f3
DG
189 BEPIu = *BATu & BATU32_BEPIU;
190 BEPIl = *BATu & BATU32_BEPIL;
98132796
DG
191 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
192 hash32_bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
193 } else {
194 hash32_bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
195 }
196 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
197 " BATl " TARGET_FMT_lx "\n", __func__,
198 type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
d5aea6f3
DG
199 if ((virtual & BATU32_BEPIU) == BEPIu &&
200 ((virtual & BATU32_BEPIL) & ~bl) == BEPIl) {
98132796
DG
201 /* BAT matches */
202 if (valid != 0) {
203 /* Get physical address */
d5aea6f3
DG
204 ctx->raddr = (*BATl & BATL32_BRPNU) |
205 ((virtual & BATU32_BEPIL & bl) | (*BATl & BATL32_BRPNL)) |
98132796
DG
206 (virtual & 0x0001F000);
207 /* Compute access rights */
208 ctx->prot = prot;
91cda45b 209 ret = ppc_hash32_check_prot(ctx->prot, rwx);
98132796
DG
210 if (ret == 0) {
211 LOG_BATS("BAT %d match: r " TARGET_FMT_plx " prot=%c%c\n",
212 i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
213 ctx->prot & PAGE_WRITE ? 'W' : '-');
214 }
215 break;
216 }
217 }
218 }
219 if (ret < 0) {
220#if defined(DEBUG_BATS)
221 if (qemu_log_enabled()) {
222 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", virtual);
223 for (i = 0; i < 4; i++) {
224 BATu = &BATut[i];
225 BATl = &BATlt[i];
d5aea6f3
DG
226 BEPIu = *BATu & BATU32_BEPIU;
227 BEPIl = *BATu & BATU32_BEPIL;
98132796
DG
228 bl = (*BATu & 0x00001FFC) << 15;
229 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
230 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
231 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
232 __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
233 *BATu, *BATl, BEPIu, BEPIl, bl);
234 }
235 }
236#endif
237 }
238 /* No hit */
239 return ret;
240}
241
723ed73a
DG
242static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
243 target_ulong eaddr, int rwx,
244 hwaddr *raddr, int *prot)
245{
246 int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
247
248 LOG_MMU("direct store...\n");
249
250 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
251 /* Memory-forced I/O controller interface access */
252 /* If T=1 and BUID=x'07F', the 601 performs a memory access
253 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
254 */
255 *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
256 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
257 return 0;
258 }
259
260 if (rwx == 2) {
261 /* No code fetch is allowed in direct-store areas */
262 return -4;
263 }
264
265 switch (env->access_type) {
266 case ACCESS_INT:
267 /* Integer load/store : only access allowed */
268 break;
269 case ACCESS_FLOAT:
270 /* Floating point load/store */
271 return -4;
272 case ACCESS_RES:
273 /* lwarx, ldarx or srwcx. */
274 return -4;
275 case ACCESS_CACHE:
276 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
277 /* Should make the instruction do no-op.
278 * As it already do no-op, it's quite easy :-)
279 */
280 *raddr = eaddr;
281 return 0;
282 case ACCESS_EXT:
283 /* eciwx or ecowx */
284 return -4;
285 default:
286 qemu_log("ERROR: instruction should not need "
287 "address translation\n");
288 return -4;
289 }
290 if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
291 *raddr = eaddr;
292 return 2;
293 } else {
294 return -2;
295 }
296}
297
6a980110
DG
298static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, uint32_t *pte1p,
299 int ret, int rwx)
496272a7
DG
300{
301 int store = 0;
302
303 /* Update page flags */
d5aea6f3 304 if (!(*pte1p & HPTE32_R_R)) {
496272a7 305 /* Update accessed flag */
d5aea6f3 306 *pte1p |= HPTE32_R_R;
496272a7
DG
307 store = 1;
308 }
d5aea6f3 309 if (!(*pte1p & HPTE32_R_C)) {
91cda45b 310 if (rwx == 1 && ret == 0) {
496272a7 311 /* Update changed flag */
d5aea6f3 312 *pte1p |= HPTE32_R_C;
496272a7
DG
313 store = 1;
314 } else {
315 /* Force page fault for first write access */
316 ctx->prot &= ~PAGE_WRITE;
317 }
318 }
319
320 return store;
321}
322
59191721
DG
323hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
324{
d5aea6f3 325 return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
59191721
DG
326}
327
aea390e4
DG
328static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
329 bool secondary, target_ulong ptem,
330 ppc_hash_pte32_t *pte)
331{
332 hwaddr pte_offset = pteg_off;
333 target_ulong pte0, pte1;
334 int i;
335
336 for (i = 0; i < HPTES_PER_GROUP; i++) {
337 pte0 = ppc_hash32_load_hpte0(env, pte_offset);
338 pte1 = ppc_hash32_load_hpte1(env, pte_offset);
339
340 if ((pte0 & HPTE32_V_VALID)
341 && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
342 && HPTE32_V_COMPARE(pte0, ptem)) {
343 pte->pte0 = pte0;
344 pte->pte1 = pte1;
345 return pte_offset;
346 }
347
348 pte_offset += HASH_PTE_SIZE_32;
349 }
350
351 return -1;
352}
353
7f3bdc2d
DG
354static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
355 target_ulong sr, target_ulong eaddr,
356 ppc_hash_pte32_t *pte)
c69b6151 357{
aea390e4 358 hwaddr pteg_off, pte_offset;
a1ff751a
DG
359 hwaddr hash;
360 uint32_t vsid, pgidx, ptem;
c69b6151 361
a1ff751a 362 vsid = sr & SR32_VSID;
a1ff751a
DG
363 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
364 hash = vsid ^ pgidx;
365 ptem = (vsid << 7) | (pgidx >> 10);
366
367 /* Page address translation */
368 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
369 " hash " TARGET_FMT_plx "\n",
370 env->htab_base, env->htab_mask, hash);
371
372 /* Primary PTEG lookup */
373 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
374 " vsid=%" PRIx32 " ptem=%" PRIx32
375 " hash=" TARGET_FMT_plx "\n",
376 env->htab_base, env->htab_mask, vsid, ptem, hash);
377 pteg_off = get_pteg_offset32(env, hash);
7f3bdc2d 378 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte);
a1ff751a
DG
379 if (pte_offset == -1) {
380 /* Secondary PTEG lookup */
381 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
382 " vsid=%" PRIx32 " api=%" PRIx32
383 " hash=" TARGET_FMT_plx "\n", env->htab_base,
384 env->htab_mask, vsid, ptem, ~hash);
385 pteg_off = get_pteg_offset32(env, ~hash);
7f3bdc2d 386 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte);
a1ff751a
DG
387 }
388
7f3bdc2d 389 return pte_offset;
c69b6151 390}
0480884f 391
65d61643
DG
392static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
393 target_ulong eaddr, int rwx)
0480884f 394{
a1ff751a
DG
395 int ret;
396 target_ulong sr;
7f3bdc2d
DG
397 hwaddr pte_offset;
398 ppc_hash_pte32_t pte;
0480884f 399
6a980110
DG
400 assert((rwx == 0) || (rwx == 1) || (rwx == 2));
401
65d61643
DG
402 /* 1. Handle real mode accesses */
403 if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
404 /* Translation is off */
405 ctx->raddr = eaddr;
406 ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
407 return 0;
408 }
409
410 /* 2. Check Block Address Translation entries (BATs) */
411 if (env->nb_BATs != 0) {
412 ret = ppc_hash32_get_bat(env, ctx, eaddr, rwx);
413 if (ret == 0) {
414 return 0;
415 }
416 }
417
4b9605a5 418 /* 3. Look up the Segment Register */
0480884f 419 sr = env->sr[eaddr >> 28];
4b9605a5 420
4b9605a5
DG
421 /* 4. Handle direct store segments */
422 if (sr & SR32_T) {
723ed73a
DG
423 return ppc_hash32_direct_store(env, sr, eaddr, rwx,
424 &ctx->raddr, &ctx->prot);
4b9605a5
DG
425 }
426
bb218042
DG
427 /* 5. Check for segment level no-execute violation */
428 ctx->nx = !!(sr & SR32_NX);
429 if ((rwx == 2) && ctx->nx) {
430 return -3;
431 }
7f3bdc2d
DG
432
433 /* 6. Locate the PTE in the hash table */
434 pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
435 if (pte_offset == -1) {
436 return -1;
437 }
438 LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
439
440 /* 7. Check access permissions */
441 ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
442 ((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
6a980110
DG
443
444 int access, pp;
445
446 pp = pte.pte1 & HPTE32_R_PP;
447 /* Compute access rights */
448 access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
449 /* Keep the matching PTE informations */
450 ctx->raddr = pte.pte1;
451 ctx->prot = access;
452 ret = ppc_hash32_check_prot(ctx->prot, rwx);
453 if (ret == 0) {
454 /* Access granted */
455 LOG_MMU("PTE access granted !\n");
456 } else {
457 /* Access right violation */
458 LOG_MMU("PTE access rejected\n");
459 }
460
7f3bdc2d
DG
461 /* Update page flags */
462 if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
463 ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
464 }
0480884f
DG
465
466 return ret;
467}
629bd516 468
f2ad6be8
DG
469hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
470{
5dc68eb0 471 struct mmu_ctx_hash32 ctx;
f2ad6be8 472
91cda45b
DG
473 /* FIXME: Will not behave sanely for direct store segments, but
474 * they're almost never used */
65d61643 475 if (unlikely(ppc_hash32_translate(env, &ctx, addr, 0)
f2ad6be8
DG
476 != 0)) {
477 return -1;
478 }
479
480 return ctx.raddr & TARGET_PAGE_MASK;
481}
482
91cda45b 483int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
25de24ab
DG
484 int mmu_idx)
485{
5dc68eb0 486 struct mmu_ctx_hash32 ctx;
25de24ab
DG
487 int ret = 0;
488
65d61643 489 ret = ppc_hash32_translate(env, &ctx, address, rwx);
25de24ab
DG
490 if (ret == 0) {
491 tlb_set_page(env, address & TARGET_PAGE_MASK,
492 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
493 mmu_idx, TARGET_PAGE_SIZE);
494 ret = 0;
495 } else if (ret < 0) {
496 LOG_MMU_STATE(env);
91cda45b 497 if (rwx == 2) {
25de24ab
DG
498 switch (ret) {
499 case -1:
500 /* No matches in page tables or TLB */
501 env->exception_index = POWERPC_EXCP_ISI;
502 env->error_code = 0x40000000;
503 break;
504 case -2:
505 /* Access rights violation */
506 env->exception_index = POWERPC_EXCP_ISI;
507 env->error_code = 0x08000000;
508 break;
509 case -3:
510 /* No execute protection violation */
511 env->exception_index = POWERPC_EXCP_ISI;
512 env->error_code = 0x10000000;
513 break;
514 case -4:
515 /* Direct store exception */
516 /* No code fetch is allowed in direct-store areas */
517 env->exception_index = POWERPC_EXCP_ISI;
518 env->error_code = 0x10000000;
519 break;
520 }
521 } else {
522 switch (ret) {
523 case -1:
524 /* No matches in page tables or TLB */
525 env->exception_index = POWERPC_EXCP_DSI;
526 env->error_code = 0;
527 env->spr[SPR_DAR] = address;
91cda45b 528 if (rwx == 1) {
25de24ab
DG
529 env->spr[SPR_DSISR] = 0x42000000;
530 } else {
531 env->spr[SPR_DSISR] = 0x40000000;
532 }
533 break;
534 case -2:
535 /* Access rights violation */
536 env->exception_index = POWERPC_EXCP_DSI;
537 env->error_code = 0;
538 env->spr[SPR_DAR] = address;
91cda45b 539 if (rwx == 1) {
25de24ab
DG
540 env->spr[SPR_DSISR] = 0x0A000000;
541 } else {
542 env->spr[SPR_DSISR] = 0x08000000;
543 }
544 break;
545 case -4:
546 /* Direct store exception */
91cda45b 547 switch (env->access_type) {
25de24ab
DG
548 case ACCESS_FLOAT:
549 /* Floating point load/store */
550 env->exception_index = POWERPC_EXCP_ALIGN;
551 env->error_code = POWERPC_EXCP_ALIGN_FP;
552 env->spr[SPR_DAR] = address;
553 break;
554 case ACCESS_RES:
555 /* lwarx, ldarx or stwcx. */
556 env->exception_index = POWERPC_EXCP_DSI;
557 env->error_code = 0;
558 env->spr[SPR_DAR] = address;
91cda45b 559 if (rwx == 1) {
25de24ab
DG
560 env->spr[SPR_DSISR] = 0x06000000;
561 } else {
562 env->spr[SPR_DSISR] = 0x04000000;
563 }
564 break;
565 case ACCESS_EXT:
566 /* eciwx or ecowx */
567 env->exception_index = POWERPC_EXCP_DSI;
568 env->error_code = 0;
569 env->spr[SPR_DAR] = address;
91cda45b 570 if (rwx == 1) {
25de24ab
DG
571 env->spr[SPR_DSISR] = 0x06100000;
572 } else {
573 env->spr[SPR_DSISR] = 0x04100000;
574 }
575 break;
576 default:
577 printf("DSI: invalid exception (%d)\n", ret);
578 env->exception_index = POWERPC_EXCP_PROGRAM;
579 env->error_code =
580 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
581 env->spr[SPR_DAR] = address;
582 break;
583 }
584 break;
585 }
586 }
587#if 0
588 printf("%s: set exception to %d %02x\n", __func__,
589 env->exception, env->error_code);
590#endif
591 ret = 1;
592 }
593
594 return ret;
595}