1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* QEMU LoongArch user cpu_loop.
*
* Copyright (c) 2021 Loongson Technology Corporation Limited
*/
#include "qemu/osdep.h"
#include "qemu.h"
#include "user-internals.h"
#include "user/cpu_loop.h"
#include "signal-common.h"
/* Break codes */
enum {
BRK_OVERFLOW = 6,
BRK_DIVZERO = 7
};
void cpu_loop(CPULoongArchState *env)
{
CPUState *cs = env_cpu(env);
int trapnr, si_code;
abi_long ret;
for (;;) {
cpu_exec_start(cs);
trapnr = cpu_exec(cs);
cpu_exec_end(cs);
process_queued_cpu_work(cs);
switch (trapnr) {
case EXCP_INTERRUPT:
/* just indicate that signals should be handled asap */
break;
case EXCCODE_SYS:
env->pc += 4;
ret = do_syscall(env, env->gpr[11],
env->gpr[4], env->gpr[5],
env->gpr[6], env->gpr[7],
env->gpr[8], env->gpr[9],
-1, -1);
if (ret == -QEMU_ERESTARTSYS) {
env->pc -= 4;
break;
}
if (ret == -QEMU_ESIGRETURN) {
/*
* Returning from a successful sigreturn syscall.
* Avoid clobbering register state.
*/
break;
}
env->gpr[4] = ret;
break;
case EXCCODE_INE:
force_sig_fault(TARGET_SIGILL, 0, env->pc);
break;
case EXCCODE_FPE:
si_code = TARGET_FPE_FLTUNK;
if (GET_FP_CAUSE(env->fcsr0) & FP_INVALID) {
si_code = TARGET_FPE_FLTINV;
} else if (GET_FP_CAUSE(env->fcsr0) & FP_DIV0) {
si_code = TARGET_FPE_FLTDIV;
} else if (GET_FP_CAUSE(env->fcsr0) & FP_OVERFLOW) {
si_code = TARGET_FPE_FLTOVF;
} else if (GET_FP_CAUSE(env->fcsr0) & FP_UNDERFLOW) {
si_code = TARGET_FPE_FLTUND;
} else if (GET_FP_CAUSE(env->fcsr0) & FP_INEXACT) {
si_code = TARGET_FPE_FLTRES;
}
force_sig_fault(TARGET_SIGFPE, si_code, env->pc);
break;
case EXCP_DEBUG:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
break;
case EXCCODE_BRK:
{
unsigned int opcode;
get_user_u32(opcode, env->pc);
switch (opcode & 0x7fff) {
case BRK_OVERFLOW:
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTOVF, env->pc);
break;
case BRK_DIVZERO:
force_sig_fault(TARGET_SIGFPE, TARGET_FPE_INTDIV, env->pc);
break;
default:
force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
}
}
break;
case EXCCODE_BCE:
force_sig_fault(TARGET_SIGSYS, TARGET_SI_KERNEL, env->pc);
break;
/*
* Begin with LSX and LASX disabled, then enable on the first trap.
* In this way we can tell if the unit is in use. This is used to
* choose the layout of any signal frame.
*/
case EXCCODE_SXD:
env->CSR_EUEN |= R_CSR_EUEN_SXE_MASK;
break;
case EXCCODE_ASXD:
env->CSR_EUEN |= R_CSR_EUEN_ASXE_MASK;
break;
case EXCP_ATOMIC:
cpu_exec_step_atomic(cs);
break;
default:
EXCP_DUMP(env, "qemu: unhandled CPU exception 0x%x - aborting\n",
trapnr);
exit(EXIT_FAILURE);
}
process_pending_signals(env);
}
}
void target_cpu_copy_regs(CPUArchState *env, target_pt_regs *regs)
{
int i;
for (i = 0; i < 32; i++) {
env->gpr[i] = regs->regs[i];
}
env->pc = regs->csr.era;
}
|