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