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