]> git.proxmox.com Git - mirror_qemu.git/blame - target-alpha/helper.c
xics: Add xics_find_source()
[mirror_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"
2ef6175a 26#include "exec/helper-proto.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)
7510454e 171int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
a44a2777 172 int rw, int mmu_idx)
4c9649a9 173{
7510454e
AF
174 AlphaCPU *cpu = ALPHA_CPU(cs);
175
27103424 176 cs->exception_index = EXCP_MMFAULT;
7510454e 177 cpu->env.trap_arg0 = address;
4c9649a9
JM
178 return 1;
179}
4c9649a9 180#else
4d5712f1 181void swap_shadow_regs(CPUAlphaState *env)
21d2beaa
RH
182{
183 uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
184
185 i0 = env->ir[8];
186 i1 = env->ir[9];
187 i2 = env->ir[10];
188 i3 = env->ir[11];
189 i4 = env->ir[12];
190 i5 = env->ir[13];
191 i6 = env->ir[14];
192 i7 = env->ir[25];
193
194 env->ir[8] = env->shadow[0];
195 env->ir[9] = env->shadow[1];
196 env->ir[10] = env->shadow[2];
197 env->ir[11] = env->shadow[3];
198 env->ir[12] = env->shadow[4];
199 env->ir[13] = env->shadow[5];
200 env->ir[14] = env->shadow[6];
201 env->ir[25] = env->shadow[7];
202
203 env->shadow[0] = i0;
204 env->shadow[1] = i1;
205 env->shadow[2] = i2;
206 env->shadow[3] = i3;
207 env->shadow[4] = i4;
208 env->shadow[5] = i5;
209 env->shadow[6] = i6;
210 env->shadow[7] = i7;
211}
212
a3b9af16 213/* Returns the OSF/1 entMM failure indication, or -1 on success. */
4d5712f1 214static int get_physical_address(CPUAlphaState *env, target_ulong addr,
a3b9af16
RH
215 int prot_need, int mmu_idx,
216 target_ulong *pphys, int *pprot)
4c9649a9 217{
d2810ffd 218 CPUState *cs = CPU(alpha_env_get_cpu(env));
a3b9af16
RH
219 target_long saddr = addr;
220 target_ulong phys = 0;
221 target_ulong L1pte, L2pte, L3pte;
222 target_ulong pt, index;
223 int prot = 0;
224 int ret = MM_K_ACV;
225
226 /* Ensure that the virtual address is properly sign-extended from
227 the last implemented virtual address bit. */
228 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
229 goto exit;
230 }
231
232 /* Translate the superpage. */
233 /* ??? When we do more than emulate Unix PALcode, we'll need to
fa6e0a63
RH
234 determine which KSEG is actually active. */
235 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
236 /* User-space cannot access KSEG addresses. */
a3b9af16
RH
237 if (mmu_idx != MMU_KERNEL_IDX) {
238 goto exit;
239 }
240
fa6e0a63
RH
241 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
242 We would not do this if the 48-bit KSEG is enabled. */
a3b9af16 243 phys = saddr & ((1ull << 40) - 1);
fa6e0a63
RH
244 phys |= (saddr & (1ull << 40)) << 3;
245
a3b9af16
RH
246 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
247 ret = -1;
248 goto exit;
249 }
250
251 /* Interpret the page table exactly like PALcode does. */
252
253 pt = env->ptbr;
254
255 /* L1 page table read. */
256 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
2c17449b 257 L1pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
258
259 if (unlikely((L1pte & PTE_VALID) == 0)) {
260 ret = MM_K_TNV;
261 goto exit;
262 }
263 if (unlikely((L1pte & PTE_KRE) == 0)) {
264 goto exit;
265 }
266 pt = L1pte >> 32 << TARGET_PAGE_BITS;
267
268 /* L2 page table read. */
269 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
2c17449b 270 L2pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
271
272 if (unlikely((L2pte & PTE_VALID) == 0)) {
273 ret = MM_K_TNV;
274 goto exit;
275 }
276 if (unlikely((L2pte & PTE_KRE) == 0)) {
277 goto exit;
278 }
279 pt = L2pte >> 32 << TARGET_PAGE_BITS;
280
281 /* L3 page table read. */
282 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
2c17449b 283 L3pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
284
285 phys = L3pte >> 32 << TARGET_PAGE_BITS;
286 if (unlikely((L3pte & PTE_VALID) == 0)) {
287 ret = MM_K_TNV;
288 goto exit;
289 }
290
291#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
292# error page bits out of date
293#endif
294
295 /* Check access violations. */
296 if (L3pte & (PTE_KRE << mmu_idx)) {
297 prot |= PAGE_READ | PAGE_EXEC;
298 }
299 if (L3pte & (PTE_KWE << mmu_idx)) {
300 prot |= PAGE_WRITE;
301 }
302 if (unlikely((prot & prot_need) == 0 && prot_need)) {
303 goto exit;
304 }
305
306 /* Check fault-on-operation violations. */
307 prot &= ~(L3pte >> 1);
308 ret = -1;
309 if (unlikely((prot & prot_need) == 0)) {
310 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
311 prot_need & PAGE_WRITE ? MM_K_FOW :
312 prot_need & PAGE_READ ? MM_K_FOR : -1);
313 }
314
315 exit:
316 *pphys = phys;
317 *pprot = prot;
318 return ret;
4c9649a9
JM
319}
320
00b941e5 321hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
4c9649a9 322{
00b941e5 323 AlphaCPU *cpu = ALPHA_CPU(cs);
a3b9af16
RH
324 target_ulong phys;
325 int prot, fail;
326
00b941e5 327 fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot);
a3b9af16
RH
328 return (fail >= 0 ? -1 : phys);
329}
330
7510454e 331int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, int rw,
97b348e7 332 int mmu_idx)
a3b9af16 333{
7510454e
AF
334 AlphaCPU *cpu = ALPHA_CPU(cs);
335 CPUAlphaState *env = &cpu->env;
a3b9af16
RH
336 target_ulong phys;
337 int prot, fail;
338
339 fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
340 if (unlikely(fail >= 0)) {
27103424 341 cs->exception_index = EXCP_MMFAULT;
a3b9af16
RH
342 env->trap_arg0 = addr;
343 env->trap_arg1 = fail;
344 env->trap_arg2 = (rw == 2 ? -1 : rw);
345 return 1;
346 }
347
0c591eb0 348 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
a3b9af16 349 prot, mmu_idx, TARGET_PAGE_SIZE);
129d8aa5 350 return 0;
4c9649a9 351}
3a6fa678 352#endif /* USER_ONLY */
4c9649a9 353
97a8ea5a 354void alpha_cpu_do_interrupt(CPUState *cs)
4c9649a9 355{
97a8ea5a
AF
356 AlphaCPU *cpu = ALPHA_CPU(cs);
357 CPUAlphaState *env = &cpu->env;
27103424 358 int i = cs->exception_index;
3a6fa678
RH
359
360 if (qemu_loglevel_mask(CPU_LOG_INT)) {
361 static int count;
362 const char *name = "<unknown>";
363
364 switch (i) {
365 case EXCP_RESET:
366 name = "reset";
367 break;
368 case EXCP_MCHK:
369 name = "mchk";
370 break;
371 case EXCP_SMP_INTERRUPT:
372 name = "smp_interrupt";
373 break;
374 case EXCP_CLK_INTERRUPT:
375 name = "clk_interrupt";
376 break;
377 case EXCP_DEV_INTERRUPT:
378 name = "dev_interrupt";
379 break;
380 case EXCP_MMFAULT:
381 name = "mmfault";
382 break;
383 case EXCP_UNALIGN:
384 name = "unalign";
385 break;
386 case EXCP_OPCDEC:
387 name = "opcdec";
388 break;
389 case EXCP_ARITH:
390 name = "arith";
391 break;
392 case EXCP_FEN:
393 name = "fen";
394 break;
395 case EXCP_CALL_PAL:
396 name = "call_pal";
397 break;
398 case EXCP_STL_C:
399 name = "stl_c";
400 break;
401 case EXCP_STQ_C:
402 name = "stq_c";
403 break;
404 }
405 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
406 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
407 }
408
27103424 409 cs->exception_index = -1;
3a6fa678
RH
410
411#if !defined(CONFIG_USER_ONLY)
412 switch (i) {
413 case EXCP_RESET:
414 i = 0x0000;
415 break;
416 case EXCP_MCHK:
417 i = 0x0080;
418 break;
419 case EXCP_SMP_INTERRUPT:
420 i = 0x0100;
421 break;
422 case EXCP_CLK_INTERRUPT:
423 i = 0x0180;
424 break;
425 case EXCP_DEV_INTERRUPT:
426 i = 0x0200;
427 break;
428 case EXCP_MMFAULT:
429 i = 0x0280;
430 break;
431 case EXCP_UNALIGN:
432 i = 0x0300;
433 break;
434 case EXCP_OPCDEC:
435 i = 0x0380;
436 break;
437 case EXCP_ARITH:
438 i = 0x0400;
439 break;
440 case EXCP_FEN:
441 i = 0x0480;
442 break;
443 case EXCP_CALL_PAL:
444 i = env->error_code;
445 /* There are 64 entry points for both privileged and unprivileged,
446 with bit 0x80 indicating unprivileged. Each entry point gets
447 64 bytes to do its job. */
448 if (i & 0x80) {
449 i = 0x2000 + (i - 0x80) * 64;
450 } else {
451 i = 0x1000 + i * 64;
452 }
453 break;
454 default:
a47dddd7 455 cpu_abort(cs, "Unhandled CPU exception");
3a6fa678
RH
456 }
457
458 /* Remember where the exception happened. Emulate real hardware in
459 that the low bit of the PC indicates PALmode. */
460 env->exc_addr = env->pc | env->pal_mode;
461
462 /* Continue execution at the PALcode entry point. */
463 env->pc = env->palbr + i;
464
465 /* Switch to PALmode. */
21d2beaa
RH
466 if (!env->pal_mode) {
467 env->pal_mode = 1;
468 swap_shadow_regs(env);
469 }
3a6fa678 470#endif /* !USER_ONLY */
4c9649a9 471}
4c9649a9 472
878096ee
AF
473void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
474 int flags)
4c9649a9 475{
b55266b5 476 static const char *linux_reg_names[] = {
4c9649a9
JM
477 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
478 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
479 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
480 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
481 };
878096ee
AF
482 AlphaCPU *cpu = ALPHA_CPU(cs);
483 CPUAlphaState *env = &cpu->env;
4c9649a9
JM
484 int i;
485
129d8aa5 486 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
4c9649a9
JM
487 env->pc, env->ps);
488 for (i = 0; i < 31; i++) {
489 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
490 linux_reg_names[i], env->ir[i]);
491 if ((i % 3) == 2)
492 cpu_fprintf(f, "\n");
493 }
6910b8f6
RH
494
495 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
496 env->lock_addr, env->lock_value);
497
4c9649a9
JM
498 for (i = 0; i < 31; i++) {
499 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
500 *((uint64_t *)(&env->fir[i])));
501 if ((i % 3) == 2)
502 cpu_fprintf(f, "\n");
503 }
6910b8f6 504 cpu_fprintf(f, "\n");
4c9649a9 505}
b9f0923e 506
b9f0923e
RH
507/* This should only be called from translate, via gen_excp.
508 We expect that ENV->PC has already been updated. */
509void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
510{
27103424
AF
511 AlphaCPU *cpu = alpha_env_get_cpu(env);
512 CPUState *cs = CPU(cpu);
513
514 cs->exception_index = excp;
b9f0923e 515 env->error_code = error;
5638d180 516 cpu_loop_exit(cs);
b9f0923e
RH
517}
518
519/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
20503968 520void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
b9f0923e
RH
521 int excp, int error)
522{
27103424
AF
523 AlphaCPU *cpu = alpha_env_get_cpu(env);
524 CPUState *cs = CPU(cpu);
525
526 cs->exception_index = excp;
b9f0923e 527 env->error_code = error;
a8a826a3 528 if (retaddr) {
3f38f309 529 cpu_restore_state(cs, retaddr);
a8a826a3 530 }
5638d180 531 cpu_loop_exit(cs);
b9f0923e
RH
532}
533
20503968 534void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
b9f0923e
RH
535 int exc, uint64_t mask)
536{
537 env->trap_arg0 = exc;
538 env->trap_arg1 = mask;
539 dynamic_excp(env, retaddr, EXCP_ARITH, 0);
540}