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