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