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