aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/os-Linux/skas
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2007-05-06 17:51:48 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-05-07 15:13:04 -0400
commit16dd07bc6404c8da0bdfeb7a5cde4e4a63991c00 (patch)
treede8401aeebfe1bbdaecaff3b81d92196c50c85d7 /arch/um/os-Linux/skas
parent3ec704e6660aa58505110a50102e57cdb9daa044 (diff)
uml: more page fault path trimming
More trimming of the page fault path. Permissions are passed around in a single int rather than one bit per int. The permission values are copied from libc so that they can be passed to mmap and mprotect without any further conversion. The register sets used by do_syscall_stub and copy_context_skas0 are initialized once, at boot time, rather than once per call. wait_stub_done checks whether it is getting the signals it expects by comparing the wait status to a mask containing bits for the signals of interest rather than comparing individually to the signal numbers. It also has one check for a wait failure instead of two. The caller is expected to do the initial continue of the stub. This gets rid of an argument and some logic. The fname argument is gone, as that can be had from a stack trace. user_signal() is collapsed into userspace() as it is basically one or two lines of code afterwards. The physical memory remapping stuff is gone, as it is unused. flush_tlb_page is inlined. Signed-off-by: Jeff Dike <jdike@linux.intel.com> Cc: Paolo 'Blaisorblade' Giarrusso <blaisorblade@yahoo.it> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/um/os-Linux/skas')
-rw-r--r--arch/um/os-Linux/skas/mem.c51
-rw-r--r--arch/um/os-Linux/skas/process.c122
-rw-r--r--arch/um/os-Linux/skas/trap.c17
3 files changed, 103 insertions, 87 deletions
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c
index af0790719b77..8e490fff3d47 100644
--- a/arch/um/os-Linux/skas/mem.c
+++ b/arch/um/os-Linux/skas/mem.c
@@ -24,10 +24,11 @@
24#include "uml-config.h" 24#include "uml-config.h"
25#include "sysdep/ptrace.h" 25#include "sysdep/ptrace.h"
26#include "sysdep/stub.h" 26#include "sysdep/stub.h"
27#include "init.h"
27 28
28extern unsigned long batch_syscall_stub, __syscall_stub_start; 29extern unsigned long batch_syscall_stub, __syscall_stub_start;
29 30
30extern void wait_stub_done(int pid, int sig, char * fname); 31extern void wait_stub_done(int pid);
31 32
32static inline unsigned long *check_init_stack(struct mm_id * mm_idp, 33static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
33 unsigned long *stack) 34 unsigned long *stack)
@@ -39,6 +40,19 @@ static inline unsigned long *check_init_stack(struct mm_id * mm_idp,
39 return stack; 40 return stack;
40} 41}
41 42
43static unsigned long syscall_regs[MAX_REG_NR];
44
45static int __init init_syscall_regs(void)
46{
47 get_safe_registers(syscall_regs, NULL);
48 syscall_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
49 ((unsigned long) &batch_syscall_stub -
50 (unsigned long) &__syscall_stub_start);
51 return 0;
52}
53
54__initcall(init_syscall_regs);
55
42extern int proc_mm; 56extern int proc_mm;
43 57
44int single_count = 0; 58int single_count = 0;
@@ -47,12 +61,11 @@ int multi_op_count = 0;
47 61
48static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr) 62static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
49{ 63{
50 unsigned long regs[MAX_REG_NR];
51 int n, i; 64 int n, i;
52 long ret, offset; 65 long ret, offset;
53 unsigned long * data; 66 unsigned long * data;
54 unsigned long * syscall; 67 unsigned long * syscall;
55 int pid = mm_idp->u.pid; 68 int err, pid = mm_idp->u.pid;
56 69
57 if(proc_mm) 70 if(proc_mm)
58#warning Need to look up userspace_pid by cpu 71#warning Need to look up userspace_pid by cpu
@@ -60,21 +73,21 @@ static inline long do_syscall_stub(struct mm_id * mm_idp, void **addr)
60 73
61 multi_count++; 74 multi_count++;
62 75
63 get_safe_registers(regs, NULL); 76 n = ptrace_setregs(pid, syscall_regs);
64 regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
65 ((unsigned long) &batch_syscall_stub -
66 (unsigned long) &__syscall_stub_start);
67
68 n = ptrace_setregs(pid, regs);
69 if(n < 0){ 77 if(n < 0){
70 printk("Registers - \n"); 78 printk("Registers - \n");
71 for(i = 0; i < MAX_REG_NR; i++) 79 for(i = 0; i < MAX_REG_NR; i++)
72 printk("\t%d\t0x%lx\n", i, regs[i]); 80 printk("\t%d\t0x%lx\n", i, syscall_regs[i]);
73 panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n", 81 panic("do_syscall_stub : PTRACE_SETREGS failed, errno = %d\n",
74 -n); 82 -n);
75 } 83 }
76 84
77 wait_stub_done(pid, 0, "do_syscall_stub"); 85 err = ptrace(PTRACE_CONT, pid, 0, 0);
86 if(err)
87 panic("Failed to continue stub, pid = %d, errno = %d\n", pid,
88 errno);
89
90 wait_stub_done(pid);
78 91
79 /* When the stub stops, we find the following values on the 92 /* When the stub stops, we find the following values on the
80 * beginning of the stack: 93 * beginning of the stack:
@@ -176,14 +189,10 @@ long syscall_stub_data(struct mm_id * mm_idp,
176 return 0; 189 return 0;
177} 190}
178 191
179int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, 192int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len, int prot,
180 int r, int w, int x, int phys_fd, unsigned long long offset, 193 int phys_fd, unsigned long long offset, int done, void **data)
181 int done, void **data)
182{ 194{
183 int prot, ret; 195 int ret;
184
185 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
186 (x ? PROT_EXEC : 0);
187 196
188 if(proc_mm){ 197 if(proc_mm){
189 struct proc_mm_op map; 198 struct proc_mm_op map;
@@ -253,13 +262,11 @@ int unmap(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
253} 262}
254 263
255int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len, 264int protect(struct mm_id * mm_idp, unsigned long addr, unsigned long len,
256 int r, int w, int x, int done, void **data) 265 unsigned int prot, int done, void **data)
257{ 266{
258 struct proc_mm_op protect; 267 struct proc_mm_op protect;
259 int prot, ret; 268 int ret;
260 269
261 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
262 (x ? PROT_EXEC : 0);
263 if(proc_mm){ 270 if(proc_mm){
264 int fd = mm_idp->u.mm_fd; 271 int fd = mm_idp->u.mm_fd;
265 272
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c
index 1f39f2bf7ce9..5c088a55396c 100644
--- a/arch/um/os-Linux/skas/process.c
+++ b/arch/um/os-Linux/skas/process.c
@@ -34,6 +34,7 @@
34#include "process.h" 34#include "process.h"
35#include "longjmp.h" 35#include "longjmp.h"
36#include "kern_constants.h" 36#include "kern_constants.h"
37#include "as-layout.h"
37 38
38int is_skas_winch(int pid, int fd, void *data) 39int is_skas_winch(int pid, int fd, void *data)
39{ 40{
@@ -60,37 +61,42 @@ static int ptrace_dump_regs(int pid)
60 return 0; 61 return 0;
61} 62}
62 63
63void wait_stub_done(int pid, int sig, char * fname) 64/*
65 * Signals that are OK to receive in the stub - we'll just continue it.
66 * SIGWINCH will happen when UML is inside a detached screen.
67 */
68#define STUB_SIG_MASK ((1 << SIGVTALRM) | (1 << SIGWINCH))
69
70/* Signals that the stub will finish with - anything else is an error */
71#define STUB_DONE_MASK ((1 << SIGUSR1) | (1 << SIGTRAP))
72
73void wait_stub_done(int pid)
64{ 74{
65 int n, status, err; 75 int n, status, err;
66 76
67 do { 77 while(1){
68 if ( sig != -1 ) {
69 err = ptrace(PTRACE_CONT, pid, 0, sig);
70 if(err)
71 panic("%s : continue failed, errno = %d\n",
72 fname, errno);
73 }
74 sig = 0;
75
76 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED)); 78 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
77 } while((n >= 0) && WIFSTOPPED(status) && 79 if((n < 0) || !WIFSTOPPED(status))
78 ((WSTOPSIG(status) == SIGVTALRM) || 80 goto bad_wait;
79 /* running UML inside a detached screen can cause 81
80 * SIGWINCHes 82 if(((1 << WSTOPSIG(status)) & STUB_SIG_MASK) == 0)
81 */ 83 break;
82 (WSTOPSIG(status) == SIGWINCH))); 84
83 85 err = ptrace(PTRACE_CONT, pid, 0, 0);
84 if((n < 0) || !WIFSTOPPED(status) ||
85 (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
86 err = ptrace_dump_regs(pid);
87 if(err) 86 if(err)
88 printk("Failed to get registers from stub, " 87 panic("wait_stub_done : continue failed, errno = %d\n",
89 "errno = %d\n", -err); 88 errno);
90 panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
91 "pid = %d, n = %d, errno = %d, status = 0x%x\n",
92 fname, pid, n, errno, status);
93 } 89 }
90
91 if(((1 << WSTOPSIG(status)) & STUB_DONE_MASK) != 0)
92 return;
93
94bad_wait:
95 err = ptrace_dump_regs(pid);
96 if(err)
97 printk("Failed to get registers from stub, errno = %d\n", -err);
98 panic("wait_stub_done : failed to wait for SIGUSR1/SIGTRAP, pid = %d, "
99 "n = %d, errno = %d, status = 0x%x\n", pid, n, errno, status);
94} 100}
95 101
96extern unsigned long current_stub_stack(void); 102extern unsigned long current_stub_stack(void);
@@ -112,7 +118,11 @@ void get_skas_faultinfo(int pid, struct faultinfo * fi)
112 sizeof(struct ptrace_faultinfo)); 118 sizeof(struct ptrace_faultinfo));
113 } 119 }
114 else { 120 else {
115 wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo"); 121 err = ptrace(PTRACE_CONT, pid, 0, SIGSEGV);
122 if(err)
123 panic("Failed to continue stub, pid = %d, errno = %d\n",
124 pid, errno);
125 wait_stub_done(pid);
116 126
117 /* faultinfo is prepared by the stub-segv-handler at start of 127 /* faultinfo is prepared by the stub-segv-handler at start of
118 * the stub stack page. We just have to copy it. 128 * the stub stack page. We just have to copy it.
@@ -304,10 +314,13 @@ void userspace(union uml_pt_regs *regs)
304 UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ 314 UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */
305 315
306 if(WIFSTOPPED(status)){ 316 if(WIFSTOPPED(status)){
307 switch(WSTOPSIG(status)){ 317 int sig = WSTOPSIG(status);
318 switch(sig){
308 case SIGSEGV: 319 case SIGSEGV:
309 if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo) 320 if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo){
310 user_signal(SIGSEGV, regs, pid); 321 get_skas_faultinfo(pid, &regs->skas.faultinfo);
322 (*sig_info[SIGSEGV])(SIGSEGV, regs);
323 }
311 else handle_segv(pid, regs); 324 else handle_segv(pid, regs);
312 break; 325 break;
313 case SIGTRAP + 0x80: 326 case SIGTRAP + 0x80:
@@ -322,11 +335,13 @@ void userspace(union uml_pt_regs *regs)
322 case SIGBUS: 335 case SIGBUS:
323 case SIGFPE: 336 case SIGFPE:
324 case SIGWINCH: 337 case SIGWINCH:
325 user_signal(WSTOPSIG(status), regs, pid); 338 block_signals();
339 (*sig_info[sig])(sig, regs);
340 unblock_signals();
326 break; 341 break;
327 default: 342 default:
328 printk("userspace - child stopped with signal " 343 printk("userspace - child stopped with signal "
329 "%d\n", WSTOPSIG(status)); 344 "%d\n", sig);
330 } 345 }
331 pid = userspace_pid[0]; 346 pid = userspace_pid[0];
332 interrupt_end(); 347 interrupt_end();
@@ -338,11 +353,29 @@ void userspace(union uml_pt_regs *regs)
338 } 353 }
339} 354}
340 355
356static unsigned long thread_regs[MAX_REG_NR];
357static unsigned long thread_fp_regs[HOST_FP_SIZE];
358
359static int __init init_thread_regs(void)
360{
361 get_safe_registers(thread_regs, thread_fp_regs);
362 /* Set parent's instruction pointer to start of clone-stub */
363 thread_regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
364 (unsigned long) stub_clone_handler -
365 (unsigned long) &__syscall_stub_start;
366 thread_regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
367 sizeof(void *);
368#ifdef __SIGNAL_FRAMESIZE
369 thread_regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
370#endif
371 return 0;
372}
373
374__initcall(init_thread_regs);
375
341int copy_context_skas0(unsigned long new_stack, int pid) 376int copy_context_skas0(unsigned long new_stack, int pid)
342{ 377{
343 int err; 378 int err;
344 unsigned long regs[MAX_REG_NR];
345 unsigned long fp_regs[HOST_FP_SIZE];
346 unsigned long current_stack = current_stub_stack(); 379 unsigned long current_stack = current_stub_stack();
347 struct stub_data *data = (struct stub_data *) current_stack; 380 struct stub_data *data = (struct stub_data *) current_stack;
348 struct stub_data *child_data = (struct stub_data *) new_stack; 381 struct stub_data *child_data = (struct stub_data *) new_stack;
@@ -357,23 +390,12 @@ int copy_context_skas0(unsigned long new_stack, int pid)
357 .timer = ((struct itimerval) 390 .timer = ((struct itimerval)
358 { { 0, 1000000 / hz() }, 391 { { 0, 1000000 / hz() },
359 { 0, 1000000 / hz() }})}); 392 { 0, 1000000 / hz() }})});
360 get_safe_registers(regs, fp_regs); 393 err = ptrace_setregs(pid, thread_regs);
361
362 /* Set parent's instruction pointer to start of clone-stub */
363 regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
364 (unsigned long) stub_clone_handler -
365 (unsigned long) &__syscall_stub_start;
366 regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
367 sizeof(void *);
368#ifdef __SIGNAL_FRAMESIZE
369 regs[REGS_SP_INDEX] -= __SIGNAL_FRAMESIZE;
370#endif
371 err = ptrace_setregs(pid, regs);
372 if(err < 0) 394 if(err < 0)
373 panic("copy_context_skas0 : PTRACE_SETREGS failed, " 395 panic("copy_context_skas0 : PTRACE_SETREGS failed, "
374 "pid = %d, errno = %d\n", pid, -err); 396 "pid = %d, errno = %d\n", pid, -err);
375 397
376 err = ptrace_setfpregs(pid, fp_regs); 398 err = ptrace_setfpregs(pid, thread_fp_regs);
377 if(err < 0) 399 if(err < 0)
378 panic("copy_context_skas0 : PTRACE_SETFPREGS failed, " 400 panic("copy_context_skas0 : PTRACE_SETFPREGS failed, "
379 "pid = %d, errno = %d\n", pid, -err); 401 "pid = %d, errno = %d\n", pid, -err);
@@ -384,7 +406,11 @@ int copy_context_skas0(unsigned long new_stack, int pid)
384 /* Wait, until parent has finished its work: read child's pid from 406 /* Wait, until parent has finished its work: read child's pid from
385 * parent's stack, and check, if bad result. 407 * parent's stack, and check, if bad result.
386 */ 408 */
387 wait_stub_done(pid, 0, "copy_context_skas0"); 409 err = ptrace(PTRACE_CONT, pid, 0, 0);
410 if(err)
411 panic("Failed to continue new process, pid = %d, "
412 "errno = %d\n", pid, errno);
413 wait_stub_done(pid);
388 414
389 pid = data->err; 415 pid = data->err;
390 if(pid < 0) 416 if(pid < 0)
@@ -394,7 +420,7 @@ int copy_context_skas0(unsigned long new_stack, int pid)
394 /* Wait, until child has finished too: read child's result from 420 /* Wait, until child has finished too: read child's result from
395 * child's stack and check it. 421 * child's stack and check it.
396 */ 422 */
397 wait_stub_done(pid, -1, "copy_context_skas0"); 423 wait_stub_done(pid);
398 if (child_data->err != UML_CONFIG_STUB_DATA) 424 if (child_data->err != UML_CONFIG_STUB_DATA)
399 panic("copy_context_skas0 - stub-child reports error %ld\n", 425 panic("copy_context_skas0 - stub-child reports error %ld\n",
400 child_data->err); 426 child_data->err);
diff --git a/arch/um/os-Linux/skas/trap.c b/arch/um/os-Linux/skas/trap.c
index 5110eff51b90..3b600c2e63b8 100644
--- a/arch/um/os-Linux/skas/trap.c
+++ b/arch/um/os-Linux/skas/trap.c
@@ -64,20 +64,3 @@ void sig_handler_common_skas(int sig, void *sc_ptr)
64 errno = save_errno; 64 errno = save_errno;
65 r->skas.is_user = save_user; 65 r->skas.is_user = save_user;
66} 66}
67
68extern int ptrace_faultinfo;
69
70void user_signal(int sig, union uml_pt_regs *regs, int pid)
71{
72 void (*handler)(int, union uml_pt_regs *);
73 int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
74 (sig == SIGILL) || (sig == SIGTRAP));
75
76 if (segv)
77 get_skas_faultinfo(pid, &regs->skas.faultinfo);
78
79 handler = sig_info[sig];
80 handler(sig, (union uml_pt_regs *) regs);
81
82 unblock_signals();
83}