|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.