Annotation of qemu/target-alpha/helper.c, revision 1.1.1.6

1.1       root        1: /*
                      2:  *  Alpha emulation cpu helpers for qemu.
                      3:  *
                      4:  *  Copyright (c) 2007 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
1.1.1.3   root       17:  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
1.1       root       18:  */
                     19: 
                     20: #include <stdint.h>
                     21: #include <stdlib.h>
                     22: #include <stdio.h>
                     23: 
                     24: #include "cpu.h"
1.1.1.4   root       25: #include "softfloat.h"
                     26: 
                     27: uint64_t cpu_alpha_load_fpcr (CPUState *env)
                     28: {
                     29:     uint64_t r = 0;
                     30:     uint8_t t;
                     31: 
                     32:     t = env->fpcr_exc_status;
                     33:     if (t) {
                     34:         r = FPCR_SUM;
                     35:         if (t & float_flag_invalid) {
                     36:             r |= FPCR_INV;
                     37:         }
                     38:         if (t & float_flag_divbyzero) {
                     39:             r |= FPCR_DZE;
                     40:         }
                     41:         if (t & float_flag_overflow) {
                     42:             r |= FPCR_OVF;
                     43:         }
                     44:         if (t & float_flag_underflow) {
                     45:             r |= FPCR_UNF;
                     46:         }
                     47:         if (t & float_flag_inexact) {
                     48:             r |= FPCR_INE;
                     49:         }
                     50:     }
                     51: 
                     52:     t = env->fpcr_exc_mask;
                     53:     if (t & float_flag_invalid) {
                     54:         r |= FPCR_INVD;
                     55:     }
                     56:     if (t & float_flag_divbyzero) {
                     57:         r |= FPCR_DZED;
                     58:     }
                     59:     if (t & float_flag_overflow) {
                     60:         r |= FPCR_OVFD;
                     61:     }
                     62:     if (t & float_flag_underflow) {
                     63:         r |= FPCR_UNFD;
                     64:     }
                     65:     if (t & float_flag_inexact) {
                     66:         r |= FPCR_INED;
                     67:     }
                     68: 
                     69:     switch (env->fpcr_dyn_round) {
                     70:     case float_round_nearest_even:
                     71:         r |= FPCR_DYN_NORMAL;
                     72:         break;
                     73:     case float_round_down:
                     74:         r |= FPCR_DYN_MINUS;
                     75:         break;
                     76:     case float_round_up:
                     77:         r |= FPCR_DYN_PLUS;
                     78:         break;
                     79:     case float_round_to_zero:
                     80:         r |= FPCR_DYN_CHOPPED;
                     81:         break;
                     82:     }
                     83: 
                     84:     if (env->fpcr_dnz) {
                     85:         r |= FPCR_DNZ;
                     86:     }
                     87:     if (env->fpcr_dnod) {
                     88:         r |= FPCR_DNOD;
                     89:     }
                     90:     if (env->fpcr_undz) {
                     91:         r |= FPCR_UNDZ;
                     92:     }
                     93: 
                     94:     return r;
                     95: }
                     96: 
                     97: void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
                     98: {
                     99:     uint8_t t;
                    100: 
                    101:     t = 0;
                    102:     if (val & FPCR_INV) {
                    103:         t |= float_flag_invalid;
                    104:     }
                    105:     if (val & FPCR_DZE) {
                    106:         t |= float_flag_divbyzero;
                    107:     }
                    108:     if (val & FPCR_OVF) {
                    109:         t |= float_flag_overflow;
                    110:     }
                    111:     if (val & FPCR_UNF) {
                    112:         t |= float_flag_underflow;
                    113:     }
                    114:     if (val & FPCR_INE) {
                    115:         t |= float_flag_inexact;
                    116:     }
                    117:     env->fpcr_exc_status = t;
                    118: 
                    119:     t = 0;
                    120:     if (val & FPCR_INVD) {
                    121:         t |= float_flag_invalid;
                    122:     }
                    123:     if (val & FPCR_DZED) {
                    124:         t |= float_flag_divbyzero;
                    125:     }
                    126:     if (val & FPCR_OVFD) {
                    127:         t |= float_flag_overflow;
                    128:     }
                    129:     if (val & FPCR_UNFD) {
                    130:         t |= float_flag_underflow;
                    131:     }
                    132:     if (val & FPCR_INED) {
                    133:         t |= float_flag_inexact;
                    134:     }
                    135:     env->fpcr_exc_mask = t;
                    136: 
                    137:     switch (val & FPCR_DYN_MASK) {
                    138:     case FPCR_DYN_CHOPPED:
                    139:         t = float_round_to_zero;
                    140:         break;
                    141:     case FPCR_DYN_MINUS:
                    142:         t = float_round_down;
                    143:         break;
                    144:     case FPCR_DYN_NORMAL:
                    145:         t = float_round_nearest_even;
                    146:         break;
                    147:     case FPCR_DYN_PLUS:
                    148:         t = float_round_up;
                    149:         break;
                    150:     }
                    151:     env->fpcr_dyn_round = t;
                    152: 
                    153:     env->fpcr_flush_to_zero
                    154:       = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
                    155: 
                    156:     env->fpcr_dnz = (val & FPCR_DNZ) != 0;
                    157:     env->fpcr_dnod = (val & FPCR_DNOD) != 0;
                    158:     env->fpcr_undz = (val & FPCR_UNDZ) != 0;
                    159: }
