1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include "qemu/osdep.h"
21
22#include "cpu.h"
23#include "exec/exec-all.h"
24#include "fpu/softfloat-types.h"
25#include "exec/helper-proto.h"
26#include "qemu/qemu-print.h"
27
28
29#define CONVERT_BIT(X, SRC, DST) \
30 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
31
32uint64_t cpu_alpha_load_fpcr(CPUAlphaState *env)
33{
34 return (uint64_t)env->fpcr << 32;
35}
36
37void cpu_alpha_store_fpcr(CPUAlphaState *env, uint64_t val)
38{
39 static const uint8_t rm_map[] = {
40 [FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT] = float_round_nearest_even,
41 [FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT] = float_round_to_zero,
42 [FPCR_DYN_MINUS >> FPCR_DYN_SHIFT] = float_round_down,
43 [FPCR_DYN_PLUS >> FPCR_DYN_SHIFT] = float_round_up,
44 };
45
46 uint32_t fpcr = val >> 32;
47 uint32_t t = 0;
48
49
50 env->fpcr = fpcr;
51
52#ifdef CONFIG_USER_ONLY
53
54
55
56
57
58
59 uint32_t soft_fpcr = alpha_ieee_swcr_to_fpcr(env->swcr) >> 32;
60 fpcr |= soft_fpcr & (FPCR_STATUS_MASK | FPCR_DNZ);
61
62
63
64
65
66
67 t |= CONVERT_BIT(soft_fpcr, FPCR_INVD, FPCR_IOV);
68#endif
69
70 t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
71 t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
72 t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
73 t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
74 t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
75
76 env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
77
78 env->fpcr_dyn_round = rm_map[(fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT];
79 env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
80
81 t = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
82#ifdef CONFIG_USER_ONLY
83 t |= (env->swcr & SWCR_MAP_UMZ) != 0;
84#endif
85 env->fpcr_flush_to_zero = t;
86}
87
88uint64_t helper_load_fpcr(CPUAlphaState *env)
89{
90 return cpu_alpha_load_fpcr(env);
91}
92
93void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
94{
95 cpu_alpha_store_fpcr(env, val);
96}
97
98static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg)
99{
100#ifndef CONFIG_USER_ONLY
101 if (env->flags & ENV_FLAG_PAL_MODE) {
102 if (reg >= 8 && reg <= 14) {
103 return &env->shadow[reg - 8];
104 } else if (reg == 25) {
105 return &env->shadow[7];
106 }
107 }
108#endif
109 return &env->ir[reg];
110}
111
112uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg)
113{
114 return *cpu_alpha_addr_gr(env, reg);
115}
116
117void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
118{
119 *cpu_alpha_addr_gr(env, reg) = val;
120}
121
122#if defined(CONFIG_USER_ONLY)
123bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
124 MMUAccessType access_type, int mmu_idx,
125 bool probe, uintptr_t retaddr)
126{
127 AlphaCPU *cpu = ALPHA_CPU(cs);
128
129 cs->exception_index = EXCP_MMFAULT;
130 cpu->env.trap_arg0 = address;
131 cpu_loop_exit_restore(cs, retaddr);
132}
133#else
134
135static int get_physical_address(CPUAlphaState *env, target_ulong addr,
136 int prot_need, int mmu_idx,
137 target_ulong *pphys, int *pprot)
138{
139 CPUState *cs = env_cpu(env);
140 target_long saddr = addr;
141 target_ulong phys = 0;
142 target_ulong L1pte, L2pte, L3pte;
143 target_ulong pt, index;
144 int prot = 0;
145 int ret = MM_K_ACV;
146
147
148 if (mmu_idx == MMU_PHYS_IDX) {
149 phys = addr;
150 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
151 ret = -1;
152 goto exit;
153 }
154
155
156
157 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
158 goto exit;
159 }
160
161
162
163
164 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
165
166 if (mmu_idx != MMU_KERNEL_IDX) {
167 goto exit;
168 }
169
170
171
172 phys = saddr & ((1ull << 40) - 1);
173 phys |= (saddr & (1ull << 40)) << 3;
174
175 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
176 ret = -1;
177 goto exit;
178 }
179
180
181
182 pt = env->ptbr;
183
184
185
186
187
188
189
190
191
192
193 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
194 L1pte = ldq_phys(cs->as, pt + index*8);
195
196 if (unlikely((L1pte & PTE_VALID) == 0)) {
197 ret = MM_K_TNV;
198 goto exit;
199 }
200 if (unlikely((L1pte & PTE_KRE) == 0)) {
201 goto exit;
202 }
203 pt = L1pte >> 32 << TARGET_PAGE_BITS;
204
205
206 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
207 L2pte = ldq_phys(cs->as, pt + index*8);
208
209 if (unlikely((L2pte & PTE_VALID) == 0)) {
210 ret = MM_K_TNV;
211 goto exit;
212 }
213 if (unlikely((L2pte & PTE_KRE) == 0)) {
214 goto exit;
215 }
216 pt = L2pte >> 32 << TARGET_PAGE_BITS;
217
218
219 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
220 L3pte = ldq_phys(cs->as, pt + index*8);
221
222 phys = L3pte >> 32 << TARGET_PAGE_BITS;
223 if (unlikely((L3pte & PTE_VALID) == 0)) {
224 ret = MM_K_TNV;
225 goto exit;
226 }
227
228#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
229# error page bits out of date
230#endif
231
232
233 if (L3pte & (PTE_KRE << mmu_idx)) {
234 prot |= PAGE_READ | PAGE_EXEC;
235 }
236 if (L3pte & (PTE_KWE << mmu_idx)) {
237 prot |= PAGE_WRITE;
238 }
239 if (unlikely((prot & prot_need) == 0 && prot_need)) {
240 goto exit;
241 }
242
243
244 prot &= ~(L3pte >> 1);
245 ret = -1;
246 if (unlikely((prot & prot_need) == 0)) {
247 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
248 prot_need & PAGE_WRITE ? MM_K_FOW :
249 prot_need & PAGE_READ ? MM_K_FOR : -1);
250 }
251
252 exit:
253 *pphys = phys;
254 *pprot = prot;
255 return ret;
256}
257
258hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
259{
260 AlphaCPU *cpu = ALPHA_CPU(cs);
261 target_ulong phys;
262 int prot, fail;
263
264 fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot);
265 return (fail >= 0 ? -1 : phys);
266}
267
268bool alpha_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
269 MMUAccessType access_type, int mmu_idx,
270 bool probe, uintptr_t retaddr)
271{
272 AlphaCPU *cpu = ALPHA_CPU(cs);
273 CPUAlphaState *env = &cpu->env;
274 target_ulong phys;
275 int prot, fail;
276
277 fail = get_physical_address(env, addr, 1 << access_type,
278 mmu_idx, &phys, &prot);
279 if (unlikely(fail >= 0)) {
280 if (probe) {
281 return false;
282 }
283 cs->exception_index = EXCP_MMFAULT;
284 env->trap_arg0 = addr;
285 env->trap_arg1 = fail;
286 env->trap_arg2 = (access_type == MMU_DATA_LOAD ? 0ull :
287 access_type == MMU_DATA_STORE ? 1ull :
288 -1ull);
289 cpu_loop_exit_restore(cs, retaddr);
290 }
291
292 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
293 prot, mmu_idx, TARGET_PAGE_SIZE);
294 return true;
295}
296#endif
297
298void alpha_cpu_do_interrupt(CPUState *cs)
299{
300 AlphaCPU *cpu = ALPHA_CPU(cs);
301 CPUAlphaState *env = &cpu->env;
302 int i = cs->exception_index;
303
304 if (qemu_loglevel_mask(CPU_LOG_INT)) {
305 static int count;
306 const char *name = "<unknown>";
307
308 switch (i) {
309 case EXCP_RESET:
310 name = "reset";
311 break;
312 case EXCP_MCHK:
313 name = "mchk";
314 break;
315 case EXCP_SMP_INTERRUPT:
316 name = "smp_interrupt";
317 break;
318 case EXCP_CLK_INTERRUPT:
319 name = "clk_interrupt";
320 break;
321 case EXCP_DEV_INTERRUPT:
322 name = "dev_interrupt";
323 break;
324 case EXCP_MMFAULT:
325 name = "mmfault";
326 break;
327 case EXCP_UNALIGN:
328 name = "unalign";
329 break;
330 case EXCP_OPCDEC:
331 name = "opcdec";
332 break;
333 case EXCP_ARITH:
334 name = "arith";
335 break;
336 case EXCP_FEN:
337 name = "fen";
338 break;
339 case EXCP_CALL_PAL:
340 name = "call_pal";
341 break;
342 }
343 qemu_log("INT %6d: %s(%#x) cpu=%d pc=%016"
344 PRIx64 " sp=%016" PRIx64 "\n",
345 ++count, name, env->error_code, cs->cpu_index,
346 env->pc, env->ir[IR_SP]);
347 }
348
349 cs->exception_index = -1;
350
351#if !defined(CONFIG_USER_ONLY)
352 switch (i) {
353 case EXCP_RESET:
354 i = 0x0000;
355 break;
356 case EXCP_MCHK:
357 i = 0x0080;
358 break;
359 case EXCP_SMP_INTERRUPT:
360 i = 0x0100;
361 break;
362 case EXCP_CLK_INTERRUPT:
363 i = 0x0180;
364 break;
365 case EXCP_DEV_INTERRUPT:
366 i = 0x0200;
367 break;
368 case EXCP_MMFAULT:
369 i = 0x0280;
370 break;
371 case EXCP_UNALIGN:
372 i = 0x0300;
373 break;
374 case EXCP_OPCDEC:
375 i = 0x0380;
376 break;
377 case EXCP_ARITH:
378 i = 0x0400;
379 break;
380 case EXCP_FEN:
381 i = 0x0480;
382 break;
383 case EXCP_CALL_PAL:
384 i = env->error_code;
385
386
387
388 if (i & 0x80) {
389 i = 0x2000 + (i - 0x80) * 64;
390 } else {
391 i = 0x1000 + i * 64;
392 }
393 break;
394 default:
395 cpu_abort(cs, "Unhandled CPU exception");
396 }
397
398
399
400 env->exc_addr = env->pc | (env->flags & ENV_FLAG_PAL_MODE);
401
402
403 env->pc = env->palbr + i;
404
405
406 env->flags |= ENV_FLAG_PAL_MODE;
407#endif
408}
409
410bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
411{
412 AlphaCPU *cpu = ALPHA_CPU(cs);
413 CPUAlphaState *env = &cpu->env;
414 int idx = -1;
415
416
417 if (env->flags & ENV_FLAG_PAL_MODE) {
418 return false;
419 }
420
421
422
423
424 switch ((env->flags >> ENV_FLAG_PS_SHIFT) & PS_INT_MASK) {
425 case 0 ... 3:
426 if (interrupt_request & CPU_INTERRUPT_HARD) {
427 idx = EXCP_DEV_INTERRUPT;
428 }
429
430 case 4:
431 if (interrupt_request & CPU_INTERRUPT_TIMER) {
432 idx = EXCP_CLK_INTERRUPT;
433 }
434
435 case 5:
436 if (interrupt_request & CPU_INTERRUPT_SMP) {
437 idx = EXCP_SMP_INTERRUPT;
438 }
439
440 case 6:
441 if (interrupt_request & CPU_INTERRUPT_MCHK) {
442 idx = EXCP_MCHK;
443 }
444 }
445 if (idx >= 0) {
446 cs->exception_index = idx;
447 env->error_code = 0;
448 alpha_cpu_do_interrupt(cs);
449 return true;
450 }
451 return false;
452}
453
454void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags)
455{
456 static const char linux_reg_names[31][4] = {
457 "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
458 "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
459 "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
460 "t10", "t11", "ra", "t12", "at", "gp", "sp"
461 };
462 AlphaCPU *cpu = ALPHA_CPU(cs);
463 CPUAlphaState *env = &cpu->env;
464 int i;
465
466 qemu_fprintf(f, "PC " TARGET_FMT_lx " PS %02x\n",
467 env->pc, extract32(env->flags, ENV_FLAG_PS_SHIFT, 8));
468 for (i = 0; i < 31; i++) {
469 qemu_fprintf(f, "%-8s" TARGET_FMT_lx "%c",
470 linux_reg_names[i], cpu_alpha_load_gr(env, i),
471 (i % 3) == 2 ? '\n' : ' ');
472 }
473
474 qemu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
475 env->lock_addr, env->lock_value);
476
477 if (flags & CPU_DUMP_FPU) {
478 for (i = 0; i < 31; i++) {
479 qemu_fprintf(f, "f%-7d%016" PRIx64 "%c", i, env->fir[i],
480 (i % 3) == 2 ? '\n' : ' ');
481 }
482 qemu_fprintf(f, "fpcr %016" PRIx64 "\n", cpu_alpha_load_fpcr(env));
483 }
484 qemu_fprintf(f, "\n");
485}
486
487
488
489void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
490{
491 CPUState *cs = env_cpu(env);
492
493 cs->exception_index = excp;
494 env->error_code = error;
495 cpu_loop_exit(cs);
496}
497
498
499void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
500 int excp, int error)
501{
502 CPUState *cs = env_cpu(env);
503
504 cs->exception_index = excp;
505 env->error_code = error;
506 if (retaddr) {
507 cpu_restore_state(cs, retaddr, true);
508
509 env->pc += 4;
510 }
511 cpu_loop_exit(cs);
512}
513
514void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
515 int exc, uint64_t mask)
516{
517 env->trap_arg0 = exc;
518 env->trap_arg1 = mask;
519 dynamic_excp(env, retaddr, EXCP_ARITH, 0);
520}
521