]> git.proxmox.com Git - qemu.git/blob - target-ppc/mmu-hash32.c
mmu-hash*: Don't update PTE flags when permission is denied
[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 static target_ulong hash32_bat_size(CPUPPCState *env,
117 target_ulong batu, target_ulong batl)
118 {
119 if ((msr_pr && !(batu & BATU32_VP))
120 || (!msr_pr && !(batu & BATU32_VS))) {
121 return 0;
122 }
123
124 return BATU32_BEPI & ~((batu & BATU32_BL) << 15);
125 }
126
127 static int hash32_bat_prot(CPUPPCState *env,
128 target_ulong batu, target_ulong batl)
129 {
130 int pp, prot;
131
132 prot = 0;
133 pp = batl & BATL32_PP;
134 if (pp != 0) {
135 prot = PAGE_READ | PAGE_EXEC;
136 if (pp == 0x2) {
137 prot |= PAGE_WRITE;
138 }
139 }
140 return prot;
141 }
142
143 static target_ulong hash32_bat_601_size(CPUPPCState *env,
144 target_ulong batu, target_ulong batl)
145 {
146 if (!(batl & BATL32_601_V)) {
147 return 0;
148 }
149
150 return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
151 }
152
153 static int hash32_bat_601_prot(CPUPPCState *env,
154 target_ulong batu, target_ulong batl)
155 {
156 int key, pp;
157
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 return ppc_hash32_pp_check(key, pp, 0);
165 }
166
167 static hwaddr ppc_hash32_bat_lookup(CPUPPCState *env, target_ulong ea, int rwx,
168 int *prot)
169 {
170 target_ulong *BATlt, *BATut;
171 int i;
172
173 LOG_BATS("%s: %cBAT v " TARGET_FMT_lx "\n", __func__,
174 rwx == 2 ? 'I' : 'D', ea);
175 if (rwx == 2) {
176 BATlt = env->IBAT[1];
177 BATut = env->IBAT[0];
178 } else {
179 BATlt = env->DBAT[1];
180 BATut = env->DBAT[0];
181 }
182 for (i = 0; i < env->nb_BATs; i++) {
183 target_ulong batu = BATut[i];
184 target_ulong batl = BATlt[i];
185 target_ulong mask;
186
187 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
188 mask = hash32_bat_601_size(env, batu, batl);
189 } else {
190 mask = hash32_bat_size(env, batu, batl);
191 }
192 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
193 " BATl " TARGET_FMT_lx "\n", __func__,
194 type == ACCESS_CODE ? 'I' : 'D', i, ea, batu, batl);
195
196 if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
197 hwaddr raddr = (batl & mask) | (ea & ~mask);
198
199 if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
200 *prot = hash32_bat_601_prot(env, batu, batl);
201 } else {
202 *prot = hash32_bat_prot(env, batu, batl);
203 }
204
205 return raddr & TARGET_PAGE_MASK;
206 }
207 }
208
209 /* No hit */
210 #if defined(DEBUG_BATS)
211 if (qemu_log_enabled()) {
212 LOG_BATS("no BAT match for " TARGET_FMT_lx ":\n", ea);
213 for (i = 0; i < 4; i++) {
214 BATu = &BATut[i];
215 BATl = &BATlt[i];
216 BEPIu = *BATu & BATU32_BEPIU;
217 BEPIl = *BATu & BATU32_BEPIL;
218 bl = (*BATu & 0x00001FFC) << 15;
219 LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
220 " BATl " TARGET_FMT_lx "\n\t" TARGET_FMT_lx " "
221 TARGET_FMT_lx " " TARGET_FMT_lx "\n",
222 __func__, type == ACCESS_CODE ? 'I' : 'D', i, ea,
223 *BATu, *BATl, BEPIu, BEPIl, bl);
224 }
225 }
226 #endif
227
228 return -1;
229 }
230
231 static int ppc_hash32_direct_store(CPUPPCState *env, target_ulong sr,
232 target_ulong eaddr, int rwx,
233 hwaddr *raddr, int *prot)
234 {
235 int key = !!(msr_pr ? (sr & SR32_KP) : (sr & SR32_KS));
236
237 LOG_MMU("direct store...\n");
238
239 if ((sr & 0x1FF00000) >> 20 == 0x07f) {
240 /* Memory-forced I/O controller interface access */
241 /* If T=1 and BUID=x'07F', the 601 performs a memory access
242 * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
243 */
244 *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
245 *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
246 return 0;
247 }
248
249 if (rwx == 2) {
250 /* No code fetch is allowed in direct-store areas */
251 return -4;
252 }
253
254 switch (env->access_type) {
255 case ACCESS_INT:
256 /* Integer load/store : only access allowed */
257 break;
258 case ACCESS_FLOAT:
259 /* Floating point load/store */
260 return -4;
261 case ACCESS_RES:
262 /* lwarx, ldarx or srwcx. */
263 return -4;
264 case ACCESS_CACHE:
265 /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
266 /* Should make the instruction do no-op.
267 * As it already do no-op, it's quite easy :-)
268 */
269 *raddr = eaddr;
270 return 0;
271 case ACCESS_EXT:
272 /* eciwx or ecowx */
273 return -4;
274 default:
275 qemu_log("ERROR: instruction should not need "
276 "address translation\n");
277 return -4;
278 }
279 if ((rwx == 1 || key != 1) && (rwx == 0 || key != 0)) {
280 *raddr = eaddr;
281 return 2;
282 } else {
283 return -2;
284 }
285 }
286
287 static int ppc_hash32_pte_update_flags(struct mmu_ctx_hash32 *ctx, uint32_t *pte1p,
288 int ret, int rwx)
289 {
290 int store = 0;
291
292 /* Update page flags */
293 if (!(*pte1p & HPTE32_R_R)) {
294 /* Update accessed flag */
295 *pte1p |= HPTE32_R_R;
296 store = 1;
297 }
298 if (!(*pte1p & HPTE32_R_C)) {
299 if (rwx == 1 && ret == 0) {
300 /* Update changed flag */
301 *pte1p |= HPTE32_R_C;
302 store = 1;
303 } else {
304 /* Force page fault for first write access */
305 ctx->prot &= ~PAGE_WRITE;
306 }
307 }
308
309 return store;
310 }
311
312 hwaddr get_pteg_offset32(CPUPPCState *env, hwaddr hash)
313 {
314 return (hash * HASH_PTEG_SIZE_32) & env->htab_mask;
315 }
316
317 static hwaddr ppc_hash32_pteg_search(CPUPPCState *env, hwaddr pteg_off,
318 bool secondary, target_ulong ptem,
319 ppc_hash_pte32_t *pte)
320 {
321 hwaddr pte_offset = pteg_off;
322 target_ulong pte0, pte1;
323 int i;
324
325 for (i = 0; i < HPTES_PER_GROUP; i++) {
326 pte0 = ppc_hash32_load_hpte0(env, pte_offset);
327 pte1 = ppc_hash32_load_hpte1(env, pte_offset);
328
329 if ((pte0 & HPTE32_V_VALID)
330 && (secondary == !!(pte0 & HPTE32_V_SECONDARY))
331 && HPTE32_V_COMPARE(pte0, ptem)) {
332 pte->pte0 = pte0;
333 pte->pte1 = pte1;
334 return pte_offset;
335 }
336
337 pte_offset += HASH_PTE_SIZE_32;
338 }
339
340 return -1;
341 }
342
343 static hwaddr ppc_hash32_htab_lookup(CPUPPCState *env,
344 target_ulong sr, target_ulong eaddr,
345 ppc_hash_pte32_t *pte)
346 {
347 hwaddr pteg_off, pte_offset;
348 hwaddr hash;
349 uint32_t vsid, pgidx, ptem;
350
351 vsid = sr & SR32_VSID;
352 pgidx = (eaddr & ~SEGMENT_MASK_256M) >> TARGET_PAGE_BITS;
353 hash = vsid ^ pgidx;
354 ptem = (vsid << 7) | (pgidx >> 10);
355
356 /* Page address translation */
357 LOG_MMU("htab_base " TARGET_FMT_plx " htab_mask " TARGET_FMT_plx
358 " hash " TARGET_FMT_plx "\n",
359 env->htab_base, env->htab_mask, hash);
360
361 /* Primary PTEG lookup */
362 LOG_MMU("0 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
363 " vsid=%" PRIx32 " ptem=%" PRIx32
364 " hash=" TARGET_FMT_plx "\n",
365 env->htab_base, env->htab_mask, vsid, ptem, hash);
366 pteg_off = get_pteg_offset32(env, hash);
367 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 0, ptem, pte);
368 if (pte_offset == -1) {
369 /* Secondary PTEG lookup */
370 LOG_MMU("1 htab=" TARGET_FMT_plx "/" TARGET_FMT_plx
371 " vsid=%" PRIx32 " api=%" PRIx32
372 " hash=" TARGET_FMT_plx "\n", env->htab_base,
373 env->htab_mask, vsid, ptem, ~hash);
374 pteg_off = get_pteg_offset32(env, ~hash);
375 pte_offset = ppc_hash32_pteg_search(env, pteg_off, 1, ptem, pte);
376 }
377
378 return pte_offset;
379 }
380
381 static int ppc_hash32_translate(CPUPPCState *env, struct mmu_ctx_hash32 *ctx,
382 target_ulong eaddr, int rwx)
383 {
384 int ret;
385 target_ulong sr;
386 hwaddr pte_offset;
387 ppc_hash_pte32_t pte;
388
389 assert((rwx == 0) || (rwx == 1) || (rwx == 2));
390
391 /* 1. Handle real mode accesses */
392 if (((rwx == 2) && (msr_ir == 0)) || ((rwx != 2) && (msr_dr == 0))) {
393 /* Translation is off */
394 ctx->raddr = eaddr;
395 ctx->prot = PAGE_READ | PAGE_EXEC | PAGE_WRITE;
396 return 0;
397 }
398
399 /* 2. Check Block Address Translation entries (BATs) */
400 if (env->nb_BATs != 0) {
401 ctx->raddr = ppc_hash32_bat_lookup(env, eaddr, rwx, &ctx->prot);
402 if (ctx->raddr != -1) {
403 return ppc_hash32_check_prot(ctx->prot, rwx);
404 }
405 }
406
407 /* 3. Look up the Segment Register */
408 sr = env->sr[eaddr >> 28];
409
410 /* 4. Handle direct store segments */
411 if (sr & SR32_T) {
412 return ppc_hash32_direct_store(env, sr, eaddr, rwx,
413 &ctx->raddr, &ctx->prot);
414 }
415
416 /* 5. Check for segment level no-execute violation */
417 ctx->nx = !!(sr & SR32_NX);
418 if ((rwx == 2) && ctx->nx) {
419 return -3;
420 }
421
422 /* 6. Locate the PTE in the hash table */
423 pte_offset = ppc_hash32_htab_lookup(env, sr, eaddr, &pte);
424 if (pte_offset == -1) {
425 return -1;
426 }
427 LOG_MMU("found PTE at offset %08" HWADDR_PRIx "\n", pte_offset);
428
429 /* 7. Check access permissions */
430 ctx->key = (((sr & SR32_KP) && (msr_pr != 0)) ||
431 ((sr & SR32_KS) && (msr_pr == 0))) ? 1 : 0;
432
433 int access, pp;
434
435 pp = pte.pte1 & HPTE32_R_PP;
436 /* Compute access rights */
437 access = ppc_hash32_pp_check(ctx->key, pp, ctx->nx);
438 /* Keep the matching PTE informations */
439 ctx->raddr = pte.pte1;
440 ctx->prot = access;
441 ret = ppc_hash32_check_prot(ctx->prot, rwx);
442
443 if (ret) {
444 /* Access right violation */
445 LOG_MMU("PTE access rejected\n");
446 return ret;
447 }
448
449 LOG_MMU("PTE access granted !\n");
450
451 /* 8. Update PTE referenced and changed bits if necessary */
452
453 if (ppc_hash32_pte_update_flags(ctx, &pte.pte1, ret, rwx) == 1) {
454 ppc_hash32_store_hpte1(env, pte_offset, pte.pte1);
455 }
456
457 return ret;
458 }
459
460 hwaddr ppc_hash32_get_phys_page_debug(CPUPPCState *env, target_ulong addr)
461 {
462 struct mmu_ctx_hash32 ctx;
463
464 /* FIXME: Will not behave sanely for direct store segments, but
465 * they're almost never used */
466 if (unlikely(ppc_hash32_translate(env, &ctx, addr, 0)
467 != 0)) {
468 return -1;
469 }
470
471 return ctx.raddr & TARGET_PAGE_MASK;
472 }
473
474 int ppc_hash32_handle_mmu_fault(CPUPPCState *env, target_ulong address, int rwx,
475 int mmu_idx)
476 {
477 struct mmu_ctx_hash32 ctx;
478 int ret = 0;
479
480 ret = ppc_hash32_translate(env, &ctx, address, rwx);
481 if (ret == 0) {
482 tlb_set_page(env, address & TARGET_PAGE_MASK,
483 ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
484 mmu_idx, TARGET_PAGE_SIZE);
485 ret = 0;
486 } else if (ret < 0) {
487 LOG_MMU_STATE(env);
488 if (rwx == 2) {
489 switch (ret) {
490 case -1:
491 /* No matches in page tables or TLB */
492 env->exception_index = POWERPC_EXCP_ISI;
493 env->error_code = 0x40000000;
494 break;
495 case -2:
496 /* Access rights violation */
497 env->exception_index = POWERPC_EXCP_ISI;
498 env->error_code = 0x08000000;
499 break;
500 case -3:
501 /* No execute protection violation */
502 env->exception_index = POWERPC_EXCP_ISI;
503 env->error_code = 0x10000000;
504 break;
505 case -4:
506 /* Direct store exception */
507 /* No code fetch is allowed in direct-store areas */
508 env->exception_index = POWERPC_EXCP_ISI;
509 env->error_code = 0x10000000;
510 break;
511 }
512 } else {
513 switch (ret) {
514 case -1:
515 /* No matches in page tables or TLB */
516 env->exception_index = POWERPC_EXCP_DSI;
517 env->error_code = 0;
518 env->spr[SPR_DAR] = address;
519 if (rwx == 1) {
520 env->spr[SPR_DSISR] = 0x42000000;
521 } else {
522 env->spr[SPR_DSISR] = 0x40000000;
523 }
524 break;
525 case -2:
526 /* Access rights violation */
527 env->exception_index = POWERPC_EXCP_DSI;
528 env->error_code = 0;
529 env->spr[SPR_DAR] = address;
530 if (rwx == 1) {
531 env->spr[SPR_DSISR] = 0x0A000000;
532 } else {
533 env->spr[SPR_DSISR] = 0x08000000;
534 }
535 break;
536 case -4:
537 /* Direct store exception */
538 switch (env->access_type) {
539 case ACCESS_FLOAT:
540 /* Floating point load/store */
541 env->exception_index = POWERPC_EXCP_ALIGN;
542 env->error_code = POWERPC_EXCP_ALIGN_FP;
543 env->spr[SPR_DAR] = address;
544 break;
545 case ACCESS_RES:
546 /* lwarx, ldarx or stwcx. */
547 env->exception_index = POWERPC_EXCP_DSI;
548 env->error_code = 0;
549 env->spr[SPR_DAR] = address;
550 if (rwx == 1) {
551 env->spr[SPR_DSISR] = 0x06000000;
552 } else {
553 env->spr[SPR_DSISR] = 0x04000000;
554 }
555 break;
556 case ACCESS_EXT:
557 /* eciwx or ecowx */
558 env->exception_index = POWERPC_EXCP_DSI;
559 env->error_code = 0;
560 env->spr[SPR_DAR] = address;
561 if (rwx == 1) {
562 env->spr[SPR_DSISR] = 0x06100000;
563 } else {
564 env->spr[SPR_DSISR] = 0x04100000;
565 }
566 break;
567 default:
568 printf("DSI: invalid exception (%d)\n", ret);
569 env->exception_index = POWERPC_EXCP_PROGRAM;
570 env->error_code =
571 POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
572 env->spr[SPR_DAR] = address;
573 break;
574 }
575 break;
576 }
577 }
578 #if 0
579 printf("%s: set exception to %d %02x\n", __func__,
580 env->exception, env->error_code);
581 #endif
582 ret = 1;
583 }
584
585 return ret;
586 }