aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@ftp.linux.org.uk>2011-08-18 15:00:49 -0400
committerRichard Weinberger <richard@nod.at>2011-11-02 09:14:42 -0400
commita955bd611d6426bf7b61cab01f8ddee9cc169736 (patch)
treef2f42f996bbb757e6f8ebd805fe1e975893dcc32
parent3d72210bdc1ef67b72ffbd3e74873cae7287f2c6 (diff)
um: series of __get_user() is costly in sigframe handling
It's not x86, where __get_user() is a single dereference; here it's a single ptrace(2) call in host, which obviously costs a lot more. IOW, it's cheaper to do copy_{to,from}_user() once than bother with fields one by one... Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Richard Weinberger <richard@nod.at>
-rw-r--r--arch/um/sys-i386/signal.c48
-rw-r--r--arch/um/sys-x86_64/signal.c118
2 files changed, 80 insertions, 86 deletions
diff --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index b87195b92fcc..bcbfb0d64813 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -10,28 +10,6 @@
10#include "frame_kern.h" 10#include "frame_kern.h"
11#include "skas.h" 11#include "skas.h"
12 12
13static void copy_sc(struct uml_pt_regs *regs, void *from)
14{
15 struct sigcontext *sc = from;
16
17 REGS_GS(regs->gp) = sc->gs;
18 REGS_FS(regs->gp) = sc->fs;
19 REGS_ES(regs->gp) = sc->es;
20 REGS_DS(regs->gp) = sc->ds;
21 REGS_EDI(regs->gp) = sc->di;
22 REGS_ESI(regs->gp) = sc->si;
23 REGS_EBP(regs->gp) = sc->bp;
24 REGS_SP(regs->gp) = sc->sp;
25 REGS_EBX(regs->gp) = sc->bx;
26 REGS_EDX(regs->gp) = sc->dx;
27 REGS_ECX(regs->gp) = sc->cx;
28 REGS_EAX(regs->gp) = sc->ax;
29 REGS_IP(regs->gp) = sc->ip;
30 REGS_CS(regs->gp) = sc->cs;
31 REGS_EFLAGS(regs->gp) = sc->flags;
32 REGS_SS(regs->gp) = sc->ss;
33}
34
35/* 13/*
36 * FPU tag word conversions. 14 * FPU tag word conversions.
37 */ 15 */
@@ -175,7 +153,27 @@ static int copy_sc_from_user(struct pt_regs *regs,
175 return err; 153 return err;
176 154
177 pid = userspace_pid[current_thread_info()->cpu]; 155 pid = userspace_pid[current_thread_info()->cpu];
178 copy_sc(&regs->regs, &sc); 156
157#define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname
158
159 GETREG(GS, gs);
160 GETREG(FS, fs);
161 GETREG(ES, es);
162 GETREG(DS, ds);
163 GETREG(EDI, di);
164 GETREG(ESI, si);
165 GETREG(EBP, bp);
166 GETREG(SP, sp);
167 GETREG(EBX, bx);
168 GETREG(EDX, dx);
169 GETREG(ECX, cx);
170 GETREG(EAX, ax);
171 GETREG(IP, ip);
172 GETREG(CS, cs);
173 GETREG(EFLAGS, flags);
174 GETREG(SS, ss);
175
176#undef GETREG
179 if (have_fpx_regs) { 177 if (have_fpx_regs) {
180 struct user_fxsr_struct fpx; 178 struct user_fxsr_struct fpx;
181 179
@@ -196,8 +194,7 @@ static int copy_sc_from_user(struct pt_regs *regs,
196 -err); 194 -err);
197 return 1; 195 return 1;
198 } 196 }
199 } 197 } else {
200 else {
201 struct user_i387_struct fp; 198 struct user_i387_struct fp;
202 199
203 err = copy_from_user(&fp, sc.fpstate, 200 err = copy_from_user(&fp, sc.fpstate,
@@ -224,6 +221,7 @@ static int copy_sc_to_user(struct sigcontext __user *to,
224 struct sigcontext sc; 221 struct sigcontext sc;
225 struct faultinfo * fi = &current->thread.arch.faultinfo; 222 struct faultinfo * fi = &current->thread.arch.faultinfo;
226 int err, pid; 223 int err, pid;
224 memset(&sc, 0, sizeof(struct sigcontext));
227 225
228 sc.gs = REGS_GS(regs->regs.gp); 226 sc.gs = REGS_GS(regs->regs.gp);
229 sc.fs = REGS_FS(regs->regs.gp); 227 sc.fs = REGS_FS(regs->regs.gp);
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index 61ad980890c7..255b2ca0ce67 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -16,41 +16,39 @@
16static int copy_sc_from_user(struct pt_regs *regs, 16static int copy_sc_from_user(struct pt_regs *regs,
17 struct sigcontext __user *from) 17 struct sigcontext __user *from)
18{ 18{
19 struct sigcontext sc;
19 struct user_i387_struct fp; 20 struct user_i387_struct fp;
20 void __user *buf; 21 void __user *buf;
21 int err = 0; 22 int err;
22 23
23#define GETREG(regs, regno, sc, regname) \ 24 err = copy_from_user(&sc, from, sizeof(sc));
24 __get_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \
25 &(sc)->regname)
26
27 err |= GETREG(regs, R8, from, r8);
28 err |= GETREG(regs, R9, from, r9);
29 err |= GETREG(regs, R10, from, r10);
30 err |= GETREG(regs, R11, from, r11);
31 err |= GETREG(regs, R12, from, r12);
32 err |= GETREG(regs, R13, from, r13);
33 err |= GETREG(regs, R14, from, r14);
34 err |= GETREG(regs, R15, from, r15);
35 err |= GETREG(regs, RDI, from, di);
36 err |= GETREG(regs, RSI, from, si);
37 err |= GETREG(regs, RBP, from, bp);
38 err |= GETREG(regs, RBX, from, bx);
39 err |= GETREG(regs, RDX, from, dx);
40 err |= GETREG(regs, RAX, from, ax);
41 err |= GETREG(regs, RCX, from, cx);
42 err |= GETREG(regs, RSP, from, sp);
43 err |= GETREG(regs, RIP, from, ip);
44 err |= GETREG(regs, EFLAGS, from, flags);
45 err |= GETREG(regs, CS, from, cs);
46 if (err) 25 if (err)
47 return 1; 26 return err;
48 27
28#define GETREG(regno, regname) regs->regs.gp[HOST_##regno] = sc.regname
29
30 GETREG(R8, r8);
31 GETREG(R9, r9);
32 GETREG(R10, r10);
33 GETREG(R11, r11);
34 GETREG(R12, r12);
35 GETREG(R13, r13);
36 GETREG(R14, r14);
37 GETREG(R15, r15);
38 GETREG(RDI, di);
39 GETREG(RSI, si);
40 GETREG(RBP, bp);
41 GETREG(RBX, bx);
42 GETREG(RDX, dx);
43 GETREG(RAX, ax);
44 GETREG(RCX, cx);
45 GETREG(SP, sp);
46 GETREG(IP, ip);
47 GETREG(EFLAGS, flags);
48 GETREG(CS, cs);
49#undef GETREG 49#undef GETREG
50 50
51 err = __get_user(buf, &from->fpstate); 51 buf = sc.fpstate;
52 if (err)
53 return 1;
54 52
55 err = copy_from_user(&fp, buf, sizeof(struct user_i387_struct)); 53 err = copy_from_user(&fp, buf, sizeof(struct user_i387_struct));
56 if (err) 54 if (err)
@@ -73,48 +71,46 @@ static int copy_sc_to_user(struct sigcontext __user *to,
73 unsigned long mask, unsigned long sp) 71 unsigned long mask, unsigned long sp)
74{ 72{
75 struct faultinfo * fi = &current->thread.arch.faultinfo; 73 struct faultinfo * fi = &current->thread.arch.faultinfo;
74 struct sigcontext sc;
76 struct user_i387_struct fp; 75 struct user_i387_struct fp;
77 int err = 0; 76 int err = 0;
77 memset(&sc, 0, sizeof(struct sigcontext));
78 78
79 err |= __put_user(0, &to->gs); 79#define PUTREG(regno, regname) sc.regname = regs->regs.gp[HOST_##regno]
80 err |= __put_user(0, &to->fs);
81
82#define PUTREG(regs, regno, sc, regname) \
83 __put_user((regs)->regs.gp[(regno) / sizeof(unsigned long)], \
84 &(sc)->regname)
85 80
86 err |= PUTREG(regs, RDI, to, di); 81 PUTREG(RDI, di);
87 err |= PUTREG(regs, RSI, to, si); 82 PUTREG(RSI, si);
88 err |= PUTREG(regs, RBP, to, bp); 83 PUTREG(RBP, bp);
89 /* 84 /*
90 * Must use original RSP, which is passed in, rather than what's in 85 * Must use original RSP, which is passed in, rather than what's in
91 * the pt_regs, because that's already been updated to point at the
92 * signal frame. 86 * signal frame.
93 */ 87 */
94 err |= __put_user(sp, &to->sp); 88 sc.sp = sp;
95 err |= PUTREG(regs, RBX, to, bx); 89 PUTREG(RBX, bx);
96 err |= PUTREG(regs, RDX, to, dx); 90 PUTREG(RDX, dx);
97 err |= PUTREG(regs, RCX, to, cx); 91 PUTREG(RCX, cx);
98 err |= PUTREG(regs, RAX, to, ax); 92 PUTREG(RAX, ax);
99 err |= PUTREG(regs, R8, to, r8); 93 PUTREG(R8, r8);
100 err |= PUTREG(regs, R9, to, r9); 94 PUTREG(R9, r9);
101 err |= PUTREG(regs, R10, to, r10); 95 PUTREG(R10, r10);
102 err |= PUTREG(regs, R11, to, r11); 96 PUTREG(R11, r11);
103 err |= PUTREG(regs, R12, to, r12); 97 PUTREG(R12, r12);
104 err |= PUTREG(regs, R13, to, r13); 98 PUTREG(R13, r13);
105 err |= PUTREG(regs, R14, to, r14); 99 PUTREG(R14, r14);
106 err |= PUTREG(regs, R15, to, r15); 100 PUTREG(R15, r15);
107 err |= PUTREG(regs, CS, to, cs); /* XXX x86_64 doesn't do this */ 101 PUTREG(CS, cs); /* XXX x86_64 doesn't do this */
108 102
109 err |= __put_user(fi->cr2, &to->cr2); 103 sc.cr2 = fi->cr2;
110 err |= __put_user(fi->error_code, &to->err); 104 sc.err = fi->error_code;
111 err |= __put_user(fi->trap_no, &to->trapno); 105 sc.trapno = fi->trap_no;
112 106
113 err |= PUTREG(regs, RIP, to, ip); 107 PUTREG(IP, ip);
114 err |= PUTREG(regs, EFLAGS, to, flags); 108 PUTREG(EFLAGS, flags);
115#undef PUTREG 109#undef PUTREG
116 110
117 err |= __put_user(mask, &to->oldmask); 111 sc.oldmask = mask;
112
113 err = copy_to_user(to, &sc, sizeof(struct sigcontext));
118 if (err) 114 if (err)
119 return 1; 115 return 1;
120 116