1.1       root      160: 
                    161: #if defined(CONFIG_USER_ONLY)
                    162: int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
                    163:                                 int mmu_idx, int is_softmmu)
                    164: {
1.1.1.6 ! root      165:     env->exception_index = EXCP_MMFAULT;
        !           166:     env->trap_arg0 = address;
1.1       root      167:     return 1;
                    168: }
1.1.1.6 ! root      169: #else
        !           170: void swap_shadow_regs(CPUState *env)
1.1       root      171: {
1.1.1.6 ! root      172:     uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
        !           173: 
        !           174:     i0 = env->ir[8];
        !           175:     i1 = env->ir[9];
        !           176:     i2 = env->ir[10];
        !           177:     i3 = env->ir[11];
        !           178:     i4 = env->ir[12];
        !           179:     i5 = env->ir[13];
        !           180:     i6 = env->ir[14];
        !           181:     i7 = env->ir[25];
        !           182: 
        !           183:     env->ir[8]  = env->shadow[0];
        !           184:     env->ir[9]  = env->shadow[1];
        !           185:     env->ir[10] = env->shadow[2];
        !           186:     env->ir[11] = env->shadow[3];
        !           187:     env->ir[12] = env->shadow[4];
        !           188:     env->ir[13] = env->shadow[5];
        !           189:     env->ir[14] = env->shadow[6];
        !           190:     env->ir[25] = env->shadow[7];
        !           191: 
        !           192:     env->shadow[0] = i0;
        !           193:     env->shadow[1] = i1;
        !           194:     env->shadow[2] = i2;
        !           195:     env->shadow[3] = i3;
        !           196:     env->shadow[4] = i4;
        !           197:     env->shadow[5] = i5;
        !           198:     env->shadow[6] = i6;
        !           199:     env->shadow[7] = i7;
1.1       root      200: }
                    201: 
