Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/um/sys-x86_64/signal.c
10820 views
1
/*
2
* Copyright (C) 2003 PathScale, Inc.
3
* Copyright (C) 2003 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
4
* Licensed under the GPL
5
*/
6
7
#include <linux/personality.h>
8
#include <linux/ptrace.h>
9
#include <linux/kernel.h>
10
#include <asm/unistd.h>
11
#include <asm/uaccess.h>
12
#include <asm/ucontext.h>
13
#include "frame_kern.h"
14
#include "skas.h"
15
16
void copy_sc(struct uml_pt_regs *regs, void *from)
17
{
18
struct sigcontext *sc = from;
19
20
#define GETREG(regs, regno, sc, regname) \
21
(regs)->gp[(regno) / sizeof(unsigned long)] = (sc)->regname
22
23
GETREG(regs, R8, sc, r8);
24
GETREG(regs, R9, sc, r9);
25
GETREG(regs, R10, sc, r10);
26
GETREG(regs, R11, sc, r11);
27
GETREG(regs, R12, sc, r12);
28
GETREG(regs, R13, sc, r13);
29
GETREG(regs, R14, sc, r14);
30
GETREG(regs, R15, sc, r15);
31
GETREG(regs, RDI, sc, di);
32
GETREG(regs, RSI, sc, si);
33
GETREG(regs, RBP, sc, bp);
34
GETREG(regs, RBX, sc, bx);
35
GETREG(regs, RDX, sc, dx);
36
GETREG(regs, RAX, sc, ax);
37
GETREG(regs, RCX, sc, cx);
38
GETREG(regs, RSP, sc, sp);
39
GETREG(regs, RIP, sc, ip);
40
GETREG(regs, EFLAGS, sc, flags);
41
GETREG(regs, CS, sc, cs);
42
43
#undef GETREG
44
}
45
46
static int copy_sc_from_user(struct pt_regs *regs,
47
struct sigcontext __user *from,
48
struct _fpstate __user *fpp)
49
{
50
struct user_i387_struct fp;
51
int err = 0;
52
53
#define GETREG(regs, regno, sc, regname) \
54
__get_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \
55
&(sc)->regname)
56
57
err |= GETREG(regs, R8, from, r8);
58
err |= GETREG(regs, R9, from, r9);
59
err |= GETREG(regs, R10, from, r10);
60
err |= GETREG(regs, R11, from, r11);
61
err |= GETREG(regs, R12, from, r12);
62
err |= GETREG(regs, R13, from, r13);
63
err |= GETREG(regs, R14, from, r14);
64
err |= GETREG(regs, R15, from, r15);
65
err |= GETREG(regs, RDI, from, di);
66
err |= GETREG(regs, RSI, from, si);
67
err |= GETREG(regs, RBP, from, bp);
68
err |= GETREG(regs, RBX, from, bx);
69
err |= GETREG(regs, RDX, from, dx);
70
err |= GETREG(regs, RAX, from, ax);
71
err |= GETREG(regs, RCX, from, cx);
72
err |= GETREG(regs, RSP, from, sp);
73
err |= GETREG(regs, RIP, from, ip);
74
err |= GETREG(regs, EFLAGS, from, flags);
75
err |= GETREG(regs, CS, from, cs);
76
if (err)
77
return 1;
78
79
#undef GETREG
80
81
err = copy_from_user(&fp, fpp, sizeof(struct user_i387_struct));
82
if (err)
83
return 1;
84
85
err = restore_fp_registers(userspace_pid[current_thread_info()->cpu],
86
(unsigned long *) &fp);
87
if (err < 0) {
88
printk(KERN_ERR "copy_sc_from_user - "
89
"restore_fp_registers failed, errno = %d\n",
90
-err);
91
return 1;
92
}
93
94
return 0;
95
}
96
97
static int copy_sc_to_user(struct sigcontext __user *to,
98
struct _fpstate __user *to_fp, struct pt_regs *regs,
99
unsigned long mask, unsigned long sp)
100
{
101
struct faultinfo * fi = &current->thread.arch.faultinfo;
102
struct user_i387_struct fp;
103
int err = 0;
104
105
err |= __put_user(0, &to->gs);
106
err |= __put_user(0, &to->fs);
107
108
#define PUTREG(regs, regno, sc, regname) \
109
__put_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \
110
&(sc)->regname)
111
112
err |= PUTREG(regs, RDI, to, di);
113
err |= PUTREG(regs, RSI, to, si);
114
err |= PUTREG(regs, RBP, to, bp);
115
/*
116
* Must use original RSP, which is passed in, rather than what's in
117
* the pt_regs, because that's already been updated to point at the
118
* signal frame.
119
*/
120
err |= __put_user(sp, &to->sp);
121
err |= PUTREG(regs, RBX, to, bx);
122
err |= PUTREG(regs, RDX, to, dx);
123
err |= PUTREG(regs, RCX, to, cx);
124
err |= PUTREG(regs, RAX, to, ax);
125
err |= PUTREG(regs, R8, to, r8);
126
err |= PUTREG(regs, R9, to, r9);
127
err |= PUTREG(regs, R10, to, r10);
128
err |= PUTREG(regs, R11, to, r11);
129
err |= PUTREG(regs, R12, to, r12);
130
err |= PUTREG(regs, R13, to, r13);
131
err |= PUTREG(regs, R14, to, r14);
132
err |= PUTREG(regs, R15, to, r15);
133
err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */
134
135
err |= __put_user(fi->cr2, &to->cr2);
136
err |= __put_user(fi->error_code, &to->err);
137
err |= __put_user(fi->trap_no, &to->trapno);
138
139
err |= PUTREG(regs, RIP, to, ip);
140
err |= PUTREG(regs, EFLAGS, to, flags);
141
#undef PUTREG
142
143
err |= __put_user(mask, &to->oldmask);
144
if (err)
145
return 1;
146
147
err = save_fp_registers(userspace_pid[current_thread_info()->cpu],
148
(unsigned long *) &fp);
149
if (err < 0) {
150
printk(KERN_ERR "copy_sc_from_user - restore_fp_registers "
151
"failed, errno = %d\n", -err);
152
return 1;
153
}
154
155
if (copy_to_user(to_fp, &fp, sizeof(struct user_i387_struct)))
156
return 1;
157
158
return err;
159
}
160
161
struct rt_sigframe
162
{
163
char __user *pretcode;
164
struct ucontext uc;
165
struct siginfo info;
166
struct _fpstate fpstate;
167
};
168
169
int setup_signal_stack_si(unsigned long stack_top, int sig,
170
struct k_sigaction *ka, struct pt_regs * regs,
171
siginfo_t *info, sigset_t *set)
172
{
173
struct rt_sigframe __user *frame;
174
unsigned long save_sp = PT_REGS_RSP(regs);
175
int err = 0;
176
struct task_struct *me = current;
177
178
frame = (struct rt_sigframe __user *)
179
round_down(stack_top - sizeof(struct rt_sigframe), 16);
180
/* Subtract 128 for a red zone and 8 for proper alignment */
181
frame = (struct rt_sigframe __user *) ((unsigned long) frame - 128 - 8);
182
183
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
184
goto out;
185
186
if (ka->sa.sa_flags & SA_SIGINFO) {
187
err |= copy_siginfo_to_user(&frame->info, info);
188
if (err)
189
goto out;
190
}
191
192
/*
193
* Update SP now because the page fault handler refuses to extend
194
* the stack if the faulting address is too far below the current
195
* SP, which frame now certainly is. If there's an error, the original
196
* value is restored on the way out.
197
* When writing the sigcontext to the stack, we have to write the
198
* original value, so that's passed to copy_sc_to_user, which does
199
* the right thing with it.
200
*/
201
PT_REGS_RSP(regs) = (unsigned long) frame;
202
203
/* Create the ucontext. */
204
err |= __put_user(0, &frame->uc.uc_flags);
205
err |= __put_user(0, &frame->uc.uc_link);
206
err |= __put_user(me->sas_ss_sp, &frame->uc.uc_stack.ss_sp);
207
err |= __put_user(sas_ss_flags(save_sp),
208
&frame->uc.uc_stack.ss_flags);
209
err |= __put_user(me->sas_ss_size, &frame->uc.uc_stack.ss_size);
210
err |= copy_sc_to_user(&frame->uc.uc_mcontext, &frame->fpstate, regs,
211
set->sig[0], save_sp);
212
err |= __put_user(&frame->fpstate, &frame->uc.uc_mcontext.fpstate);
213
if (sizeof(*set) == 16) {
214
__put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]);
215
__put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]);
216
}
217
else
218
err |= __copy_to_user(&frame->uc.uc_sigmask, set,
219
sizeof(*set));
220
221
/*
222
* Set up to return from userspace. If provided, use a stub
223
* already in userspace.
224
*/
225
/* x86-64 should always use SA_RESTORER. */
226
if (ka->sa.sa_flags & SA_RESTORER)
227
err |= __put_user(ka->sa.sa_restorer, &frame->pretcode);
228
else
229
/* could use a vstub here */
230
goto restore_sp;
231
232
if (err)
233
goto restore_sp;
234
235
/* Set up registers for signal handler */
236
{
237
struct exec_domain *ed = current_thread_info()->exec_domain;
238
if (unlikely(ed && ed->signal_invmap && sig < 32))
239
sig = ed->signal_invmap[sig];
240
}
241
242
PT_REGS_RDI(regs) = sig;
243
/* In case the signal handler was declared without prototypes */
244
PT_REGS_RAX(regs) = 0;
245
246
/*
247
* This also works for non SA_SIGINFO handlers because they expect the
248
* next argument after the signal number on the stack.
249
*/
250
PT_REGS_RSI(regs) = (unsigned long) &frame->info;
251
PT_REGS_RDX(regs) = (unsigned long) &frame->uc;
252
PT_REGS_RIP(regs) = (unsigned long) ka->sa.sa_handler;
253
out:
254
return err;
255
256
restore_sp:
257
PT_REGS_RSP(regs) = save_sp;
258
return err;
259
}
260
261
long sys_rt_sigreturn(struct pt_regs *regs)
262
{
263
unsigned long sp = PT_REGS_SP(&current->thread.regs);
264
struct rt_sigframe __user *frame =
265
(struct rt_sigframe __user *)(sp - 8);
266
struct ucontext __user *uc = &frame->uc;
267
sigset_t set;
268
269
if (copy_from_user(&set, &uc->uc_sigmask, sizeof(set)))
270
goto segfault;
271
272
sigdelsetmask(&set, ~_BLOCKABLE);
273
274
spin_lock_irq(&current->sighand->siglock);
275
current->blocked = set;
276
recalc_sigpending();
277
spin_unlock_irq(&current->sighand->siglock);
278
279
if (copy_sc_from_user(&current->thread.regs, &uc->uc_mcontext,
280
&frame->fpstate))
281
goto segfault;
282
283
/* Avoid ERESTART handling */
284
PT_REGS_SYSCALL_NR(&current->thread.regs) = -1;
285
return PT_REGS_SYSCALL_RET(&current->thread.regs);
286
287
segfault:
288
force_sig(SIGSEGV, current);
289
return 0;
290
}
291
292