File:  [Qemu by Fabrice Bellard] / qemu / target-mips / helper.c
Revision 1.1.1.7 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:55:01 2018 UTC (3 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, HEAD
qemu 0.10.0

    1: /*
    2:  *  MIPS emulation helpers for qemu.
    3:  *
    4:  *  Copyright (c) 2004-2005 Jocelyn Mayer
    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., 51 Franklin Street, Fifth Floor, Boston MA  02110-1301 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"
   30: 
   31: enum {
   32:     TLBRET_DIRTY = -4,
   33:     TLBRET_INVALID = -3,
   34:     TLBRET_NOMATCH = -2,
   35:     TLBRET_BADADDR = -1,
   36:     TLBRET_MATCH = 0
   37: };
   38: 
   39: /* no MMU emulation */
   40: int no_mmu_map_address (CPUState *env, target_ulong *physical, int *prot,
   41:                         target_ulong address, int rw, int access_type)
   42: {
   43:     *physical = address;
   44:     *prot = PAGE_READ | PAGE_WRITE;
   45:     return TLBRET_MATCH;
   46: }
   47: 
   48: /* fixed mapping MMU emulation */
   49: int fixed_mmu_map_address (CPUState *env, target_ulong *physical, int *prot,
   50:                            target_ulong address, int rw, int access_type)
   51: {
   52:     if (address <= (int32_t)0x7FFFFFFFUL) {
   53:         if (!(env->CP0_Status & (1 << CP0St_ERL)))
   54:             *physical = address + 0x40000000UL;
   55:         else
   56:             *physical = address;
   57:     } else if (address <= (int32_t)0xBFFFFFFFUL)
   58:         *physical = address & 0x1FFFFFFF;
   59:     else
   60:         *physical = address;
   61: 
   62:     *prot = PAGE_READ | PAGE_WRITE;
   63:     return TLBRET_MATCH;
   64: }
   65: 
   66: /* MIPS32/MIPS64 R4000-style MMU emulation */
   67: int r4k_map_address (CPUState *env, target_ulong *physical, int *prot,
   68:                      target_ulong address, int rw, int access_type)
   69: {
   70:     uint8_t ASID = env->CP0_EntryHi & 0xFF;
   71:     int i;
   72: 
   73:     for (i = 0; i < env->tlb->tlb_in_use; i++) {
   74:         r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
   75:         /* 1k pages are not supported. */
   76:         target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
   77:         target_ulong tag = address & ~mask;
   78:         target_ulong VPN = tlb->VPN & ~mask;
   79: #if defined(TARGET_MIPS64)
   80:         tag &= env->SEGMask;
   81: #endif
   82: 
   83:         /* Check ASID, virtual page number & size */
   84:         if ((tlb->G == 1 || tlb->ASID == ASID) && VPN == tag) {
   85:             /* TLB match */
   86:             int n = !!(address & mask & ~(mask >> 1));
   87:             /* Check access rights */
   88:             if (!(n ? tlb->V1 : tlb->V0))
   89:                 return TLBRET_INVALID;
   90:             if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
   91:                 *physical = tlb->PFN[n] | (address & (mask >> 1));
   92:                 *prot = PAGE_READ;
   93:                 if (n ? tlb->D1 : tlb->D0)
   94:                     *prot |= PAGE_WRITE;
   95:                 return TLBRET_MATCH;
   96:             }
   97:             return TLBRET_DIRTY;
   98:         }
   99:     }
  100:     return TLBRET_NOMATCH;
  101: }
  102: 
  103: #if !defined(CONFIG_USER_ONLY)
  104: static int get_physical_address (CPUState *env, target_ulong *physical,
  105:                                 int *prot, target_ulong address,
  106:                                 int rw, int access_type)
  107: {
  108:     /* User mode can only access useg/xuseg */
  109:     int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
  110:     int supervisor_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_SM;
  111:     int kernel_mode = !user_mode && !supervisor_mode;
  112: #if defined(TARGET_MIPS64)
  113:     int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
  114:     int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
  115:     int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
  116: #endif
  117:     int ret = TLBRET_MATCH;
  118: 
  119: #if 0
  120:     qemu_log("user mode %d h %08x\n", user_mode, env->hflags);
  121: #endif
  122: 
  123:     if (address <= (int32_t)0x7FFFFFFFUL) {
  124:         /* useg */
  125:         if (env->CP0_Status & (1 << CP0St_ERL)) {
  126:             *physical = address & 0xFFFFFFFF;
  127:             *prot = PAGE_READ | PAGE_WRITE;
  128:         } else {
  129:             ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
  130:         }
  131: #if defined(TARGET_MIPS64)
  132:     } else if (address < 0x4000000000000000ULL) {
  133:         /* xuseg */
  134:         if (UX && address <= (0x3FFFFFFFFFFFFFFFULL & env->SEGMask)) {
  135:             ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
  136:         } else {
  137:             ret = TLBRET_BADADDR;
  138:         }
  139:     } else if (address < 0x8000000000000000ULL) {
  140:         /* xsseg */
  141:         if ((supervisor_mode || kernel_mode) &&
  142:             SX && address <= (0x7FFFFFFFFFFFFFFFULL & env->SEGMask)) {
  143:             ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
  144:         } else {
  145:             ret = TLBRET_BADADDR;
  146:         }
  147:     } else if (address < 0xC000000000000000ULL) {
  148:         /* xkphys */
  149:         if (kernel_mode && KX &&
  150:             (address & 0x07FFFFFFFFFFFFFFULL) <= env->PAMask) {
  151:             *physical = address & env->PAMask;
  152:             *prot = PAGE_READ | PAGE_WRITE;
  153:         } else {
  154:             ret = TLBRET_BADADDR;
  155:         }
  156:     } else if (address < 0xFFFFFFFF80000000ULL) {
  157:         /* xkseg */
  158:         if (kernel_mode && KX &&
  159:             address <= (0xFFFFFFFF7FFFFFFFULL & env->SEGMask)) {
  160:             ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
  161:         } else {
  162:             ret = TLBRET_BADADDR;
  163:         }
  164: #endif
  165:     } else if (address < (int32_t)0xA0000000UL) {
  166:         /* kseg0 */
  167:         if (kernel_mode) {
  168:             *physical = address - (int32_t)0x80000000UL;
  169:             *prot = PAGE_READ | PAGE_WRITE;
  170:         } else {
  171:             ret = TLBRET_BADADDR;
  172:         }
  173:     } else if (address < (int32_t)0xC0000000UL) {
  174:         /* kseg1 */
  175:         if (kernel_mode) {
  176:             *physical = address - (int32_t)0xA0000000UL;
  177:             *prot = PAGE_READ | PAGE_WRITE;
  178:         } else {
  179:             ret = TLBRET_BADADDR;
  180:         }
  181:     } else if (address < (int32_t)0xE0000000UL) {
  182:         /* sseg (kseg2) */
  183:         if (supervisor_mode || kernel_mode) {
  184:             ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
  185:         } else {
  186:             ret = TLBRET_BADADDR;
  187:         }
  188:     } else {
  189:         /* kseg3 */
  190:         /* XXX: debug segment is not emulated */
  191:         if (kernel_mode) {
  192:             ret = env->tlb->map_address(env, physical, prot, address, rw, access_type);
  193:         } else {
  194:             ret = TLBRET_BADADDR;
  195:         }
  196:     }
  197: #if 0
  198:     qemu_log(TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n",
  199:             address, rw, access_type, *physical, *prot, ret);
  200:     }
  201: #endif
  202: 
  203:     return ret;
  204: }
  205: #endif
  206: 
  207: target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
  208: {
  209: #if defined(CONFIG_USER_ONLY)
  210:     return addr;
  211: #else
  212:     target_ulong phys_addr;
  213:     int prot;
  214: 
  215:     if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
  216:         return -1;
  217:     return phys_addr;
  218: #endif
  219: }
  220: 
  221: int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
  222:                                int mmu_idx, int is_softmmu)
  223: {
  224: #if !defined(CONFIG_USER_ONLY)
  225:     target_ulong physical;
  226:     int prot;
  227: #endif
  228:     int exception = 0, error_code = 0;
  229:     int access_type;
  230:     int ret = 0;
  231: 
  232: #if 0
  233:     log_cpu_state(env, 0);
  234: #endif
  235:     qemu_log("%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d mmu_idx %d smmu %d\n",
  236:               __func__, env->active_tc.PC, address, rw, mmu_idx, is_softmmu);
  237: 
  238:     rw &= 1;
  239: 
  240:     /* data access */
  241:     /* XXX: put correct access by using cpu_restore_state()
  242:        correctly */
  243:     access_type = ACCESS_INT;
  244: #if defined(CONFIG_USER_ONLY)
  245:     ret = TLBRET_NOMATCH;
  246: #else
  247:     ret = get_physical_address(env, &physical, &prot,
  248:                                address, rw, access_type);
  249:     qemu_log("%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_lx " prot %d\n",
  250:               __func__, address, ret, physical, prot);
  251:     if (ret == TLBRET_MATCH) {
  252:        ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
  253:                           physical & TARGET_PAGE_MASK, prot,
  254:                           mmu_idx, is_softmmu);
  255:     } else if (ret < 0)
  256: #endif
  257:     {
  258:         switch (ret) {
  259:         default:
  260:         case TLBRET_BADADDR:
  261:             /* Reference to kernel address from user mode or supervisor mode */
  262:             /* Reference to supervisor address from user mode */
  263:             if (rw)
  264:                 exception = EXCP_AdES;
  265:             else
  266:                 exception = EXCP_AdEL;
  267:             break;
  268:         case TLBRET_NOMATCH:
  269:             /* No TLB match for a mapped address */
  270:             if (rw)
  271:                 exception = EXCP_TLBS;
  272:             else
  273:                 exception = EXCP_TLBL;
  274:             error_code = 1;
  275:             break;
  276:         case TLBRET_INVALID:
  277:             /* TLB match with no valid bit */
  278:             if (rw)
  279:                 exception = EXCP_TLBS;
  280:             else
  281:                 exception = EXCP_TLBL;
  282:             break;
  283:         case TLBRET_DIRTY:
  284:             /* TLB match but 'D' bit is cleared */
  285:             exception = EXCP_LTLBL;
  286:             break;
  287: 
  288:         }
  289:         /* Raise exception */
  290:         env->CP0_BadVAddr = address;
  291:         env->CP0_Context = (env->CP0_Context & ~0x007fffff) |
  292:                            ((address >> 9) &   0x007ffff0);
  293:         env->CP0_EntryHi =
  294:             (env->CP0_EntryHi & 0xFF) | (address & (TARGET_PAGE_MASK << 1));
  295: #if defined(TARGET_MIPS64)
  296:         env->CP0_EntryHi &= env->SEGMask;
  297:         env->CP0_XContext = (env->CP0_XContext & ((~0ULL) << (env->SEGBITS - 7))) |
  298:                             ((address & 0xC00000000000ULL) >> (55 - env->SEGBITS)) |
  299:                             ((address & ((1ULL << env->SEGBITS) - 1) & 0xFFFFFFFFFFFFE000ULL) >> 9);
  300: #endif
  301:         env->exception_index = exception;
  302:         env->error_code = error_code;
  303:         ret = 1;
  304:     }
  305: 
  306:     return ret;
  307: }
  308: 
  309: static const char * const excp_names[EXCP_LAST + 1] = {
  310:     [EXCP_RESET] = "reset",
  311:     [EXCP_SRESET] = "soft reset",
  312:     [EXCP_DSS] = "debug single step",
  313:     [EXCP_DINT] = "debug interrupt",
  314:     [EXCP_NMI] = "non-maskable interrupt",
  315:     [EXCP_MCHECK] = "machine check",
  316:     [EXCP_EXT_INTERRUPT] = "interrupt",
  317:     [EXCP_DFWATCH] = "deferred watchpoint",
  318:     [EXCP_DIB] = "debug instruction breakpoint",
  319:     [EXCP_IWATCH] = "instruction fetch watchpoint",
  320:     [EXCP_AdEL] = "address error load",
  321:     [EXCP_AdES] = "address error store",
  322:     [EXCP_TLBF] = "TLB refill",
  323:     [EXCP_IBE] = "instruction bus error",
  324:     [EXCP_DBp] = "debug breakpoint",
  325:     [EXCP_SYSCALL] = "syscall",
  326:     [EXCP_BREAK] = "break",
  327:     [EXCP_CpU] = "coprocessor unusable",
  328:     [EXCP_RI] = "reserved instruction",
  329:     [EXCP_OVERFLOW] = "arithmetic overflow",
  330:     [EXCP_TRAP] = "trap",
  331:     [EXCP_FPE] = "floating point",
  332:     [EXCP_DDBS] = "debug data break store",
  333:     [EXCP_DWATCH] = "data watchpoint",
  334:     [EXCP_LTLBL] = "TLB modify",
  335:     [EXCP_TLBL] = "TLB load",
  336:     [EXCP_TLBS] = "TLB store",
  337:     [EXCP_DBE] = "data bus error",
  338:     [EXCP_DDBL] = "debug data break load",
  339:     [EXCP_THREAD] = "thread",
  340:     [EXCP_MDMX] = "MDMX",
  341:     [EXCP_C2E] = "precise coprocessor 2",
  342:     [EXCP_CACHE] = "cache error",
  343: };
  344: 
  345: void do_interrupt (CPUState *env)
  346: {
  347: #if !defined(CONFIG_USER_ONLY)
  348:     target_ulong offset;
  349:     int cause = -1;
  350:     const char *name;
  351: 
  352:     if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
  353:         if (env->exception_index < 0 || env->exception_index > EXCP_LAST)
  354:             name = "unknown";
  355:         else
  356:             name = excp_names[env->exception_index];
  357: 
  358:         qemu_log("%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " %s exception\n",
  359:                  __func__, env->active_tc.PC, env->CP0_EPC, name);
  360:     }
  361:     if (env->exception_index == EXCP_EXT_INTERRUPT &&
  362:         (env->hflags & MIPS_HFLAG_DM))
  363:         env->exception_index = EXCP_DINT;
  364:     offset = 0x180;
  365:     switch (env->exception_index) {
  366:     case EXCP_DSS:
  367:         env->CP0_Debug |= 1 << CP0DB_DSS;
  368:         /* Debug single step cannot be raised inside a delay slot and
  369:            resume will always occur on the next instruction
  370:            (but we assume the pc has always been updated during
  371:            code translation). */
  372:         env->CP0_DEPC = env->active_tc.PC;
  373:         goto enter_debug_mode;
  374:     case EXCP_DINT:
  375:         env->CP0_Debug |= 1 << CP0DB_DINT;
  376:         goto set_DEPC;
  377:     case EXCP_DIB:
  378:         env->CP0_Debug |= 1 << CP0DB_DIB;
  379:         goto set_DEPC;
  380:     case EXCP_DBp:
  381:         env->CP0_Debug |= 1 << CP0DB_DBp;
  382:         goto set_DEPC;
  383:     case EXCP_DDBS:
  384:         env->CP0_Debug |= 1 << CP0DB_DDBS;
  385:         goto set_DEPC;
  386:     case EXCP_DDBL:
  387:         env->CP0_Debug |= 1 << CP0DB_DDBL;
  388:     set_DEPC:
  389:         if (env->hflags & MIPS_HFLAG_BMASK) {
  390:             /* If the exception was raised from a delay slot,
  391:                come back to the jump.  */
  392:             env->CP0_DEPC = env->active_tc.PC - 4;
  393:             env->hflags &= ~MIPS_HFLAG_BMASK;
  394:         } else {
  395:             env->CP0_DEPC = env->active_tc.PC;
  396:         }
  397:  enter_debug_mode:
  398:         env->hflags |= MIPS_HFLAG_DM | MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
  399:         env->hflags &= ~(MIPS_HFLAG_KSU);
  400:         /* EJTAG probe trap enable is not implemented... */
  401:         if (!(env->CP0_Status & (1 << CP0St_EXL)))
  402:             env->CP0_Cause &= ~(1 << CP0Ca_BD);
  403:         env->active_tc.PC = (int32_t)0xBFC00480;
  404:         break;
  405:     case EXCP_RESET:
  406:         cpu_reset(env);
  407:         break;
  408:     case EXCP_SRESET:
  409:         env->CP0_Status |= (1 << CP0St_SR);
  410:         memset(env->CP0_WatchLo, 0, sizeof(*env->CP0_WatchLo));
  411:         goto set_error_EPC;
  412:     case EXCP_NMI:
  413:         env->CP0_Status |= (1 << CP0St_NMI);
  414:  set_error_EPC:
  415:         if (env->hflags & MIPS_HFLAG_BMASK) {
  416:             /* If the exception was raised from a delay slot,
  417:                come back to the jump.  */
  418:             env->CP0_ErrorEPC = env->active_tc.PC - 4;
  419:             env->hflags &= ~MIPS_HFLAG_BMASK;
  420:         } else {
  421:             env->CP0_ErrorEPC = env->active_tc.PC;
  422:         }
  423:         env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
  424:         env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
  425:         env->hflags &= ~(MIPS_HFLAG_KSU);
  426:         if (!(env->CP0_Status & (1 << CP0St_EXL)))
  427:             env->CP0_Cause &= ~(1 << CP0Ca_BD);
  428:         env->active_tc.PC = (int32_t)0xBFC00000;
  429:         break;
  430:     case EXCP_EXT_INTERRUPT:
  431:         cause = 0;
  432:         if (env->CP0_Cause & (1 << CP0Ca_IV))
  433:             offset = 0x200;
  434:         goto set_EPC;
  435:     case EXCP_LTLBL:
  436:         cause = 1;
  437:         goto set_EPC;
  438:     case EXCP_TLBL:
  439:         cause = 2;
  440:         if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
  441: #if defined(TARGET_MIPS64)
  442:             int R = env->CP0_BadVAddr >> 62;
  443:             int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
  444:             int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
  445:             int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
  446: 
  447:             if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
  448:                 offset = 0x080;
  449:             else
  450: #endif
  451:                 offset = 0x000;
  452:         }
  453:         goto set_EPC;
  454:     case EXCP_TLBS:
  455:         cause = 3;
  456:         if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
  457: #if defined(TARGET_MIPS64)
  458:             int R = env->CP0_BadVAddr >> 62;
  459:             int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
  460:             int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
  461:             int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
  462: 
  463:             if ((R == 0 && UX) || (R == 1 && SX) || (R == 3 && KX))
  464:                 offset = 0x080;
  465:             else
  466: #endif
  467:                 offset = 0x000;
  468:         }
  469:         goto set_EPC;
  470:     case EXCP_AdEL:
  471:         cause = 4;
  472:         goto set_EPC;
  473:     case EXCP_AdES:
  474:         cause = 5;
  475:         goto set_EPC;
  476:     case EXCP_IBE:
  477:         cause = 6;
  478:         goto set_EPC;
  479:     case EXCP_DBE:
  480:         cause = 7;
  481:         goto set_EPC;
  482:     case EXCP_SYSCALL:
  483:         cause = 8;
  484:         goto set_EPC;
  485:     case EXCP_BREAK:
  486:         cause = 9;
  487:         goto set_EPC;
  488:     case EXCP_RI:
  489:         cause = 10;
  490:         goto set_EPC;
  491:     case EXCP_CpU:
  492:         cause = 11;
  493:         env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
  494:                          (env->error_code << CP0Ca_CE);
  495:         goto set_EPC;
  496:     case EXCP_OVERFLOW:
  497:         cause = 12;
  498:         goto set_EPC;
  499:     case EXCP_TRAP:
  500:         cause = 13;
  501:         goto set_EPC;
  502:     case EXCP_FPE:
  503:         cause = 15;
  504:         goto set_EPC;
  505:     case EXCP_C2E:
  506:         cause = 18;
  507:         goto set_EPC;
  508:     case EXCP_MDMX:
  509:         cause = 22;
  510:         goto set_EPC;
  511:     case EXCP_DWATCH:
  512:         cause = 23;
  513:         /* XXX: TODO: manage defered watch exceptions */
  514:         goto set_EPC;
  515:     case EXCP_MCHECK:
  516:         cause = 24;
  517:         goto set_EPC;
  518:     case EXCP_THREAD:
  519:         cause = 25;
  520:         goto set_EPC;
  521:     case EXCP_CACHE:
  522:         cause = 30;
  523:         if (env->CP0_Status & (1 << CP0St_BEV)) {
  524:             offset = 0x100;
  525:         } else {
  526:             offset = 0x20000100;
  527:         }
  528:  set_EPC:
  529:         if (!(env->CP0_Status & (1 << CP0St_EXL))) {
  530:             if (env->hflags & MIPS_HFLAG_BMASK) {
  531:                 /* If the exception was raised from a delay slot,
  532:                    come back to the jump.  */
  533:                 env->CP0_EPC = env->active_tc.PC - 4;
  534:                 env->CP0_Cause |= (1 << CP0Ca_BD);
  535:             } else {
  536:                 env->CP0_EPC = env->active_tc.PC;
  537:                 env->CP0_Cause &= ~(1 << CP0Ca_BD);
  538:             }
  539:             env->CP0_Status |= (1 << CP0St_EXL);
  540:             env->hflags |= MIPS_HFLAG_64 | MIPS_HFLAG_CP0;
  541:             env->hflags &= ~(MIPS_HFLAG_KSU);
  542:         }
  543:         env->hflags &= ~MIPS_HFLAG_BMASK;
  544:         if (env->CP0_Status & (1 << CP0St_BEV)) {
  545:             env->active_tc.PC = (int32_t)0xBFC00200;
  546:         } else {
  547:             env->active_tc.PC = (int32_t)(env->CP0_EBase & ~0x3ff);
  548:         }
  549:         env->active_tc.PC += offset;
  550:         env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
  551:         break;
  552:     default:
  553:         qemu_log("Invalid MIPS exception %d. Exiting\n", env->exception_index);
  554:         printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
  555:         exit(1);
  556:     }
  557:     if (qemu_log_enabled() && env->exception_index != EXCP_EXT_INTERRUPT) {
  558:         qemu_log("%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d\n"
  559:                 "    S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
  560:                 __func__, env->active_tc.PC, env->CP0_EPC, cause,
  561:                 env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
  562:                 env->CP0_DEPC);
  563:     }
  564: #endif
  565:     env->exception_index = EXCP_NONE;
  566: }
  567: 
  568: void r4k_invalidate_tlb (CPUState *env, int idx, int use_extra)
  569: {
  570:     r4k_tlb_t *tlb;
  571:     target_ulong addr;
  572:     target_ulong end;
  573:     uint8_t ASID = env->CP0_EntryHi & 0xFF;
  574:     target_ulong mask;
  575: 
  576:     tlb = &env->tlb->mmu.r4k.tlb[idx];
  577:     /* The qemu TLB is flushed when the ASID changes, so no need to
  578:        flush these entries again.  */
  579:     if (tlb->G == 0 && tlb->ASID != ASID) {
  580:         return;
  581:     }
  582: 
  583:     if (use_extra && env->tlb->tlb_in_use < MIPS_TLB_MAX) {
  584:         /* For tlbwr, we can shadow the discarded entry into
  585:            a new (fake) TLB entry, as long as the guest can not
  586:            tell that it's there.  */
  587:         env->tlb->mmu.r4k.tlb[env->tlb->tlb_in_use] = *tlb;
  588:         env->tlb->tlb_in_use++;
  589:         return;
  590:     }
  591: 
  592:     /* 1k pages are not supported. */
  593:     mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
  594:     if (tlb->V0) {
  595:         addr = tlb->VPN & ~mask;
  596: #if defined(TARGET_MIPS64)
  597:         if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
  598:             addr |= 0x3FFFFF0000000000ULL;
  599:         }
  600: #endif
  601:         end = addr | (mask >> 1);
  602:         while (addr < end) {
  603:             tlb_flush_page (env, addr);
  604:             addr += TARGET_PAGE_SIZE;
  605:         }
  606:     }
  607:     if (tlb->V1) {
  608:         addr = (tlb->VPN & ~mask) | ((mask >> 1) + 1);
  609: #if defined(TARGET_MIPS64)
  610:         if (addr >= (0xFFFFFFFF80000000ULL & env->SEGMask)) {
  611:             addr |= 0x3FFFFF0000000000ULL;
  612:         }
  613: #endif
  614:         end = addr | mask;
  615:         while (addr - 1 < end) {
  616:             tlb_flush_page (env, addr);
  617:             addr += TARGET_PAGE_SIZE;
  618:         }
  619:     }
  620: }

unix.superglobalmegacorp.com