nbd: avoid unaligned uint64_t store
[qemu/ar7.git] / target-alpha / helper.c
blob6dec2639b141490340b2ca1f4ef0d90feb8f7345
1 /*
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"
22 #include "cpu.h"
23 #include "fpu/softfloat.h"
24 #include "exec/helper-proto.h"
27 #define CONVERT_BIT(X, SRC, DST) \
28 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
30 uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
32 return (uint64_t)env->fpcr << 32;
35 void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
37 uint32_t fpcr = val >> 32;
38 uint32_t t = 0;
40 t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
41 t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
42 t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
43 t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
44 t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
46 env->fpcr = fpcr;
47 env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
49 switch (fpcr & FPCR_DYN_MASK) {
50 case FPCR_DYN_NORMAL:
51 default:
52 t = float_round_nearest_even;
53 break;
54 case FPCR_DYN_CHOPPED:
55 t = float_round_to_zero;
56 break;
57 case FPCR_DYN_MINUS:
58 t = float_round_down;
59 break;
60 case FPCR_DYN_PLUS:
61 t = float_round_up;
62 break;
64 env->fpcr_dyn_round = t;
66 env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
67 env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
70 uint64_t helper_load_fpcr(CPUAlphaState *env)
72 return cpu_alpha_load_fpcr(env);
75 void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
77 cpu_alpha_store_fpcr(env, val);
80 static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg)
82 #ifndef CONFIG_USER_ONLY
83 if (env->pal_mode) {
84 if (reg >= 8 && reg <= 14) {
85 return &env->shadow[reg - 8];
86 } else if (reg == 25) {
87 return &env->shadow[7];
90 #endif
91 return &env->ir[reg];
94 uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg)
96 return *cpu_alpha_addr_gr(env, reg);
99 void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
101 *cpu_alpha_addr_gr(env, reg) = val;
104 #if defined(CONFIG_USER_ONLY)
105 int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
106 int rw, int mmu_idx)
108 AlphaCPU *cpu = ALPHA_CPU(cs);
110 cs->exception_index = EXCP_MMFAULT;
111 cpu->env.trap_arg0 = address;
112 return 1;
114 #else
115 /* Returns the OSF/1 entMM failure indication, or -1 on success. */
116 static int get_physical_address(CPUAlphaState *env, target_ulong addr,
117 int prot_need, int mmu_idx,
118 target_ulong *pphys, int *pprot)
120 CPUState *cs = CPU(alpha_env_get_cpu(env));
121 target_long saddr = addr;
122 target_ulong phys = 0;
123 target_ulong L1pte, L2pte, L3pte;
124 target_ulong pt, index;
125 int prot = 0;
126 int ret = MM_K_ACV;
128 /* Ensure that the virtual address is properly sign-extended from
129 the last implemented virtual address bit. */
130 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
131 goto exit;
134 /* Translate the superpage. */
135 /* ??? When we do more than emulate Unix PALcode, we'll need to
136 determine which KSEG is actually active. */
137 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
138 /* User-space cannot access KSEG addresses. */
139 if (mmu_idx != MMU_KERNEL_IDX) {
140 goto exit;
143 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
144 We would not do this if the 48-bit KSEG is enabled. */
145 phys = saddr & ((1ull << 40) - 1);
146 phys |= (saddr & (1ull << 40)) << 3;
148 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
149 ret = -1;
150 goto exit;
153 /* Interpret the page table exactly like PALcode does. */
155 pt = env->ptbr;
157 /* L1 page table read. */
158 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
159 L1pte = ldq_phys(cs->as, pt + index*8);
161 if (unlikely((L1pte & PTE_VALID) == 0)) {
162 ret = MM_K_TNV;
163 goto exit;
165 if (unlikely((L1pte & PTE_KRE) == 0)) {
166 goto exit;
168 pt = L1pte >> 32 << TARGET_PAGE_BITS;
170 /* L2 page table read. */
171 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
172 L2pte = ldq_phys(cs->as, pt + index*8);
174 if (unlikely((L2pte & PTE_VALID) == 0)) {
175 ret = MM_K_TNV;
176 goto exit;
178 if (unlikely((L2pte & PTE_KRE) == 0)) {
179 goto exit;
181 pt = L2pte >> 32 << TARGET_PAGE_BITS;
183 /* L3 page table read. */
184 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
185 L3pte = ldq_phys(cs->as, pt + index*8);
187 phys = L3pte >> 32 << TARGET_PAGE_BITS;
188 if (unlikely((L3pte & PTE_VALID) == 0)) {
189 ret = MM_K_TNV;
190 goto exit;
193 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
194 # error page bits out of date
195 #endif
197 /* Check access violations. */
198 if (L3pte & (PTE_KRE << mmu_idx)) {
199 prot |= PAGE_READ | PAGE_EXEC;
201 if (L3pte & (PTE_KWE << mmu_idx)) {
202 prot |= PAGE_WRITE;
204 if (unlikely((prot & prot_need) == 0 && prot_need)) {
205 goto exit;
208 /* Check fault-on-operation violations. */
209 prot &= ~(L3pte >> 1);
210 ret = -1;
211 if (unlikely((prot & prot_need) == 0)) {
212 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
213 prot_need & PAGE_WRITE ? MM_K_FOW :
214 prot_need & PAGE_READ ? MM_K_FOR : -1);
217 exit:
218 *pphys = phys;
219 *pprot = prot;
220 return ret;
223 hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
225 AlphaCPU *cpu = ALPHA_CPU(cs);
226 target_ulong phys;
227 int prot, fail;
229 fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot);
230 return (fail >= 0 ? -1 : phys);
233 int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, int rw,
234 int mmu_idx)
236 AlphaCPU *cpu = ALPHA_CPU(cs);
237 CPUAlphaState *env = &cpu->env;
238 target_ulong phys;
239 int prot, fail;
241 fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
242 if (unlikely(fail >= 0)) {
243 cs->exception_index = EXCP_MMFAULT;
244 env->trap_arg0 = addr;
245 env->trap_arg1 = fail;
246 env->trap_arg2 = (rw == 2 ? -1 : rw);
247 return 1;
250 tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
251 prot, mmu_idx, TARGET_PAGE_SIZE);
252 return 0;
254 #endif /* USER_ONLY */
256 void alpha_cpu_do_interrupt(CPUState *cs)
258 AlphaCPU *cpu = ALPHA_CPU(cs);
259 CPUAlphaState *env = &cpu->env;
260 int i = cs->exception_index;
262 if (qemu_loglevel_mask(CPU_LOG_INT)) {
263 static int count;
264 const char *name = "<unknown>";
266 switch (i) {
267 case EXCP_RESET:
268 name = "reset";
269 break;
270 case EXCP_MCHK:
271 name = "mchk";
272 break;
273 case EXCP_SMP_INTERRUPT:
274 name = "smp_interrupt";
275 break;
276 case EXCP_CLK_INTERRUPT:
277 name = "clk_interrupt";
278 break;
279 case EXCP_DEV_INTERRUPT:
280 name = "dev_interrupt";
281 break;
282 case EXCP_MMFAULT:
283 name = "mmfault";
284 break;
285 case EXCP_UNALIGN:
286 name = "unalign";
287 break;
288 case EXCP_OPCDEC:
289 name = "opcdec";
290 break;
291 case EXCP_ARITH:
292 name = "arith";
293 break;
294 case EXCP_FEN:
295 name = "fen";
296 break;
297 case EXCP_CALL_PAL:
298 name = "call_pal";
299 break;
300 case EXCP_STL_C:
301 name = "stl_c";
302 break;
303 case EXCP_STQ_C:
304 name = "stq_c";
305 break;
307 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
308 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
311 cs->exception_index = -1;
313 #if !defined(CONFIG_USER_ONLY)
314 switch (i) {
315 case EXCP_RESET:
316 i = 0x0000;
317 break;
318 case EXCP_MCHK:
319 i = 0x0080;
320 break;
321 case EXCP_SMP_INTERRUPT:
322 i = 0x0100;
323 break;
324 case EXCP_CLK_INTERRUPT:
325 i = 0x0180;
326 break;
327 case EXCP_DEV_INTERRUPT:
328 i = 0x0200;
329 break;
330 case EXCP_MMFAULT:
331 i = 0x0280;
332 break;
333 case EXCP_UNALIGN:
334 i = 0x0300;
335 break;
336 case EXCP_OPCDEC:
337 i = 0x0380;
338 break;
339 case EXCP_ARITH:
340 i = 0x0400;
341 break;
342 case EXCP_FEN:
343 i = 0x0480;
344 break;
345 case EXCP_CALL_PAL:
346 i = env->error_code;
347 /* There are 64 entry points for both privileged and unprivileged,
348 with bit 0x80 indicating unprivileged. Each entry point gets
349 64 bytes to do its job. */
350 if (i & 0x80) {
351 i = 0x2000 + (i - 0x80) * 64;
352 } else {
353 i = 0x1000 + i * 64;
355 break;
356 default:
357 cpu_abort(cs, "Unhandled CPU exception");
360 /* Remember where the exception happened. Emulate real hardware in
361 that the low bit of the PC indicates PALmode. */
362 env->exc_addr = env->pc | env->pal_mode;
364 /* Continue execution at the PALcode entry point. */
365 env->pc = env->palbr + i;
367 /* Switch to PALmode. */
368 env->pal_mode = 1;
369 #endif /* !USER_ONLY */
372 bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
374 AlphaCPU *cpu = ALPHA_CPU(cs);
375 CPUAlphaState *env = &cpu->env;
376 int idx = -1;
378 /* We never take interrupts while in PALmode. */
379 if (env->pal_mode) {
380 return false;
383 /* Fall through the switch, collecting the highest priority
384 interrupt that isn't masked by the processor status IPL. */
385 /* ??? This hard-codes the OSF/1 interrupt levels. */
386 switch (env->ps & PS_INT_MASK) {
387 case 0 ... 3:
388 if (interrupt_request & CPU_INTERRUPT_HARD) {
389 idx = EXCP_DEV_INTERRUPT;
391 /* FALLTHRU */
392 case 4:
393 if (interrupt_request & CPU_INTERRUPT_TIMER) {
394 idx = EXCP_CLK_INTERRUPT;
396 /* FALLTHRU */
397 case 5:
398 if (interrupt_request & CPU_INTERRUPT_SMP) {
399 idx = EXCP_SMP_INTERRUPT;
401 /* FALLTHRU */
402 case 6:
403 if (interrupt_request & CPU_INTERRUPT_MCHK) {
404 idx = EXCP_MCHK;
407 if (idx >= 0) {
408 cs->exception_index = idx;
409 env->error_code = 0;
410 alpha_cpu_do_interrupt(cs);
411 return true;
413 return false;
416 void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
417 int flags)
419 static const char *linux_reg_names[] = {
420 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
421 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
422 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
423 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
425 AlphaCPU *cpu = ALPHA_CPU(cs);
426 CPUAlphaState *env = &cpu->env;
427 int i;
429 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
430 env->pc, env->ps);
431 for (i = 0; i < 31; i++) {
432 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
433 linux_reg_names[i], cpu_alpha_load_gr(env, i));
434 if ((i % 3) == 2)
435 cpu_fprintf(f, "\n");
438 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
439 env->lock_addr, env->lock_value);
441 for (i = 0; i < 31; i++) {
442 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
443 *((uint64_t *)(&env->fir[i])));
444 if ((i % 3) == 2)
445 cpu_fprintf(f, "\n");
447 cpu_fprintf(f, "\n");
450 /* This should only be called from translate, via gen_excp.
451 We expect that ENV->PC has already been updated. */
452 void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
454 AlphaCPU *cpu = alpha_env_get_cpu(env);
455 CPUState *cs = CPU(cpu);
457 cs->exception_index = excp;
458 env->error_code = error;
459 cpu_loop_exit(cs);
462 /* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
463 void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
464 int excp, int error)
466 AlphaCPU *cpu = alpha_env_get_cpu(env);
467 CPUState *cs = CPU(cpu);
469 cs->exception_index = excp;
470 env->error_code = error;
471 if (retaddr) {
472 cpu_restore_state(cs, retaddr);
473 /* Floating-point exceptions (our only users) point to the next PC. */
474 env->pc += 4;
476 cpu_loop_exit(cs);
479 void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
480 int exc, uint64_t mask)
482 env->trap_arg0 = exc;
483 env->trap_arg1 = mask;
484 dynamic_excp(env, retaddr, EXCP_ARITH, 0);