1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <stdint.h>
21#include <stdlib.h>
22#include <stdio.h>
23
24#include "cpu.h"
25#include "fpu/softfloat.h"
26#include "helper.h"
27
28uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
29{
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) {
71 case float_round_nearest_even:
72 r |= FPCR_DYN_NORMAL;
73 break;
74 case float_round_down:
75 r |= FPCR_DYN_MINUS;
76 break;
77 case float_round_up:
78 r |= FPCR_DYN_PLUS;
79 break;
80 case float_round_to_zero:
81 r |= FPCR_DYN_CHOPPED;
82 break;
83 }
84
85 if (env->fp_status.flush_inputs_to_zero) {
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;
96}
97
98void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
99{
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;
141 break;
142 case FPCR_DYN_MINUS:
143 t = float_round_down;
144 break;
145 case FPCR_DYN_NORMAL:
146 t = float_round_nearest_even;
147 break;
148 case FPCR_DYN_PLUS:
149 t = float_round_up;
150 break;
151 }
152 env->fpcr_dyn_round = t;
153
154 env->fpcr_dnod = (val & FPCR_DNOD) != 0;
155 env->fpcr_undz = (val & FPCR_UNDZ) != 0;
156 env->fpcr_flush_to_zero = env->fpcr_dnod & env->fpcr_undz;
157 env->fp_status.flush_inputs_to_zero = (val & FPCR_DNZ) != 0;
158}
159
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
170#if defined(CONFIG_USER_ONLY)
171int cpu_alpha_handle_mmu_fault(CPUAlphaState *env, target_ulong address,
172 int rw, int mmu_idx)
173{
174 env->exception_index = EXCP_MMFAULT;
175 env->trap_arg0 = address;
176 return 1;
177}
178#else
179void swap_shadow_regs(CPUAlphaState *env)
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
211
212static int get_physical_address(CPUAlphaState *env, target_ulong addr,
213 int prot_need, int mmu_idx,
214 target_ulong *pphys, int *pprot)
215{
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
224
225 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
226 goto exit;
227 }
228
229
230
231
232 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
233
234 if (mmu_idx != MMU_KERNEL_IDX) {
235 goto exit;
236 }
237
238
239
240 phys = saddr & ((1ull << 40) - 1);
241 phys |= (saddr & (1ull << 40)) << 3;
242
243 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
244 ret = -1;
245 goto exit;
246 }
247
248
249
250 pt = env->ptbr;
251
252
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
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
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
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
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;
316}
317
318hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
319{
320 AlphaCPU *cpu = ALPHA_CPU(cs);
321 target_ulong phys;
322 int prot, fail;
323
324 fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot);
325 return (fail >= 0 ? -1 : phys);
326}
327
328int cpu_alpha_handle_mmu_fault(CPUAlphaState *env, target_ulong addr, int rw,
329 int mmu_idx)
330{
331 target_ulong phys;
332 int prot, fail;
333
334 fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
335 if (unlikely(fail >= 0)) {
336 env->exception_index = EXCP_MMFAULT;
337 env->trap_arg0 = addr;
338 env->trap_arg1 = fail;
339 env->trap_arg2 = (rw == 2 ? -1 : rw);
340 return 1;
341 }
342
343 tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
344 prot, mmu_idx, TARGET_PAGE_SIZE);
345 return 0;
346}
347#endif
348
349void alpha_cpu_do_interrupt(CPUState *cs)
350{
351 AlphaCPU *cpu = ALPHA_CPU(cs);
352 CPUAlphaState *env = &cpu->env;
353 int i = env->exception_index;
354
355 if (qemu_loglevel_mask(CPU_LOG_INT)) {
356 static int count;
357 const char *name = "<unknown>";
358
359 switch (i) {
360 case EXCP_RESET:
361 name = "reset";
362 break;
363 case EXCP_MCHK:
364 name = "mchk";
365 break;
366 case EXCP_SMP_INTERRUPT:
367 name = "smp_interrupt";
368 break;
369 case EXCP_CLK_INTERRUPT:
370 name = "clk_interrupt";
371 break;
372 case EXCP_DEV_INTERRUPT:
373 name = "dev_interrupt";
374 break;
375 case EXCP_MMFAULT:
376 name = "mmfault";
377 break;
378 case EXCP_UNALIGN:
379 name = "unalign";
380 break;
381 case EXCP_OPCDEC:
382 name = "opcdec";
383 break;
384 case EXCP_ARITH:
385 name = "arith";
386 break;
387 case EXCP_FEN:
388 name = "fen";
389 break;
390 case EXCP_CALL_PAL:
391 name = "call_pal";
392 break;
393 case EXCP_STL_C:
394 name = "stl_c";
395 break;
396 case EXCP_STQ_C:
397 name = "stq_c";
398 break;
399 }
400 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
401 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
402 }
403
404 env->exception_index = -1;
405
406#if !defined(CONFIG_USER_ONLY)
407 switch (i) {
408 case EXCP_RESET:
409 i = 0x0000;
410 break;
411 case EXCP_MCHK:
412 i = 0x0080;
413 break;
414 case EXCP_SMP_INTERRUPT:
415 i = 0x0100;
416 break;
417 case EXCP_CLK_INTERRUPT:
418 i = 0x0180;
419 break;
420 case EXCP_DEV_INTERRUPT:
421 i = 0x0200;
422 break;
423 case EXCP_MMFAULT:
424 i = 0x0280;
425 break;
426 case EXCP_UNALIGN:
427 i = 0x0300;
428 break;
429 case EXCP_OPCDEC:
430 i = 0x0380;
431 break;
432 case EXCP_ARITH:
433 i = 0x0400;
434 break;
435 case EXCP_FEN:
436 i = 0x0480;
437 break;
438 case EXCP_CALL_PAL:
439 i = env->error_code;
440
441
442
443 if (i & 0x80) {
444 i = 0x2000 + (i - 0x80) * 64;
445 } else {
446 i = 0x1000 + i * 64;
447 }
448 break;
449 default:
450 cpu_abort(env, "Unhandled CPU exception");
451 }
452
453
454
455 env->exc_addr = env->pc | env->pal_mode;
456
457
458 env->pc = env->palbr + i;
459
460
461 if (!env->pal_mode) {
462 env->pal_mode = 1;
463 swap_shadow_regs(env);
464 }
465#endif
466}
467
468void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
469 int flags)
470{
471 static const char *linux_reg_names[] = {
472 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
473 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
474 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
475 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
476 };
477 AlphaCPU *cpu = ALPHA_CPU(cs);
478 CPUAlphaState *env = &cpu->env;
479 int i;
480
481 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
482 env->pc, env->ps);
483 for (i = 0; i < 31; i++) {
484 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
485 linux_reg_names[i], env->ir[i]);
486 if ((i % 3) == 2)
487 cpu_fprintf(f, "\n");
488 }
489
490 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
491 env->lock_addr, env->lock_value);
492
493 for (i = 0; i < 31; i++) {
494 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
495 *((uint64_t *)(&env->fir[i])));
496 if ((i % 3) == 2)
497 cpu_fprintf(f, "\n");
498 }
499 cpu_fprintf(f, "\n");
500}
501
502
503
504void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
505{
506 env->exception_index = excp;
507 env->error_code = error;
508 cpu_loop_exit(env);
509}
510
511
512void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
513 int excp, int error)
514{
515 env->exception_index = excp;
516 env->error_code = error;
517 if (retaddr) {
518 cpu_restore_state(env, retaddr);
519 }
520 cpu_loop_exit(env);
521}
522
523void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
524 int exc, uint64_t mask)
525{
526 env->trap_arg0 = exc;
527 env->trap_arg1 = mask;
528 dynamic_excp(env, retaddr, EXCP_ARITH, 0);
529}
530