1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#include "qemu/osdep.h"
20#include "qemu.h"
21#include "signal-common.h"
22#include "linux-user/trace.h"
23
24
25
26
27
28
29
30
31
32struct target_sigcontext {
33 abi_long pc;
34 abi_long gpr[31];
35 uint64_t fpr[32];
36 uint32_t fcsr;
37};
38
39struct target_ucontext {
40 unsigned long uc_flags;
41 struct target_ucontext *uc_link;
42 target_stack_t uc_stack;
43 struct target_sigcontext uc_mcontext;
44 target_sigset_t uc_sigmask;
45};
46
47struct target_rt_sigframe {
48 uint32_t tramp[2];
49 struct target_siginfo info;
50 struct target_ucontext uc;
51};
52
53static abi_ulong get_sigframe(struct target_sigaction *ka,
54 CPURISCVState *regs, size_t framesize)
55{
56 abi_ulong sp = get_sp_from_cpustate(regs);
57
58
59
60 if (on_sig_stack(sp) && !likely(on_sig_stack(sp - framesize))) {
61 return -1L;
62 }
63
64
65 sp = target_sigsp(sp, ka) - framesize;
66
67
68 sp &= ~3UL;
69
70 return sp;
71}
72
73static void setup_sigcontext(struct target_sigcontext *sc, CPURISCVState *env)
74{
75 int i;
76
77 __put_user(env->pc, &sc->pc);
78
79 for (i = 1; i < 32; i++) {
80 __put_user(env->gpr[i], &sc->gpr[i - 1]);
81 }
82 for (i = 0; i < 32; i++) {
83 __put_user(env->fpr[i], &sc->fpr[i]);
84 }
85
86 uint32_t fcsr = riscv_csr_read(env, CSR_FCSR);
87 __put_user(fcsr, &sc->fcsr);
88}
89
90static void setup_ucontext(struct target_ucontext *uc,
91 CPURISCVState *env, target_sigset_t *set)
92{
93 __put_user(0, &(uc->uc_flags));
94 __put_user(0, &(uc->uc_link));
95
96 target_save_altstack(&uc->uc_stack, env);
97
98 int i;
99 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
100 __put_user(set->sig[i], &(uc->uc_sigmask.sig[i]));
101 }
102
103 setup_sigcontext(&uc->uc_mcontext, env);
104}
105
106static inline void install_sigtramp(uint32_t *tramp)
107{
108 __put_user(0x08b00893, tramp + 0);
109 __put_user(0x00000073, tramp + 1);
110}
111
112void setup_rt_frame(int sig, struct target_sigaction *ka,
113 target_siginfo_t *info,
114 target_sigset_t *set, CPURISCVState *env)
115{
116 abi_ulong frame_addr;
117 struct target_rt_sigframe *frame;
118
119 frame_addr = get_sigframe(ka, env, sizeof(*frame));
120 trace_user_setup_rt_frame(env, frame_addr);
121
122 if (!lock_user_struct(VERIFY_WRITE, frame, frame_addr, 0)) {
123 goto badframe;
124 }
125
126 setup_ucontext(&frame->uc, env, set);
127 tswap_siginfo(&frame->info, info);
128 install_sigtramp(frame->tramp);
129
130 env->pc = ka->_sa_handler;
131 env->gpr[xSP] = frame_addr;
132 env->gpr[xA0] = sig;
133 env->gpr[xA1] = frame_addr + offsetof(struct target_rt_sigframe, info);
134 env->gpr[xA2] = frame_addr + offsetof(struct target_rt_sigframe, uc);
135 env->gpr[xRA] = frame_addr + offsetof(struct target_rt_sigframe, tramp);
136
137 return;
138
139badframe:
140 unlock_user_struct(frame, frame_addr, 1);
141 if (sig == TARGET_SIGSEGV) {
142 ka->_sa_handler = TARGET_SIG_DFL;
143 }
144 force_sig(TARGET_SIGSEGV);
145}
146
147static void restore_sigcontext(CPURISCVState *env, struct target_sigcontext *sc)
148{
149 int i;
150
151 __get_user(env->pc, &sc->pc);
152
153 for (i = 1; i < 32; ++i) {
154 __get_user(env->gpr[i], &sc->gpr[i - 1]);
155 }
156 for (i = 0; i < 32; ++i) {
157 __get_user(env->fpr[i], &sc->fpr[i]);
158 }
159
160 uint32_t fcsr;
161 __get_user(fcsr, &sc->fcsr);
162 riscv_csr_write(env, CSR_FCSR, fcsr);
163}
164
165static void restore_ucontext(CPURISCVState *env, struct target_ucontext *uc)
166{
167 sigset_t blocked;
168 target_sigset_t target_set;
169 int i;
170
171 target_sigemptyset(&target_set);
172 for (i = 0; i < TARGET_NSIG_WORDS; i++) {
173 __get_user(target_set.sig[i], &(uc->uc_sigmask.sig[i]));
174 }
175
176 target_to_host_sigset_internal(&blocked, &target_set);
177 set_sigmask(&blocked);
178
179 restore_sigcontext(env, &uc->uc_mcontext);
180}
181
182long do_rt_sigreturn(CPURISCVState *env)
183{
184 struct target_rt_sigframe *frame;
185 abi_ulong frame_addr;
186
187 frame_addr = env->gpr[xSP];
188 trace_user_do_sigreturn(env, frame_addr);
189 if (!lock_user_struct(VERIFY_READ, frame, frame_addr, 1)) {
190 goto badframe;
191 }
192
193 restore_ucontext(env, &frame->uc);
194
195 if (do_sigaltstack(frame_addr + offsetof(struct target_rt_sigframe,
196 uc.uc_stack), 0, get_sp_from_cpustate(env)) == -EFAULT) {
197 goto badframe;
198 }
199
200 unlock_user_struct(frame, frame_addr, 0);
201 return -TARGET_QEMU_ESIGRETURN;
202
203badframe:
204 unlock_user_struct(frame, frame_addr, 0);
205 force_sig(TARGET_SIGSEGV);
206 return 0;
207}
208