]> git.proxmox.com Git - mirror_qemu.git/blame - target/alpha/helper.c
Merge tag 'pull-maintainer-may24-160524-2' of https://gitlab.com/stsquad/qemu into...
[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
d6ea4236 9 * version 2.1 of the License, or (at your option) any later version.
4c9649a9
JM
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
e2e5e114 20#include "qemu/osdep.h"
cd617484 21#include "qemu/log.h"
4c9649a9 22#include "cpu.h"
63c91552 23#include "exec/exec-all.h"
74781c08 24#include "exec/page-protection.h"
5f8ab000 25#include "fpu/softfloat-types.h"
2ef6175a 26#include "exec/helper-proto.h"
90c84c56 27#include "qemu/qemu-print.h"
ba0e276d 28
8443effb 29
f3d3aad4
RH
30#define CONVERT_BIT(X, SRC, DST) \
31 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
8443effb 32
21ba8564 33uint64_t cpu_alpha_load_fpcr(CPUAlphaState *env)
f3d3aad4
RH
34{
35 return (uint64_t)env->fpcr << 32;
ba0e276d
RH
36}
37
21ba8564 38void cpu_alpha_store_fpcr(CPUAlphaState *env, uint64_t val)
ba0e276d 39{
ea937ded
RH
40 static const uint8_t rm_map[] = {
41 [FPCR_DYN_NORMAL >> FPCR_DYN_SHIFT] = float_round_nearest_even,
42 [FPCR_DYN_CHOPPED >> FPCR_DYN_SHIFT] = float_round_to_zero,
43 [FPCR_DYN_MINUS >> FPCR_DYN_SHIFT] = float_round_down,
44 [FPCR_DYN_PLUS >> FPCR_DYN_SHIFT] = float_round_up,
45 };
46
f3d3aad4
RH
47 uint32_t fpcr = val >> 32;
48 uint32_t t = 0;
8443effb 49
106e1319
RH
50 /* Record the raw value before adjusting for linux-user. */
51 env->fpcr = fpcr;
52
53#ifdef CONFIG_USER_ONLY
54 /*
55 * Override some of these bits with the contents of ENV->SWCR.
56 * In system mode, some of these would trap to the kernel, at
57 * which point the kernel's handler would emulate and apply
58 * the software exception mask.
59 */
60 uint32_t soft_fpcr = alpha_ieee_swcr_to_fpcr(env->swcr) >> 32;
8cd99905 61 fpcr |= soft_fpcr & (FPCR_STATUS_MASK | FPCR_DNZ);
80093070
RH
62
63 /*
64 * The IOV exception is disabled by the kernel with SWCR_TRAP_ENABLE_INV,
65 * which got mapped by alpha_ieee_swcr_to_fpcr to FPCR_INVD.
66 * Add FPCR_IOV to fpcr_exc_enable so that it is handled identically.
67 */
68 t |= CONVERT_BIT(soft_fpcr, FPCR_INVD, FPCR_IOV);
106e1319
RH
69#endif
70
f3d3aad4
RH
71 t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
72 t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
73 t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
74 t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
75 t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
8443effb 76
f3d3aad4 77 env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
8443effb 78
ea937ded 79 env->fpcr_dyn_round = rm_map[(fpcr & FPCR_DYN_MASK) >> FPCR_DYN_SHIFT];
f3d3aad4 80 env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
a8938e5f
RH
81
82 t = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
21ba8564 83#ifdef CONFIG_USER_ONLY
a8938e5f 84 t |= (env->swcr & SWCR_MAP_UMZ) != 0;
21ba8564 85#endif
a8938e5f 86 env->fpcr_flush_to_zero = t;
ba0e276d 87}
4c9649a9 88
a44a2777
RH
89uint64_t helper_load_fpcr(CPUAlphaState *env)
90{
91 return cpu_alpha_load_fpcr(env);
92}
93
94void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
95{
96 cpu_alpha_store_fpcr(env, val);
97}
98
59124384
RH
99static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg)
100{
101#ifndef CONFIG_USER_ONLY
bcd2625d 102 if (env->flags & ENV_FLAG_PAL_MODE) {
59124384
RH
103 if (reg >= 8 && reg <= 14) {
104 return &env->shadow[reg - 8];
105 } else if (reg == 25) {
106 return &env->shadow[7];
107 }
108 }
109#endif
110 return &env->ir[reg];
111}
112
113uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg)
114{
115 return *cpu_alpha_addr_gr(env, reg);
116}
117
118void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
119{
120 *cpu_alpha_addr_gr(env, reg) = val;
121}
122
5fafdf24 123#if defined(CONFIG_USER_ONLY)
90113883
RH
124void alpha_cpu_record_sigsegv(CPUState *cs, vaddr address,
125 MMUAccessType access_type,
126 bool maperr, uintptr_t retaddr)
4c9649a9 127{
ab709f13 128 CPUAlphaState *env = cpu_env(cs);
90113883
RH
129 target_ulong mmcsr, cause;
130
131 /* Assuming !maperr, infer the missing protection. */
132 switch (access_type) {
133 case MMU_DATA_LOAD:
134 mmcsr = MM_K_FOR;
135 cause = 0;
136 break;
137 case MMU_DATA_STORE:
138 mmcsr = MM_K_FOW;
139 cause = 1;
140 break;
141 case MMU_INST_FETCH:
142 mmcsr = MM_K_FOE;
143 cause = -1;
144 break;
145 default:
146 g_assert_not_reached();
147 }
148 if (maperr) {
149 if (address < BIT_ULL(TARGET_VIRT_ADDR_SPACE_BITS - 1)) {
150 /* Userspace address, therefore page not mapped. */
151 mmcsr = MM_K_TNV;
152 } else {
153 /* Kernel or invalid address. */
154 mmcsr = MM_K_ACV;
155 }
156 }
7510454e 157
90113883 158 /* Record the arguments that PALcode would give to the kernel. */
ab709f13
RH
159 env->trap_arg0 = address;
160 env->trap_arg1 = mmcsr;
161 env->trap_arg2 = cause;
4c9649a9 162}
4c9649a9 163#else
a3b9af16 164/* Returns the OSF/1 entMM failure indication, or -1 on success. */
4d5712f1 165static int get_physical_address(CPUAlphaState *env, target_ulong addr,
a3b9af16
RH
166 int prot_need, int mmu_idx,
167 target_ulong *pphys, int *pprot)
4c9649a9 168{
1c7ad260 169 CPUState *cs = env_cpu(env);
a3b9af16
RH
170 target_long saddr = addr;
171 target_ulong phys = 0;
172 target_ulong L1pte, L2pte, L3pte;
173 target_ulong pt, index;
174 int prot = 0;
175 int ret = MM_K_ACV;
176
6a73ecf5
RH
177 /* Handle physical accesses. */
178 if (mmu_idx == MMU_PHYS_IDX) {
179 phys = addr;
180 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
181 ret = -1;
182 goto exit;
183 }
184
a3b9af16
RH
185 /* Ensure that the virtual address is properly sign-extended from
186 the last implemented virtual address bit. */
187 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
188 goto exit;
189 }
190
191 /* Translate the superpage. */
192 /* ??? When we do more than emulate Unix PALcode, we'll need to
fa6e0a63
RH
193 determine which KSEG is actually active. */
194 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
195 /* User-space cannot access KSEG addresses. */
a3b9af16
RH
196 if (mmu_idx != MMU_KERNEL_IDX) {
197 goto exit;
198 }
199
fa6e0a63
RH
200 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
201 We would not do this if the 48-bit KSEG is enabled. */
a3b9af16 202 phys = saddr & ((1ull << 40) - 1);
fa6e0a63
RH
203 phys |= (saddr & (1ull << 40)) << 3;
204
a3b9af16
RH
205 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
206 ret = -1;
207 goto exit;
208 }
209
210 /* Interpret the page table exactly like PALcode does. */
211
212 pt = env->ptbr;
213
6ad4d7ee
PM
214 /* TODO: rather than using ldq_phys() to read the page table we should
215 * use address_space_ldq() so that we can handle the case when
216 * the page table read gives a bus fault, rather than ignoring it.
217 * For the existing code the zero data that ldq_phys will return for
218 * an access to invalid memory will result in our treating the page
219 * table as invalid, which may even be the right behaviour.
220 */
221
a3b9af16
RH
222 /* L1 page table read. */
223 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
2c17449b 224 L1pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
225
226 if (unlikely((L1pte & PTE_VALID) == 0)) {
227 ret = MM_K_TNV;
228 goto exit;
229 }
230 if (unlikely((L1pte & PTE_KRE) == 0)) {
231 goto exit;
232 }
233 pt = L1pte >> 32 << TARGET_PAGE_BITS;
234
235 /* L2 page table read. */
236 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
2c17449b 237 L2pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
238
239 if (unlikely((L2pte & PTE_VALID) == 0)) {
240 ret = MM_K_TNV;
241 goto exit;
242 }
243 if (unlikely((L2pte & PTE_KRE) == 0)) {
244 goto exit;
245 }
246 pt = L2pte >> 32 << TARGET_PAGE_BITS;
247
248 /* L3 page table read. */
249 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
2c17449b 250 L3pte = ldq_phys(cs->as, pt + index*8);
a3b9af16
RH
251
252 phys = L3pte >> 32 << TARGET_PAGE_BITS;
253 if (unlikely((L3pte & PTE_VALID) == 0)) {
254 ret = MM_K_TNV;
255 goto exit;
256 }
257
258#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
259# error page bits out of date
260#endif
261
262 /* Check access violations. */
263 if (L3pte & (PTE_KRE << mmu_idx)) {
264 prot |= PAGE_READ | PAGE_EXEC;
265 }
266 if (L3pte & (PTE_KWE << mmu_idx)) {
267 prot |= PAGE_WRITE;
268 }
269 if (unlikely((prot & prot_need) == 0 && prot_need)) {
270 goto exit;
271 }
272
273 /* Check fault-on-operation violations. */
274 prot &= ~(L3pte >> 1);
275 ret = -1;
276 if (unlikely((prot & prot_need) == 0)) {
277 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
278 prot_need & PAGE_WRITE ? MM_K_FOW :
279 prot_need & PAGE_READ ? MM_K_FOR : -1);
280 }
281
282 exit:
283 *pphys = phys;
284 *pprot = prot;
285 return ret;
4c9649a9
JM
286}
287
00b941e5 288hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
4c9649a9 289{
a3b9af16
RH
290 target_ulong phys;
291 int prot, fail;
292
50cb36ce 293 fail = get_physical_address(cpu_env(cs), addr, 0, 0, &phys, &prot);
a3b9af16
RH
294 return (fail >= 0 ? -1 : phys);
295}
296
e41c9452
RH
297bool alpha_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
298 MMUAccessType access_type, int mmu_idx,
299 bool probe, uintptr_t retaddr)
a3b9af16 300{
50cb36ce 301 CPUAlphaState *env = cpu_env(cs);
a3b9af16
RH
302 target_ulong phys;
303 int prot, fail;
304
e41c9452
RH
305 fail = get_physical_address(env, addr, 1 << access_type,
306 mmu_idx, &phys, &prot);
a3b9af16 307 if (unlikely(fail >= 0)) {
e41c9452
RH
308 if (probe) {
309 return false;
310 }
27103424 311 cs->exception_index = EXCP_MMFAULT;
a3b9af16
RH
312 env->trap_arg0 = addr;
313 env->trap_arg1 = fail;
cb1de55a
AJ
314 env->trap_arg2 = (access_type == MMU_DATA_LOAD ? 0ull :
315 access_type == MMU_DATA_STORE ? 1ull :
316 /* access_type == MMU_INST_FETCH */ -1ull);
e41c9452 317 cpu_loop_exit_restore(cs, retaddr);
a3b9af16
RH
318 }
319
0c591eb0 320 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
a3b9af16 321 prot, mmu_idx, TARGET_PAGE_SIZE);
e41c9452
RH
322 return true;
323}
4c9649a9 324
97a8ea5a 325void alpha_cpu_do_interrupt(CPUState *cs)
4c9649a9 326{
50cb36ce 327 CPUAlphaState *env = cpu_env(cs);
27103424 328 int i = cs->exception_index;
3a6fa678
RH
329
330 if (qemu_loglevel_mask(CPU_LOG_INT)) {
331 static int count;
332 const char *name = "<unknown>";
333
334 switch (i) {
335 case EXCP_RESET:
336 name = "reset";
337 break;
338 case EXCP_MCHK:
339 name = "mchk";
340 break;
341 case EXCP_SMP_INTERRUPT:
342 name = "smp_interrupt";
343 break;
344 case EXCP_CLK_INTERRUPT:
345 name = "clk_interrupt";
346 break;
347 case EXCP_DEV_INTERRUPT:
348 name = "dev_interrupt";
349 break;
350 case EXCP_MMFAULT:
351 name = "mmfault";
352 break;
353 case EXCP_UNALIGN:
354 name = "unalign";
355 break;
356 case EXCP_OPCDEC:
357 name = "opcdec";
358 break;
359 case EXCP_ARITH:
360 name = "arith";
361 break;
362 case EXCP_FEN:
363 name = "fen";
364 break;
365 case EXCP_CALL_PAL:
366 name = "call_pal";
367 break;
3a6fa678 368 }
022f52e0
RH
369 qemu_log("INT %6d: %s(%#x) cpu=%d pc=%016"
370 PRIx64 " sp=%016" PRIx64 "\n",
371 ++count, name, env->error_code, cs->cpu_index,
372 env->pc, env->ir[IR_SP]);
3a6fa678
RH
373 }
374
27103424 375 cs->exception_index = -1;
3a6fa678 376
3a6fa678
RH
377 switch (i) {
378 case EXCP_RESET:
379 i = 0x0000;
380 break;
381 case EXCP_MCHK:
382 i = 0x0080;
383 break;
384 case EXCP_SMP_INTERRUPT:
385 i = 0x0100;
386 break;
387 case EXCP_CLK_INTERRUPT:
388 i = 0x0180;
389 break;
390 case EXCP_DEV_INTERRUPT:
391 i = 0x0200;
392 break;
393 case EXCP_MMFAULT:
394 i = 0x0280;
395 break;
396 case EXCP_UNALIGN:
397 i = 0x0300;
398 break;
399 case EXCP_OPCDEC:
400 i = 0x0380;
401 break;
402 case EXCP_ARITH:
403 i = 0x0400;
404 break;
405 case EXCP_FEN:
406 i = 0x0480;
407 break;
408 case EXCP_CALL_PAL:
409 i = env->error_code;
410 /* There are 64 entry points for both privileged and unprivileged,
411 with bit 0x80 indicating unprivileged. Each entry point gets
412 64 bytes to do its job. */
413 if (i & 0x80) {
414 i = 0x2000 + (i - 0x80) * 64;
415 } else {
416 i = 0x1000 + i * 64;
417 }
418 break;
419 default:
a47dddd7 420 cpu_abort(cs, "Unhandled CPU exception");
3a6fa678
RH
421 }
422
423 /* Remember where the exception happened. Emulate real hardware in
424 that the low bit of the PC indicates PALmode. */
bcd2625d 425 env->exc_addr = env->pc | (env->flags & ENV_FLAG_PAL_MODE);
3a6fa678
RH
426
427 /* Continue execution at the PALcode entry point. */
428 env->pc = env->palbr + i;
429
430 /* Switch to PALmode. */
bcd2625d 431 env->flags |= ENV_FLAG_PAL_MODE;
4c9649a9 432}
4c9649a9 433
dde7c241
RH
434bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
435{
50cb36ce 436 CPUAlphaState *env = cpu_env(cs);
dde7c241
RH
437 int idx = -1;
438
439 /* We never take interrupts while in PALmode. */
bcd2625d 440 if (env->flags & ENV_FLAG_PAL_MODE) {
dde7c241
RH
441 return false;
442 }
443
444 /* Fall through the switch, collecting the highest priority
445 interrupt that isn't masked by the processor status IPL. */
446 /* ??? This hard-codes the OSF/1 interrupt levels. */
bcd2625d 447 switch ((env->flags >> ENV_FLAG_PS_SHIFT) & PS_INT_MASK) {
dde7c241
RH
448 case 0 ... 3:
449 if (interrupt_request & CPU_INTERRUPT_HARD) {
450 idx = EXCP_DEV_INTERRUPT;
451 }
452 /* FALLTHRU */
453 case 4:
454 if (interrupt_request & CPU_INTERRUPT_TIMER) {
455 idx = EXCP_CLK_INTERRUPT;
456 }
457 /* FALLTHRU */
458 case 5:
459 if (interrupt_request & CPU_INTERRUPT_SMP) {
460 idx = EXCP_SMP_INTERRUPT;
461 }
462 /* FALLTHRU */
463 case 6:
464 if (interrupt_request & CPU_INTERRUPT_MCHK) {
465 idx = EXCP_MCHK;
466 }
467 }
468 if (idx >= 0) {
469 cs->exception_index = idx;
470 env->error_code = 0;
471 alpha_cpu_do_interrupt(cs);
472 return true;
473 }
474 return false;
475}
476
9354e694
PMD
477#endif /* !CONFIG_USER_ONLY */
478
90c84c56 479void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags)
4c9649a9 480{
4a247932
RH
481 static const char linux_reg_names[31][4] = {
482 "v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
483 "t7", "s0", "s1", "s2", "s3", "s4", "s5", "fp",
484 "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
485 "t10", "t11", "ra", "t12", "at", "gp", "sp"
4c9649a9 486 };
50cb36ce 487 CPUAlphaState *env = cpu_env(cs);
4c9649a9
JM
488 int i;
489
4a247932 490 qemu_fprintf(f, "PC " TARGET_FMT_lx " PS %02x\n",
90c84c56 491 env->pc, extract32(env->flags, ENV_FLAG_PS_SHIFT, 8));
4c9649a9 492 for (i = 0; i < 31; i++) {
4a247932 493 qemu_fprintf(f, "%-8s" TARGET_FMT_lx "%c",
90c84c56
MA
494 linux_reg_names[i], cpu_alpha_load_gr(env, i),
495 (i % 3) == 2 ? '\n' : ' ');
4c9649a9 496 }
6910b8f6 497
4a247932 498 qemu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
90c84c56 499 env->lock_addr, env->lock_value);
6910b8f6 500
a68d82b8
RH
501 if (flags & CPU_DUMP_FPU) {
502 for (i = 0; i < 31; i++) {
4a247932 503 qemu_fprintf(f, "f%-7d%016" PRIx64 "%c", i, env->fir[i],
90c84c56 504 (i % 3) == 2 ? '\n' : ' ');
a68d82b8 505 }
4a247932 506 qemu_fprintf(f, "fpcr %016" PRIx64 "\n", cpu_alpha_load_fpcr(env));
4c9649a9 507 }
90c84c56 508 qemu_fprintf(f, "\n");
4c9649a9 509}
b9f0923e 510
b9f0923e
RH
511/* This should only be called from translate, via gen_excp.
512 We expect that ENV->PC has already been updated. */
8905770b 513G_NORETURN void helper_excp(CPUAlphaState *env, int excp, int error)
b9f0923e 514{
1c7ad260 515 CPUState *cs = env_cpu(env);
27103424
AF
516
517 cs->exception_index = excp;
b9f0923e 518 env->error_code = error;
5638d180 519 cpu_loop_exit(cs);
b9f0923e
RH
520}
521
522/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
8905770b
MAL
523G_NORETURN void dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
524 int excp, int error)
b9f0923e 525{
1c7ad260 526 CPUState *cs = env_cpu(env);
27103424
AF
527
528 cs->exception_index = excp;
b9f0923e 529 env->error_code = error;
a8a826a3 530 if (retaddr) {
3d419a4d 531 cpu_restore_state(cs, retaddr);
ba9c5de5
RH
532 /* Floating-point exceptions (our only users) point to the next PC. */
533 env->pc += 4;
a8a826a3 534 }
5638d180 535 cpu_loop_exit(cs);
b9f0923e
RH
536}
537
8905770b
MAL
538G_NORETURN void arith_excp(CPUAlphaState *env, uintptr_t retaddr,
539 int exc, uint64_t mask)
b9f0923e
RH
540{
541 env->trap_arg0 = exc;
542 env->trap_arg1 = mask;
543 dynamic_excp(env, retaddr, EXCP_ARITH, 0);
544}