1.1.1.6 ! root      202: /* Returns the OSF/1 entMM failure indication, or -1 on success.  */
        !           203: static int get_physical_address(CPUState *env, target_ulong addr,
        !           204:                                 int prot_need, int mmu_idx,
        !           205:                                 target_ulong *pphys, int *pprot)
        !           206: {
        !           207:     target_long saddr = addr;
        !           208:     target_ulong phys = 0;
        !           209:     target_ulong L1pte, L2pte, L3pte;
        !           210:     target_ulong pt, index;
        !           211:     int prot = 0;
        !           212:     int ret = MM_K_ACV;
        !           213: 
        !           214:     /* Ensure that the virtual address is properly sign-extended from
        !           215:        the last implemented virtual address bit.  */
        !           216:     if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
        !           217:         goto exit;
        !           218:     }
        !           219: 
        !           220:     /* Translate the superpage.  */
        !           221:     /* ??? When we do more than emulate Unix PALcode, we'll need to
        !           222:        determine which KSEG is actually active.  */
        !           223:     if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
        !           224:         /* User-space cannot access KSEG addresses.  */
        !           225:         if (mmu_idx != MMU_KERNEL_IDX) {
        !           226:             goto exit;
        !           227:         }
        !           228: 
        !           229:         /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
        !           230:            We would not do this if the 48-bit KSEG is enabled.  */
        !           231:         phys = saddr & ((1ull << 40) - 1);
        !           232:         phys |= (saddr & (1ull << 40)) << 3;
        !           233: 
        !           234:         prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
        !           235:         ret = -1;
        !           236:         goto exit;
        !           237:     }
        !           238: 
        !           239:     /* Interpret the page table exactly like PALcode does.  */
        !           240: 
        !           241:     pt = env->ptbr;
        !           242: 
        !           243:     /* L1 page table read.  */
        !           244:     index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
        !           245:     L1pte = ldq_phys(pt + index*8);
        !           246: 
        !           247:     if (unlikely((L1pte & PTE_VALID) == 0)) {
        !           248:         ret = MM_K_TNV;
        !           249:         goto exit;
        !           250:     }
        !           251:     if (unlikely((L1pte & PTE_KRE) == 0)) {
        !           252:         goto exit;
        !           253:     }
        !           254:     pt = L1pte >> 32 << TARGET_PAGE_BITS;
        !           255: 
        !           256:     /* L2 page table read.  */
        !           257:     index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
        !           258:     L2pte = ldq_phys(pt + index*8);
        !           259: 
        !           260:     if (unlikely((L2pte & PTE_VALID) == 0)) {
        !           261:         ret = MM_K_TNV;
        !           262:         goto exit;
        !           263:     }
        !           264:     if (unlikely((L2pte & PTE_KRE) == 0)) {
        !           265:         goto exit;
        !           266:     }
        !           267:     pt = L2pte >> 32 << TARGET_PAGE_BITS;
        !           268: 
        !           269:     /* L3 page table read.  */
        !           270:     index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
        !           271:     L3pte = ldq_phys(pt + index*8);
        !           272: 
        !           273:     phys = L3pte >> 32 << TARGET_PAGE_BITS;
        !           274:     if (unlikely((L3pte & PTE_VALID) == 0)) {
        !           275:         ret = MM_K_TNV;
        !           276:         goto exit;
        !           277:     }
        !           278: 
        !           279: #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
        !           280: # error page bits out of date
        !           281: #endif
1.1       root      282: 
1.1.1.6 ! root      283:     /* Check access violations.  */
        !           284:     if (L3pte & (PTE_KRE << mmu_idx)) {
        !           285:         prot |= PAGE_READ | PAGE_EXEC;
        !           286:     }
        !           287:     if (L3pte & (PTE_KWE << mmu_idx)) {
        !           288:         prot |= PAGE_WRITE;
        !           289:     }
        !           290:     if (unlikely((prot & prot_need) == 0 && prot_need)) {
        !           291:         goto exit;
        !           292:     }
        !           293: 
        !           294:     /* Check fault-on-operation violations.  */
        !           295:     prot &= ~(L3pte >> 1);
        !           296:     ret = -1;
        !           297:     if (unlikely((prot & prot_need) == 0)) {
        !           298:         ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
        !           299:                prot_need & PAGE_WRITE ? MM_K_FOW :
        !           300:                prot_need & PAGE_READ ? MM_K_FOR : -1);
        !           301:     }
        !           302: 
        !           303:  exit:
        !           304:     *pphys = phys;
        !           305:     *pprot = prot;
        !           306:     return ret;
        !           307: }
        !           308: 
        !           309: target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
