]> git.proxmox.com Git - qemu.git/blob - target-ppc/mmu-hash32.c
mmu-hash*: Fold pte_check*() logic into caller
[qemu.git] / target-ppc / mmu-hash32.c
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
28 //#define DEBUG_BAT
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
38 #ifdef DEBUG_BATS
39 # define LOG_BATS(...) qemu_log(__VA_ARGS__)
40 #else
41 # define LOG_BATS(...) do { } while (0)
42 #endif
43
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 */
49 };
50
51 static 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
89 static int ppc_hash32_check_prot(int prot, int rwx)
90 {
91 int ret;
92
93 if (rwx == 2) {
94 if (prot & PAGE_EXEC) {
95 ret = 0;
96 } else {
97 ret = -2;
98 }
99 } else if (rwx) {
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
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)
120 {
121 target_ulong bl;
122 int pp, valid, prot;
123
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;
135 }
136 }
137 }
138 *blp = bl;
139 *validp = valid;
140 *protp = prot;
141 }
142
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)
146 {
147 target_ulong bl;
148 int key, pp, valid, prot;
149
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);
161 }
162 prot = ppc_hash32_pp_check(key, pp, 0);
163 }
164 *blp = bl;
165 *validp = valid;
166 *protp = prot;
167 }
168
169 static int ppc_hash32_get_bat(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
170 target_ulong virtual, int rwx)
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__,
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];
185 }
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);
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);
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' : '-');
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];
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);
234 }
235 }
236 #endif
237 }
238 /* No hit */
239 return ret;
240 }
241
242 static 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
298 static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, uint32_t *pte1p,
299 int ret, int rwx)
300 {
301 int store = 0;
302
303 /* Update page flags */
304 if (!(*pte1p & HPTE32_R_R)) {
305 /* Update accessed flag */
306 *pte1p |= HPTE32_R_R;
307 store = 1;
308 }
309 if (!(*pte1p & HPTE32_R_C)) {
310 if (rwx == 1 && ret == 0) {
311 /* Update changed flag */
312 *pte1p |= HPTE32_R_C;
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
323 hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
324 {
325 return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
326 }
327
328 static 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
354 static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
355 target_ulong sr, target_ulong eaddr,
356 ppc_hash_pte32_t *pte)
357 {
358 hwaddr pteg_off, pte_offset;
359 hwaddr hash;
360 uint32_t vsid, pgidx, ptem;
361
362 vsid = sr & SR32_VSID;
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);
378 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte);
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);
386 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte);
387 }
388
389 return pte_offset;
390 }
391
392 static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
393 target_ulong eaddr, int rwx)
394 {
395 int ret;
396 target_ulong sr;
397 hwaddr pte_offset;
398 ppc_hash_pte32_t pte;
399
400 assert((rwx == 0) || (rwx == 1) || (rwx == 2));
401
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
418 /* 3. Look up the Segment Register */
419 sr = env->sr[eaddr >> 28];
420
421 /* 4. Handle direct store segments */
422 if (sr & SR32_T) {
423 return ppc_hash32_direct_store(env, sr, eaddr, rwx,
424 &ctx->raddr, &ctx->prot);
425 }
426
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 }
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;
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
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 }
465
466 return ret;
467 }
468
469 hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
470 {
471 struct mmu_ctx_hash32 ctx;
472
473 /* FIXME: Will not behave sanely for direct store segments, but
474 * they're almost never used */
475 if (unlikely(ppc_hash32_translate(env, &ctx, addr, 0)
476 != 0)) {
477 return -1;
478 }
479
480 return ctx.raddr & TARGET_PAGE_MASK;
481 }
482
483 int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
484 int mmu_idx)
485 {
486 struct mmu_ctx_hash32 ctx;
487 int ret = 0;
488
489 ret = ppc_hash32_translate(env, &ctx, address, rwx);
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);
497 if (rwx == 2) {
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;
528 if (rwx == 1) {
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;
539 if (rwx == 1) {
540 env->spr[SPR_DSISR] = 0x0A000000;
541 } else {
542 env->spr[SPR_DSISR] = 0x08000000;
543 }
544 break;
545 case -4:
546 /* Direct store exception */
547 switch (env->access_type) {
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;
559 if (rwx == 1) {
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;
570 if (rwx == 1) {
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 }