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

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,
1.1.1.7 ! root      163:                                 int mmu_idx)
1.1       root      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,
1.1.1.7 ! root      319:                                int mmu_idx)
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.