1.1       root      310: {
1.1.1.6 ! root      311:     target_ulong phys;
        !           312:     int prot, fail;
        !           313: 
        !           314:     fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
        !           315:     return (fail >= 0 ? -1 : phys);
1.1       root      316: }
                    317: 
1.1.1.6 ! root      318: int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
        !           319:                                int mmu_idx, int is_softmmu)
1.1       root      320: {
1.1.1.6 ! root      321:     target_ulong phys;
        !           322:     int prot, fail;
1.1       root      323: 
1.1.1.6 ! root      324:     fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
        !           325:     if (unlikely(fail >= 0)) {
        !           326:         env->exception_index = EXCP_MMFAULT;
        !           327:         env->trap_arg0 = addr;
        !           328:         env->trap_arg1 = fail;
        !           329:         env->trap_arg2 = (rw == 2 ? -1 : rw);
        !           330:         return 1;
1.1       root      331:     }
                    332: 
1.1.1.6 ! root      333:     tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
        !           334:                  prot, mmu_idx, TARGET_PAGE_SIZE);
        !           335:     return 0;
1.1       root      336: }
1.1.1.6 ! root      337: #endif /* USER_ONLY */
1.1       root      338: 
1.1.1.6 ! root      339: void do_interrupt (CPUState *env)
1.1       root      340: {
1.1.1.6 ! root      341:     int i = env->exception_index;
1.1       root      342: 
1.1.1.6 ! root      343:     if (qemu_loglevel_mask(CPU_LOG_INT)) {
        !           344:         static int count;
        !           345:         const char *name = "<unknown>";
        !           346: 
        !           347:         switch (i) {
        !           348:         case EXCP_RESET:
        !           349:             name = "reset";
        !           350:             break;
        !           351:         case EXCP_MCHK:
        !           352:             name = "mchk";
        !           353:             break;
        !           354:         case EXCP_SMP_INTERRUPT:
        !           355:             name = "smp_interrupt";
        !           356:             break;
        !           357:         case EXCP_CLK_INTERRUPT:
        !           358:             name = "clk_interrupt";
        !           359:             break;
        !           360:         case EXCP_DEV_INTERRUPT:
        !           361:             name = "dev_interrupt";
        !           362:             break;
        !           363:         case EXCP_MMFAULT:
        !           364:             name = "mmfault";
        !           365:             break;
        !           366:         case EXCP_UNALIGN:
        !           367:             name = "unalign";
        !           368:             break;
        !           369:         case EXCP_OPCDEC:
        !           370:             name = "opcdec";
        !           371:             break;
        !           372:         case EXCP_ARITH:
        !           373:             name = "arith";
        !           374:             break;
        !           375:         case EXCP_FEN:
        !           376:             name = "fen";
        !           377:             break;
        !           378:         case EXCP_CALL_PAL:
        !           379:             name = "call_pal";
        !           380:             break;
        !           381:         case EXCP_STL_C:
        !           382:             name = "stl_c";
        !           383:             break;
        !           384:         case EXCP_STQ_C:
        !           385:             name = "stq_c";
        !           386:             break;
1.1       root      387:         }
1.1.1.6 ! root      388:         qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
        !           389:                  ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
1.1       root      390:     }
                    391: 
1.1.1.6 ! root      392:     env->exception_index = -1;
1.1       root      393: 
1.1.1.6 ! root      394: #if !defined(CONFIG_USER_ONLY)
        !           395:     switch (i) {
        !           396:     case EXCP_RESET:
        !           397:         i = 0x0000;
1.1       root      398:         break;
1.1.1.6 ! root      399:     case EXCP_MCHK:
        !           400:         i = 0x0080;
1.1       root      401:         break;
1.1.1.6 ! root      402:     case EXCP_SMP_INTERRUPT:
        !           403:         i = 0x0100;
1.1       root      404:         break;
1.1.1.6 ! root      405:     case EXCP_CLK_INTERRUPT:
        !           406:         i = 0x0180;
1.1.1.4   root      407:         break;
1.1.1.6 ! root      408:     case EXCP_DEV_INTERRUPT:
        !           409:         i = 0x0200;
1.1       root      410:         break;
1.1.1.6 ! root      411:     case EXCP_MMFAULT:
        !           412:         i = 0x0280;
1.1       root      413:         break;
1.1.1.6 ! root      414:     case EXCP_UNALIGN:
        !           415:         i = 0x0300;
1.1       root      416:         break;
1.1.1.6 ! root      417:     case EXCP_OPCDEC:
        !           418:         i = 0x0380;
1.1       root      419:         break;
1.1.1.6 ! root      420:     case EXCP_ARITH:
        !           421:         i = 0x0400;
1.1       root      422:         break;
1.1.1.6 ! root      423:     case EXCP_FEN:
        !           424:         i = 0x0480;
1.1       root      425:         break;
1.1.1.6 ! root      426:     case EXCP_CALL_PAL:
        !           427:         i = env->error_code;
        !           428:         /* There are 64 entry points for both privileged and unprivileged,
        !           429:            with bit 0x80 indicating unprivileged.  Each entry point gets
        !           430:            64 bytes to do its job.  */
        !           431:         if (i & 0x80) {
        !           432:             i = 0x2000 + (i - 0x80) * 64;
        !           433:         } else {
        !           434:             i = 0x1000 + i * 64;
        !           435:         }
1.1       root      436:         break;
                    437:     default:
1.1.1.6 ! root      438:         cpu_abort(env, "Unhandled CPU exception");
1.1       root      439:     }
                    440: 
1.1.1.6 ! root      441:     /* Remember where the exception happened.  Emulate real hardware in
        !           442:        that the low bit of the PC indicates PALmode.  */
        !           443:     env->exc_addr = env->pc | env->pal_mode;
1.1       root      444: 
1.1.1.6 ! root      445:     /* Continue execution at the PALcode entry point.  */
        !           446:     env->pc = env->palbr + i;
1.1       root      447: 
1.1.1.6 ! root      448:     /* Switch to PALmode.  */
        !           449:     if (!env->pal_mode) {
        !           450:         env->pal_mode = 1;
        !           451:         swap_shadow_regs(env);
1.1       root      452:     }
1.1.1.6 ! root      453: #endif /* !USER_ONLY */
1.1       root      454: }
                    455: 
