]> git.proxmox.com Git - qemu.git/blame - target-alpha/helper.c
target-alpha: Implement cpu_alpha_handle_mmu_fault for system mode.
[qemu.git] / target-alpha / helper.c
CommitLineData
4c9649a9
JM
1/*
2 * Alpha emulation cpu helpers for qemu.
5fafdf24 3 *
4c9649a9
JM
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
8167ee88 17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
4c9649a9
JM
18 */
19
20#include <stdint.h>
21#include <stdlib.h>
22#include <stdio.h>
23
24#include "cpu.h"
25#include "exec-all.h"
ba0e276d
RH
26#include "softfloat.h"
27
28uint64_t cpu_alpha_load_fpcr (CPUState *env)
29{
8443effb
RH
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) {
ba0e276d 71 case float_round_nearest_even:
8443effb 72 r |= FPCR_DYN_NORMAL;
ba0e276d
RH
73 break;
74 case float_round_down:
8443effb 75 r |= FPCR_DYN_MINUS;
ba0e276d
RH
76 break;
77 case float_round_up:
8443effb 78 r |= FPCR_DYN_PLUS;
ba0e276d
RH
79 break;
80 case float_round_to_zero:
8443effb 81 r |= FPCR_DYN_CHOPPED;
ba0e276d
RH
82 break;
83 }
8443effb
RH
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;
ba0e276d
RH
96}
97
98void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
99{
8443effb
RH
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;
ba0e276d 141 break;
8443effb
RH
142 case FPCR_DYN_MINUS:
143 t = float_round_down;
ba0e276d 144 break;
8443effb
RH
145 case FPCR_DYN_NORMAL:
146 t = float_round_nearest_even;
ba0e276d 147 break;
8443effb
RH
148 case FPCR_DYN_PLUS:
149 t = float_round_up;
ba0e276d
RH
150 break;
151 }
8443effb
RH
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;
ba0e276d 160}
4c9649a9 161
5fafdf24 162#if defined(CONFIG_USER_ONLY)
4c9649a9 163int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
6ebbf390 164 int mmu_idx, int is_softmmu)
4c9649a9 165{
07b6c13b 166 env->exception_index = EXCP_MMFAULT;
129d8aa5 167 env->trap_arg0 = address;
4c9649a9
JM
168 return 1;
169}
4c9649a9 170#else
21d2beaa
RH
171void 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
a3b9af16
RH
203/* Returns the OSF/1 entMM failure indication, or -1 on success. */
204static int get_physical_address(CPUState *env, target_ulong addr,
205 int prot_need, int mmu_idx,
206 target_ulong *pphys, int *pprot)
4c9649a9 207{
a3b9af16
RH
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 superpage is actually active. */
224 if (saddr < 0 && (saddr >> (TARGET_VIRT_ADDR_SPACE_BITS - 2) & 3) == 2) {
225 /* User-space cannot access kseg addresses. */
226 if (mmu_idx != MMU_KERNEL_IDX) {
227 goto exit;
228 }
229
230 phys = saddr & ((1ull << 40) - 1);
231 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
232 ret = -1;
233 goto exit;
234 }
235
236 /* Interpret the page table exactly like PALcode does. */
237
238 pt = env->ptbr;
239
240 /* L1 page table read. */
241 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
242 L1pte = ldq_phys(pt + index*8);
243
244 if (unlikely((L1pte & PTE_VALID) == 0)) {
245 ret = MM_K_TNV;
246 goto exit;
247 }
248 if (unlikely((L1pte & PTE_KRE) == 0)) {
249 goto exit;
250 }
251 pt = L1pte >> 32 << TARGET_PAGE_BITS;
252
253 /* L2 page table read. */
254 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
255 L2pte = ldq_phys(pt + index*8);
256
257 if (unlikely((L2pte & PTE_VALID) == 0)) {
258 ret = MM_K_TNV;
259 goto exit;
260 }
261 if (unlikely((L2pte & PTE_KRE) == 0)) {
262 goto exit;
263 }
264 pt = L2pte >> 32 << TARGET_PAGE_BITS;
265
266 /* L3 page table read. */
267 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
268 L3pte = ldq_phys(pt + index*8);
269
270 phys = L3pte >> 32 << TARGET_PAGE_BITS;
271 if (unlikely((L3pte & PTE_VALID) == 0)) {
272 ret = MM_K_TNV;
273 goto exit;
274 }
275
276#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
277# error page bits out of date
278#endif
279
280 /* Check access violations. */
281 if (L3pte & (PTE_KRE << mmu_idx)) {
282 prot |= PAGE_READ | PAGE_EXEC;
283 }
284 if (L3pte & (PTE_KWE << mmu_idx)) {
285 prot |= PAGE_WRITE;
286 }
287 if (unlikely((prot & prot_need) == 0 && prot_need)) {
288 goto exit;
289 }
290
291 /* Check fault-on-operation violations. */
292 prot &= ~(L3pte >> 1);
293 ret = -1;
294 if (unlikely((prot & prot_need) == 0)) {
295 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
296 prot_need & PAGE_WRITE ? MM_K_FOW :
297 prot_need & PAGE_READ ? MM_K_FOR : -1);
298 }
299
300 exit:
301 *pphys = phys;
302 *pprot = prot;
303 return ret;
4c9649a9
JM
304}
305
a3b9af16 306target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
4c9649a9 307{
a3b9af16
RH
308 target_ulong phys;
309 int prot, fail;
310
311 fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
312 return (fail >= 0 ? -1 : phys);
313}
314
315int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
316 int mmu_idx, int is_softmmu)
317{
318 target_ulong phys;
319 int prot, fail;
320
321 fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
322 if (unlikely(fail >= 0)) {
323 env->exception_index = EXCP_MMFAULT;
324 env->trap_arg0 = addr;
325 env->trap_arg1 = fail;
326 env->trap_arg2 = (rw == 2 ? -1 : rw);
327 return 1;
328 }
329
330 tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
331 prot, mmu_idx, TARGET_PAGE_SIZE);
129d8aa5 332 return 0;
4c9649a9 333}
3a6fa678 334#endif /* USER_ONLY */
4c9649a9
JM
335
336void do_interrupt (CPUState *env)
337{
3a6fa678
RH
338 int i = env->exception_index;
339
340 if (qemu_loglevel_mask(CPU_LOG_INT)) {
341 static int count;
342 const char *name = "<unknown>";
343
344 switch (i) {
345 case EXCP_RESET:
346 name = "reset";
347 break;
348 case EXCP_MCHK:
349 name = "mchk";
350 break;
351 case EXCP_SMP_INTERRUPT:
352 name = "smp_interrupt";
353 break;
354 case EXCP_CLK_INTERRUPT:
355 name = "clk_interrupt";
356 break;
357 case EXCP_DEV_INTERRUPT:
358 name = "dev_interrupt";
359 break;
360 case EXCP_MMFAULT:
361 name = "mmfault";
362 break;
363 case EXCP_UNALIGN:
364 name = "unalign";
365 break;
366 case EXCP_OPCDEC:
367 name = "opcdec";
368 break;
369 case EXCP_ARITH:
370 name = "arith";
371 break;
372 case EXCP_FEN:
373 name = "fen";
374 break;
375 case EXCP_CALL_PAL:
376 name = "call_pal";
377 break;
378 case EXCP_STL_C:
379 name = "stl_c";
380 break;
381 case EXCP_STQ_C:
382 name = "stq_c";
383 break;
384 }
385 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
386 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
387 }
388
389 env->exception_index = -1;
390
391#if !defined(CONFIG_USER_ONLY)
392 switch (i) {
393 case EXCP_RESET:
394 i = 0x0000;
395 break;
396 case EXCP_MCHK:
397 i = 0x0080;
398 break;
399 case EXCP_SMP_INTERRUPT:
400 i = 0x0100;
401 break;
402 case EXCP_CLK_INTERRUPT:
403 i = 0x0180;
404 break;
405 case EXCP_DEV_INTERRUPT:
406 i = 0x0200;
407 break;
408 case EXCP_MMFAULT:
409 i = 0x0280;
410 break;
411 case EXCP_UNALIGN:
412 i = 0x0300;
413 break;
414 case EXCP_OPCDEC:
415 i = 0x0380;
416 break;
417 case EXCP_ARITH:
418 i = 0x0400;
419 break;
420 case EXCP_FEN:
421 i = 0x0480;
422 break;
423 case EXCP_CALL_PAL:
424 i = env->error_code;
425 /* There are 64 entry points for both privileged and unprivileged,
426 with bit 0x80 indicating unprivileged. Each entry point gets
427 64 bytes to do its job. */
428 if (i & 0x80) {
429 i = 0x2000 + (i - 0x80) * 64;
430 } else {
431 i = 0x1000 + i * 64;
432 }
433 break;
434 default:
435 cpu_abort(env, "Unhandled CPU exception");
436 }
437
438 /* Remember where the exception happened. Emulate real hardware in
439 that the low bit of the PC indicates PALmode. */
440 env->exc_addr = env->pc | env->pal_mode;
441
442 /* Continue execution at the PALcode entry point. */
443 env->pc = env->palbr + i;
444
445 /* Switch to PALmode. */
21d2beaa
RH
446 if (!env->pal_mode) {
447 env->pal_mode = 1;
448 swap_shadow_regs(env);
449 }
3a6fa678 450#endif /* !USER_ONLY */
4c9649a9 451}
4c9649a9 452
9a78eead 453void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
4c9649a9
JM
454 int flags)
455{
b55266b5 456 static const char *linux_reg_names[] = {
4c9649a9
JM
457 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
458 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
459 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
460 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
461 };
462 int i;
463
129d8aa5 464 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
4c9649a9
JM
465 env->pc, env->ps);
466 for (i = 0; i < 31; i++) {
467 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
468 linux_reg_names[i], env->ir[i]);
469 if ((i % 3) == 2)
470 cpu_fprintf(f, "\n");
471 }
6910b8f6
RH
472
473 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
474 env->lock_addr, env->lock_value);
475
4c9649a9
JM
476 for (i = 0; i < 31; i++) {
477 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
478 *((uint64_t *)(&env->fir[i])));
479 if ((i % 3) == 2)
480 cpu_fprintf(f, "\n");
481 }
6910b8f6 482 cpu_fprintf(f, "\n");
4c9649a9 483}