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