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