]> git.proxmox.com Git - qemu.git/blob - target-ppc/mmu-hash32.c
mmu-hash*: Make find_pte{32, 64} do more of the job of finding ptes
[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 pte_check_hash32(struct mmu_ctx_hash32 *ctx, target_ulong pte0,
299 target_ulong pte1, int rwx)
300 {
301 int access, ret, pp;
302
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");
316 }
317
318 return ret;
319 }
320
321 static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx,
322 uint32_t *pte1p, int ret, int rwx)
323 {
324 int store = 0;
325
326 /* Update page flags */
327 if (!(*pte1p & HPTE32_R_R)) {
328 /* Update accessed flag */
329 *pte1p |= HPTE32_R_R;
330 store = 1;
331 }
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;
340 }
341 }
342
343 return store;
344 }
345
346 hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
347 {
348 return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
349 }
350
351 static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
352 bool secondary, target_ulong ptem,
353 ppc_hash_pte32_t *pte)
354 {
355 hwaddr pte_offset = pteg_off;
356 target_ulong pte0, pte1;
357 int i;
358
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);
362
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;
369 }
370
371 pte_offset += HASH_PTE_SIZE_32;
372 }
373
374 return -1;
375 }
376
377 static int find_pte32(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
378 target_ulong sr, target_ulong eaddr, int rwx)
379 {
380 hwaddr pteg_off, pte_offset;
381 ppc_hash_pte32_t pte;
382 hwaddr hash;
383 uint32_t vsid, pgidx, ptem;
384 int ret;
385
386 ret = -1; /* No entry found */
387 vsid = sr & SR32_VSID;
388 ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
389 ((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
390 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
391 hash = vsid ^ pgidx;
392 ptem = (vsid << 7) | (pgidx >> 10);
393
394 /* Page address translation */
395 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
396 " hash " TARGET_FMT_plx "\n",
397 env->htab_base, env->htab_mask, hash);
398
399 /* Primary PTEG lookup */
400 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
401 " vsid=%" PRIx32 " ptem=%" PRIx32
402 " hash=" TARGET_FMT_plx "\n",
403 env->htab_base, env->htab_mask, vsid, ptem, hash);
404 pteg_off = get_pteg_offset32(env, hash);
405 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, &pte);
406 if (pte_offset == -1) {
407 /* Secondary PTEG lookup */
408 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
409 " vsid=%" PRIx32 " api=%" PRIx32
410 " hash=" TARGET_FMT_plx "\n", env->htab_base,
411 env->htab_mask, vsid, ptem, ~hash);
412 pteg_off = get_pteg_offset32(env, ~hash);
413 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, &pte);
414 }
415
416 if (pte_offset != -1) {
417 ret = pte_check_hash32(ctx, pte.pte0, pte.pte1, rwx);
418 LOG_MMU("found PTE at addr %08" HWADDR_PRIx " prot=%01x ret=%d\n",
419 ctx->raddr, ctx->prot, ret);
420 /* Update page flags */
421 if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
422 ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
423 }
424 }
425
426 return ret;
427 }
428
429 static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
430 target_ulong eaddr, int rwx)
431 {
432 int ret;
433 target_ulong sr;
434
435 /* 1. Handle real mode accesses */
436 if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
437 /* Translation is off */
438 ctx->raddr = eaddr;
439 ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
440 return 0;
441 }
442
443 /* 2. Check Block Address Translation entries (BATs) */
444 if (env->nb_BATs != 0) {
445 ret = ppc_hash32_get_bat(env, ctx, eaddr, rwx);
446 if (ret == 0) {
447 return 0;
448 }
449 }
450
451 /* 3. Look up the Segment Register */
452 sr = env->sr[eaddr >> 28];
453
454 /* 4. Handle direct store segments */
455 if (sr & SR32_T) {
456 return ppc_hash32_direct_store(env, sr, eaddr, rwx,
457 &ctx->raddr, &ctx->prot);
458 }
459
460 /* 5. Check for segment level no-execute violation */
461 ctx->nx = !!(sr & SR32_NX);
462 if ((rwx == 2) && ctx->nx) {
463 return -3;
464 }
465 ret = find_pte32(env, ctx, sr, eaddr, rwx);
466
467 return ret;
468 }
469
470 hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
471 {
472 struct mmu_ctx_hash32 ctx;
473
474 /* FIXME: Will not behave sanely for direct store segments, but
475 * they're almost never used */
476 if (unlikely(ppc_hash32_translate(env, &ctx, addr, 0)
477 != 0)) {
478 return -1;
479 }
480
481 return ctx.raddr & TARGET_PAGE_MASK;
482 }
483
484 int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
485 int mmu_idx)
486 {
487 struct mmu_ctx_hash32 ctx;
488 int ret = 0;
489
490 ret = ppc_hash32_translate(env, &ctx, address, rwx);
491 if (ret == 0) {
492 tlb_set_page(env, address & TARGET_PAGE_MASK,
493 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
494 mmu_idx, TARGET_PAGE_SIZE);
495 ret = 0;
496 } else if (ret < 0) {
497 LOG_MMU_STATE(env);
498 if (rwx == 2) {
499 switch (ret) {
500 case -1:
501 /* No matches in page tables or TLB */
502 env->exception_index = POWERPC_EXCP_ISI;
503 env->error_code = 0x40000000;
504 break;
505 case -2:
506 /* Access rights violation */
507 env->exception_index = POWERPC_EXCP_ISI;
508 env->error_code = 0x08000000;
509 break;
510 case -3:
511 /* No execute protection violation */
512 env->exception_index = POWERPC_EXCP_ISI;
513 env->error_code = 0x10000000;
514 break;
515 case -4:
516 /* Direct store exception */
517 /* No code fetch is allowed in direct-store areas */
518 env->exception_index = POWERPC_EXCP_ISI;
519 env->error_code = 0x10000000;
520 break;
521 }
522 } else {
523 switch (ret) {
524 case -1:
525 /* No matches in page tables or TLB */
526 env->exception_index = POWERPC_EXCP_DSI;
527 env->error_code = 0;
528 env->spr[SPR_DAR] = address;
529 if (rwx == 1) {
530 env->spr[SPR_DSISR] = 0x42000000;
531 } else {
532 env->spr[SPR_DSISR] = 0x40000000;
533 }
534 break;
535 case -2:
536 /* Access rights violation */
537 env->exception_index = POWERPC_EXCP_DSI;
538 env->error_code = 0;
539 env->spr[SPR_DAR] = address;
540 if (rwx == 1) {
541 env->spr[SPR_DSISR] = 0x0A000000;
542 } else {
543 env->spr[SPR_DSISR] = 0x08000000;
544 }
545 break;
546 case -4:
547 /* Direct store exception */
548 switch (env->access_type) {
549 case ACCESS_FLOAT:
550 /* Floating point load/store */
551 env->exception_index = POWERPC_EXCP_ALIGN;
552 env->error_code = POWERPC_EXCP_ALIGN_FP;
553 env->spr[SPR_DAR] = address;
554 break;
555 case ACCESS_RES:
556 /* lwarx, ldarx or stwcx. */
557 env->exception_index = POWERPC_EXCP_DSI;
558 env->error_code = 0;
559 env->spr[SPR_DAR] = address;
560 if (rwx == 1) {
561 env->spr[SPR_DSISR] = 0x06000000;
562 } else {
563 env->spr[SPR_DSISR] = 0x04000000;
564 }
565 break;
566 case ACCESS_EXT:
567 /* eciwx or ecowx */
568 env->exception_index = POWERPC_EXCP_DSI;
569 env->error_code = 0;
570 env->spr[SPR_DAR] = address;
571 if (rwx == 1) {
572 env->spr[SPR_DSISR] = 0x06100000;
573 } else {
574 env->spr[SPR_DSISR] = 0x04100000;
575 }
576 break;
577 default:
578 printf("DSI: invalid exception (%d)\n", ret);
579 env->exception_index = POWERPC_EXCP_PROGRAM;
580 env->error_code =
581 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
582 env->spr[SPR_DAR] = address;
583 break;
584 }
585 break;
586 }
587 }
588 #if 0
589 printf("%s: set exception to %d %02x\n", __func__,
590 env->exception, env->error_code);
591 #endif
592 ret = 1;
593 }
594
595 return ret;
596 }