mmu-hash*: Remove permission checking from find_pte{32, 64}()
[qemu/agraf.git] / target-ppc / mmu-hash32.c
blob8b403fecb104d96cd991a51c19d8e484c06f0105
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 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 "cpu.h"
22 #include "helper.h"
23 #include "sysemu/kvm.h"
24 #include "kvm_ppc.h"
25 #include "mmu-hash32.h"
27 //#define DEBUG_MMU
28 //#define DEBUG_BAT
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
38 #ifdef DEBUG_BATS
39 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
40 #else
41 # define LOG_BATS(...) do { } while (0)
42 #endif
44 struct mmu_ctx_hash32 {
45 hwaddr raddr; /* Real address */
46 int prot; /* Protection bits */
47 int key; /* Access key */
48 int nx; /* Non-execute area */
51 static int ppc_hash32_pp_check(int key, int pp, int nx)
53 int access;
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;
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;
82 if (nx == 0) {
83 access |= PAGE_EXEC;
86 return access;
89 static int ppc_hash32_check_prot(int prot, int rwx)
91 int ret;
93 if (rwx == 2) {
94 if (prot & PAGE_EXEC) {
95 ret = 0;
96 } else {
97 ret = -2;
99 } else if (rwx) {
100 if (prot & PAGE_WRITE) {
101 ret = 0;
102 } else {
103 ret = -2;
105 } else {
106 if (prot & PAGE_READ) {
107 ret = 0;
108 } else {
109 ret = -2;
113 return ret;
116 /* Perform BAT hit & translation */
117 static void hash32_bat_size_prot(CPUPPCState *env, target_ulong *blp,
118 int *validp, int *protp, target_ulong *BATu,
119 target_ulong *BATl)
121 target_ulong bl;
122 int pp, valid, prot;
124 bl = (*BATu & BATU32_BL) << 15;
125 valid = 0;
126 prot = 0;
127 if (((msr_pr == 0) && (*BATu & BATU32_VS)) ||
128 ((msr_pr != 0) && (*BATu & BATU32_VP))) {
129 valid = 1;
130 pp = *BATl & BATL32_PP;
131 if (pp != 0) {
132 prot = PAGE_READ | PAGE_EXEC;
133 if (pp == 0x2) {
134 prot |= PAGE_WRITE;
138 *blp = bl;
139 *validp = valid;
140 *protp = prot;
143 static void hash32_bat_601_size_prot(CPUPPCState *env, target_ulong *blp,
144 int *validp, int *protp,
145 target_ulong *BATu, target_ulong *BATl)
147 target_ulong bl;
148 int key, pp, valid, prot;
150 bl = (*BATl & BATL32_601_BL) << 17;
151 LOG_BATS("b %02x ==> bl " TARGET_FMT_lx " msk " TARGET_FMT_lx "\n",
152 (uint8_t)(*BATl & BATL32_601_BL), bl, ~bl);
153 prot = 0;
154 valid = !!(*BATl & BATL32_601_V);
155 if (valid) {
156 pp = *BATu & BATU32_601_PP;
157 if (msr_pr == 0) {
158 key = !!(*BATu & BATU32_601_KS);
159 } else {
160 key = !!(*BATu & BATU32_601_KP);
162 prot = ppc_hash32_pp_check(key, pp, 0);
164 *blp = bl;
165 *validp = valid;
166 *protp = prot;
169 static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
170 target_ulong virtual, int rwx)
172 target_ulong *BATlt, *BATut, *BATu, *BATl;
173 target_ulong BEPIl, BEPIu, bl;
174 int i, valid, prot;
175 int ret = -1;
177 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
178 rwx == 2 ? 'I' : 'D', virtual);
179 if (rwx == 2) {
180 BATlt = env->IBAT[1];
181 BATut = env->IBAT[0];
182 } else {
183 BATlt = env->DBAT[1];
184 BATut = env->DBAT[0];
186 for (i = 0; i < env->nb_BATs; i++) {
187 BATu = &BATut[i];
188 BATl = &BATlt[i];
189 BEPIu = *BATu & BATU32_BEPIU;
190 BEPIl = *BATu & BATU32_BEPIL;
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);
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);
199 if ((virtual & BATU32_BEPIU) == BEPIu &&
200 ((virtual & BATU32_BEPIL) & ~bl) == BEPIl) {
201 /* BAT matches */
202 if (valid != 0) {
203 /* Get physical address */
204 ctx->raddr = (*BATl & BATL32_BRPNU) |
205 ((virtual & BATU32_BEPIL & bl) | (*BATl & BATL32_BRPNL)) |
206 (virtual & 0x0001F000);
207 /* Compute access rights */
208 ctx->prot = prot;
209 ret = ppc_hash32_check_prot(ctx->prot, rwx);
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' : '-');
215 break;
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];
226 BEPIu = *BATu & BATU32_BEPIU;
227 BEPIl = *BATu & BATU32_BEPIL;
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);
236 #endif
238 /* No hit */
239 return ret;
242 static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
243 target_ulong eaddr, int rwx,
244 hwaddr *raddr, int *prot)
246 int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
248 LOG_MMU("direct store...\n");
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.
255 *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
256 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
257 return 0;
260 if (rwx == 2) {
261 /* No code fetch is allowed in direct-store areas */
262 return -4;
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 :-)
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;
290 if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
291 *raddr = eaddr;
292 return 2;
293 } else {
294 return -2;
298 static int pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
299 target_ulong pte1, int rwx)
301 int access, ret, pp;
303 pp = pte1 & HPTE32_R_PP;
304 /* Compute access rights */
305 access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
306 /* Keep the matching PTE informations */
307 ctx->raddr = pte1;
308 ctx->prot = access;
309 ret = ppc_hash32_check_prot(ctx->prot, rwx);
310 if (ret == 0) {
311 /* Access granted */
312 LOG_MMU("PTE access granted !\n");
313 } else {
314 /* Access right violation */
315 LOG_MMU("PTE access rejected\n");
318 return ret;
321 static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx,
322 uint32_t *pte1p, int ret, int rwx)
324 int store = 0;
326 /* Update page flags */
327 if (!(*pte1p & HPTE32_R_R)) {
328 /* Update accessed flag */
329 *pte1p |= HPTE32_R_R;
330 store = 1;
332 if (!(*pte1p & HPTE32_R_C)) {
333 if (rwx == 1 && ret == 0) {
334 /* Update changed flag */
335 *pte1p |= HPTE32_R_C;
336 store = 1;
337 } else {
338 /* Force page fault for first write access */
339 ctx->prot &= ~PAGE_WRITE;
343 return store;
346 hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
348 return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
351 static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
352 bool secondary, target_ulong ptem,
353 ppc_hash_pte32_t *pte)
355 hwaddr pte_offset = pteg_off;
356 target_ulong pte0, pte1;
357 int i;
359 for (i = 0; i < HPTES_PER_GROUP; i++) {
360 pte0 = ppc_hash32_load_hpte0(env, pte_offset);
361 pte1 = ppc_hash32_load_hpte1(env, pte_offset);
363 if ((pte0 & HPTE32_V_VALID)
364 && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
365 && HPTE32_V_COMPARE(pte0, ptem)) {
366 pte->pte0 = pte0;
367 pte->pte1 = pte1;
368 return pte_offset;
371 pte_offset += HASH_PTE_SIZE_32;
374 return -1;
377 static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
378 target_ulong sr, target_ulong eaddr,
379 ppc_hash_pte32_t *pte)
381 hwaddr pteg_off, pte_offset;
382 hwaddr hash;
383 uint32_t vsid, pgidx, ptem;
385 vsid = sr & SR32_VSID;
386 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
387 hash = vsid ^ pgidx;
388 ptem = (vsid << 7) | (pgidx >> 10);
390 /* Page address translation */
391 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
392 " hash " TARGET_FMT_plx "\n",
393 env->htab_base, env->htab_mask, hash);
395 /* Primary PTEG lookup */
396 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
397 " vsid=%" PRIx32 " ptem=%" PRIx32
398 " hash=" TARGET_FMT_plx "\n",
399 env->htab_base, env->htab_mask, vsid, ptem, hash);
400 pteg_off = get_pteg_offset32(env, hash);
401 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte);
402 if (pte_offset == -1) {
403 /* Secondary PTEG lookup */
404 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
405 " vsid=%" PRIx32 " api=%" PRIx32
406 " hash=" TARGET_FMT_plx "\n", env->htab_base,
407 env->htab_mask, vsid, ptem, ~hash);
408 pteg_off = get_pteg_offset32(env, ~hash);
409 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte);
412 return pte_offset;
415 static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
416 target_ulong eaddr, int rwx)
418 int ret;
419 target_ulong sr;
420 hwaddr pte_offset;
421 ppc_hash_pte32_t pte;
423 /* 1. Handle real mode accesses */
424 if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
425 /* Translation is off */
426 ctx->raddr = eaddr;
427 ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
428 return 0;
431 /* 2. Check Block Address Translation entries (BATs) */
432 if (env->nb_BATs != 0) {
433 ret = ppc_hash32_get_bat(env, ctx, eaddr, rwx);
434 if (ret == 0) {
435 return 0;
439 /* 3. Look up the Segment Register */
440 sr = env->sr[eaddr >> 28];
442 /* 4. Handle direct store segments */
443 if (sr & SR32_T) {
444 return ppc_hash32_direct_store(env, sr, eaddr, rwx,
445 &ctx->raddr, &ctx->prot);
448 /* 5. Check for segment level no-execute violation */
449 ctx->nx = !!(sr & SR32_NX);
450 if ((rwx == 2) && ctx->nx) {
451 return -3;
454 /* 6. Locate the PTE in the hash table */
455 pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
456 if (pte_offset == -1) {
457 return -1;
459 LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
461 /* 7. Check access permissions */
462 ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
463 ((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
464 ret = pte_check_hash32(ctx, pte.pte0, pte.pte1, rwx);
465 /* Update page flags */
466 if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
467 ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
470 return ret;
473 hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
475 struct mmu_ctx_hash32 ctx;
477 /* FIXME: Will not behave sanely for direct store segments, but
478 * they're almost never used */
479 if (unlikely(ppc_hash32_translate(env, &ctx, addr, 0)
480 != 0)) {
481 return -1;
484 return ctx.raddr & TARGET_PAGE_MASK;
487 int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
488 int mmu_idx)
490 struct mmu_ctx_hash32 ctx;
491 int ret = 0;
493 ret = ppc_hash32_translate(env, &ctx, address, rwx);
494 if (ret == 0) {
495 tlb_set_page(env, address & TARGET_PAGE_MASK,
496 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
497 mmu_idx, TARGET_PAGE_SIZE);
498 ret = 0;
499 } else if (ret < 0) {
500 LOG_MMU_STATE(env);
501 if (rwx == 2) {
502 switch (ret) {
503 case -1:
504 /* No matches in page tables or TLB */
505 env->exception_index = POWERPC_EXCP_ISI;
506 env->error_code = 0x40000000;
507 break;
508 case -2:
509 /* Access rights violation */
510 env->exception_index = POWERPC_EXCP_ISI;
511 env->error_code = 0x08000000;
512 break;
513 case -3:
514 /* No execute protection violation */
515 env->exception_index = POWERPC_EXCP_ISI;
516 env->error_code = 0x10000000;
517 break;
518 case -4:
519 /* Direct store exception */
520 /* No code fetch is allowed in direct-store areas */
521 env->exception_index = POWERPC_EXCP_ISI;
522 env->error_code = 0x10000000;
523 break;
525 } else {
526 switch (ret) {
527 case -1:
528 /* No matches in page tables or TLB */
529 env->exception_index = POWERPC_EXCP_DSI;
530 env->error_code = 0;
531 env->spr[SPR_DAR] = address;
532 if (rwx == 1) {
533 env->spr[SPR_DSISR] = 0x42000000;
534 } else {
535 env->spr[SPR_DSISR] = 0x40000000;
537 break;
538 case -2:
539 /* Access rights violation */
540 env->exception_index = POWERPC_EXCP_DSI;
541 env->error_code = 0;
542 env->spr[SPR_DAR] = address;
543 if (rwx == 1) {
544 env->spr[SPR_DSISR] = 0x0A000000;
545 } else {
546 env->spr[SPR_DSISR] = 0x08000000;
548 break;
549 case -4:
550 /* Direct store exception */
551 switch (env->access_type) {
552 case ACCESS_FLOAT:
553 /* Floating point load/store */
554 env->exception_index = POWERPC_EXCP_ALIGN;
555 env->error_code = POWERPC_EXCP_ALIGN_FP;
556 env->spr[SPR_DAR] = address;
557 break;
558 case ACCESS_RES:
559 /* lwarx, ldarx or stwcx. */
560 env->exception_index = POWERPC_EXCP_DSI;
561 env->error_code = 0;
562 env->spr[SPR_DAR] = address;
563 if (rwx == 1) {
564 env->spr[SPR_DSISR] = 0x06000000;
565 } else {
566 env->spr[SPR_DSISR] = 0x04000000;
568 break;
569 case ACCESS_EXT:
570 /* eciwx or ecowx */
571 env->exception_index = POWERPC_EXCP_DSI;
572 env->error_code = 0;
573 env->spr[SPR_DAR] = address;
574 if (rwx == 1) {
575 env->spr[SPR_DSISR] = 0x06100000;
576 } else {
577 env->spr[SPR_DSISR] = 0x04100000;
579 break;
580 default:
581 printf("DSI: invalid exception (%d)\n", ret);
582 env->exception_index = POWERPC_EXCP_PROGRAM;
583 env->error_code =
584 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
585 env->spr[SPR_DAR] = address;
586 break;
588 break;
591 #if 0
592 printf("%s: set exception to %d %02x\n", __func__,
593 env->exception, env->error_code);
594 #endif
595 ret = 1;
598 return ret;