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"
23
#include "exec/exec-all.h"
24
#include "fpu/softfloat.h"
25
#include "exec/helper-proto.h"
28
#define CONVERT_BIT(X, SRC, DST) \
29
(SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
31
uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env)
33
return (uint64_t)env->fpcr << 32;
36
void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val)
38
uint32_t fpcr = val >> 32;
41
t |= CONVERT_BIT(fpcr, FPCR_INED, FPCR_INE);
42
t |= CONVERT_BIT(fpcr, FPCR_UNFD, FPCR_UNF);
43
t |= CONVERT_BIT(fpcr, FPCR_OVFD, FPCR_OVF);
44
t |= CONVERT_BIT(fpcr, FPCR_DZED, FPCR_DZE);
45
t |= CONVERT_BIT(fpcr, FPCR_INVD, FPCR_INV);
48
env->fpcr_exc_enable = ~t & FPCR_STATUS_MASK;
50
switch (fpcr & FPCR_DYN_MASK) {
53
t = float_round_nearest_even;
55
case FPCR_DYN_CHOPPED:
56
t = float_round_to_zero;
65
env->fpcr_dyn_round = t;
67
env->fpcr_flush_to_zero = (fpcr & FPCR_UNFD) && (fpcr & FPCR_UNDZ);
68
env->fp_status.flush_inputs_to_zero = (fpcr & FPCR_DNZ) != 0;
71
uint64_t helper_load_fpcr(CPUAlphaState *env)
73
return cpu_alpha_load_fpcr(env);
76
void helper_store_fpcr(CPUAlphaState *env, uint64_t val)
78
cpu_alpha_store_fpcr(env, val);
81
static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg)
83
#ifndef CONFIG_USER_ONLY
85
if (reg >= 8 && reg <= 14) {
86
return &env->shadow[reg - 8];
87
} else if (reg == 25) {
88
return &env->shadow[7];
95
uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg)
97
return *cpu_alpha_addr_gr(env, reg);
100
void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val)
102
*cpu_alpha_addr_gr(env, reg) = val;
105
#if defined(CONFIG_USER_ONLY)
106
int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address,
109
AlphaCPU *cpu = ALPHA_CPU(cs);
111
cs->exception_index = EXCP_MMFAULT;
112
cpu->env.trap_arg0 = address;
116
/* Returns the OSF/1 entMM failure indication, or -1 on success. */
117
static int get_physical_address(CPUAlphaState *env, target_ulong addr,
118
int prot_need, int mmu_idx,
119
target_ulong *pphys, int *pprot)
121
CPUState *cs = CPU(alpha_env_get_cpu(env));
122
target_long saddr = addr;
123
target_ulong phys = 0;
124
target_ulong L1pte, L2pte, L3pte;
125
target_ulong pt, index;
129
/* Handle physical accesses. */
130
if (mmu_idx == MMU_PHYS_IDX) {
132
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
137
/* Ensure that the virtual address is properly sign-extended from
138
the last implemented virtual address bit. */
139
if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
143
/* Translate the superpage. */
144
/* ??? When we do more than emulate Unix PALcode, we'll need to
145
determine which KSEG is actually active. */
146
if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
147
/* User-space cannot access KSEG addresses. */
148
if (mmu_idx != MMU_KERNEL_IDX) {
152
/* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
153
We would not do this if the 48-bit KSEG is enabled. */
154
phys = saddr & ((1ull << 40) - 1);
155
phys |= (saddr & (1ull << 40)) << 3;
157
prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
162
/* Interpret the page table exactly like PALcode does. */
166
/* L1 page table read. */
167
index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
168
L1pte = ldq_phys(cs->as, pt + index*8);
170
if (unlikely((L1pte & PTE_VALID) == 0)) {
174
if (unlikely((L1pte & PTE_KRE) == 0)) {
177
pt = L1pte >> 32 << TARGET_PAGE_BITS;
179
/* L2 page table read. */
180
index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
181
L2pte = ldq_phys(cs->as, pt + index*8);
183
if (unlikely((L2pte & PTE_VALID) == 0)) {
187
if (unlikely((L2pte & PTE_KRE) == 0)) {
190
pt = L2pte >> 32 << TARGET_PAGE_BITS;
192
/* L3 page table read. */
193
index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
194
L3pte = ldq_phys(cs->as, pt + index*8);
196
phys = L3pte >> 32 << TARGET_PAGE_BITS;
197
if (unlikely((L3pte & PTE_VALID) == 0)) {
202
#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
203
# error page bits out of date
206
/* Check access violations. */
207
if (L3pte & (PTE_KRE << mmu_idx)) {
208
prot |= PAGE_READ | PAGE_EXEC;
210
if (L3pte & (PTE_KWE << mmu_idx)) {
213
if (unlikely((prot & prot_need) == 0 && prot_need)) {
217
/* Check fault-on-operation violations. */
218
prot &= ~(L3pte >> 1);
220
if (unlikely((prot & prot_need) == 0)) {
221
ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
222
prot_need & PAGE_WRITE ? MM_K_FOW :
223
prot_need & PAGE_READ ? MM_K_FOR : -1);
232
hwaddr alpha_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
234
AlphaCPU *cpu = ALPHA_CPU(cs);
238
fail = get_physical_address(&cpu->env, addr, 0, 0, &phys, &prot);
239
return (fail >= 0 ? -1 : phys);
242
int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr addr, int rw,
245
AlphaCPU *cpu = ALPHA_CPU(cs);
246
CPUAlphaState *env = &cpu->env;
250
fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
251
if (unlikely(fail >= 0)) {
252
cs->exception_index = EXCP_MMFAULT;
253
env->trap_arg0 = addr;
254
env->trap_arg1 = fail;
255
env->trap_arg2 = (rw == 2 ? -1 : rw);
259
tlb_set_page(cs, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
260
prot, mmu_idx, TARGET_PAGE_SIZE);
263
#endif /* USER_ONLY */
265
void alpha_cpu_do_interrupt(CPUState *cs)
267
AlphaCPU *cpu = ALPHA_CPU(cs);
268
CPUAlphaState *env = &cpu->env;
269
int i = cs->exception_index;
271
if (qemu_loglevel_mask(CPU_LOG_INT)) {
273
const char *name = "<unknown>";
282
case EXCP_SMP_INTERRUPT:
283
name = "smp_interrupt";
285
case EXCP_CLK_INTERRUPT:
286
name = "clk_interrupt";
288
case EXCP_DEV_INTERRUPT:
289
name = "dev_interrupt";
310
qemu_log("INT %6d: %s(%#x) cpu=%d pc=%016"
311
PRIx64 " sp=%016" PRIx64 "\n",
312
++count, name, env->error_code, cs->cpu_index,
313
env->pc, env->ir[IR_SP]);
316
cs->exception_index = -1;
318
#if !defined(CONFIG_USER_ONLY)
326
case EXCP_SMP_INTERRUPT:
329
case EXCP_CLK_INTERRUPT:
332
case EXCP_DEV_INTERRUPT:
352
/* There are 64 entry points for both privileged and unprivileged,
353
with bit 0x80 indicating unprivileged. Each entry point gets
354
64 bytes to do its job. */
356
i = 0x2000 + (i - 0x80) * 64;
362
cpu_abort(cs, "Unhandled CPU exception");
365
/* Remember where the exception happened. Emulate real hardware in
366
that the low bit of the PC indicates PALmode. */
367
env->exc_addr = env->pc | env->pal_mode;
369
/* Continue execution at the PALcode entry point. */
370
env->pc = env->palbr + i;
372
/* Switch to PALmode. */
374
#endif /* !USER_ONLY */
377
bool alpha_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
379
AlphaCPU *cpu = ALPHA_CPU(cs);
380
CPUAlphaState *env = &cpu->env;
383
/* We never take interrupts while in PALmode. */
388
/* Fall through the switch, collecting the highest priority
389
interrupt that isn't masked by the processor status IPL. */
390
/* ??? This hard-codes the OSF/1 interrupt levels. */
391
switch (env->ps & PS_INT_MASK) {
393
if (interrupt_request & CPU_INTERRUPT_HARD) {
394
idx = EXCP_DEV_INTERRUPT;
398
if (interrupt_request & CPU_INTERRUPT_TIMER) {
399
idx = EXCP_CLK_INTERRUPT;
403
if (interrupt_request & CPU_INTERRUPT_SMP) {
404
idx = EXCP_SMP_INTERRUPT;
408
if (interrupt_request & CPU_INTERRUPT_MCHK) {
413
cs->exception_index = idx;
415
alpha_cpu_do_interrupt(cs);
421
void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
424
static const char *linux_reg_names[] = {
425
"v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
426
"t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
427
"a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
428
"t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
430
AlphaCPU *cpu = ALPHA_CPU(cs);
431
CPUAlphaState *env = &cpu->env;
434
cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
436
for (i = 0; i < 31; i++) {
437
cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
438
linux_reg_names[i], cpu_alpha_load_gr(env, i));
440
cpu_fprintf(f, "\n");
443
cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
444
env->lock_addr, env->lock_value);
446
for (i = 0; i < 31; i++) {
447
cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
448
*((uint64_t *)(&env->fir[i])));
450
cpu_fprintf(f, "\n");
452
cpu_fprintf(f, "\n");
455
/* This should only be called from translate, via gen_excp.
456
We expect that ENV->PC has already been updated. */
457
void QEMU_NORETURN helper_excp(CPUAlphaState *env, int excp, int error)
459
AlphaCPU *cpu = alpha_env_get_cpu(env);
460
CPUState *cs = CPU(cpu);
462
cs->exception_index = excp;
463
env->error_code = error;
467
/* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
468
void QEMU_NORETURN dynamic_excp(CPUAlphaState *env, uintptr_t retaddr,
471
AlphaCPU *cpu = alpha_env_get_cpu(env);
472
CPUState *cs = CPU(cpu);
474
cs->exception_index = excp;
475
env->error_code = error;
477
cpu_restore_state(cs, retaddr);
478
/* Floating-point exceptions (our only users) point to the next PC. */
484
void QEMU_NORETURN arith_excp(CPUAlphaState *env, uintptr_t retaddr,
485
int exc, uint64_t mask)
487
env->trap_arg0 = exc;
488
env->trap_arg1 = mask;
489
dynamic_excp(env, retaddr, EXCP_ARITH, 0);