2 * Alpha emulation cpu helpers for qemu.
4 * Copyright (c) 2007 Jocelyn Mayer
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.
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.
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/>.
20 #include "qemu/osdep.h"
23 #include "exec/exec-all.h"
24 #include "fpu/softfloat.h"
25 #include "exec/helper-proto.h"
26 #include "qemu/qemu-print.h"
29 #define CONVERT_BIT(X, SRC, DST) \
30 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
32 uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
34 return (uint64_t)env->fpcr << 32;
37 void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
39 uint32_t fpcr = val >> 32;
42 t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
43 t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
44 t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
45 t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
46 t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
49 env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
51 switch (fpcr & FPCR_DYN_MASK) {
54 t = float_round_nearest_even;
56 case FPCR_DYN_CHOPPED:
57 t = float_round_to_zero;
66 env->fpcr_dyn_round = t;
68 env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
69 env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
72 uint64_t helper_load_fpcr(CPUAlphaState *env)
74 return cpu_alpha_load_fpcr(env);
77 void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
79 cpu_alpha_store_fpcr(env, val);
82 static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg)
84 #ifndef CONFIG_USER_ONLY
85 if (env->flags & ENV_FLAG_PAL_MODE) {
86 if (reg >= 8 && reg <= 14) {
87 return &env->shadow[reg - 8];
88 } else if (reg == 25) {
89 return &env->shadow[7];
96 uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg)
98 return *cpu_alpha_addr_gr(env, reg);
101 void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
103 *cpu_alpha_addr_gr(env, reg) = val;
106 #if defined(CONFIG_USER_ONLY)
107 bool alpha_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
108 MMUAccessType access_type, int mmu_idx,
109 bool probe, uintptr_t retaddr)
111 AlphaCPU *cpu = ALPHA_CPU(cs);
113 cs->exception_index = EXCP_MMFAULT;
114 cpu->env.trap_arg0 = address;
115 cpu_loop_exit_restore(cs, retaddr);
118 /* Returns the OSF/1 entMM failure indication, or -1 on success. */
119 static int get_physical_address(CPUAlphaState *env, target_ulong addr,
120 int prot_need, int mmu_idx,
121 target_ulong *pphys, int *pprot)
123 CPUState *cs = CPU(alpha_env_get_cpu(env));
124 target_long saddr = addr;
125 target_ulong phys = 0;
126 target_ulong L1pte, L2pte, L3pte;
127 target_ulong pt, index;
131 /* Handle physical accesses. */
132 if (mmu_idx == MMU_PHYS_IDX) {
134 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
139 /* Ensure that the virtual address is properly sign-extended from
140 the last implemented virtual address bit. */
141 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
145 /* Translate the superpage. */
146 /* ??? When we do more than emulate Unix PALcode, we'll need to
147 determine which KSEG is actually active. */
148 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
149 /* User-space cannot access KSEG addresses. */
150 if (mmu_idx != MMU_KERNEL_IDX) {
154 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
155 We would not do this if the 48-bit KSEG is enabled. */
156 phys = saddr & ((1ull << 40) - 1);
157 phys |= (saddr & (1ull << 40)) << 3;
159 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
164 /* Interpret the page table exactly like PALcode does. */
168 /* TODO: rather than using ldq_phys() to read the page table we should
169 * use address_space_ldq() so that we can handle the case when
170 * the page table read gives a bus fault, rather than ignoring it.
171 * For the existing code the zero data that ldq_phys will return for
172 * an access to invalid memory will result in our treating the page
173 * table as invalid, which may even be the right behaviour.
176 /* L1 page table read. */
177 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
178 L1pte = ldq_phys(cs->as, pt + index*8);
180 if (unlikely((L1pte & PTE_VALID) == 0)) {
184 if (unlikely((L1pte & PTE_KRE) == 0)) {
187 pt = L1pte >> 32 << TARGET_PAGE_BITS;
189 /* L2 page table read. */
190 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
191 L2pte = ldq_phys(cs->as, pt + index*8);
193 if (unlikely((L2pte & PTE_VALID) == 0)) {
197 if (unlikely((L2pte & PTE_KRE) == 0)) {
200 pt = L2pte >> 32 << TARGET_PAGE_BITS;
202 /* L3 page table read. */
203 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
204 L3pte = ldq_phys(cs->as, pt + index*8);
206 phys = L3pte >> 32 << TARGET_PAGE_BITS;
207 if (unlikely((L3pte & PTE_VALID) == 0)) {
212 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
213 # error page bits out of date
216 /* Check access violations. */
217 if (L3pte & (PTE_KRE << mmu_idx)) {
218 prot |= PAGE_READ | PAGE_EXEC;
220 if (L3pte & (PTE_KWE << mmu_idx)) {
223 if (unlikely((prot & prot_need) == 0 && prot_need)) {
227 /* Check fault-on-operation violations. */
228 prot &= ~(L3pte >> 1);
230 if (unlikely((prot & prot_need) == 0)) {
231 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
232 prot_need & PAGE_WRITE ? MM_K_FOW :
233 prot_need & PAGE_READ ? MM_K_FOR : -1);
242 hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
244 AlphaCPU *cpu = ALPHA_CPU(cs);
248 fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot);
249 return (fail >= 0 ? -1 : phys);
252 bool alpha_cpu_tlb_fill(CPUState *cs, vaddr addr, int size,
253 MMUAccessType access_type, int mmu_idx,
254 bool probe, uintptr_t retaddr)
256 AlphaCPU *cpu = ALPHA_CPU(cs);
257 CPUAlphaState *env = &cpu->env;
261 fail = get_physical_address(env, addr, 1 << access_type,
262 mmu_idx, &phys, &prot);
263 if (unlikely(fail >= 0)) {
267 cs->exception_index = EXCP_MMFAULT;
268 env->trap_arg0 = addr;
269 env->trap_arg1 = fail;
270 env->trap_arg2 = (access_type == MMU_INST_FETCH ? -1 : access_type);
271 cpu_loop_exit_restore(cs, retaddr);
274 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
275 prot, mmu_idx, TARGET_PAGE_SIZE);
279 void tlb_fill(CPUState *cs, target_ulong addr, int size,
280 MMUAccessType access_type, int mmu_idx, uintptr_t retaddr)
282 alpha_cpu_tlb_fill(cs, addr, size, access_type, mmu_idx, false, retaddr);
284 #endif /* USER_ONLY */
286 void alpha_cpu_do_interrupt(CPUState *cs)
288 AlphaCPU *cpu = ALPHA_CPU(cs);
289 CPUAlphaState *env = &cpu->env;
290 int i = cs->exception_index;
292 if (qemu_loglevel_mask(CPU_LOG_INT)) {
294 const char *name = "<unknown>";
303 case EXCP_SMP_INTERRUPT:
304 name = "smp_interrupt";
306 case EXCP_CLK_INTERRUPT:
307 name = "clk_interrupt";
309 case EXCP_DEV_INTERRUPT:
310 name = "dev_interrupt";
331 qemu_log("INT %6d: %s(%#x) cpu=%d pc=%016"
332 PRIx64 " sp=%016" PRIx64 "\n",
333 ++count, name, env->error_code, cs->cpu_index,
334 env->pc, env->ir[IR_SP]);
337 cs->exception_index = -1;
339 #if !defined(CONFIG_USER_ONLY)
347 case EXCP_SMP_INTERRUPT:
350 case EXCP_CLK_INTERRUPT:
353 case EXCP_DEV_INTERRUPT:
373 /* There are 64 entry points for both privileged and unprivileged,
374 with bit 0x80 indicating unprivileged. Each entry point gets
375 64 bytes to do its job. */
377 i = 0x2000 + (i - 0x80) * 64;
383 cpu_abort(cs, "Unhandled CPU exception");
386 /* Remember where the exception happened. Emulate real hardware in
387 that the low bit of the PC indicates PALmode. */
388 env->exc_addr = env->pc | (env->flags & ENV_FLAG_PAL_MODE);
390 /* Continue execution at the PALcode entry point. */
391 env->pc = env->palbr + i;
393 /* Switch to PALmode. */
394 env->flags |= ENV_FLAG_PAL_MODE;
395 #endif /* !USER_ONLY */
398 bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
400 AlphaCPU *cpu = ALPHA_CPU(cs);
401 CPUAlphaState *env = &cpu->env;
404 /* We never take interrupts while in PALmode. */
405 if (env->flags & ENV_FLAG_PAL_MODE) {
409 /* Fall through the switch, collecting the highest priority
410 interrupt that isn't masked by the processor status IPL. */
411 /* ??? This hard-codes the OSF/1 interrupt levels. */
412 switch ((env->flags >> ENV_FLAG_PS_SHIFT) & PS_INT_MASK) {
414 if (interrupt_request & CPU_INTERRUPT_HARD) {
415 idx = EXCP_DEV_INTERRUPT;
419 if (interrupt_request & CPU_INTERRUPT_TIMER) {
420 idx = EXCP_CLK_INTERRUPT;
424 if (interrupt_request & CPU_INTERRUPT_SMP) {
425 idx = EXCP_SMP_INTERRUPT;
429 if (interrupt_request & CPU_INTERRUPT_MCHK) {
434 cs->exception_index = idx;
436 alpha_cpu_do_interrupt(cs);
442 void alpha_cpu_dump_state(CPUState *cs, FILE *f, int flags)
444 static const char *linux_reg_names[] = {
445 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
446 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
447 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
448 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
450 AlphaCPU *cpu = ALPHA_CPU(cs);
451 CPUAlphaState *env = &cpu->env;
454 qemu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
455 env->pc, extract32(env->flags, ENV_FLAG_PS_SHIFT, 8));
456 for (i = 0; i < 31; i++) {
457 qemu_fprintf(f, "IR%02d %s " TARGET_FMT_lx "%c", i,
458 linux_reg_names[i], cpu_alpha_load_gr(env, i),
459 (i % 3) == 2 ? '\n' : ' ');
462 qemu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
463 env->lock_addr, env->lock_value);
465 if (flags & CPU_DUMP_FPU) {
466 for (i = 0; i < 31; i++) {
467 qemu_fprintf(f, "FIR%02d %016" PRIx64 "%c", i, env->fir[i],
468 (i % 3) == 2 ? '\n' : ' ');
471 qemu_fprintf(f, "\n");
474 /* This should only be called from translate, via gen_excp.
475 We expect that ENV->PC has already been updated. */
476 void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
478 AlphaCPU *cpu = alpha_env_get_cpu(env);
479 CPUState *cs = CPU(cpu);
481 cs->exception_index = excp;
482 env->error_code = error;
486 /* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
487 void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
490 AlphaCPU *cpu = alpha_env_get_cpu(env);
491 CPUState *cs = CPU(cpu);
493 cs->exception_index = excp;
494 env->error_code = error;
496 cpu_restore_state(cs, retaddr, true);
497 /* Floating-point exceptions (our only users) point to the next PC. */
503 void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
504 int exc, uint64_t mask)
506 env->trap_arg0 = exc;
507 env->trap_arg1 = mask;
508 dynamic_excp(env, retaddr, EXCP_ARITH, 0);