|
|
1.1 root 1: /*
2: * PowerPC emulation helpers for qemu.
1.1.1.4 root 3: *
4: * Copyright (c) 2003-2007 Jocelyn Mayer
1.1 root 5: *
6: * This library is free software; you can redistribute it and/or
7: * modify it under the terms of the GNU Lesser General Public
8: * License as published by the Free Software Foundation; either
9: * version 2 of the License, or (at your option) any later version.
10: *
11: * This library is distributed in the hope that it will be useful,
12: * but WITHOUT ANY WARRANTY; without even the implied warranty of
13: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14: * Lesser General Public License for more details.
15: *
16: * You should have received a copy of the GNU Lesser General Public
17: * License along with this library; if not, write to the Free Software
1.1.1.5 ! root 18: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA
1.1 root 19: */
20: #include <stdarg.h>
21: #include <stdlib.h>
22: #include <stdio.h>
23: #include <string.h>
24: #include <inttypes.h>
25: #include <signal.h>
26: #include <assert.h>
27:
28: #include "cpu.h"
29: #include "exec-all.h"
1.1.1.4 root 30: #include "helper_regs.h"
1.1.1.5 ! root 31: #include "qemu-common.h"
! 32: #include "kvm.h"
1.1 root 33:
34: //#define DEBUG_MMU
35: //#define DEBUG_BATS
1.1.1.4 root 36: //#define DEBUG_SLB
37: //#define DEBUG_SOFTWARE_TLB
38: //#define DUMP_PAGE_TABLES
1.1 root 39: //#define DEBUG_EXCEPTIONS
40: //#define FLUSH_ALL_TLBS
41:
1.1.1.5 ! root 42: #ifdef DEBUG_MMU
! 43: # define LOG_MMU(...) qemu_log(__VA_ARGS__)
! 44: # define LOG_MMU_STATE(env) log_cpu_state((env), 0)
! 45: #else
! 46: # define LOG_MMU(...) do { } while (0)
! 47: # define LOG_MMU_STATE(...) do { } while (0)
! 48: #endif
! 49:
! 50:
! 51: #ifdef DEBUG_SOFTWARE_TLB
! 52: # define LOG_SWTLB(...) qemu_log(__VA_ARGS__)
! 53: #else
! 54: # define LOG_SWTLB(...) do { } while (0)
! 55: #endif
! 56:
! 57: #ifdef DEBUG_BATS
! 58: # define LOG_BATS(...) qemu_log(__VA_ARGS__)
! 59: #else
! 60: # define LOG_BATS(...) do { } while (0)
! 61: #endif
! 62:
! 63: #ifdef DEBUG_SLB
! 64: # define LOG_SLB(...) qemu_log(__VA_ARGS__)
! 65: #else
! 66: # define LOG_SLB(...) do { } while (0)
! 67: #endif
! 68:
! 69: #ifdef DEBUG_EXCEPTIONS
! 70: # define LOG_EXCP(...) qemu_log(__VA_ARGS__)
! 71: #else
! 72: # define LOG_EXCP(...) do { } while (0)
! 73: #endif
! 74:
! 75:
1.1 root 76: /*****************************************************************************/
77: /* PowerPC MMU emulation */
78:
1.1.1.4 root 79: #if defined(CONFIG_USER_ONLY)
80: int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
81: int mmu_idx, int is_softmmu)
1.1.1.2 root 82: {
83: int exception, error_code;
1.1.1.4 root 84:
1.1.1.2 root 85: if (rw == 2) {
1.1.1.4 root 86: exception = POWERPC_EXCP_ISI;
87: error_code = 0x40000000;
1.1.1.2 root 88: } else {
1.1.1.4 root 89: exception = POWERPC_EXCP_DSI;
90: error_code = 0x40000000;
1.1.1.2 root 91: if (rw)
92: error_code |= 0x02000000;
93: env->spr[SPR_DAR] = address;
94: env->spr[SPR_DSISR] = error_code;
95: }
96: env->exception_index = exception;
97: env->error_code = error_code;
1.1.1.4 root 98:
1.1.1.2 root 99: return 1;
100: }
1.1.1.4 root 101:
102: target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
1.1.1.2 root 103: {
104: return addr;
105: }
1.1.1.4 root 106:
107: #else
108: /* Common routines used by software and hardware TLBs emulation */
109: static always_inline int pte_is_valid (target_ulong pte0)
110: {
111: return pte0 & 0x80000000 ? 1 : 0;
112: }
113:
114: static always_inline void pte_invalidate (target_ulong *pte0)
115: {
116: *pte0 &= ~0x80000000;
117: }
118:
119: #if defined(TARGET_PPC64)
120: static always_inline int pte64_is_valid (target_ulong pte0)
121: {
122: return pte0 & 0x0000000000000001ULL ? 1 : 0;
123: }
124:
125: static always_inline void pte64_invalidate (target_ulong *pte0)
126: {
127: *pte0 &= ~0x0000000000000001ULL;
128: }
129: #endif
130:
131: #define PTE_PTEM_MASK 0x7FFFFFBF
132: #define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
133: #if defined(TARGET_PPC64)
134: #define PTE64_PTEM_MASK 0xFFFFFFFFFFFFFF80ULL
135: #define PTE64_CHECK_MASK (TARGET_PAGE_MASK | 0x7F)
136: #endif
137:
138: static always_inline int pp_check (int key, int pp, int nx)
139: {
140: int access;
141:
142: /* Compute access rights */
143: /* When pp is 3/7, the result is undefined. Set it to noaccess */
144: access = 0;
145: if (key == 0) {
146: switch (pp) {
147: case 0x0:
148: case 0x1:
149: case 0x2:
150: access |= PAGE_WRITE;
151: /* No break here */
152: case 0x3:
153: case 0x6:
154: access |= PAGE_READ;
155: break;
156: }
157: } else {
158: switch (pp) {
159: case 0x0:
160: case 0x6:
161: access = 0;
162: break;
163: case 0x1:
164: case 0x3:
165: access = PAGE_READ;
166: break;
167: case 0x2:
168: access = PAGE_READ | PAGE_WRITE;
169: break;
170: }
171: }
172: if (nx == 0)
173: access |= PAGE_EXEC;
174:
175: return access;
176: }
177:
178: static always_inline int check_prot (int prot, int rw, int access_type)
179: {
180: int ret;
181:
182: if (access_type == ACCESS_CODE) {
183: if (prot & PAGE_EXEC)
184: ret = 0;
185: else
186: ret = -2;
187: } else if (rw) {
188: if (prot & PAGE_WRITE)
189: ret = 0;
190: else
191: ret = -2;
192: } else {
193: if (prot & PAGE_READ)
194: ret = 0;
195: else
196: ret = -2;
197: }
198:
199: return ret;
200: }
201:
202: static always_inline int _pte_check (mmu_ctx_t *ctx, int is_64b,
203: target_ulong pte0, target_ulong pte1,
204: int h, int rw, int type)
205: {
206: target_ulong ptem, mmask;
207: int access, ret, pteh, ptev, pp;
208:
209: access = 0;
210: ret = -1;
211: /* Check validity and table match */
212: #if defined(TARGET_PPC64)
213: if (is_64b) {
214: ptev = pte64_is_valid(pte0);
215: pteh = (pte0 >> 1) & 1;
216: } else
217: #endif
218: {
219: ptev = pte_is_valid(pte0);
220: pteh = (pte0 >> 6) & 1;
221: }
222: if (ptev && h == pteh) {
223: /* Check vsid & api */
224: #if defined(TARGET_PPC64)
225: if (is_64b) {
226: ptem = pte0 & PTE64_PTEM_MASK;
227: mmask = PTE64_CHECK_MASK;
228: pp = (pte1 & 0x00000003) | ((pte1 >> 61) & 0x00000004);
229: ctx->nx |= (pte1 >> 2) & 1; /* No execute bit */
230: ctx->nx |= (pte1 >> 3) & 1; /* Guarded bit */
231: } else
232: #endif
233: {
234: ptem = pte0 & PTE_PTEM_MASK;
235: mmask = PTE_CHECK_MASK;
236: pp = pte1 & 0x00000003;
237: }
238: if (ptem == ctx->ptem) {
239: if (ctx->raddr != (target_phys_addr_t)-1ULL) {
240: /* all matches should have equal RPN, WIMG & PP */
241: if ((ctx->raddr & mmask) != (pte1 & mmask)) {
1.1.1.5 ! root 242: qemu_log("Bad RPN/WIMG/PP\n");
1.1.1.4 root 243: return -3;
244: }
245: }
246: /* Compute access rights */
247: access = pp_check(ctx->key, pp, ctx->nx);
248: /* Keep the matching PTE informations */
249: ctx->raddr = pte1;
250: ctx->prot = access;
251: ret = check_prot(ctx->prot, rw, type);
252: if (ret == 0) {
253: /* Access granted */
1.1.1.5 ! root 254: LOG_MMU("PTE access granted !\n");
1.1.1.4 root 255: } else {
256: /* Access right violation */
1.1.1.5 ! root 257: LOG_MMU("PTE access rejected\n");
1.1.1.4 root 258: }
259: }
260: }
261:
262: return ret;
263: }
264:
265: static always_inline int pte32_check (mmu_ctx_t *ctx,
266: target_ulong pte0, target_ulong pte1,
267: int h, int rw, int type)
268: {
269: return _pte_check(ctx, 0, pte0, pte1, h, rw, type);
270: }
271:
272: #if defined(TARGET_PPC64)
273: static always_inline int pte64_check (mmu_ctx_t *ctx,
274: target_ulong pte0, target_ulong pte1,
275: int h, int rw, int type)
276: {
277: return _pte_check(ctx, 1, pte0, pte1, h, rw, type);
278: }
279: #endif
280:
281: static always_inline int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
282: int ret, int rw)
283: {
284: int store = 0;
285:
286: /* Update page flags */
287: if (!(*pte1p & 0x00000100)) {
288: /* Update accessed flag */
289: *pte1p |= 0x00000100;
290: store = 1;
291: }
292: if (!(*pte1p & 0x00000080)) {
293: if (rw == 1 && ret == 0) {
294: /* Update changed flag */
295: *pte1p |= 0x00000080;
296: store = 1;
297: } else {
298: /* Force page fault for first write access */
299: ctx->prot &= ~PAGE_WRITE;
300: }
301: }
302:
303: return store;
304: }
305:
306: /* Software driven TLB helpers */
307: static always_inline int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
308: int way, int is_code)
309: {
310: int nr;
311:
312: /* Select TLB num in a way from address */
313: nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
314: /* Select TLB way */
315: nr += env->tlb_per_way * way;
316: /* 6xx have separate TLBs for instructions and data */
317: if (is_code && env->id_tlbs == 1)
318: nr += env->nb_tlb;
319:
320: return nr;
321: }
322:
323: static always_inline void ppc6xx_tlb_invalidate_all (CPUState *env)
324: {
325: ppc6xx_tlb_t *tlb;
326: int nr, max;
327:
1.1.1.5 ! root 328: //LOG_SWTLB("Invalidate all TLBs\n");
1.1.1.4 root 329: /* Invalidate all defined software TLB */
330: max = env->nb_tlb;
331: if (env->id_tlbs == 1)
332: max *= 2;
333: for (nr = 0; nr < max; nr++) {
334: tlb = &env->tlb[nr].tlb6;
335: pte_invalidate(&tlb->pte0);
336: }
337: tlb_flush(env, 1);
338: }
339:
340: static always_inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
341: target_ulong eaddr,
342: int is_code,
343: int match_epn)
344: {
345: #if !defined(FLUSH_ALL_TLBS)
346: ppc6xx_tlb_t *tlb;
347: int way, nr;
348:
349: /* Invalidate ITLB + DTLB, all ways */
350: for (way = 0; way < env->nb_ways; way++) {
351: nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
352: tlb = &env->tlb[nr].tlb6;
353: if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
1.1.1.5 ! root 354: LOG_SWTLB("TLB invalidate %d/%d " ADDRX "\n",
1.1.1.4 root 355: nr, env->nb_tlb, eaddr);
356: pte_invalidate(&tlb->pte0);
357: tlb_flush_page(env, tlb->EPN);
358: }
359: }
1.1.1.2 root 360: #else
1.1.1.4 root 361: /* XXX: PowerPC specification say this is valid as well */
362: ppc6xx_tlb_invalidate_all(env);
363: #endif
364: }
365:
366: static always_inline void ppc6xx_tlb_invalidate_virt (CPUState *env,
367: target_ulong eaddr,
368: int is_code)
369: {
370: __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
371: }
372:
373: void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
374: target_ulong pte0, target_ulong pte1)
375: {
376: ppc6xx_tlb_t *tlb;
377: int nr;
378:
379: nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
380: tlb = &env->tlb[nr].tlb6;
1.1.1.5 ! root 381: LOG_SWTLB("Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX
1.1.1.4 root 382: " PTE1 " ADDRX "\n", nr, env->nb_tlb, EPN, pte0, pte1);
383: /* Invalidate any pending reference in Qemu for this virtual address */
384: __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
385: tlb->pte0 = pte0;
386: tlb->pte1 = pte1;
387: tlb->EPN = EPN;
388: /* Store last way for LRU mechanism */
389: env->last_way = way;
390: }
391:
392: static always_inline int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
393: target_ulong eaddr, int rw,
394: int access_type)
395: {
396: ppc6xx_tlb_t *tlb;
397: int nr, best, way;
398: int ret;
399:
400: best = -1;
401: ret = -1; /* No TLB found */
402: for (way = 0; way < env->nb_ways; way++) {
403: nr = ppc6xx_tlb_getnum(env, eaddr, way,
404: access_type == ACCESS_CODE ? 1 : 0);
405: tlb = &env->tlb[nr].tlb6;
406: /* This test "emulates" the PTE index match for hardware TLBs */
407: if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
1.1.1.5 ! root 408: LOG_SWTLB("TLB %d/%d %s [" ADDRX " " ADDRX
1.1.1.4 root 409: "] <> " ADDRX "\n",
410: nr, env->nb_tlb,
411: pte_is_valid(tlb->pte0) ? "valid" : "inval",
412: tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
413: continue;
414: }
1.1.1.5 ! root 415: LOG_SWTLB("TLB %d/%d %s " ADDRX " <> " ADDRX " " ADDRX
1.1.1.4 root 416: " %c %c\n",
417: nr, env->nb_tlb,
418: pte_is_valid(tlb->pte0) ? "valid" : "inval",
419: tlb->EPN, eaddr, tlb->pte1,
420: rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
421: switch (pte32_check(ctx, tlb->pte0, tlb->pte1, 0, rw, access_type)) {
422: case -3:
423: /* TLB inconsistency */
424: return -1;
425: case -2:
426: /* Access violation */
427: ret = -2;
428: best = nr;
429: break;
430: case -1:
431: default:
432: /* No match */
433: break;
434: case 0:
435: /* access granted */
436: /* XXX: we should go on looping to check all TLBs consistency
437: * but we can speed-up the whole thing as the
438: * result would be undefined if TLBs are not consistent.
439: */
440: ret = 0;
441: best = nr;
442: goto done;
443: }
444: }
445: if (best != -1) {
446: done:
1.1.1.5 ! root 447: LOG_SWTLB("found TLB at addr " PADDRX " prot=%01x ret=%d\n",
1.1.1.4 root 448: ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
449: /* Update page flags */
450: pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
451: }
452:
453: return ret;
454: }
455:
1.1 root 456: /* Perform BAT hit & translation */
1.1.1.4 root 457: static always_inline void bat_size_prot (CPUState *env, target_ulong *blp,
458: int *validp, int *protp,
459: target_ulong *BATu, target_ulong *BATl)
460: {
461: target_ulong bl;
462: int pp, valid, prot;
463:
464: bl = (*BATu & 0x00001FFC) << 15;
465: valid = 0;
466: prot = 0;
467: if (((msr_pr == 0) && (*BATu & 0x00000002)) ||
468: ((msr_pr != 0) && (*BATu & 0x00000001))) {
469: valid = 1;
470: pp = *BATl & 0x00000003;
471: if (pp != 0) {
472: prot = PAGE_READ | PAGE_EXEC;
473: if (pp == 0x2)
474: prot |= PAGE_WRITE;
475: }
476: }
477: *blp = bl;
478: *validp = valid;
479: *protp = prot;
480: }
481:
482: static always_inline void bat_601_size_prot (CPUState *env,target_ulong *blp,
483: int *validp, int *protp,
484: target_ulong *BATu,
485: target_ulong *BATl)
1.1 root 486: {
1.1.1.4 root 487: target_ulong bl;
488: int key, pp, valid, prot;
489:
490: bl = (*BATl & 0x0000003F) << 17;
1.1.1.5 ! root 491: LOG_BATS("b %02x ==> bl " ADDRX " msk " ADDRX "\n",
1.1.1.4 root 492: (uint8_t)(*BATl & 0x0000003F), bl, ~bl);
493: prot = 0;
494: valid = (*BATl >> 6) & 1;
495: if (valid) {
496: pp = *BATu & 0x00000003;
497: if (msr_pr == 0)
498: key = (*BATu >> 3) & 1;
499: else
500: key = (*BATu >> 2) & 1;
501: prot = pp_check(key, pp, 0);
502: }
503: *blp = bl;
504: *validp = valid;
505: *protp = prot;
506: }
507:
508: static always_inline int get_bat (CPUState *env, mmu_ctx_t *ctx,
509: target_ulong virtual, int rw, int type)
510: {
511: target_ulong *BATlt, *BATut, *BATu, *BATl;
512: target_ulong base, BEPIl, BEPIu, bl;
513: int i, valid, prot;
1.1 root 514: int ret = -1;
515:
1.1.1.5 ! root 516: LOG_BATS("%s: %cBAT v " ADDRX "\n", __func__,
1.1.1.4 root 517: type == ACCESS_CODE ? 'I' : 'D', virtual);
1.1 root 518: switch (type) {
519: case ACCESS_CODE:
520: BATlt = env->IBAT[1];
521: BATut = env->IBAT[0];
522: break;
523: default:
524: BATlt = env->DBAT[1];
525: BATut = env->DBAT[0];
526: break;
527: }
528: base = virtual & 0xFFFC0000;
1.1.1.4 root 529: for (i = 0; i < env->nb_BATs; i++) {
1.1 root 530: BATu = &BATut[i];
531: BATl = &BATlt[i];
532: BEPIu = *BATu & 0xF0000000;
533: BEPIl = *BATu & 0x0FFE0000;
1.1.1.4 root 534: if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
535: bat_601_size_prot(env, &bl, &valid, &prot, BATu, BATl);
536: } else {
537: bat_size_prot(env, &bl, &valid, &prot, BATu, BATl);
538: }
1.1.1.5 ! root 539: LOG_BATS("%s: %cBAT%d v " ADDRX " BATu " ADDRX
1.1.1.4 root 540: " BATl " ADDRX "\n", __func__,
541: type == ACCESS_CODE ? 'I' : 'D', i, virtual, *BATu, *BATl);
1.1 root 542: if ((virtual & 0xF0000000) == BEPIu &&
543: ((virtual & 0x0FFE0000) & ~bl) == BEPIl) {
544: /* BAT matches */
1.1.1.4 root 545: if (valid != 0) {
1.1 root 546: /* Get physical address */
1.1.1.4 root 547: ctx->raddr = (*BATl & 0xF0000000) |
1.1 root 548: ((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
549: (virtual & 0x0001F000);
1.1.1.4 root 550: /* Compute access rights */
551: ctx->prot = prot;
552: ret = check_prot(ctx->prot, rw, type);
1.1.1.5 ! root 553: if (ret == 0)
! 554: LOG_BATS("BAT %d match: r " PADDRX " prot=%c%c\n",
! 555: i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
! 556: ctx->prot & PAGE_WRITE ? 'W' : '-');
1.1 root 557: break;
558: }
559: }
560: }
561: if (ret < 0) {
1.1.1.5 ! root 562: #if defined(DEBUG_BATS)
! 563: if (IS_LOGGING) {
! 564: QEMU_LOG0("no BAT match for " ADDRX ":\n", virtual);
1.1.1.4 root 565: for (i = 0; i < 4; i++) {
566: BATu = &BATut[i];
567: BATl = &BATlt[i];
568: BEPIu = *BATu & 0xF0000000;
569: BEPIl = *BATu & 0x0FFE0000;
570: bl = (*BATu & 0x00001FFC) << 15;
1.1.1.5 ! root 571: QEMU_LOG0("%s: %cBAT%d v " ADDRX " BATu " ADDRX
1.1.1.4 root 572: " BATl " ADDRX " \n\t" ADDRX " " ADDRX " " ADDRX "\n",
573: __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
574: *BATu, *BATl, BEPIu, BEPIl, bl);
575: }
1.1 root 576: }
577: #endif
578: }
579: /* No hit */
580: return ret;
581: }
582:
583: /* PTE table lookup */
1.1.1.4 root 584: static always_inline int _find_pte (mmu_ctx_t *ctx, int is_64b, int h,
585: int rw, int type)
1.1 root 586: {
1.1.1.4 root 587: target_ulong base, pte0, pte1;
588: int i, good = -1;
589: int ret, r;
1.1 root 590:
1.1.1.4 root 591: ret = -1; /* No entry found */
592: base = ctx->pg_addr[h];
1.1 root 593: for (i = 0; i < 8; i++) {
1.1.1.4 root 594: #if defined(TARGET_PPC64)
595: if (is_64b) {
596: pte0 = ldq_phys(base + (i * 16));
597: pte1 = ldq_phys(base + (i * 16) + 8);
598: r = pte64_check(ctx, pte0, pte1, h, rw, type);
1.1.1.5 ! root 599: LOG_MMU("Load pte from " ADDRX " => " ADDRX " " ADDRX
1.1.1.4 root 600: " %d %d %d " ADDRX "\n",
601: base + (i * 16), pte0, pte1,
602: (int)(pte0 & 1), h, (int)((pte0 >> 1) & 1),
603: ctx->ptem);
604: } else
1.1 root 605: #endif
1.1.1.4 root 606: {
607: pte0 = ldl_phys(base + (i * 8));
608: pte1 = ldl_phys(base + (i * 8) + 4);
609: r = pte32_check(ctx, pte0, pte1, h, rw, type);
1.1.1.5 ! root 610: LOG_MMU("Load pte from " ADDRX " => " ADDRX " " ADDRX
1.1.1.4 root 611: " %d %d %d " ADDRX "\n",
612: base + (i * 8), pte0, pte1,
613: (int)(pte0 >> 31), h, (int)((pte0 >> 6) & 1),
614: ctx->ptem);
615: }
616: switch (r) {
617: case -3:
618: /* PTE inconsistency */
619: return -1;
620: case -2:
621: /* Access violation */
622: ret = -2;
623: good = i;
624: break;
625: case -1:
626: default:
627: /* No PTE match */
628: break;
629: case 0:
630: /* access granted */
631: /* XXX: we should go on looping to check all PTEs consistency
632: * but if we can speed-up the whole thing as the
633: * result would be undefined if PTEs are not consistent.
634: */
635: ret = 0;
636: good = i;
637: goto done;
1.1 root 638: }
639: }
640: if (good != -1) {
1.1.1.4 root 641: done:
1.1.1.5 ! root 642: LOG_MMU("found PTE at addr " PADDRX " prot=%01x ret=%d\n",
1.1.1.4 root 643: ctx->raddr, ctx->prot, ret);
1.1 root 644: /* Update page flags */
1.1.1.4 root 645: pte1 = ctx->raddr;
646: if (pte_update_flags(ctx, &pte1, ret, rw) == 1) {
647: #if defined(TARGET_PPC64)
648: if (is_64b) {
649: stq_phys_notdirty(base + (good * 16) + 8, pte1);
650: } else
651: #endif
652: {
653: stl_phys_notdirty(base + (good * 8) + 4, pte1);
1.1 root 654: }
655: }
656: }
657:
658: return ret;
659: }
660:
1.1.1.4 root 661: static always_inline int find_pte32 (mmu_ctx_t *ctx, int h, int rw, int type)
1.1 root 662: {
1.1.1.4 root 663: return _find_pte(ctx, 0, h, rw, type);
1.1 root 664: }
665:
1.1.1.4 root 666: #if defined(TARGET_PPC64)
667: static always_inline int find_pte64 (mmu_ctx_t *ctx, int h, int rw, int type)
1.1 root 668: {
1.1.1.4 root 669: return _find_pte(ctx, 1, h, rw, type);
670: }
671: #endif
1.1 root 672:
1.1.1.4 root 673: static always_inline int find_pte (CPUState *env, mmu_ctx_t *ctx,
674: int h, int rw, int type)
675: {
676: #if defined(TARGET_PPC64)
677: if (env->mmu_model & POWERPC_MMU_64)
678: return find_pte64(ctx, h, rw, type);
1.1 root 679: #endif
1.1.1.4 root 680:
681: return find_pte32(ctx, h, rw, type);
682: }
683:
684: #if defined(TARGET_PPC64)
685: static always_inline int slb_is_valid (uint64_t slb64)
686: {
687: return slb64 & 0x0000000008000000ULL ? 1 : 0;
688: }
689:
690: static always_inline void slb_invalidate (uint64_t *slb64)
691: {
692: *slb64 &= ~0x0000000008000000ULL;
693: }
694:
695: static always_inline int slb_lookup (CPUPPCState *env, target_ulong eaddr,
696: target_ulong *vsid,
697: target_ulong *page_mask, int *attr)
698: {
699: target_phys_addr_t sr_base;
700: target_ulong mask;
701: uint64_t tmp64;
702: uint32_t tmp;
703: int n, ret;
704:
705: ret = -5;
706: sr_base = env->spr[SPR_ASR];
1.1.1.5 ! root 707: LOG_SLB("%s: eaddr " ADDRX " base " PADDRX "\n",
1.1.1.4 root 708: __func__, eaddr, sr_base);
709: mask = 0x0000000000000000ULL; /* Avoid gcc warning */
710: for (n = 0; n < env->slb_nr; n++) {
711: tmp64 = ldq_phys(sr_base);
712: tmp = ldl_phys(sr_base + 8);
1.1.1.5 ! root 713: LOG_SLB("%s: seg %d " PADDRX " %016" PRIx64 " %08"
1.1.1.4 root 714: PRIx32 "\n", __func__, n, sr_base, tmp64, tmp);
715: if (slb_is_valid(tmp64)) {
716: /* SLB entry is valid */
717: switch (tmp64 & 0x0000000006000000ULL) {
718: case 0x0000000000000000ULL:
719: /* 256 MB segment */
720: mask = 0xFFFFFFFFF0000000ULL;
721: break;
722: case 0x0000000002000000ULL:
723: /* 1 TB segment */
724: mask = 0xFFFF000000000000ULL;
725: break;
726: case 0x0000000004000000ULL:
727: case 0x0000000006000000ULL:
728: /* Reserved => segment is invalid */
729: continue;
1.1 root 730: }
1.1.1.4 root 731: if ((eaddr & mask) == (tmp64 & mask)) {
732: /* SLB match */
733: *vsid = ((tmp64 << 24) | (tmp >> 8)) & 0x0003FFFFFFFFFFFFULL;
734: *page_mask = ~mask;
735: *attr = tmp & 0xFF;
736: ret = n;
737: break;
738: }
739: }
740: sr_base += 12;
741: }
742:
743: return ret;
744: }
745:
746: void ppc_slb_invalidate_all (CPUPPCState *env)
747: {
748: target_phys_addr_t sr_base;
749: uint64_t tmp64;
750: int n, do_invalidate;
751:
752: do_invalidate = 0;
753: sr_base = env->spr[SPR_ASR];
754: /* XXX: Warning: slbia never invalidates the first segment */
755: for (n = 1; n < env->slb_nr; n++) {
756: tmp64 = ldq_phys(sr_base);
757: if (slb_is_valid(tmp64)) {
758: slb_invalidate(&tmp64);
759: stq_phys(sr_base, tmp64);
760: /* XXX: given the fact that segment size is 256 MB or 1TB,
761: * and we still don't have a tlb_flush_mask(env, n, mask)
762: * in Qemu, we just invalidate all TLBs
763: */
764: do_invalidate = 1;
765: }
766: sr_base += 12;
767: }
768: if (do_invalidate)
769: tlb_flush(env, 1);
770: }
771:
772: void ppc_slb_invalidate_one (CPUPPCState *env, uint64_t T0)
773: {
774: target_phys_addr_t sr_base;
775: target_ulong vsid, page_mask;
776: uint64_t tmp64;
777: int attr;
778: int n;
779:
780: n = slb_lookup(env, T0, &vsid, &page_mask, &attr);
781: if (n >= 0) {
782: sr_base = env->spr[SPR_ASR];
783: sr_base += 12 * n;
784: tmp64 = ldq_phys(sr_base);
785: if (slb_is_valid(tmp64)) {
786: slb_invalidate(&tmp64);
787: stq_phys(sr_base, tmp64);
788: /* XXX: given the fact that segment size is 256 MB or 1TB,
789: * and we still don't have a tlb_flush_mask(env, n, mask)
790: * in Qemu, we just invalidate all TLBs
791: */
792: tlb_flush(env, 1);
1.1 root 793: }
1.1.1.4 root 794: }
795: }
796:
797: target_ulong ppc_load_slb (CPUPPCState *env, int slb_nr)
798: {
799: target_phys_addr_t sr_base;
800: target_ulong rt;
801: uint64_t tmp64;
802: uint32_t tmp;
803:
804: sr_base = env->spr[SPR_ASR];
805: sr_base += 12 * slb_nr;
806: tmp64 = ldq_phys(sr_base);
807: tmp = ldl_phys(sr_base + 8);
808: if (tmp64 & 0x0000000008000000ULL) {
809: /* SLB entry is valid */
810: /* Copy SLB bits 62:88 to Rt 37:63 (VSID 23:49) */
811: rt = tmp >> 8; /* 65:88 => 40:63 */
812: rt |= (tmp64 & 0x7) << 24; /* 62:64 => 37:39 */
813: /* Copy SLB bits 89:92 to Rt 33:36 (KsKpNL) */
814: rt |= ((tmp >> 4) & 0xF) << 27;
1.1 root 815: } else {
1.1.1.4 root 816: rt = 0;
817: }
1.1.1.5 ! root 818: LOG_SLB("%s: " PADDRX " %016" PRIx64 " %08" PRIx32 " => %d "
1.1.1.4 root 819: ADDRX "\n", __func__, sr_base, tmp64, tmp, slb_nr, rt);
820:
821: return rt;
822: }
823:
824: void ppc_store_slb (CPUPPCState *env, int slb_nr, target_ulong rs)
825: {
826: target_phys_addr_t sr_base;
827: uint64_t tmp64;
828: uint32_t tmp;
829:
830: sr_base = env->spr[SPR_ASR];
831: sr_base += 12 * slb_nr;
832: /* Copy Rs bits 37:63 to SLB 62:88 */
833: tmp = rs << 8;
834: tmp64 = (rs >> 24) & 0x7;
835: /* Copy Rs bits 33:36 to SLB 89:92 */
836: tmp |= ((rs >> 27) & 0xF) << 4;
837: /* Set the valid bit */
838: tmp64 |= 1 << 27;
839: /* Set ESID */
840: tmp64 |= (uint32_t)slb_nr << 28;
1.1.1.5 ! root 841: LOG_SLB("%s: %d " ADDRX " => " PADDRX " %016" PRIx64
1.1.1.4 root 842: " %08" PRIx32 "\n", __func__,
843: slb_nr, rs, sr_base, tmp64, tmp);
844: /* Write SLB entry to memory */
845: stq_phys(sr_base, tmp64);
846: stl_phys(sr_base + 8, tmp);
847: }
848: #endif /* defined(TARGET_PPC64) */
849:
850: /* Perform segment based translation */
851: static always_inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
852: int sdr_sh,
853: target_phys_addr_t hash,
854: target_phys_addr_t mask)
855: {
856: return (sdr1 & ((target_phys_addr_t)(-1ULL) << sdr_sh)) | (hash & mask);
857: }
858:
859: static always_inline int get_segment (CPUState *env, mmu_ctx_t *ctx,
860: target_ulong eaddr, int rw, int type)
861: {
862: target_phys_addr_t sdr, hash, mask, sdr_mask, htab_mask;
863: target_ulong sr, vsid, vsid_mask, pgidx, page_mask;
864: #if defined(TARGET_PPC64)
865: int attr;
866: #endif
867: int ds, vsid_sh, sdr_sh, pr;
868: int ret, ret2;
869:
870: pr = msr_pr;
871: #if defined(TARGET_PPC64)
872: if (env->mmu_model & POWERPC_MMU_64) {
1.1.1.5 ! root 873: LOG_MMU("Check SLBs\n");
1.1.1.4 root 874: ret = slb_lookup(env, eaddr, &vsid, &page_mask, &attr);
875: if (ret < 0)
876: return ret;
877: ctx->key = ((attr & 0x40) && (pr != 0)) ||
878: ((attr & 0x80) && (pr == 0)) ? 1 : 0;
879: ds = 0;
880: ctx->nx = attr & 0x20 ? 1 : 0;
881: vsid_mask = 0x00003FFFFFFFFF80ULL;
882: vsid_sh = 7;
883: sdr_sh = 18;
884: sdr_mask = 0x3FF80;
885: } else
886: #endif /* defined(TARGET_PPC64) */
887: {
888: sr = env->sr[eaddr >> 28];
889: page_mask = 0x0FFFFFFF;
890: ctx->key = (((sr & 0x20000000) && (pr != 0)) ||
891: ((sr & 0x40000000) && (pr == 0))) ? 1 : 0;
892: ds = sr & 0x80000000 ? 1 : 0;
893: ctx->nx = sr & 0x10000000 ? 1 : 0;
894: vsid = sr & 0x00FFFFFF;
895: vsid_mask = 0x01FFFFC0;
896: vsid_sh = 6;
897: sdr_sh = 16;
898: sdr_mask = 0xFFC0;
1.1.1.5 ! root 899: LOG_MMU("Check segment v=" ADDRX " %d " ADDRX
1.1.1.4 root 900: " nip=" ADDRX " lr=" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n",
901: eaddr, (int)(eaddr >> 28), sr, env->nip,
902: env->lr, (int)msr_ir, (int)msr_dr, pr != 0 ? 1 : 0,
903: rw, type);
904: }
1.1.1.5 ! root 905: LOG_MMU("pte segment: key=%d ds %d nx %d vsid " ADDRX "\n",
1.1.1.4 root 906: ctx->key, ds, ctx->nx, vsid);
907: ret = -1;
908: if (!ds) {
909: /* Check if instruction fetch is allowed, if needed */
910: if (type != ACCESS_CODE || ctx->nx == 0) {
911: /* Page address translation */
912: /* Primary table address */
913: sdr = env->sdr1;
914: pgidx = (eaddr & page_mask) >> TARGET_PAGE_BITS;
915: #if defined(TARGET_PPC64)
916: if (env->mmu_model & POWERPC_MMU_64) {
917: htab_mask = 0x0FFFFFFF >> (28 - (sdr & 0x1F));
918: /* XXX: this is false for 1 TB segments */
919: hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
920: } else
921: #endif
922: {
923: htab_mask = sdr & 0x000001FF;
924: hash = ((vsid ^ pgidx) << vsid_sh) & vsid_mask;
925: }
926: mask = (htab_mask << sdr_sh) | sdr_mask;
1.1.1.5 ! root 927: LOG_MMU("sdr " PADDRX " sh %d hash " PADDRX
1.1.1.4 root 928: " mask " PADDRX " " ADDRX "\n",
929: sdr, sdr_sh, hash, mask, page_mask);
930: ctx->pg_addr[0] = get_pgaddr(sdr, sdr_sh, hash, mask);
931: /* Secondary table address */
932: hash = (~hash) & vsid_mask;
1.1.1.5 ! root 933: LOG_MMU("sdr " PADDRX " sh %d hash " PADDRX
1.1.1.4 root 934: " mask " PADDRX "\n",
935: sdr, sdr_sh, hash, mask);
936: ctx->pg_addr[1] = get_pgaddr(sdr, sdr_sh, hash, mask);
937: #if defined(TARGET_PPC64)
938: if (env->mmu_model & POWERPC_MMU_64) {
939: /* Only 5 bits of the page index are used in the AVPN */
940: ctx->ptem = (vsid << 12) | ((pgidx >> 4) & 0x0F80);
941: } else
942: #endif
943: {
944: ctx->ptem = (vsid << 7) | (pgidx >> 10);
945: }
946: /* Initialize real address with an invalid value */
947: ctx->raddr = (target_phys_addr_t)-1ULL;
948: if (unlikely(env->mmu_model == POWERPC_MMU_SOFT_6xx ||
949: env->mmu_model == POWERPC_MMU_SOFT_74xx)) {
950: /* Software TLB search */
951: ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
952: } else {
1.1.1.5 ! root 953: LOG_MMU("0 sdr1=" PADDRX " vsid=" ADDRX " "
1.1.1.4 root 954: "api=" ADDRX " hash=" PADDRX
955: " pg_addr=" PADDRX "\n",
956: sdr, vsid, pgidx, hash, ctx->pg_addr[0]);
957: /* Primary table lookup */
958: ret = find_pte(env, ctx, 0, rw, type);
959: if (ret < 0) {
960: /* Secondary table lookup */
1.1.1.5 ! root 961: if (eaddr != 0xEFFFFFFF)
! 962: LOG_MMU("1 sdr1=" PADDRX " vsid=" ADDRX " "
1.1.1.4 root 963: "api=" ADDRX " hash=" PADDRX
964: " pg_addr=" PADDRX "\n",
965: sdr, vsid, pgidx, hash, ctx->pg_addr[1]);
966: ret2 = find_pte(env, ctx, 1, rw, type);
967: if (ret2 != -1)
968: ret = ret2;
969: }
970: }
971: #if defined (DUMP_PAGE_TABLES)
1.1.1.5 ! root 972: if (qemu_log_enabled()) {
1.1.1.4 root 973: target_phys_addr_t curaddr;
974: uint32_t a0, a1, a2, a3;
1.1.1.5 ! root 975: qemu_log("Page table: " PADDRX " len " PADDRX "\n",
! 976: sdr, mask + 0x80);
1.1.1.4 root 977: for (curaddr = sdr; curaddr < (sdr + mask + 0x80);
978: curaddr += 16) {
979: a0 = ldl_phys(curaddr);
980: a1 = ldl_phys(curaddr + 4);
981: a2 = ldl_phys(curaddr + 8);
982: a3 = ldl_phys(curaddr + 12);
983: if (a0 != 0 || a1 != 0 || a2 != 0 || a3 != 0) {
1.1.1.5 ! root 984: qemu_log(PADDRX ": %08x %08x %08x %08x\n",
! 985: curaddr, a0, a1, a2, a3);
1.1.1.4 root 986: }
987: }
988: }
989: #endif
990: } else {
1.1.1.5 ! root 991: LOG_MMU("No access allowed\n");
1.1.1.4 root 992: ret = -3;
993: }
994: } else {
1.1.1.5 ! root 995: LOG_MMU("direct store...\n");
1.1.1.4 root 996: /* Direct-store segment : absolutely *BUGGY* for now */
997: switch (type) {
998: case ACCESS_INT:
999: /* Integer load/store : only access allowed */
1000: break;
1001: case ACCESS_CODE:
1002: /* No code fetch is allowed in direct-store areas */
1003: return -4;
1004: case ACCESS_FLOAT:
1.1 root 1005: /* Floating point load/store */
1006: return -4;
1007: case ACCESS_RES:
1008: /* lwarx, ldarx or srwcx. */
1009: return -4;
1010: case ACCESS_CACHE:
1011: /* dcba, dcbt, dcbtst, dcbf, dcbi, dcbst, dcbz, or icbi */
1012: /* Should make the instruction do no-op.
1013: * As it already do no-op, it's quite easy :-)
1014: */
1.1.1.4 root 1015: ctx->raddr = eaddr;
1.1 root 1016: return 0;
1017: case ACCESS_EXT:
1018: /* eciwx or ecowx */
1019: return -4;
1020: default:
1.1.1.5 ! root 1021: qemu_log("ERROR: instruction should not need "
1.1 root 1022: "address translation\n");
1023: return -4;
1024: }
1.1.1.4 root 1025: if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
1026: ctx->raddr = eaddr;
1.1 root 1027: ret = 2;
1028: } else {
1029: ret = -2;
1030: }
1031: }
1032:
1033: return ret;
1034: }
1035:
1.1.1.4 root 1036: /* Generic TLB check function for embedded PowerPC implementations */
1037: static always_inline int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb,
1038: target_phys_addr_t *raddrp,
1039: target_ulong address,
1040: uint32_t pid, int ext, int i)
1041: {
1042: target_ulong mask;
1043:
1044: /* Check valid flag */
1045: if (!(tlb->prot & PAGE_VALID)) {
1.1.1.5 ! root 1046: qemu_log("%s: TLB %d not valid\n", __func__, i);
1.1.1.4 root 1047: return -1;
1048: }
1049: mask = ~(tlb->size - 1);
1.1.1.5 ! root 1050: LOG_SWTLB("%s: TLB %d address " ADDRX " PID %u <=> " ADDRX
1.1.1.4 root 1051: " " ADDRX " %u\n",
1052: __func__, i, address, pid, tlb->EPN, mask, (uint32_t)tlb->PID);
1053: /* Check PID */
1054: if (tlb->PID != 0 && tlb->PID != pid)
1055: return -1;
1056: /* Check effective address */
1057: if ((address & mask) != tlb->EPN)
1058: return -1;
1059: *raddrp = (tlb->RPN & mask) | (address & ~mask);
1060: #if (TARGET_PHYS_ADDR_BITS >= 36)
1061: if (ext) {
1062: /* Extend the physical address to 36 bits */
1063: *raddrp |= (target_phys_addr_t)(tlb->RPN & 0xF) << 32;
1064: }
1065: #endif
1066:
1067: return 0;
1068: }
1069:
1070: /* Generic TLB search function for PowerPC embedded implementations */
1071: int ppcemb_tlb_search (CPUPPCState *env, target_ulong address, uint32_t pid)
1072: {
1073: ppcemb_tlb_t *tlb;
1074: target_phys_addr_t raddr;
1075: int i, ret;
1076:
1077: /* Default return value is no match */
1078: ret = -1;
1079: for (i = 0; i < env->nb_tlb; i++) {
1080: tlb = &env->tlb[i].tlbe;
1081: if (ppcemb_tlb_check(env, tlb, &raddr, address, pid, 0, i) == 0) {
1082: ret = i;
1083: break;
1084: }
1085: }
1086:
1087: return ret;
1088: }
1089:
1090: /* Helpers specific to PowerPC 40x implementations */
1091: static always_inline void ppc4xx_tlb_invalidate_all (CPUState *env)
1092: {
1093: ppcemb_tlb_t *tlb;
1094: int i;
1095:
1096: for (i = 0; i < env->nb_tlb; i++) {
1097: tlb = &env->tlb[i].tlbe;
1098: tlb->prot &= ~PAGE_VALID;
1099: }
1100: tlb_flush(env, 1);
1101: }
1102:
1103: static always_inline void ppc4xx_tlb_invalidate_virt (CPUState *env,
1104: target_ulong eaddr,
1105: uint32_t pid)
1106: {
1107: #if !defined(FLUSH_ALL_TLBS)
1108: ppcemb_tlb_t *tlb;
1109: target_phys_addr_t raddr;
1110: target_ulong page, end;
1111: int i;
1112:
1113: for (i = 0; i < env->nb_tlb; i++) {
1114: tlb = &env->tlb[i].tlbe;
1115: if (ppcemb_tlb_check(env, tlb, &raddr, eaddr, pid, 0, i) == 0) {
1116: end = tlb->EPN + tlb->size;
1117: for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
1118: tlb_flush_page(env, page);
1119: tlb->prot &= ~PAGE_VALID;
1120: break;
1121: }
1122: }
1123: #else
1124: ppc4xx_tlb_invalidate_all(env);
1125: #endif
1126: }
1127:
1.1.1.5 ! root 1128: static int mmu40x_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
1.1.1.4 root 1129: target_ulong address, int rw, int access_type)
1130: {
1131: ppcemb_tlb_t *tlb;
1132: target_phys_addr_t raddr;
1133: int i, ret, zsel, zpr, pr;
1134:
1135: ret = -1;
1136: raddr = (target_phys_addr_t)-1ULL;
1137: pr = msr_pr;
1138: for (i = 0; i < env->nb_tlb; i++) {
1139: tlb = &env->tlb[i].tlbe;
1140: if (ppcemb_tlb_check(env, tlb, &raddr, address,
1141: env->spr[SPR_40x_PID], 0, i) < 0)
1142: continue;
1143: zsel = (tlb->attr >> 4) & 0xF;
1144: zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
1.1.1.5 ! root 1145: LOG_SWTLB("%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
1.1.1.4 root 1146: __func__, i, zsel, zpr, rw, tlb->attr);
1147: /* Check execute enable bit */
1148: switch (zpr) {
1149: case 0x2:
1150: if (pr != 0)
1151: goto check_perms;
1152: /* No break here */
1153: case 0x3:
1154: /* All accesses granted */
1155: ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
1156: ret = 0;
1157: break;
1158: case 0x0:
1159: if (pr != 0) {
1160: ctx->prot = 0;
1161: ret = -2;
1162: break;
1163: }
1164: /* No break here */
1165: case 0x1:
1166: check_perms:
1167: /* Check from TLB entry */
1168: /* XXX: there is a problem here or in the TLB fill code... */
1169: ctx->prot = tlb->prot;
1170: ctx->prot |= PAGE_EXEC;
1171: ret = check_prot(ctx->prot, rw, access_type);
1172: break;
1173: }
1174: if (ret >= 0) {
1175: ctx->raddr = raddr;
1.1.1.5 ! root 1176: LOG_SWTLB("%s: access granted " ADDRX " => " PADDRX
1.1.1.4 root 1177: " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
1178: ret);
1179: return 0;
1180: }
1181: }
1.1.1.5 ! root 1182: LOG_SWTLB("%s: access refused " ADDRX " => " PADDRX
1.1.1.4 root 1183: " %d %d\n", __func__, address, raddr, ctx->prot,
1184: ret);
1185:
1186: return ret;
1187: }
1188:
1189: void store_40x_sler (CPUPPCState *env, uint32_t val)
1190: {
1191: /* XXX: TO BE FIXED */
1192: if (val != 0x00000000) {
1193: cpu_abort(env, "Little-endian regions are not supported by now\n");
1194: }
1195: env->spr[SPR_405_SLER] = val;
1196: }
1197:
1.1.1.5 ! root 1198: static int mmubooke_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
! 1199: target_ulong address, int rw,
! 1200: int access_type)
1.1.1.4 root 1201: {
1202: ppcemb_tlb_t *tlb;
1203: target_phys_addr_t raddr;
1204: int i, prot, ret;
1205:
1206: ret = -1;
1207: raddr = (target_phys_addr_t)-1ULL;
1208: for (i = 0; i < env->nb_tlb; i++) {
1209: tlb = &env->tlb[i].tlbe;
1210: if (ppcemb_tlb_check(env, tlb, &raddr, address,
1211: env->spr[SPR_BOOKE_PID], 1, i) < 0)
1212: continue;
1213: if (msr_pr != 0)
1214: prot = tlb->prot & 0xF;
1215: else
1216: prot = (tlb->prot >> 4) & 0xF;
1217: /* Check the address space */
1218: if (access_type == ACCESS_CODE) {
1219: if (msr_ir != (tlb->attr & 1))
1220: continue;
1221: ctx->prot = prot;
1222: if (prot & PAGE_EXEC) {
1223: ret = 0;
1224: break;
1225: }
1226: ret = -3;
1227: } else {
1228: if (msr_dr != (tlb->attr & 1))
1229: continue;
1230: ctx->prot = prot;
1231: if ((!rw && prot & PAGE_READ) || (rw && (prot & PAGE_WRITE))) {
1232: ret = 0;
1233: break;
1234: }
1235: ret = -2;
1236: }
1237: }
1238: if (ret >= 0)
1239: ctx->raddr = raddr;
1240:
1241: return ret;
1242: }
1243:
1244: static always_inline int check_physical (CPUState *env, mmu_ctx_t *ctx,
1245: target_ulong eaddr, int rw)
1246: {
1247: int in_plb, ret;
1248:
1249: ctx->raddr = eaddr;
1250: ctx->prot = PAGE_READ | PAGE_EXEC;
1251: ret = 0;
1252: switch (env->mmu_model) {
1253: case POWERPC_MMU_32B:
1254: case POWERPC_MMU_601:
1255: case POWERPC_MMU_SOFT_6xx:
1256: case POWERPC_MMU_SOFT_74xx:
1257: case POWERPC_MMU_SOFT_4xx:
1258: case POWERPC_MMU_REAL:
1259: case POWERPC_MMU_BOOKE:
1260: ctx->prot |= PAGE_WRITE;
1261: break;
1262: #if defined(TARGET_PPC64)
1263: case POWERPC_MMU_620:
1264: case POWERPC_MMU_64B:
1265: /* Real address are 60 bits long */
1266: ctx->raddr &= 0x0FFFFFFFFFFFFFFFULL;
1267: ctx->prot |= PAGE_WRITE;
1268: break;
1269: #endif
1270: case POWERPC_MMU_SOFT_4xx_Z:
1271: if (unlikely(msr_pe != 0)) {
1272: /* 403 family add some particular protections,
1273: * using PBL/PBU registers for accesses with no translation.
1274: */
1275: in_plb =
1276: /* Check PLB validity */
1277: (env->pb[0] < env->pb[1] &&
1278: /* and address in plb area */
1279: eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
1280: (env->pb[2] < env->pb[3] &&
1281: eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
1282: if (in_plb ^ msr_px) {
1283: /* Access in protected area */
1284: if (rw == 1) {
1285: /* Access is not allowed */
1286: ret = -2;
1287: }
1288: } else {
1289: /* Read-write access is allowed */
1290: ctx->prot |= PAGE_WRITE;
1291: }
1292: }
1293: break;
1294: case POWERPC_MMU_MPC8xx:
1295: /* XXX: TODO */
1296: cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1297: break;
1298: case POWERPC_MMU_BOOKE_FSL:
1299: /* XXX: TODO */
1300: cpu_abort(env, "BookE FSL MMU model not implemented\n");
1301: break;
1302: default:
1303: cpu_abort(env, "Unknown or invalid MMU model\n");
1304: return -1;
1305: }
1306:
1307: return ret;
1308: }
1309:
1310: int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
1311: int rw, int access_type)
1.1 root 1312: {
1313: int ret;
1.1.1.4 root 1314:
1.1 root 1315: #if 0
1.1.1.5 ! root 1316: qemu_log("%s\n", __func__);
1.1.1.4 root 1317: #endif
1.1 root 1318: if ((access_type == ACCESS_CODE && msr_ir == 0) ||
1319: (access_type != ACCESS_CODE && msr_dr == 0)) {
1320: /* No address translation */
1.1.1.4 root 1321: ret = check_physical(env, ctx, eaddr, rw);
1.1 root 1322: } else {
1.1.1.4 root 1323: ret = -1;
1324: switch (env->mmu_model) {
1325: case POWERPC_MMU_32B:
1326: case POWERPC_MMU_601:
1327: case POWERPC_MMU_SOFT_6xx:
1328: case POWERPC_MMU_SOFT_74xx:
1329: #if defined(TARGET_PPC64)
1330: case POWERPC_MMU_620:
1331: case POWERPC_MMU_64B:
1332: #endif
1333: /* Try to find a BAT */
1334: if (env->nb_BATs != 0)
1335: ret = get_bat(env, ctx, eaddr, rw, access_type);
1336: if (ret < 0) {
1337: /* We didn't match any BAT entry or don't have BATs */
1338: ret = get_segment(env, ctx, eaddr, rw, access_type);
1339: }
1340: break;
1341: case POWERPC_MMU_SOFT_4xx:
1342: case POWERPC_MMU_SOFT_4xx_Z:
1343: ret = mmu40x_get_physical_address(env, ctx, eaddr,
1344: rw, access_type);
1345: break;
1346: case POWERPC_MMU_BOOKE:
1347: ret = mmubooke_get_physical_address(env, ctx, eaddr,
1348: rw, access_type);
1349: break;
1350: case POWERPC_MMU_MPC8xx:
1351: /* XXX: TODO */
1352: cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1353: break;
1354: case POWERPC_MMU_BOOKE_FSL:
1355: /* XXX: TODO */
1356: cpu_abort(env, "BookE FSL MMU model not implemented\n");
1357: return -1;
1358: case POWERPC_MMU_REAL:
1359: cpu_abort(env, "PowerPC in real mode do not do any translation\n");
1360: return -1;
1361: default:
1362: cpu_abort(env, "Unknown or invalid MMU model\n");
1363: return -1;
1.1 root 1364: }
1365: }
1366: #if 0
1.1.1.5 ! root 1367: qemu_log("%s address " ADDRX " => %d " PADDRX "\n",
1.1.1.4 root 1368: __func__, eaddr, ret, ctx->raddr);
1369: #endif
1370:
1.1 root 1371: return ret;
1372: }
1373:
1.1.1.4 root 1374: target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
1.1 root 1375: {
1.1.1.4 root 1376: mmu_ctx_t ctx;
1.1 root 1377:
1.1.1.4 root 1378: if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT) != 0))
1.1 root 1379: return -1;
1.1.1.4 root 1380:
1381: return ctx.raddr & TARGET_PAGE_MASK;
1.1 root 1382: }
1383:
1384: /* Perform address translation */
1.1.1.4 root 1385: int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
1386: int mmu_idx, int is_softmmu)
1.1 root 1387: {
1.1.1.4 root 1388: mmu_ctx_t ctx;
1.1 root 1389: int access_type;
1390: int ret = 0;
1391:
1392: if (rw == 2) {
1393: /* code access */
1394: rw = 0;
1395: access_type = ACCESS_CODE;
1396: } else {
1397: /* data access */
1.1.1.5 ! root 1398: access_type = env->access_type;
1.1 root 1399: }
1.1.1.4 root 1400: ret = get_physical_address(env, &ctx, address, rw, access_type);
1.1 root 1401: if (ret == 0) {
1.1.1.4 root 1402: ret = tlb_set_page_exec(env, address & TARGET_PAGE_MASK,
1403: ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
1404: mmu_idx, is_softmmu);
1.1 root 1405: } else if (ret < 0) {
1.1.1.5 ! root 1406: LOG_MMU_STATE(env);
1.1 root 1407: if (access_type == ACCESS_CODE) {
1408: switch (ret) {
1409: case -1:
1.1.1.4 root 1410: /* No matches in page tables or TLB */
1411: switch (env->mmu_model) {
1412: case POWERPC_MMU_SOFT_6xx:
1413: env->exception_index = POWERPC_EXCP_IFTLB;
1414: env->error_code = 1 << 18;
1415: env->spr[SPR_IMISS] = address;
1416: env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
1417: goto tlb_miss;
1418: case POWERPC_MMU_SOFT_74xx:
1419: env->exception_index = POWERPC_EXCP_IFTLB;
1420: goto tlb_miss_74xx;
1421: case POWERPC_MMU_SOFT_4xx:
1422: case POWERPC_MMU_SOFT_4xx_Z:
1423: env->exception_index = POWERPC_EXCP_ITLB;
1424: env->error_code = 0;
1425: env->spr[SPR_40x_DEAR] = address;
1426: env->spr[SPR_40x_ESR] = 0x00000000;
1427: break;
1428: case POWERPC_MMU_32B:
1429: case POWERPC_MMU_601:
1430: #if defined(TARGET_PPC64)
1431: case POWERPC_MMU_620:
1432: case POWERPC_MMU_64B:
1433: #endif
1434: env->exception_index = POWERPC_EXCP_ISI;
1435: env->error_code = 0x40000000;
1436: break;
1437: case POWERPC_MMU_BOOKE:
1438: /* XXX: TODO */
1439: cpu_abort(env, "BookE MMU model is not implemented\n");
1440: return -1;
1441: case POWERPC_MMU_BOOKE_FSL:
1442: /* XXX: TODO */
1443: cpu_abort(env, "BookE FSL MMU model is not implemented\n");
1444: return -1;
1445: case POWERPC_MMU_MPC8xx:
1446: /* XXX: TODO */
1447: cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1448: break;
1449: case POWERPC_MMU_REAL:
1450: cpu_abort(env, "PowerPC in real mode should never raise "
1451: "any MMU exceptions\n");
1452: return -1;
1453: default:
1454: cpu_abort(env, "Unknown or invalid MMU model\n");
1455: return -1;
1456: }
1.1 root 1457: break;
1458: case -2:
1459: /* Access rights violation */
1.1.1.4 root 1460: env->exception_index = POWERPC_EXCP_ISI;
1461: env->error_code = 0x08000000;
1.1 root 1462: break;
1463: case -3:
1.1.1.4 root 1464: /* No execute protection violation */
1465: env->exception_index = POWERPC_EXCP_ISI;
1466: env->error_code = 0x10000000;
1.1 root 1467: break;
1468: case -4:
1469: /* Direct store exception */
1470: /* No code fetch is allowed in direct-store areas */
1.1.1.4 root 1471: env->exception_index = POWERPC_EXCP_ISI;
1472: env->error_code = 0x10000000;
1.1 root 1473: break;
1.1.1.4 root 1474: #if defined(TARGET_PPC64)
1.1 root 1475: case -5:
1476: /* No match in segment table */
1.1.1.4 root 1477: if (env->mmu_model == POWERPC_MMU_620) {
1478: env->exception_index = POWERPC_EXCP_ISI;
1479: /* XXX: this might be incorrect */
1480: env->error_code = 0x40000000;
1481: } else {
1482: env->exception_index = POWERPC_EXCP_ISEG;
1483: env->error_code = 0;
1484: }
1.1 root 1485: break;
1.1.1.4 root 1486: #endif
1.1 root 1487: }
1488: } else {
1489: switch (ret) {
1490: case -1:
1.1.1.4 root 1491: /* No matches in page tables or TLB */
1492: switch (env->mmu_model) {
1493: case POWERPC_MMU_SOFT_6xx:
1494: if (rw == 1) {
1495: env->exception_index = POWERPC_EXCP_DSTLB;
1496: env->error_code = 1 << 16;
1497: } else {
1498: env->exception_index = POWERPC_EXCP_DLTLB;
1499: env->error_code = 0;
1500: }
1501: env->spr[SPR_DMISS] = address;
1502: env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
1503: tlb_miss:
1504: env->error_code |= ctx.key << 19;
1505: env->spr[SPR_HASH1] = ctx.pg_addr[0];
1506: env->spr[SPR_HASH2] = ctx.pg_addr[1];
1507: break;
1508: case POWERPC_MMU_SOFT_74xx:
1509: if (rw == 1) {
1510: env->exception_index = POWERPC_EXCP_DSTLB;
1511: } else {
1512: env->exception_index = POWERPC_EXCP_DLTLB;
1513: }
1514: tlb_miss_74xx:
1515: /* Implement LRU algorithm */
1516: env->error_code = ctx.key << 19;
1517: env->spr[SPR_TLBMISS] = (address & ~((target_ulong)0x3)) |
1518: ((env->last_way + 1) & (env->nb_ways - 1));
1519: env->spr[SPR_PTEHI] = 0x80000000 | ctx.ptem;
1520: break;
1521: case POWERPC_MMU_SOFT_4xx:
1522: case POWERPC_MMU_SOFT_4xx_Z:
1523: env->exception_index = POWERPC_EXCP_DTLB;
1524: env->error_code = 0;
1525: env->spr[SPR_40x_DEAR] = address;
1526: if (rw)
1527: env->spr[SPR_40x_ESR] = 0x00800000;
1528: else
1529: env->spr[SPR_40x_ESR] = 0x00000000;
1530: break;
1531: case POWERPC_MMU_32B:
1532: case POWERPC_MMU_601:
1533: #if defined(TARGET_PPC64)
1534: case POWERPC_MMU_620:
1535: case POWERPC_MMU_64B:
1536: #endif
1537: env->exception_index = POWERPC_EXCP_DSI;
1538: env->error_code = 0;
1539: env->spr[SPR_DAR] = address;
1540: if (rw == 1)
1541: env->spr[SPR_DSISR] = 0x42000000;
1542: else
1543: env->spr[SPR_DSISR] = 0x40000000;
1544: break;
1545: case POWERPC_MMU_MPC8xx:
1546: /* XXX: TODO */
1547: cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1548: break;
1549: case POWERPC_MMU_BOOKE:
1550: /* XXX: TODO */
1551: cpu_abort(env, "BookE MMU model is not implemented\n");
1552: return -1;
1553: case POWERPC_MMU_BOOKE_FSL:
1554: /* XXX: TODO */
1555: cpu_abort(env, "BookE FSL MMU model is not implemented\n");
1556: return -1;
1557: case POWERPC_MMU_REAL:
1558: cpu_abort(env, "PowerPC in real mode should never raise "
1559: "any MMU exceptions\n");
1560: return -1;
1561: default:
1562: cpu_abort(env, "Unknown or invalid MMU model\n");
1563: return -1;
1564: }
1.1 root 1565: break;
1566: case -2:
1567: /* Access rights violation */
1.1.1.4 root 1568: env->exception_index = POWERPC_EXCP_DSI;
1569: env->error_code = 0;
1570: env->spr[SPR_DAR] = address;
1571: if (rw == 1)
1572: env->spr[SPR_DSISR] = 0x0A000000;
1573: else
1574: env->spr[SPR_DSISR] = 0x08000000;
1.1 root 1575: break;
1576: case -4:
1577: /* Direct store exception */
1578: switch (access_type) {
1579: case ACCESS_FLOAT:
1580: /* Floating point load/store */
1.1.1.4 root 1581: env->exception_index = POWERPC_EXCP_ALIGN;
1582: env->error_code = POWERPC_EXCP_ALIGN_FP;
1583: env->spr[SPR_DAR] = address;
1.1 root 1584: break;
1585: case ACCESS_RES:
1.1.1.4 root 1586: /* lwarx, ldarx or stwcx. */
1587: env->exception_index = POWERPC_EXCP_DSI;
1588: env->error_code = 0;
1589: env->spr[SPR_DAR] = address;
1590: if (rw == 1)
1591: env->spr[SPR_DSISR] = 0x06000000;
1592: else
1593: env->spr[SPR_DSISR] = 0x04000000;
1.1 root 1594: break;
1595: case ACCESS_EXT:
1596: /* eciwx or ecowx */
1.1.1.4 root 1597: env->exception_index = POWERPC_EXCP_DSI;
1598: env->error_code = 0;
1599: env->spr[SPR_DAR] = address;
1600: if (rw == 1)
1601: env->spr[SPR_DSISR] = 0x06100000;
1602: else
1603: env->spr[SPR_DSISR] = 0x04100000;
1.1 root 1604: break;
1605: default:
1.1.1.4 root 1606: printf("DSI: invalid exception (%d)\n", ret);
1607: env->exception_index = POWERPC_EXCP_PROGRAM;
1608: env->error_code =
1609: POWERPC_EXCP_INVAL | POWERPC_EXCP_INVAL_INVAL;
1610: env->spr[SPR_DAR] = address;
1.1 root 1611: break;
1612: }
1613: break;
1.1.1.4 root 1614: #if defined(TARGET_PPC64)
1.1 root 1615: case -5:
1616: /* No match in segment table */
1.1.1.4 root 1617: if (env->mmu_model == POWERPC_MMU_620) {
1618: env->exception_index = POWERPC_EXCP_DSI;
1619: env->error_code = 0;
1620: env->spr[SPR_DAR] = address;
1621: /* XXX: this might be incorrect */
1622: if (rw == 1)
1623: env->spr[SPR_DSISR] = 0x42000000;
1624: else
1625: env->spr[SPR_DSISR] = 0x40000000;
1626: } else {
1627: env->exception_index = POWERPC_EXCP_DSEG;
1628: env->error_code = 0;
1629: env->spr[SPR_DAR] = address;
1630: }
1.1 root 1631: break;
1.1.1.4 root 1632: #endif
1.1 root 1633: }
1634: }
1635: #if 0
1.1.1.4 root 1636: printf("%s: set exception to %d %02x\n", __func__,
1637: env->exception, env->error_code);
1.1 root 1638: #endif
1639: ret = 1;
1640: }
1.1.1.4 root 1641:
1.1 root 1642: return ret;
1643: }
1644:
1645: /*****************************************************************************/
1646: /* BATs management */
1647: #if !defined(FLUSH_ALL_TLBS)
1.1.1.4 root 1648: static always_inline void do_invalidate_BAT (CPUPPCState *env,
1649: target_ulong BATu,
1650: target_ulong mask)
1.1 root 1651: {
1652: target_ulong base, end, page;
1.1.1.4 root 1653:
1.1 root 1654: base = BATu & ~0x0001FFFF;
1655: end = base + mask + 0x00020000;
1.1.1.5 ! root 1656: LOG_BATS("Flush BAT from " ADDRX " to " ADDRX " (" ADDRX ")\n",
1.1.1.4 root 1657: base, end, mask);
1.1 root 1658: for (page = base; page != end; page += TARGET_PAGE_SIZE)
1659: tlb_flush_page(env, page);
1.1.1.5 ! root 1660: LOG_BATS("Flush done\n");
1.1 root 1661: }
1662: #endif
1663:
1.1.1.4 root 1664: static always_inline void dump_store_bat (CPUPPCState *env, char ID,
1665: int ul, int nr, target_ulong value)
1.1 root 1666: {
1.1.1.5 ! root 1667: LOG_BATS("Set %cBAT%d%c to " ADDRX " (" ADDRX ")\n",
1.1.1.4 root 1668: ID, nr, ul == 0 ? 'u' : 'l', value, env->nip);
1.1 root 1669: }
1670:
1.1.1.5 ! root 1671: void ppc_store_ibatu (CPUPPCState *env, int nr, target_ulong value)
1.1 root 1672: {
1673: target_ulong mask;
1674:
1675: dump_store_bat(env, 'I', 0, nr, value);
1676: if (env->IBAT[0][nr] != value) {
1677: mask = (value << 15) & 0x0FFE0000UL;
1678: #if !defined(FLUSH_ALL_TLBS)
1679: do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1680: #endif
1681: /* When storing valid upper BAT, mask BEPI and BRPN
1682: * and invalidate all TLBs covered by this BAT
1683: */
1684: mask = (value << 15) & 0x0FFE0000UL;
1685: env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1686: (value & ~0x0001FFFFUL & ~mask);
1687: env->IBAT[1][nr] = (env->IBAT[1][nr] & 0x0000007B) |
1688: (env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
1689: #if !defined(FLUSH_ALL_TLBS)
1690: do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1.1.1.4 root 1691: #else
1.1 root 1692: tlb_flush(env, 1);
1693: #endif
1694: }
1695: }
1696:
1.1.1.5 ! root 1697: void ppc_store_ibatl (CPUPPCState *env, int nr, target_ulong value)
1.1 root 1698: {
1699: dump_store_bat(env, 'I', 1, nr, value);
1700: env->IBAT[1][nr] = value;
1701: }
1702:
1.1.1.5 ! root 1703: void ppc_store_dbatu (CPUPPCState *env, int nr, target_ulong value)
1.1 root 1704: {
1705: target_ulong mask;
1706:
1707: dump_store_bat(env, 'D', 0, nr, value);
1708: if (env->DBAT[0][nr] != value) {
1709: /* When storing valid upper BAT, mask BEPI and BRPN
1710: * and invalidate all TLBs covered by this BAT
1711: */
1712: mask = (value << 15) & 0x0FFE0000UL;
1713: #if !defined(FLUSH_ALL_TLBS)
1714: do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1715: #endif
1716: mask = (value << 15) & 0x0FFE0000UL;
1717: env->DBAT[0][nr] = (value & 0x00001FFFUL) |
1718: (value & ~0x0001FFFFUL & ~mask);
1719: env->DBAT[1][nr] = (env->DBAT[1][nr] & 0x0000007B) |
1720: (env->DBAT[1][nr] & ~0x0001FFFF & ~mask);
1721: #if !defined(FLUSH_ALL_TLBS)
1722: do_invalidate_BAT(env, env->DBAT[0][nr], mask);
1723: #else
1724: tlb_flush(env, 1);
1725: #endif
1726: }
1727: }
1728:
1.1.1.5 ! root 1729: void ppc_store_dbatl (CPUPPCState *env, int nr, target_ulong value)
1.1 root 1730: {
1731: dump_store_bat(env, 'D', 1, nr, value);
1732: env->DBAT[1][nr] = value;
1733: }
1734:
1.1.1.5 ! root 1735: void ppc_store_ibatu_601 (CPUPPCState *env, int nr, target_ulong value)
1.1 root 1736: {
1.1.1.4 root 1737: target_ulong mask;
1738: int do_inval;
1.1 root 1739:
1.1.1.4 root 1740: dump_store_bat(env, 'I', 0, nr, value);
1741: if (env->IBAT[0][nr] != value) {
1742: do_inval = 0;
1743: mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1744: if (env->IBAT[1][nr] & 0x40) {
1745: /* Invalidate BAT only if it is valid */
1746: #if !defined(FLUSH_ALL_TLBS)
1747: do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1748: #else
1749: do_inval = 1;
1750: #endif
1751: }
1752: /* When storing valid upper BAT, mask BEPI and BRPN
1753: * and invalidate all TLBs covered by this BAT
1754: */
1755: env->IBAT[0][nr] = (value & 0x00001FFFUL) |
1756: (value & ~0x0001FFFFUL & ~mask);
1757: env->DBAT[0][nr] = env->IBAT[0][nr];
1758: if (env->IBAT[1][nr] & 0x40) {
1759: #if !defined(FLUSH_ALL_TLBS)
1760: do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1761: #else
1762: do_inval = 1;
1763: #endif
1764: }
1765: #if defined(FLUSH_ALL_TLBS)
1766: if (do_inval)
1767: tlb_flush(env, 1);
1768: #endif
1769: }
1.1 root 1770: }
1771:
1.1.1.5 ! root 1772: void ppc_store_ibatl_601 (CPUPPCState *env, int nr, target_ulong value)
1.1 root 1773: {
1.1.1.4 root 1774: target_ulong mask;
1775: int do_inval;
1.1 root 1776:
1.1.1.4 root 1777: dump_store_bat(env, 'I', 1, nr, value);
1778: if (env->IBAT[1][nr] != value) {
1779: do_inval = 0;
1780: if (env->IBAT[1][nr] & 0x40) {
1781: #if !defined(FLUSH_ALL_TLBS)
1782: mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
1783: do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1784: #else
1785: do_inval = 1;
1786: #endif
1787: }
1788: if (value & 0x40) {
1789: #if !defined(FLUSH_ALL_TLBS)
1790: mask = (value << 17) & 0x0FFE0000UL;
1791: do_invalidate_BAT(env, env->IBAT[0][nr], mask);
1792: #else
1793: do_inval = 1;
1794: #endif
1795: }
1796: env->IBAT[1][nr] = value;
1797: env->DBAT[1][nr] = value;
1798: #if defined(FLUSH_ALL_TLBS)
1799: if (do_inval)
1800: tlb_flush(env, 1);
1801: #endif
1802: }
1803: }
1804:
1805: /*****************************************************************************/
1806: /* TLB management */
1807: void ppc_tlb_invalidate_all (CPUPPCState *env)
1808: {
1809: switch (env->mmu_model) {
1810: case POWERPC_MMU_SOFT_6xx:
1811: case POWERPC_MMU_SOFT_74xx:
1812: ppc6xx_tlb_invalidate_all(env);
1813: break;
1814: case POWERPC_MMU_SOFT_4xx:
1815: case POWERPC_MMU_SOFT_4xx_Z:
1816: ppc4xx_tlb_invalidate_all(env);
1817: break;
1818: case POWERPC_MMU_REAL:
1819: cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
1820: break;
1821: case POWERPC_MMU_MPC8xx:
1822: /* XXX: TODO */
1823: cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1824: break;
1825: case POWERPC_MMU_BOOKE:
1826: /* XXX: TODO */
1827: cpu_abort(env, "BookE MMU model is not implemented\n");
1828: break;
1829: case POWERPC_MMU_BOOKE_FSL:
1830: /* XXX: TODO */
1.1.1.5 ! root 1831: if (!kvm_enabled())
! 1832: cpu_abort(env, "BookE MMU model is not implemented\n");
1.1.1.4 root 1833: break;
1834: case POWERPC_MMU_32B:
1835: case POWERPC_MMU_601:
1836: #if defined(TARGET_PPC64)
1837: case POWERPC_MMU_620:
1838: case POWERPC_MMU_64B:
1839: #endif /* defined(TARGET_PPC64) */
1840: tlb_flush(env, 1);
1841: break;
1842: default:
1843: /* XXX: TODO */
1844: cpu_abort(env, "Unknown MMU model\n");
1845: break;
1846: }
1847: }
1848:
1849: void ppc_tlb_invalidate_one (CPUPPCState *env, target_ulong addr)
1850: {
1851: #if !defined(FLUSH_ALL_TLBS)
1852: addr &= TARGET_PAGE_MASK;
1853: switch (env->mmu_model) {
1854: case POWERPC_MMU_SOFT_6xx:
1855: case POWERPC_MMU_SOFT_74xx:
1856: ppc6xx_tlb_invalidate_virt(env, addr, 0);
1857: if (env->id_tlbs == 1)
1858: ppc6xx_tlb_invalidate_virt(env, addr, 1);
1859: break;
1860: case POWERPC_MMU_SOFT_4xx:
1861: case POWERPC_MMU_SOFT_4xx_Z:
1862: ppc4xx_tlb_invalidate_virt(env, addr, env->spr[SPR_40x_PID]);
1863: break;
1864: case POWERPC_MMU_REAL:
1865: cpu_abort(env, "No TLB for PowerPC 4xx in real mode\n");
1866: break;
1867: case POWERPC_MMU_MPC8xx:
1868: /* XXX: TODO */
1869: cpu_abort(env, "MPC8xx MMU model is not implemented\n");
1870: break;
1871: case POWERPC_MMU_BOOKE:
1872: /* XXX: TODO */
1873: cpu_abort(env, "BookE MMU model is not implemented\n");
1874: break;
1875: case POWERPC_MMU_BOOKE_FSL:
1876: /* XXX: TODO */
1877: cpu_abort(env, "BookE FSL MMU model is not implemented\n");
1878: break;
1879: case POWERPC_MMU_32B:
1880: case POWERPC_MMU_601:
1881: /* tlbie invalidate TLBs for all segments */
1882: addr &= ~((target_ulong)-1ULL << 28);
1883: /* XXX: this case should be optimized,
1884: * giving a mask to tlb_flush_page
1885: */
1886: tlb_flush_page(env, addr | (0x0 << 28));
1887: tlb_flush_page(env, addr | (0x1 << 28));
1888: tlb_flush_page(env, addr | (0x2 << 28));
1889: tlb_flush_page(env, addr | (0x3 << 28));
1890: tlb_flush_page(env, addr | (0x4 << 28));
1891: tlb_flush_page(env, addr | (0x5 << 28));
1892: tlb_flush_page(env, addr | (0x6 << 28));
1893: tlb_flush_page(env, addr | (0x7 << 28));
1894: tlb_flush_page(env, addr | (0x8 << 28));
1895: tlb_flush_page(env, addr | (0x9 << 28));
1896: tlb_flush_page(env, addr | (0xA << 28));
1897: tlb_flush_page(env, addr | (0xB << 28));
1898: tlb_flush_page(env, addr | (0xC << 28));
1899: tlb_flush_page(env, addr | (0xD << 28));
1900: tlb_flush_page(env, addr | (0xE << 28));
1901: tlb_flush_page(env, addr | (0xF << 28));
1902: break;
1903: #if defined(TARGET_PPC64)
1904: case POWERPC_MMU_620:
1905: case POWERPC_MMU_64B:
1906: /* tlbie invalidate TLBs for all segments */
1907: /* XXX: given the fact that there are too many segments to invalidate,
1908: * and we still don't have a tlb_flush_mask(env, n, mask) in Qemu,
1909: * we just invalidate all TLBs
1910: */
1911: tlb_flush(env, 1);
1912: break;
1913: #endif /* defined(TARGET_PPC64) */
1914: default:
1915: /* XXX: TODO */
1916: cpu_abort(env, "Unknown MMU model\n");
1917: break;
1918: }
1919: #else
1920: ppc_tlb_invalidate_all(env);
1921: #endif
1922: }
1923:
1924: /*****************************************************************************/
1925: /* Special registers manipulation */
1926: #if defined(TARGET_PPC64)
1927: void ppc_store_asr (CPUPPCState *env, target_ulong value)
1928: {
1929: if (env->asr != value) {
1930: env->asr = value;
1931: tlb_flush(env, 1);
1932: }
1933: }
1934: #endif
1935:
1.1.1.5 ! root 1936: void ppc_store_sdr1 (CPUPPCState *env, target_ulong value)
1.1 root 1937: {
1.1.1.5 ! root 1938: LOG_MMU("%s: " ADDRX "\n", __func__, value);
1.1 root 1939: if (env->sdr1 != value) {
1.1.1.4 root 1940: /* XXX: for PowerPC 64, should check that the HTABSIZE value
1941: * is <= 28
1942: */
1.1 root 1943: env->sdr1 = value;
1.1.1.4 root 1944: tlb_flush(env, 1);
1.1 root 1945: }
1946: }
1947:
1.1.1.5 ! root 1948: void ppc_store_sr (CPUPPCState *env, int srnum, target_ulong value)
1.1 root 1949: {
1.1.1.5 ! root 1950: LOG_MMU("%s: reg=%d " ADDRX " " ADDRX "\n",
1.1.1.4 root 1951: __func__, srnum, value, env->sr[srnum]);
1.1 root 1952: if (env->sr[srnum] != value) {
1953: env->sr[srnum] = value;
1954: #if !defined(FLUSH_ALL_TLBS) && 0
1955: {
1956: target_ulong page, end;
1957: /* Invalidate 256 MB of virtual memory */
1958: page = (16 << 20) * srnum;
1959: end = page + (16 << 20);
1960: for (; page != end; page += TARGET_PAGE_SIZE)
1961: tlb_flush_page(env, page);
1962: }
1963: #else
1.1.1.4 root 1964: tlb_flush(env, 1);
1.1 root 1965: #endif
1966: }
1967: }
1.1.1.4 root 1968: #endif /* !defined (CONFIG_USER_ONLY) */
1.1 root 1969:
1.1.1.4 root 1970: /* GDBstub can read and write MSR... */
1971: void ppc_store_msr (CPUPPCState *env, target_ulong value)
1.1 root 1972: {
1.1.1.4 root 1973: hreg_store_msr(env, value, 0);
1.1 root 1974: }
1975:
1976: /*****************************************************************************/
1977: /* Exception processing */
1978: #if defined (CONFIG_USER_ONLY)
1979: void do_interrupt (CPUState *env)
1980: {
1.1.1.4 root 1981: env->exception_index = POWERPC_EXCP_NONE;
1982: env->error_code = 0;
1.1 root 1983: }
1.1.1.4 root 1984:
1985: void ppc_hw_interrupt (CPUState *env)
1.1 root 1986: {
1.1.1.4 root 1987: env->exception_index = POWERPC_EXCP_NONE;
1988: env->error_code = 0;
1.1 root 1989: }
1.1.1.4 root 1990: #else /* defined (CONFIG_USER_ONLY) */
1991: static always_inline void dump_syscall (CPUState *env)
1.1 root 1992: {
1.1.1.5 ! root 1993: qemu_log_mask(CPU_LOG_INT, "syscall r0=" REGX " r3=" REGX " r4=" REGX
1.1.1.4 root 1994: " r5=" REGX " r6=" REGX " nip=" ADDRX "\n",
1995: ppc_dump_gpr(env, 0), ppc_dump_gpr(env, 3), ppc_dump_gpr(env, 4),
1996: ppc_dump_gpr(env, 5), ppc_dump_gpr(env, 6), env->nip);
1997: }
1.1 root 1998:
1.1.1.4 root 1999: /* Note that this function should be greatly optimized
2000: * when called with a constant excp, from ppc_hw_interrupt
2001: */
2002: static always_inline void powerpc_excp (CPUState *env,
2003: int excp_model, int excp)
2004: {
2005: target_ulong msr, new_msr, vector;
2006: int srr0, srr1, asrr0, asrr1;
2007: int lpes0, lpes1, lev;
2008:
2009: if (0) {
2010: /* XXX: find a suitable condition to enable the hypervisor mode */
2011: lpes0 = (env->spr[SPR_LPCR] >> 1) & 1;
2012: lpes1 = (env->spr[SPR_LPCR] >> 2) & 1;
2013: } else {
2014: /* Those values ensure we won't enter the hypervisor mode */
2015: lpes0 = 0;
2016: lpes1 = 1;
1.1 root 2017: }
1.1.1.4 root 2018:
1.1.1.5 ! root 2019: qemu_log_mask(CPU_LOG_INT, "Raise exception at " ADDRX " => %08x (%02x)\n",
! 2020: env->nip, excp, env->error_code);
1.1.1.4 root 2021: msr = env->msr;
2022: new_msr = msr;
2023: srr0 = SPR_SRR0;
2024: srr1 = SPR_SRR1;
2025: asrr0 = -1;
2026: asrr1 = -1;
2027: msr &= ~((target_ulong)0x783F0000);
1.1 root 2028: switch (excp) {
1.1.1.4 root 2029: case POWERPC_EXCP_NONE:
2030: /* Should never happen */
2031: return;
2032: case POWERPC_EXCP_CRITICAL: /* Critical input */
2033: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2034: switch (excp_model) {
2035: case POWERPC_EXCP_40x:
2036: srr0 = SPR_40x_SRR2;
2037: srr1 = SPR_40x_SRR3;
2038: break;
2039: case POWERPC_EXCP_BOOKE:
2040: srr0 = SPR_BOOKE_CSRR0;
2041: srr1 = SPR_BOOKE_CSRR1;
2042: break;
2043: case POWERPC_EXCP_G2:
2044: break;
2045: default:
2046: goto excp_invalid;
1.1 root 2047: }
2048: goto store_next;
1.1.1.4 root 2049: case POWERPC_EXCP_MCHECK: /* Machine check exception */
1.1 root 2050: if (msr_me == 0) {
1.1.1.4 root 2051: /* Machine check exception is not enabled.
2052: * Enter checkstop state.
2053: */
1.1.1.5 ! root 2054: if (qemu_log_enabled()) {
! 2055: qemu_log("Machine check while not allowed. "
1.1.1.4 root 2056: "Entering checkstop state\n");
2057: } else {
2058: fprintf(stderr, "Machine check while not allowed. "
2059: "Entering checkstop state\n");
2060: }
2061: env->halted = 1;
2062: env->interrupt_request |= CPU_INTERRUPT_EXITTB;
2063: }
2064: new_msr &= ~((target_ulong)1 << MSR_RI);
2065: new_msr &= ~((target_ulong)1 << MSR_ME);
2066: if (0) {
2067: /* XXX: find a suitable condition to enable the hypervisor mode */
2068: new_msr |= (target_ulong)MSR_HVB;
2069: }
2070: /* XXX: should also have something loaded in DAR / DSISR */
2071: switch (excp_model) {
2072: case POWERPC_EXCP_40x:
2073: srr0 = SPR_40x_SRR2;
2074: srr1 = SPR_40x_SRR3;
2075: break;
2076: case POWERPC_EXCP_BOOKE:
2077: srr0 = SPR_BOOKE_MCSRR0;
2078: srr1 = SPR_BOOKE_MCSRR1;
2079: asrr0 = SPR_BOOKE_CSRR0;
2080: asrr1 = SPR_BOOKE_CSRR1;
2081: break;
2082: default:
2083: break;
1.1 root 2084: }
2085: goto store_next;
1.1.1.4 root 2086: case POWERPC_EXCP_DSI: /* Data storage exception */
1.1.1.5 ! root 2087: LOG_EXCP("DSI exception: DSISR=" ADDRX" DAR=" ADDRX "\n",
1.1.1.4 root 2088: env->spr[SPR_DSISR], env->spr[SPR_DAR]);
2089: new_msr &= ~((target_ulong)1 << MSR_RI);
2090: if (lpes1 == 0)
2091: new_msr |= (target_ulong)MSR_HVB;
1.1 root 2092: goto store_next;
1.1.1.4 root 2093: case POWERPC_EXCP_ISI: /* Instruction storage exception */
1.1.1.5 ! root 2094: LOG_EXCP("ISI exception: msr=" ADDRX ", nip=" ADDRX "\n",
1.1.1.4 root 2095: msr, env->nip);
2096: new_msr &= ~((target_ulong)1 << MSR_RI);
2097: if (lpes1 == 0)
2098: new_msr |= (target_ulong)MSR_HVB;
2099: msr |= env->error_code;
1.1 root 2100: goto store_next;
1.1.1.4 root 2101: case POWERPC_EXCP_EXTERNAL: /* External input */
2102: new_msr &= ~((target_ulong)1 << MSR_RI);
2103: if (lpes0 == 1)
2104: new_msr |= (target_ulong)MSR_HVB;
2105: goto store_next;
2106: case POWERPC_EXCP_ALIGN: /* Alignment exception */
2107: new_msr &= ~((target_ulong)1 << MSR_RI);
2108: if (lpes1 == 0)
2109: new_msr |= (target_ulong)MSR_HVB;
2110: /* XXX: this is false */
2111: /* Get rS/rD and rA from faulting opcode */
2112: env->spr[SPR_DSISR] |= (ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
1.1 root 2113: goto store_current;
1.1.1.4 root 2114: case POWERPC_EXCP_PROGRAM: /* Program exception */
1.1 root 2115: switch (env->error_code & ~0xF) {
1.1.1.4 root 2116: case POWERPC_EXCP_FP:
2117: if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
1.1.1.5 ! root 2118: LOG_EXCP("Ignore floating point exception\n");
1.1.1.4 root 2119: env->exception_index = POWERPC_EXCP_NONE;
2120: env->error_code = 0;
1.1 root 2121: return;
1.1.1.4 root 2122: }
2123: new_msr &= ~((target_ulong)1 << MSR_RI);
2124: if (lpes1 == 0)
2125: new_msr |= (target_ulong)MSR_HVB;
1.1 root 2126: msr |= 0x00100000;
1.1.1.4 root 2127: if (msr_fe0 == msr_fe1)
2128: goto store_next;
2129: msr |= 0x00010000;
2130: break;
2131: case POWERPC_EXCP_INVAL:
1.1.1.5 ! root 2132: LOG_EXCP("Invalid instruction at " ADDRX "\n",
1.1.1.4 root 2133: env->nip);
2134: new_msr &= ~((target_ulong)1 << MSR_RI);
2135: if (lpes1 == 0)
2136: new_msr |= (target_ulong)MSR_HVB;
1.1 root 2137: msr |= 0x00080000;
1.1.1.4 root 2138: break;
2139: case POWERPC_EXCP_PRIV:
2140: new_msr &= ~((target_ulong)1 << MSR_RI);
2141: if (lpes1 == 0)
2142: new_msr |= (target_ulong)MSR_HVB;
1.1 root 2143: msr |= 0x00040000;
1.1.1.4 root 2144: break;
2145: case POWERPC_EXCP_TRAP:
2146: new_msr &= ~((target_ulong)1 << MSR_RI);
2147: if (lpes1 == 0)
2148: new_msr |= (target_ulong)MSR_HVB;
1.1 root 2149: msr |= 0x00020000;
2150: break;
2151: default:
2152: /* Should never occur */
1.1.1.4 root 2153: cpu_abort(env, "Invalid program exception %d. Aborting\n",
2154: env->error_code);
2155: break;
2156: }
1.1 root 2157: goto store_current;
1.1.1.4 root 2158: case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
2159: new_msr &= ~((target_ulong)1 << MSR_RI);
2160: if (lpes1 == 0)
2161: new_msr |= (target_ulong)MSR_HVB;
1.1 root 2162: goto store_current;
1.1.1.4 root 2163: case POWERPC_EXCP_SYSCALL: /* System call exception */
1.1 root 2164: /* NOTE: this is a temporary hack to support graphics OSI
2165: calls from the MOL driver */
1.1.1.4 root 2166: /* XXX: To be removed */
1.1 root 2167: if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
2168: env->osi_call) {
1.1.1.4 root 2169: if (env->osi_call(env) != 0) {
2170: env->exception_index = POWERPC_EXCP_NONE;
2171: env->error_code = 0;
1.1 root 2172: return;
1.1.1.4 root 2173: }
1.1 root 2174: }
1.1.1.5 ! root 2175: dump_syscall(env);
1.1.1.4 root 2176: new_msr &= ~((target_ulong)1 << MSR_RI);
2177: lev = env->error_code;
2178: if (lev == 1 || (lpes0 == 0 && lpes1 == 0))
2179: new_msr |= (target_ulong)MSR_HVB;
2180: goto store_next;
2181: case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
2182: new_msr &= ~((target_ulong)1 << MSR_RI);
2183: goto store_current;
2184: case POWERPC_EXCP_DECR: /* Decrementer exception */
2185: new_msr &= ~((target_ulong)1 << MSR_RI);
2186: if (lpes1 == 0)
2187: new_msr |= (target_ulong)MSR_HVB;
1.1 root 2188: goto store_next;
1.1.1.4 root 2189: case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
2190: /* FIT on 4xx */
1.1.1.5 ! root 2191: LOG_EXCP("FIT exception\n");
1.1.1.4 root 2192: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
1.1 root 2193: goto store_next;
1.1.1.4 root 2194: case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
1.1.1.5 ! root 2195: LOG_EXCP("WDT exception\n");
1.1.1.4 root 2196: switch (excp_model) {
2197: case POWERPC_EXCP_BOOKE:
2198: srr0 = SPR_BOOKE_CSRR0;
2199: srr1 = SPR_BOOKE_CSRR1;
2200: break;
2201: default:
2202: break;
2203: }
2204: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2205: goto store_next;
2206: case POWERPC_EXCP_DTLB: /* Data TLB error */
2207: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2208: goto store_next;
2209: case POWERPC_EXCP_ITLB: /* Instruction TLB error */
2210: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2211: goto store_next;
2212: case POWERPC_EXCP_DEBUG: /* Debug interrupt */
2213: switch (excp_model) {
2214: case POWERPC_EXCP_BOOKE:
2215: srr0 = SPR_BOOKE_DSRR0;
2216: srr1 = SPR_BOOKE_DSRR1;
2217: asrr0 = SPR_BOOKE_CSRR0;
2218: asrr1 = SPR_BOOKE_CSRR1;
2219: break;
2220: default:
2221: break;
2222: }
1.1 root 2223: /* XXX: TODO */
1.1.1.4 root 2224: cpu_abort(env, "Debug exception is not implemented yet !\n");
1.1 root 2225: goto store_next;
1.1.1.4 root 2226: case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable */
2227: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2228: goto store_current;
2229: case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
1.1 root 2230: /* XXX: TODO */
1.1.1.4 root 2231: cpu_abort(env, "Embedded floating point data exception "
1.1 root 2232: "is not implemented yet !\n");
2233: goto store_next;
1.1.1.4 root 2234: case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
1.1 root 2235: /* XXX: TODO */
1.1.1.4 root 2236: cpu_abort(env, "Embedded floating point round exception "
2237: "is not implemented yet !\n");
1.1 root 2238: goto store_next;
1.1.1.4 root 2239: case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
2240: new_msr &= ~((target_ulong)1 << MSR_RI);
1.1 root 2241: /* XXX: TODO */
2242: cpu_abort(env,
1.1.1.4 root 2243: "Performance counter exception is not implemented yet !\n");
1.1 root 2244: goto store_next;
1.1.1.4 root 2245: case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
2246: /* XXX: TODO */
1.1 root 2247: cpu_abort(env,
1.1.1.4 root 2248: "Embedded doorbell interrupt is not implemented yet !\n");
1.1 root 2249: goto store_next;
1.1.1.4 root 2250: case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
2251: switch (excp_model) {
2252: case POWERPC_EXCP_BOOKE:
2253: srr0 = SPR_BOOKE_CSRR0;
2254: srr1 = SPR_BOOKE_CSRR1;
1.1 root 2255: break;
2256: default:
2257: break;
2258: }
1.1.1.4 root 2259: /* XXX: TODO */
2260: cpu_abort(env, "Embedded doorbell critical interrupt "
2261: "is not implemented yet !\n");
2262: goto store_next;
2263: case POWERPC_EXCP_RESET: /* System reset exception */
2264: new_msr &= ~((target_ulong)1 << MSR_RI);
2265: if (0) {
2266: /* XXX: find a suitable condition to enable the hypervisor mode */
2267: new_msr |= (target_ulong)MSR_HVB;
1.1 root 2268: }
1.1.1.4 root 2269: goto store_next;
2270: case POWERPC_EXCP_DSEG: /* Data segment exception */
2271: new_msr &= ~((target_ulong)1 << MSR_RI);
2272: if (lpes1 == 0)
2273: new_msr |= (target_ulong)MSR_HVB;
2274: goto store_next;
2275: case POWERPC_EXCP_ISEG: /* Instruction segment exception */
2276: new_msr &= ~((target_ulong)1 << MSR_RI);
2277: if (lpes1 == 0)
2278: new_msr |= (target_ulong)MSR_HVB;
2279: goto store_next;
2280: case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
2281: srr0 = SPR_HSRR0;
2282: srr1 = SPR_HSRR1;
2283: new_msr |= (target_ulong)MSR_HVB;
2284: goto store_next;
2285: case POWERPC_EXCP_TRACE: /* Trace exception */
2286: new_msr &= ~((target_ulong)1 << MSR_RI);
2287: if (lpes1 == 0)
2288: new_msr |= (target_ulong)MSR_HVB;
2289: goto store_next;
2290: case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
2291: srr0 = SPR_HSRR0;
2292: srr1 = SPR_HSRR1;
2293: new_msr |= (target_ulong)MSR_HVB;
2294: goto store_next;
2295: case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
2296: srr0 = SPR_HSRR0;
2297: srr1 = SPR_HSRR1;
2298: new_msr |= (target_ulong)MSR_HVB;
2299: goto store_next;
2300: case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
2301: srr0 = SPR_HSRR0;
2302: srr1 = SPR_HSRR1;
2303: new_msr |= (target_ulong)MSR_HVB;
2304: goto store_next;
2305: case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
2306: srr0 = SPR_HSRR0;
2307: srr1 = SPR_HSRR1;
2308: new_msr |= (target_ulong)MSR_HVB;
2309: goto store_next;
2310: case POWERPC_EXCP_VPU: /* Vector unavailable exception */
2311: new_msr &= ~((target_ulong)1 << MSR_RI);
2312: if (lpes1 == 0)
2313: new_msr |= (target_ulong)MSR_HVB;
2314: goto store_current;
2315: case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
1.1.1.5 ! root 2316: LOG_EXCP("PIT exception\n");
1.1.1.4 root 2317: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2318: goto store_next;
2319: case POWERPC_EXCP_IO: /* IO error exception */
2320: /* XXX: TODO */
2321: cpu_abort(env, "601 IO error exception is not implemented yet !\n");
2322: goto store_next;
2323: case POWERPC_EXCP_RUNM: /* Run mode exception */
2324: /* XXX: TODO */
2325: cpu_abort(env, "601 run mode exception is not implemented yet !\n");
2326: goto store_next;
2327: case POWERPC_EXCP_EMUL: /* Emulation trap exception */
2328: /* XXX: TODO */
2329: cpu_abort(env, "602 emulation trap exception "
2330: "is not implemented yet !\n");
2331: goto store_next;
2332: case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
2333: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2334: if (lpes1 == 0) /* XXX: check this */
2335: new_msr |= (target_ulong)MSR_HVB;
2336: switch (excp_model) {
2337: case POWERPC_EXCP_602:
2338: case POWERPC_EXCP_603:
2339: case POWERPC_EXCP_603E:
2340: case POWERPC_EXCP_G2:
2341: goto tlb_miss_tgpr;
2342: case POWERPC_EXCP_7x5:
2343: goto tlb_miss;
2344: case POWERPC_EXCP_74xx:
2345: goto tlb_miss_74xx;
1.1 root 2346: default:
1.1.1.4 root 2347: cpu_abort(env, "Invalid instruction TLB miss exception\n");
1.1 root 2348: break;
2349: }
1.1.1.4 root 2350: break;
2351: case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
2352: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2353: if (lpes1 == 0) /* XXX: check this */
2354: new_msr |= (target_ulong)MSR_HVB;
2355: switch (excp_model) {
2356: case POWERPC_EXCP_602:
2357: case POWERPC_EXCP_603:
2358: case POWERPC_EXCP_603E:
2359: case POWERPC_EXCP_G2:
2360: goto tlb_miss_tgpr;
2361: case POWERPC_EXCP_7x5:
2362: goto tlb_miss;
2363: case POWERPC_EXCP_74xx:
2364: goto tlb_miss_74xx;
1.1 root 2365: default:
1.1.1.4 root 2366: cpu_abort(env, "Invalid data load TLB miss exception\n");
1.1 root 2367: break;
2368: }
1.1.1.4 root 2369: break;
2370: case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
2371: new_msr &= ~((target_ulong)1 << MSR_RI); /* XXX: check this */
2372: if (lpes1 == 0) /* XXX: check this */
2373: new_msr |= (target_ulong)MSR_HVB;
2374: switch (excp_model) {
2375: case POWERPC_EXCP_602:
2376: case POWERPC_EXCP_603:
2377: case POWERPC_EXCP_603E:
2378: case POWERPC_EXCP_G2:
2379: tlb_miss_tgpr:
2380: /* Swap temporary saved registers with GPRs */
2381: if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
2382: new_msr |= (target_ulong)1 << MSR_TGPR;
2383: hreg_swap_gpr_tgpr(env);
2384: }
2385: goto tlb_miss;
2386: case POWERPC_EXCP_7x5:
2387: tlb_miss:
1.1 root 2388: #if defined (DEBUG_SOFTWARE_TLB)
1.1.1.5 ! root 2389: if (qemu_log_enabled()) {
1.1.1.4 root 2390: const unsigned char *es;
2391: target_ulong *miss, *cmp;
2392: int en;
2393: if (excp == POWERPC_EXCP_IFTLB) {
2394: es = "I";
2395: en = 'I';
2396: miss = &env->spr[SPR_IMISS];
2397: cmp = &env->spr[SPR_ICMP];
2398: } else {
2399: if (excp == POWERPC_EXCP_DLTLB)
2400: es = "DL";
2401: else
2402: es = "DS";
2403: en = 'D';
2404: miss = &env->spr[SPR_DMISS];
2405: cmp = &env->spr[SPR_DCMP];
2406: }
1.1.1.5 ! root 2407: qemu_log("6xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
1.1.1.4 root 2408: " H1 " ADDRX " H2 " ADDRX " %08x\n",
2409: es, en, *miss, en, *cmp,
2410: env->spr[SPR_HASH1], env->spr[SPR_HASH2],
1.1 root 2411: env->error_code);
2412: }
2413: #endif
2414: msr |= env->crf[0] << 28;
2415: msr |= env->error_code; /* key, D/I, S/L bits */
2416: /* Set way using a LRU mechanism */
1.1.1.4 root 2417: msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
1.1 root 2418: break;
1.1.1.4 root 2419: case POWERPC_EXCP_74xx:
2420: tlb_miss_74xx:
2421: #if defined (DEBUG_SOFTWARE_TLB)
1.1.1.5 ! root 2422: if (qemu_log_enabled()) {
1.1.1.4 root 2423: const unsigned char *es;
2424: target_ulong *miss, *cmp;
2425: int en;
2426: if (excp == POWERPC_EXCP_IFTLB) {
2427: es = "I";
2428: en = 'I';
2429: miss = &env->spr[SPR_TLBMISS];
2430: cmp = &env->spr[SPR_PTEHI];
2431: } else {
2432: if (excp == POWERPC_EXCP_DLTLB)
2433: es = "DL";
2434: else
2435: es = "DS";
2436: en = 'D';
2437: miss = &env->spr[SPR_TLBMISS];
2438: cmp = &env->spr[SPR_PTEHI];
2439: }
1.1.1.5 ! root 2440: qemu_log("74xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
1.1.1.4 root 2441: " %08x\n",
2442: es, en, *miss, en, *cmp, env->error_code);
2443: }
2444: #endif
2445: msr |= env->error_code; /* key bit */
1.1 root 2446: break;
2447: default:
1.1.1.4 root 2448: cpu_abort(env, "Invalid data store TLB miss exception\n");
1.1 root 2449: break;
2450: }
1.1.1.4 root 2451: goto store_next;
2452: case POWERPC_EXCP_FPA: /* Floating-point assist exception */
2453: /* XXX: TODO */
2454: cpu_abort(env, "Floating point assist exception "
2455: "is not implemented yet !\n");
2456: goto store_next;
2457: case POWERPC_EXCP_DABR: /* Data address breakpoint */
2458: /* XXX: TODO */
2459: cpu_abort(env, "DABR exception is not implemented yet !\n");
2460: goto store_next;
2461: case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
2462: /* XXX: TODO */
2463: cpu_abort(env, "IABR exception is not implemented yet !\n");
2464: goto store_next;
2465: case POWERPC_EXCP_SMI: /* System management interrupt */
2466: /* XXX: TODO */
2467: cpu_abort(env, "SMI exception is not implemented yet !\n");
2468: goto store_next;
2469: case POWERPC_EXCP_THERM: /* Thermal interrupt */
2470: /* XXX: TODO */
2471: cpu_abort(env, "Thermal management exception "
2472: "is not implemented yet !\n");
2473: goto store_next;
2474: case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
2475: new_msr &= ~((target_ulong)1 << MSR_RI);
2476: if (lpes1 == 0)
2477: new_msr |= (target_ulong)MSR_HVB;
2478: /* XXX: TODO */
2479: cpu_abort(env,
2480: "Performance counter exception is not implemented yet !\n");
2481: goto store_next;
2482: case POWERPC_EXCP_VPUA: /* Vector assist exception */
2483: /* XXX: TODO */
2484: cpu_abort(env, "VPU assist exception is not implemented yet !\n");
2485: goto store_next;
2486: case POWERPC_EXCP_SOFTP: /* Soft patch exception */
2487: /* XXX: TODO */
2488: cpu_abort(env,
2489: "970 soft-patch exception is not implemented yet !\n");
2490: goto store_next;
2491: case POWERPC_EXCP_MAINT: /* Maintenance exception */
2492: /* XXX: TODO */
2493: cpu_abort(env,
2494: "970 maintenance exception is not implemented yet !\n");
2495: goto store_next;
2496: case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
2497: /* XXX: TODO */
2498: cpu_abort(env, "Maskable external exception "
2499: "is not implemented yet !\n");
2500: goto store_next;
2501: case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
2502: /* XXX: TODO */
2503: cpu_abort(env, "Non maskable external exception "
2504: "is not implemented yet !\n");
2505: goto store_next;
1.1 root 2506: default:
1.1.1.4 root 2507: excp_invalid:
2508: cpu_abort(env, "Invalid PowerPC exception %d. Aborting\n", excp);
2509: break;
1.1 root 2510: store_current:
2511: /* save current instruction location */
1.1.1.4 root 2512: env->spr[srr0] = env->nip - 4;
1.1 root 2513: break;
2514: store_next:
2515: /* save next instruction location */
1.1.1.4 root 2516: env->spr[srr0] = env->nip;
1.1 root 2517: break;
2518: }
1.1.1.4 root 2519: /* Save MSR */
2520: env->spr[srr1] = msr;
2521: /* If any alternate SRR register are defined, duplicate saved values */
2522: if (asrr0 != -1)
2523: env->spr[asrr0] = env->spr[srr0];
2524: if (asrr1 != -1)
2525: env->spr[asrr1] = env->spr[srr1];
1.1 root 2526: /* If we disactivated any translation, flush TLBs */
1.1.1.4 root 2527: if (new_msr & ((1 << MSR_IR) | (1 << MSR_DR)))
1.1 root 2528: tlb_flush(env, 1);
2529: /* reload MSR with correct bits */
1.1.1.4 root 2530: new_msr &= ~((target_ulong)1 << MSR_EE);
2531: new_msr &= ~((target_ulong)1 << MSR_PR);
2532: new_msr &= ~((target_ulong)1 << MSR_FP);
2533: new_msr &= ~((target_ulong)1 << MSR_FE0);
2534: new_msr &= ~((target_ulong)1 << MSR_SE);
2535: new_msr &= ~((target_ulong)1 << MSR_BE);
2536: new_msr &= ~((target_ulong)1 << MSR_FE1);
2537: new_msr &= ~((target_ulong)1 << MSR_IR);
2538: new_msr &= ~((target_ulong)1 << MSR_DR);
2539: #if 0 /* Fix this: not on all targets */
2540: new_msr &= ~((target_ulong)1 << MSR_PMM);
2541: #endif
2542: new_msr &= ~((target_ulong)1 << MSR_LE);
2543: if (msr_ile)
2544: new_msr |= (target_ulong)1 << MSR_LE;
2545: else
2546: new_msr &= ~((target_ulong)1 << MSR_LE);
1.1 root 2547: /* Jump to handler */
1.1.1.4 root 2548: vector = env->excp_vectors[excp];
2549: if (vector == (target_ulong)-1ULL) {
2550: cpu_abort(env, "Raised an exception without defined vector %d\n",
2551: excp);
2552: }
2553: vector |= env->excp_prefix;
2554: #if defined(TARGET_PPC64)
2555: if (excp_model == POWERPC_EXCP_BOOKE) {
2556: if (!msr_icm) {
2557: new_msr &= ~((target_ulong)1 << MSR_CM);
2558: vector = (uint32_t)vector;
2559: } else {
2560: new_msr |= (target_ulong)1 << MSR_CM;
2561: }
2562: } else {
2563: if (!msr_isf) {
2564: new_msr &= ~((target_ulong)1 << MSR_SF);
2565: vector = (uint32_t)vector;
2566: } else {
2567: new_msr |= (target_ulong)1 << MSR_SF;
2568: }
2569: }
2570: #endif
2571: /* XXX: we don't use hreg_store_msr here as already have treated
2572: * any special case that could occur. Just store MSR and update hflags
2573: */
2574: env->msr = new_msr & env->msr_mask;
2575: hreg_compute_hflags(env);
2576: env->nip = vector;
2577: /* Reset exception state */
2578: env->exception_index = POWERPC_EXCP_NONE;
2579: env->error_code = 0;
2580: }
2581:
2582: void do_interrupt (CPUState *env)
2583: {
2584: powerpc_excp(env, env->excp_model, env->exception_index);
2585: }
2586:
2587: void ppc_hw_interrupt (CPUPPCState *env)
2588: {
2589: int hdice;
2590:
2591: #if 0
1.1.1.5 ! root 2592: qemu_log_mask(CPU_LOG_INT, "%s: %p pending %08x req %08x me %d ee %d\n",
1.1.1.4 root 2593: __func__, env, env->pending_interrupts,
2594: env->interrupt_request, (int)msr_me, (int)msr_ee);
2595: #endif
2596: /* External reset */
2597: if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
2598: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
2599: powerpc_excp(env, env->excp_model, POWERPC_EXCP_RESET);
2600: return;
2601: }
2602: /* Machine check exception */
2603: if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
2604: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
2605: powerpc_excp(env, env->excp_model, POWERPC_EXCP_MCHECK);
2606: return;
2607: }
2608: #if 0 /* TODO */
2609: /* External debug exception */
2610: if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
2611: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
2612: powerpc_excp(env, env->excp_model, POWERPC_EXCP_DEBUG);
2613: return;
2614: }
2615: #endif
2616: if (0) {
2617: /* XXX: find a suitable condition to enable the hypervisor mode */
2618: hdice = env->spr[SPR_LPCR] & 1;
2619: } else {
2620: hdice = 0;
2621: }
2622: if ((msr_ee != 0 || msr_hv == 0 || msr_pr != 0) && hdice != 0) {
2623: /* Hypervisor decrementer exception */
2624: if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
2625: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
2626: powerpc_excp(env, env->excp_model, POWERPC_EXCP_HDECR);
2627: return;
2628: }
2629: }
2630: if (msr_ce != 0) {
2631: /* External critical interrupt */
2632: if (env->pending_interrupts & (1 << PPC_INTERRUPT_CEXT)) {
2633: /* Taking a critical external interrupt does not clear the external
2634: * critical interrupt status
2635: */
2636: #if 0
2637: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CEXT);
2638: #endif
2639: powerpc_excp(env, env->excp_model, POWERPC_EXCP_CRITICAL);
2640: return;
2641: }
2642: }
2643: if (msr_ee != 0) {
2644: /* Watchdog timer on embedded PowerPC */
2645: if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
2646: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
2647: powerpc_excp(env, env->excp_model, POWERPC_EXCP_WDT);
2648: return;
2649: }
2650: if (env->pending_interrupts & (1 << PPC_INTERRUPT_CDOORBELL)) {
2651: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_CDOORBELL);
2652: powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORCI);
2653: return;
2654: }
2655: /* Fixed interval timer on embedded PowerPC */
2656: if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
2657: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
2658: powerpc_excp(env, env->excp_model, POWERPC_EXCP_FIT);
2659: return;
2660: }
2661: /* Programmable interval timer on embedded PowerPC */
2662: if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
2663: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
2664: powerpc_excp(env, env->excp_model, POWERPC_EXCP_PIT);
2665: return;
2666: }
2667: /* Decrementer exception */
2668: if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
2669: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
2670: powerpc_excp(env, env->excp_model, POWERPC_EXCP_DECR);
2671: return;
2672: }
2673: /* External interrupt */
2674: if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
2675: /* Taking an external interrupt does not clear the external
2676: * interrupt status
2677: */
2678: #if 0
2679: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
2680: #endif
2681: powerpc_excp(env, env->excp_model, POWERPC_EXCP_EXTERNAL);
2682: return;
2683: }
2684: if (env->pending_interrupts & (1 << PPC_INTERRUPT_DOORBELL)) {
2685: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DOORBELL);
2686: powerpc_excp(env, env->excp_model, POWERPC_EXCP_DOORI);
2687: return;
2688: }
2689: if (env->pending_interrupts & (1 << PPC_INTERRUPT_PERFM)) {
2690: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PERFM);
2691: powerpc_excp(env, env->excp_model, POWERPC_EXCP_PERFM);
2692: return;
2693: }
2694: /* Thermal interrupt */
2695: if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
2696: env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
2697: powerpc_excp(env, env->excp_model, POWERPC_EXCP_THERM);
2698: return;
2699: }
2700: }
1.1 root 2701: }
2702: #endif /* !CONFIG_USER_ONLY */
1.1.1.4 root 2703:
2704: void cpu_dump_rfi (target_ulong RA, target_ulong msr)
2705: {
1.1.1.5 ! root 2706: qemu_log("Return from exception at " ADDRX " with flags " ADDRX "\n",
! 2707: RA, msr);
1.1.1.4 root 2708: }
2709:
2710: void cpu_ppc_reset (void *opaque)
2711: {
1.1.1.5 ! root 2712: CPUPPCState *env = opaque;
1.1.1.4 root 2713: target_ulong msr;
2714:
1.1.1.5 ! root 2715: if (qemu_loglevel_mask(CPU_LOG_RESET)) {
! 2716: qemu_log("CPU Reset (CPU %d)\n", env->cpu_index);
! 2717: log_cpu_state(env, 0);
! 2718: }
! 2719:
1.1.1.4 root 2720: msr = (target_ulong)0;
2721: if (0) {
2722: /* XXX: find a suitable condition to enable the hypervisor mode */
2723: msr |= (target_ulong)MSR_HVB;
2724: }
2725: msr |= (target_ulong)0 << MSR_AP; /* TO BE CHECKED */
2726: msr |= (target_ulong)0 << MSR_SA; /* TO BE CHECKED */
2727: msr |= (target_ulong)1 << MSR_EP;
2728: #if defined (DO_SINGLE_STEP) && 0
2729: /* Single step trace mode */
2730: msr |= (target_ulong)1 << MSR_SE;
2731: msr |= (target_ulong)1 << MSR_BE;
2732: #endif
2733: #if defined(CONFIG_USER_ONLY)
2734: msr |= (target_ulong)1 << MSR_FP; /* Allow floating point usage */
1.1.1.5 ! root 2735: msr |= (target_ulong)1 << MSR_VR; /* Allow altivec usage */
! 2736: msr |= (target_ulong)1 << MSR_SPE; /* Allow SPE usage */
1.1.1.4 root 2737: msr |= (target_ulong)1 << MSR_PR;
2738: #else
2739: env->nip = env->hreset_vector | env->excp_prefix;
2740: if (env->mmu_model != POWERPC_MMU_REAL)
2741: ppc_tlb_invalidate_all(env);
2742: #endif
1.1.1.5 ! root 2743: env->msr = msr & env->msr_mask;
1.1.1.4 root 2744: hreg_compute_hflags(env);
2745: env->reserve = (target_ulong)-1ULL;
2746: /* Be sure no exception or interrupt is pending */
2747: env->pending_interrupts = 0;
2748: env->exception_index = POWERPC_EXCP_NONE;
2749: env->error_code = 0;
2750: /* Flush all TLBs */
2751: tlb_flush(env, 1);
2752: }
2753:
2754: CPUPPCState *cpu_ppc_init (const char *cpu_model)
2755: {
2756: CPUPPCState *env;
2757: const ppc_def_t *def;
2758:
2759: def = cpu_ppc_find_by_name(cpu_model);
2760: if (!def)
2761: return NULL;
2762:
2763: env = qemu_mallocz(sizeof(CPUPPCState));
2764: cpu_exec_init(env);
1.1.1.5 ! root 2765: ppc_translate_init();
1.1.1.4 root 2766: env->cpu_model_str = cpu_model;
2767: cpu_ppc_register_internal(env, def);
2768: cpu_ppc_reset(env);
1.1.1.5 ! root 2769:
! 2770: if (kvm_enabled())
! 2771: kvm_init_vcpu(env);
! 2772:
1.1.1.4 root 2773: return env;
2774: }
2775:
2776: void cpu_ppc_close (CPUPPCState *env)
2777: {
2778: /* Should also remove all opcode tables... */
2779: qemu_free(env);
2780: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.