Remove unneeded kvm.h from cpu-exec.c
[qemu/stefanha.git] / target-alpha / helper.c
blob32c2cf9db346dd96683356989c22c3b74b959c14
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 <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
24 #include "cpu.h"
25 #include "exec-all.h"
26 #include "softfloat.h"
28 uint64_t cpu_alpha_load_fpcr (CPUState *env)
30 uint64_t r = 0;
31 uint8_t t;
33 t = env->fpcr_exc_status;
34 if (t) {
35 r = FPCR_SUM;
36 if (t & float_flag_invalid) {
37 r |= FPCR_INV;
39 if (t & float_flag_divbyzero) {
40 r |= FPCR_DZE;
42 if (t & float_flag_overflow) {
43 r |= FPCR_OVF;
45 if (t & float_flag_underflow) {
46 r |= FPCR_UNF;
48 if (t & float_flag_inexact) {
49 r |= FPCR_INE;
53 t = env->fpcr_exc_mask;
54 if (t & float_flag_invalid) {
55 r |= FPCR_INVD;
57 if (t & float_flag_divbyzero) {
58 r |= FPCR_DZED;
60 if (t & float_flag_overflow) {
61 r |= FPCR_OVFD;
63 if (t & float_flag_underflow) {
64 r |= FPCR_UNFD;
66 if (t & float_flag_inexact) {
67 r |= FPCR_INED;
70 switch (env->fpcr_dyn_round) {
71 case float_round_nearest_even:
72 r |= FPCR_DYN_NORMAL;
73 break;
74 case float_round_down:
75 r |= FPCR_DYN_MINUS;
76 break;
77 case float_round_up:
78 r |= FPCR_DYN_PLUS;
79 break;
80 case float_round_to_zero:
81 r |= FPCR_DYN_CHOPPED;
82 break;
85 if (env->fpcr_dnz) {
86 r |= FPCR_DNZ;
88 if (env->fpcr_dnod) {
89 r |= FPCR_DNOD;
91 if (env->fpcr_undz) {
92 r |= FPCR_UNDZ;
95 return r;
98 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
100 uint8_t t;
102 t = 0;
103 if (val & FPCR_INV) {
104 t |= float_flag_invalid;
106 if (val & FPCR_DZE) {
107 t |= float_flag_divbyzero;
109 if (val & FPCR_OVF) {
110 t |= float_flag_overflow;
112 if (val & FPCR_UNF) {
113 t |= float_flag_underflow;
115 if (val & FPCR_INE) {
116 t |= float_flag_inexact;
118 env->fpcr_exc_status = t;
120 t = 0;
121 if (val & FPCR_INVD) {
122 t |= float_flag_invalid;
124 if (val & FPCR_DZED) {
125 t |= float_flag_divbyzero;
127 if (val & FPCR_OVFD) {
128 t |= float_flag_overflow;
130 if (val & FPCR_UNFD) {
131 t |= float_flag_underflow;
133 if (val & FPCR_INED) {
134 t |= float_flag_inexact;
136 env->fpcr_exc_mask = t;
138 switch (val & FPCR_DYN_MASK) {
139 case FPCR_DYN_CHOPPED:
140 t = float_round_to_zero;
141 break;
142 case FPCR_DYN_MINUS:
143 t = float_round_down;
144 break;
145 case FPCR_DYN_NORMAL:
146 t = float_round_nearest_even;
147 break;
148 case FPCR_DYN_PLUS:
149 t = float_round_up;
150 break;
152 env->fpcr_dyn_round = t;
154 env->fpcr_flush_to_zero
155 = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
157 env->fpcr_dnz = (val & FPCR_DNZ) != 0;
158 env->fpcr_dnod = (val & FPCR_DNOD) != 0;
159 env->fpcr_undz = (val & FPCR_UNDZ) != 0;
162 #if defined(CONFIG_USER_ONLY)
163 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
164 int mmu_idx, int is_softmmu)
166 env->exception_index = EXCP_MMFAULT;
167 env->trap_arg0 = address;
168 return 1;
170 #else
171 void swap_shadow_regs(CPUState *env)
173 uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
175 i0 = env->ir[8];
176 i1 = env->ir[9];
177 i2 = env->ir[10];
178 i3 = env->ir[11];
179 i4 = env->ir[12];
180 i5 = env->ir[13];
181 i6 = env->ir[14];
182 i7 = env->ir[25];
184 env->ir[8] = env->shadow[0];
185 env->ir[9] = env->shadow[1];
186 env->ir[10] = env->shadow[2];
187 env->ir[11] = env->shadow[3];
188 env->ir[12] = env->shadow[4];
189 env->ir[13] = env->shadow[5];
190 env->ir[14] = env->shadow[6];
191 env->ir[25] = env->shadow[7];
193 env->shadow[0] = i0;
194 env->shadow[1] = i1;
195 env->shadow[2] = i2;
196 env->shadow[3] = i3;
197 env->shadow[4] = i4;
198 env->shadow[5] = i5;
199 env->shadow[6] = i6;
200 env->shadow[7] = i7;
203 /* Returns the OSF/1 entMM failure indication, or -1 on success. */
204 static int get_physical_address(CPUState *env, target_ulong addr,
205 int prot_need, int mmu_idx,
206 target_ulong *pphys, int *pprot)
208 target_long saddr = addr;
209 target_ulong phys = 0;
210 target_ulong L1pte, L2pte, L3pte;
211 target_ulong pt, index;
212 int prot = 0;
213 int ret = MM_K_ACV;
215 /* Ensure that the virtual address is properly sign-extended from
216 the last implemented virtual address bit. */
217 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
218 goto exit;
221 /* Translate the superpage. */
222 /* ??? When we do more than emulate Unix PALcode, we'll need to
223 determine which KSEG is actually active. */
224 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
225 /* User-space cannot access KSEG addresses. */
226 if (mmu_idx != MMU_KERNEL_IDX) {
227 goto exit;
230 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
231 We would not do this if the 48-bit KSEG is enabled. */
232 phys = saddr & ((1ull << 40) - 1);
233 phys |= (saddr & (1ull << 40)) << 3;
235 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
236 ret = -1;
237 goto exit;
240 /* Interpret the page table exactly like PALcode does. */
242 pt = env->ptbr;
244 /* L1 page table read. */
245 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
246 L1pte = ldq_phys(pt + index*8);
248 if (unlikely((L1pte & PTE_VALID) == 0)) {
249 ret = MM_K_TNV;
250 goto exit;
252 if (unlikely((L1pte & PTE_KRE) == 0)) {
253 goto exit;
255 pt = L1pte >> 32 << TARGET_PAGE_BITS;
257 /* L2 page table read. */
258 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
259 L2pte = ldq_phys(pt + index*8);
261 if (unlikely((L2pte & PTE_VALID) == 0)) {
262 ret = MM_K_TNV;
263 goto exit;
265 if (unlikely((L2pte & PTE_KRE) == 0)) {
266 goto exit;
268 pt = L2pte >> 32 << TARGET_PAGE_BITS;
270 /* L3 page table read. */
271 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
272 L3pte = ldq_phys(pt + index*8);
274 phys = L3pte >> 32 << TARGET_PAGE_BITS;
275 if (unlikely((L3pte & PTE_VALID) == 0)) {
276 ret = MM_K_TNV;
277 goto exit;
280 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
281 # error page bits out of date
282 #endif
284 /* Check access violations. */
285 if (L3pte & (PTE_KRE << mmu_idx)) {
286 prot |= PAGE_READ | PAGE_EXEC;
288 if (L3pte & (PTE_KWE << mmu_idx)) {
289 prot |= PAGE_WRITE;
291 if (unlikely((prot & prot_need) == 0 && prot_need)) {
292 goto exit;
295 /* Check fault-on-operation violations. */
296 prot &= ~(L3pte >> 1);
297 ret = -1;
298 if (unlikely((prot & prot_need) == 0)) {
299 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
300 prot_need & PAGE_WRITE ? MM_K_FOW :
301 prot_need & PAGE_READ ? MM_K_FOR : -1);
304 exit:
305 *pphys = phys;
306 *pprot = prot;
307 return ret;
310 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
312 target_ulong phys;
313 int prot, fail;
315 fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
316 return (fail >= 0 ? -1 : phys);
319 int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
320 int mmu_idx, int is_softmmu)
322 target_ulong phys;
323 int prot, fail;
325 fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
326 if (unlikely(fail >= 0)) {
327 env->exception_index = EXCP_MMFAULT;
328 env->trap_arg0 = addr;
329 env->trap_arg1 = fail;
330 env->trap_arg2 = (rw == 2 ? -1 : rw);
331 return 1;
334 tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
335 prot, mmu_idx, TARGET_PAGE_SIZE);
336 return 0;
338 #endif /* USER_ONLY */
340 void do_interrupt (CPUState *env)
342 int i = env->exception_index;
344 if (qemu_loglevel_mask(CPU_LOG_INT)) {
345 static int count;
346 const char *name = "<unknown>";
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 case EXCP_STL_C:
383 name = "stl_c";
384 break;
385 case EXCP_STQ_C:
386 name = "stq_c";
387 break;
389 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
390 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
393 env->exception_index = -1;
395 #if !defined(CONFIG_USER_ONLY)
396 switch (i) {
397 case EXCP_RESET:
398 i = 0x0000;
399 break;
400 case EXCP_MCHK:
401 i = 0x0080;
402 break;
403 case EXCP_SMP_INTERRUPT:
404 i = 0x0100;
405 break;
406 case EXCP_CLK_INTERRUPT:
407 i = 0x0180;
408 break;
409 case EXCP_DEV_INTERRUPT:
410 i = 0x0200;
411 break;
412 case EXCP_MMFAULT:
413 i = 0x0280;
414 break;
415 case EXCP_UNALIGN:
416 i = 0x0300;
417 break;
418 case EXCP_OPCDEC:
419 i = 0x0380;
420 break;
421 case EXCP_ARITH:
422 i = 0x0400;
423 break;
424 case EXCP_FEN:
425 i = 0x0480;
426 break;
427 case EXCP_CALL_PAL:
428 i = env->error_code;
429 /* There are 64 entry points for both privileged and unprivileged,
430 with bit 0x80 indicating unprivileged. Each entry point gets
431 64 bytes to do its job. */
432 if (i & 0x80) {
433 i = 0x2000 + (i - 0x80) * 64;
434 } else {
435 i = 0x1000 + i * 64;
437 break;
438 default:
439 cpu_abort(env, "Unhandled CPU exception");
442 /* Remember where the exception happened. Emulate real hardware in
443 that the low bit of the PC indicates PALmode. */
444 env->exc_addr = env->pc | env->pal_mode;
446 /* Continue execution at the PALcode entry point. */
447 env->pc = env->palbr + i;
449 /* Switch to PALmode. */
450 if (!env->pal_mode) {
451 env->pal_mode = 1;
452 swap_shadow_regs(env);
454 #endif /* !USER_ONLY */
457 void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
458 int flags)
460 static const char *linux_reg_names[] = {
461 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
462 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
463 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
464 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
466 int i;
468 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
469 env->pc, env->ps);
470 for (i = 0; i < 31; i++) {
471 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
472 linux_reg_names[i], env->ir[i]);
473 if ((i % 3) == 2)
474 cpu_fprintf(f, "\n");
477 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
478 env->lock_addr, env->lock_value);
480 for (i = 0; i < 31; i++) {
481 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
482 *((uint64_t *)(&env->fir[i])));
483 if ((i % 3) == 2)
484 cpu_fprintf(f, "\n");
486 cpu_fprintf(f, "\n");