]> git.proxmox.com Git - mirror_qemu.git/blob - target-alpha/helper.c
Merge remote-tracking branch 'qemu-kvm/uq/master' into staging
[mirror_qemu.git] / 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 "exec-all.h"
26 #include "softfloat.h"
27
28 uint64_t cpu_alpha_load_fpcr (CPUState *env)
29 {
30 uint64_t r = 0;
31 uint8_t t;
32
33 t = env->fpcr_exc_status;
34 if (t) {
35 r = FPCR_SUM;
36 if (t & float_flag_invalid) {
37 r |= FPCR_INV;
38 }
39 if (t & float_flag_divbyzero) {
40 r |= FPCR_DZE;
41 }
42 if (t & float_flag_overflow) {
43 r |= FPCR_OVF;
44 }
45 if (t & float_flag_underflow) {
46 r |= FPCR_UNF;
47 }
48 if (t & float_flag_inexact) {
49 r |= FPCR_INE;
50 }
51 }
52
53 t = env->fpcr_exc_mask;
54 if (t & float_flag_invalid) {
55 r |= FPCR_INVD;
56 }
57 if (t & float_flag_divbyzero) {
58 r |= FPCR_DZED;
59 }
60 if (t & float_flag_overflow) {
61 r |= FPCR_OVFD;
62 }
63 if (t & float_flag_underflow) {
64 r |= FPCR_UNFD;
65 }
66 if (t & float_flag_inexact) {
67 r |= FPCR_INED;
68 }
69
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;
83 }
84
85 if (env->fpcr_dnz) {
86 r |= FPCR_DNZ;
87 }
88 if (env->fpcr_dnod) {
89 r |= FPCR_DNOD;
90 }
91 if (env->fpcr_undz) {
92 r |= FPCR_UNDZ;
93 }
94
95 return r;
96 }
97
98 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
99 {
100 uint8_t t;
101
102 t = 0;
103 if (val & FPCR_INV) {
104 t |= float_flag_invalid;
105 }
106 if (val & FPCR_DZE) {
107 t |= float_flag_divbyzero;
108 }
109 if (val & FPCR_OVF) {
110 t |= float_flag_overflow;
111 }
112 if (val & FPCR_UNF) {
113 t |= float_flag_underflow;
114 }
115 if (val & FPCR_INE) {
116 t |= float_flag_inexact;
117 }
118 env->fpcr_exc_status = t;
119
120 t = 0;
121 if (val & FPCR_INVD) {
122 t |= float_flag_invalid;
123 }
124 if (val & FPCR_DZED) {
125 t |= float_flag_divbyzero;
126 }
127 if (val & FPCR_OVFD) {
128 t |= float_flag_overflow;
129 }
130 if (val & FPCR_UNFD) {
131 t |= float_flag_underflow;
132 }
133 if (val & FPCR_INED) {
134 t |= float_flag_inexact;
135 }
136 env->fpcr_exc_mask = t;
137
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;
151 }
152 env->fpcr_dyn_round = t;
153
154 env->fpcr_flush_to_zero
155 = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
156
157 env->fpcr_dnz = (val & FPCR_DNZ) != 0;
158 env->fpcr_dnod = (val & FPCR_DNOD) != 0;
159 env->fpcr_undz = (val & FPCR_UNDZ) != 0;
160 }
161
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)
165 {
166 env->exception_index = EXCP_MMFAULT;
167 env->trap_arg0 = address;
168 return 1;
169 }
170 #else
171 void swap_shadow_regs(CPUState *env)
172 {
173 uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
174
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];
183
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];
192
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;
201 }
202
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)
207 {
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;
214
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;
219 }
220
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;
228 }
229
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;
234
235 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
236 ret = -1;
237 goto exit;
238 }
239
240 /* Interpret the page table exactly like PALcode does. */
241
242 pt = env->ptbr;
243
244 /* L1 page table read. */
245 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
246 L1pte = ldq_phys(pt + index*8);
247
248 if (unlikely((L1pte & PTE_VALID) == 0)) {
249 ret = MM_K_TNV;
250 goto exit;
251 }
252 if (unlikely((L1pte & PTE_KRE) == 0)) {
253 goto exit;
254 }
255 pt = L1pte >> 32 << TARGET_PAGE_BITS;
256
257 /* L2 page table read. */
258 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
259 L2pte = ldq_phys(pt + index*8);
260
261 if (unlikely((L2pte & PTE_VALID) == 0)) {
262 ret = MM_K_TNV;
263 goto exit;
264 }
265 if (unlikely((L2pte & PTE_KRE) == 0)) {
266 goto exit;
267 }
268 pt = L2pte >> 32 << TARGET_PAGE_BITS;
269
270 /* L3 page table read. */
271 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
272 L3pte = ldq_phys(pt + index*8);
273
274 phys = L3pte >> 32 << TARGET_PAGE_BITS;
275 if (unlikely((L3pte & PTE_VALID) == 0)) {
276 ret = MM_K_TNV;
277 goto exit;
278 }
279
280 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
281 # error page bits out of date
282 #endif
283
284 /* Check access violations. */
285 if (L3pte & (PTE_KRE << mmu_idx)) {
286 prot |= PAGE_READ | PAGE_EXEC;
287 }
288 if (L3pte & (PTE_KWE << mmu_idx)) {
289 prot |= PAGE_WRITE;
290 }
291 if (unlikely((prot & prot_need) == 0 && prot_need)) {
292 goto exit;
293 }
294
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);
302 }
303
304 exit:
305 *pphys = phys;
306 *pprot = prot;
307 return ret;
308 }
309
310 target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
311 {
312 target_ulong phys;
313 int prot, fail;
314
315 fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
316 return (fail >= 0 ? -1 : phys);
317 }
318
319 int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
320 int mmu_idx, int is_softmmu)
321 {
322 target_ulong phys;
323 int prot, fail;
324
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;
332 }
333
334 tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
335 prot, mmu_idx, TARGET_PAGE_SIZE);
336 return 0;
337 }
338 #endif /* USER_ONLY */
339
340 void do_interrupt (CPUState *env)
341 {
342 int i = env->exception_index;
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 case EXCP_STL_C:
383 name = "stl_c";
384 break;
385 case EXCP_STQ_C:
386 name = "stq_c";
387 break;
388 }
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]);
391 }
392
393 env->exception_index = -1;
394
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;
436 }
437 break;
438 default:
439 cpu_abort(env, "Unhandled CPU exception");
440 }
441
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;
445
446 /* Continue execution at the PALcode entry point. */
447 env->pc = env->palbr + i;
448
449 /* Switch to PALmode. */
450 if (!env->pal_mode) {
451 env->pal_mode = 1;
452 swap_shadow_regs(env);
453 }
454 #endif /* !USER_ONLY */
455 }
456
457 void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
458 int flags)
459 {
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",
465 };
466 int i;
467
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");
475 }
476
477 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
478 env->lock_addr, env->lock_value);
479
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");
485 }
486 cpu_fprintf(f, "\n");
487 }