1.1.1.5   root      456: void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
1.1       root      457:                      int flags)
                    458: {
1.1.1.2   root      459:     static const char *linux_reg_names[] = {
1.1       root      460:         "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
                    461:         "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
                    462:         "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
                    463:         "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
                    464:     };
                    465:     int i;
                    466: 
1.1.1.6 ! root      467:     cpu_fprintf(f, "     PC  " TARGET_FMT_lx "      PS  %02x\n",
1.1       root      468:                 env->pc, env->ps);
                    469:     for (i = 0; i < 31; i++) {
                    470:         cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
                    471:                     linux_reg_names[i], env->ir[i]);
                    472:         if ((i % 3) == 2)
                    473:             cpu_fprintf(f, "\n");
                    474:     }
1.1.1.4   root      475: 
                    476:     cpu_fprintf(f, "lock_a   " TARGET_FMT_lx " lock_v   " TARGET_FMT_lx "\n",
                    477:                 env->lock_addr, env->lock_value);
                    478: 
1.1       root      479:     for (i = 0; i < 31; i++) {
                    480:         cpu_fprintf(f, "FIR%02d    " TARGET_FMT_lx " ", i,
                    481:                     *((uint64_t *)(&env->fir[i])));
                    482:         if ((i % 3) == 2)
                    483:             cpu_fprintf(f, "\n");
                    484:     }
1.1.1.4   root      485:     cpu_fprintf(f, "\n");
1.1       root      486: }

unix.superglobalmegacorp.com

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