Annotation of qemu/target-mips/helper.c, revision 1.1

1.1     ! root        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., 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"
        !            30: 
        !            31: /* MIPS32 4K MMU emulation */
        !            32: #ifdef MIPS_USES_R4K_TLB
        !            33: static int map_address (CPUState *env, target_ulong *physical, int *prot,
        !            34:                         target_ulong address, int rw, int access_type)
        !            35: {
        !            36:     tlb_t *tlb;
        !            37:     target_ulong tag;
        !            38:     uint8_t ASID;
        !            39:     int i, n;
        !            40:     int ret;
        !            41: 
        !            42:     ret = -2;
        !            43:     tag = (address & 0xFFFFE000);
        !            44:     ASID = env->CP0_EntryHi & 0x000000FF;
        !            45:     for (i = 0; i < MIPS_TLB_NB; i++) {
        !            46:         tlb = &env->tlb[i];
        !            47:         /* Check ASID, virtual page number & size */
        !            48:         if ((tlb->G == 1 || tlb->ASID == ASID) &&
        !            49:             tlb->VPN == tag && address < tlb->end) {
        !            50:             /* TLB match */
        !            51:             n = (address >> 12) & 1;
        !            52:             /* Check access rights */
        !            53:             if ((tlb->V[n] & 2) && (rw == 0 || (tlb->D[n] & 4))) {
        !            54:                 *physical = tlb->PFN[n] | (address & 0xFFF);
        !            55:                 *prot = PAGE_READ;
        !            56:                 if (tlb->D[n])
        !            57:                     *prot |= PAGE_WRITE;
        !            58:                 return 0;
        !            59:             } else if (!(tlb->V[n] & 2)) {
        !            60:                 return -3;
        !            61:             } else {
        !            62:                 return -4;
        !            63:             }
        !            64:         }
        !            65:     }
        !            66: 
        !            67:     return ret;
        !            68: }
        !            69: #endif
        !            70: 
        !            71: int get_physical_address (CPUState *env, target_ulong *physical, int *prot,
        !            72:                           target_ulong address, int rw, int access_type)
        !            73: {
        !            74:     int user_mode;
        !            75:     int ret;
        !            76: 
        !            77:     /* User mode can only access useg */
        !            78:     user_mode = ((env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM) ? 1 : 0;
        !            79: #if 0
        !            80:     if (logfile) {
        !            81:         fprintf(logfile, "user mode %d h %08x\n",
        !            82:                 user_mode, env->hflags);
        !            83:     }
        !            84: #endif
        !            85:     if (user_mode && address > 0x7FFFFFFFUL)
        !            86:         return -1;
        !            87:     ret = 0;
        !            88:     if (address < 0x80000000UL) {
        !            89:         if (!(env->hflags & MIPS_HFLAG_ERL)) {
        !            90: #ifdef MIPS_USES_R4K_TLB
        !            91:             ret = map_address(env, physical, prot, address, rw, access_type);
        !            92: #else
        !            93:             *physical = address + 0x40000000UL;
        !            94:             *prot = PAGE_READ | PAGE_WRITE;
        !            95: #endif
        !            96:         } else {
        !            97:             *physical = address;
        !            98:             *prot = PAGE_READ | PAGE_WRITE;
        !            99:         }
        !           100:     } else if (address < 0xA0000000UL) {
        !           101:         /* kseg0 */
        !           102:         /* XXX: check supervisor mode */
        !           103:         *physical = address - 0x80000000UL;
        !           104:         *prot = PAGE_READ | PAGE_WRITE;
        !           105:     } else if (address < 0xC0000000UL) {
        !           106:         /* kseg1 */
        !           107:         /* XXX: check supervisor mode */
        !           108:         *physical = address - 0xA0000000UL;
        !           109:         *prot = PAGE_READ | PAGE_WRITE;
        !           110:     } else if (address < 0xE0000000UL) {
        !           111:         /* kseg2 */
        !           112: #ifdef MIPS_USES_R4K_TLB
        !           113:         ret = map_address(env, physical, prot, address, rw, access_type);
        !           114: #else
        !           115:         *physical = address;
        !           116:         *prot = PAGE_READ | PAGE_WRITE;
        !           117: #endif
        !           118:     } else {
        !           119:         /* kseg3 */
        !           120:         /* XXX: check supervisor mode */
        !           121:         /* XXX: debug segment is not emulated */
        !           122: #ifdef MIPS_USES_R4K_TLB
        !           123:         ret = map_address(env, physical, prot, address, rw, access_type);
        !           124: #else
        !           125:         *physical = address;
        !           126:         *prot = PAGE_READ | PAGE_WRITE;
        !           127: #endif
        !           128:     }
        !           129: #if 0
        !           130:     if (logfile) {
        !           131:         fprintf(logfile, "%08x %d %d => %08x %d (%d)\n", address, rw,
        !           132:                 access_type, *physical, *prot, ret);
        !           133:     }
        !           134: #endif
        !           135: 
        !           136:     return ret;
        !           137: }
        !           138: 
        !           139: #if defined(CONFIG_USER_ONLY) 
        !           140: target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
        !           141: {
        !           142:     return addr;
        !           143: }
        !           144: #else
        !           145: target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
        !           146: {
        !           147:     target_ulong phys_addr;
        !           148:     int prot;
        !           149: 
        !           150:     if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
        !           151:         return -1;
        !           152:     return phys_addr;
        !           153: }
        !           154: 
        !           155: void cpu_mips_init_mmu (CPUState *env)
        !           156: {
        !           157: }
        !           158: #endif /* !defined(CONFIG_USER_ONLY) */
        !           159: 
        !           160: int cpu_mips_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
        !           161:                                int is_user, int is_softmmu)
        !           162: {
        !           163:     target_ulong physical;
        !           164:     int prot;
        !           165:     int exception = 0, error_code = 0;
        !           166:     int access_type;
        !           167:     int ret = 0;
        !           168: 
        !           169:     if (logfile) {
        !           170:         cpu_dump_state(env, logfile, fprintf, 0);
        !           171:         fprintf(logfile, "%s pc %08x ad %08x rw %d is_user %d smmu %d\n",
        !           172:                 __func__, env->PC, address, rw, is_user, is_softmmu);
        !           173:     }
        !           174:     /* data access */
        !           175:     /* XXX: put correct access by using cpu_restore_state()
        !           176:        correctly */
        !           177:     access_type = ACCESS_INT;
        !           178:     if (env->user_mode_only) {
        !           179:         /* user mode only emulation */
        !           180:         ret = -2;
        !           181:         goto do_fault;
        !           182:     }
        !           183:     ret = get_physical_address(env, &physical, &prot,
        !           184:                                address, rw, access_type);
        !           185:     if (logfile) {
        !           186:         fprintf(logfile, "%s address=%08x ret %d physical %08x prot %d\n",
        !           187:                 __func__, address, ret, physical, prot);
        !           188:     }
        !           189:     if (ret == 0) {
        !           190:        ret = tlb_set_page(env, address & ~0xFFF, physical & ~0xFFF, prot,
        !           191:                           is_user, is_softmmu);
        !           192:     } else if (ret < 0) {
        !           193:     do_fault:
        !           194:         switch (ret) {
        !           195:         default:
        !           196:         case -1:
        !           197:             /* Reference to kernel address from user mode or supervisor mode */
        !           198:             /* Reference to supervisor address from user mode */
        !           199:             if (rw)
        !           200:                 exception = EXCP_AdES;
        !           201:             else
        !           202:                 exception = EXCP_AdEL;
        !           203:             break;
        !           204:         case -2:
        !           205:             /* No TLB match for a mapped address */
        !           206:             if (rw)
        !           207:                 exception = EXCP_TLBS;
        !           208:             else
        !           209:                 exception = EXCP_TLBL;
        !           210:             error_code = 1;
        !           211:             break;
        !           212:         case -3:
        !           213:             /* TLB match with no valid bit */
        !           214:             if (rw)
        !           215:                 exception = EXCP_TLBS;
        !           216:             else
        !           217:                 exception = EXCP_TLBL;
        !           218:             error_code = 0;
        !           219:             break;
        !           220:         case -4:
        !           221:             /* TLB match but 'D' bit is cleared */
        !           222:             exception = EXCP_LTLBL;
        !           223:             break;
        !           224:                 
        !           225:         }
        !           226:         /* Raise exception */
        !           227:         env->CP0_BadVAddr = address;
        !           228:         env->CP0_Context = (env->CP0_Context & 0xff800000) |
        !           229:                           ((address >> 8) &   0x007ffff0);
        !           230:         env->CP0_EntryHi =
        !           231:             (env->CP0_EntryHi & 0x000000FF) | (address & 0xFFFFF000);
        !           232:         env->exception_index = exception;
        !           233:         env->error_code = error_code;
        !           234:         ret = 1;
        !           235:     }
        !           236: 
        !           237:     return ret;
        !           238: }
        !           239: 
        !           240: void do_interrupt (CPUState *env)
        !           241: {
        !           242:     target_ulong pc, offset;
        !           243:     int cause = -1;
        !           244: 
        !           245:     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
        !           246:         fprintf(logfile, "%s enter: PC %08x EPC %08x cause %d excp %d\n",
        !           247:                 __func__, env->PC, env->CP0_EPC, cause, env->exception_index);
        !           248:     }
        !           249:     if (env->exception_index == EXCP_EXT_INTERRUPT &&
        !           250:         (env->hflags & MIPS_HFLAG_DM))
        !           251:         env->exception_index = EXCP_DINT;
        !           252:     offset = 0x180;
        !           253:     switch (env->exception_index) {
        !           254:     case EXCP_DSS:
        !           255:         env->CP0_Debug |= 1 << CP0DB_DSS;
        !           256:         /* Debug single step cannot be raised inside a delay slot and
        !           257:          * resume will always occur on the next instruction
        !           258:          * (but we assume the pc has always been updated during
        !           259:          *  code translation).
        !           260:          */
        !           261:         env->CP0_DEPC = env->PC;
        !           262:         goto enter_debug_mode;
        !           263:     case EXCP_DINT:
        !           264:         env->CP0_Debug |= 1 << CP0DB_DINT;
        !           265:         goto set_DEPC;
        !           266:     case EXCP_DIB:
        !           267:         env->CP0_Debug |= 1 << CP0DB_DIB;
        !           268:         goto set_DEPC;
        !           269:     case EXCP_DBp:
        !           270:         env->CP0_Debug |= 1 << CP0DB_DBp;
        !           271:         goto set_DEPC;
        !           272:     case EXCP_DDBS:
        !           273:         env->CP0_Debug |= 1 << CP0DB_DDBS;
        !           274:         goto set_DEPC;
        !           275:     case EXCP_DDBL:
        !           276:         env->CP0_Debug |= 1 << CP0DB_DDBL;
        !           277:         goto set_DEPC;
        !           278:     set_DEPC:
        !           279:         if (env->hflags & MIPS_HFLAG_DS) {
        !           280:             /* If the exception was raised from a delay slot,
        !           281:              * come back to the jump
        !           282:              */
        !           283:             env->CP0_DEPC = env->PC - 4;
        !           284:         } else {
        !           285:             env->CP0_DEPC = env->PC;
        !           286:         }
        !           287:     enter_debug_mode:
        !           288:         env->hflags |= MIPS_HFLAG_DM;
        !           289:         /* EJTAG probe trap enable is not implemented... */
        !           290:         pc = 0xBFC00480;
        !           291:         break;
        !           292:     case EXCP_RESET:
        !           293: #ifdef MIPS_USES_R4K_TLB
        !           294:         env->CP0_random = MIPS_TLB_NB - 1;
        !           295: #endif
        !           296:         env->CP0_Wired = 0;
        !           297:         env->CP0_Config0 = MIPS_CONFIG0;
        !           298: #if defined (MIPS_CONFIG1)
        !           299:         env->CP0_Config1 = MIPS_CONFIG1;
        !           300: #endif
        !           301: #if defined (MIPS_CONFIG2)
        !           302:         env->CP0_Config2 = MIPS_CONFIG2;
        !           303: #endif
        !           304: #if defined (MIPS_CONFIG3)
        !           305:         env->CP0_Config3 = MIPS_CONFIG3;
        !           306: #endif
        !           307:         env->CP0_WatchLo = 0;
        !           308:         env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV);
        !           309:         goto set_error_EPC;
        !           310:     case EXCP_SRESET:
        !           311:         env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
        !           312:             (1 << CP0St_SR);
        !           313:         env->CP0_WatchLo = 0;
        !           314:         goto set_error_EPC;
        !           315:     case EXCP_NMI:
        !           316:         env->CP0_Status = (1 << CP0St_CU0) | (1 << CP0St_BEV) |
        !           317:             (1 << CP0St_NMI);
        !           318:     set_error_EPC:
        !           319:         env->hflags = MIPS_HFLAG_ERL;
        !           320:         if (env->hflags & MIPS_HFLAG_DS) {
        !           321:             /* If the exception was raised from a delay slot,
        !           322:              * come back to the jump
        !           323:              */
        !           324:             env->CP0_ErrorEPC = env->PC - 4;
        !           325:         } else {
        !           326:             env->CP0_ErrorEPC = env->PC;
        !           327:         }
        !           328:         pc = 0xBFC00000;
        !           329:         break;
        !           330:     case EXCP_MCHECK:
        !           331:         cause = 24;
        !           332:         goto set_EPC;
        !           333:     case EXCP_EXT_INTERRUPT:
        !           334:         cause = 0;
        !           335:         if (env->CP0_Cause & (1 << CP0Ca_IV))
        !           336:             offset = 0x200;
        !           337:         goto set_EPC;
        !           338:     case EXCP_DWATCH:
        !           339:         cause = 23;
        !           340:         /* XXX: TODO: manage defered watch exceptions */
        !           341:         goto set_EPC;
        !           342:     case EXCP_AdEL:
        !           343:     case EXCP_AdES:
        !           344:         cause = 4;
        !           345:         goto set_EPC;
        !           346:     case EXCP_TLBL:
        !           347:     case EXCP_TLBF:
        !           348:         cause = 2;
        !           349:         if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
        !           350:             offset = 0x000;
        !           351:         goto set_EPC;
        !           352:     case EXCP_IBE:
        !           353:         cause = 6;
        !           354:         goto set_EPC;
        !           355:     case EXCP_DBE:
        !           356:         cause = 7;
        !           357:         goto set_EPC;
        !           358:     case EXCP_SYSCALL:
        !           359:         cause = 8;
        !           360:         goto set_EPC;
        !           361:     case EXCP_BREAK:
        !           362:         cause = 9;
        !           363:         goto set_EPC;
        !           364:     case EXCP_RI:
        !           365:         cause = 10;
        !           366:         goto set_EPC;
        !           367:     case EXCP_CpU:
        !           368:         cause = 11;
        !           369:         /* XXX: fill in the faulty unit number */
        !           370:         goto set_EPC;
        !           371:     case EXCP_OVERFLOW:
        !           372:         cause = 12;
        !           373:         goto set_EPC;
        !           374:     case EXCP_TRAP:
        !           375:         cause = 13;
        !           376:         goto set_EPC;
        !           377:     case EXCP_LTLBL:
        !           378:         cause = 1;
        !           379:         goto set_EPC;
        !           380:     case EXCP_TLBS:
        !           381:         cause = 3;
        !           382:         if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
        !           383:             offset = 0x000;
        !           384:         goto set_EPC;
        !           385:     set_EPC:
        !           386:         if (env->CP0_Status & (1 << CP0St_BEV)) {
        !           387:             pc = 0xBFC00200;
        !           388:         } else {
        !           389:             pc = 0x80000000;
        !           390:         }
        !           391:         env->hflags |= MIPS_HFLAG_EXL;
        !           392:         pc += offset;
        !           393:         env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
        !           394:         if (env->hflags & MIPS_HFLAG_DS) {
        !           395:             /* If the exception was raised from a delay slot,
        !           396:              * come back to the jump
        !           397:              */
        !           398:             env->CP0_EPC = env->PC - 4;
        !           399:             env->CP0_Cause |= 0x80000000;
        !           400:         } else {
        !           401:             env->CP0_EPC = env->PC;
        !           402:             env->CP0_Cause &= ~0x80000000;
        !           403:         }
        !           404:         break;
        !           405:     default:
        !           406:         if (logfile) {
        !           407:             fprintf(logfile, "Invalid MIPS exception %d. Exiting\n",
        !           408:                     env->exception_index);
        !           409:         }
        !           410:         printf("Invalid MIPS exception %d. Exiting\n", env->exception_index);
        !           411:         exit(1);
        !           412:     }
        !           413:     env->PC = pc;
        !           414:     if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
        !           415:         fprintf(logfile, "%s: PC %08x EPC %08x cause %d excp %d\n"
        !           416:                 "    S %08x C %08x A %08x D %08x\n",
        !           417:                 __func__, env->PC, env->CP0_EPC, cause, env->exception_index,
        !           418:                 env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
        !           419:                 env->CP0_DEPC);
        !           420:     }
        !           421:     env->exception_index = EXCP_NONE;
        !           422: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.