diff options
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/Kconfig.x86 | 4 | ||||
-rw-r--r-- | arch/um/Makefile | 2 | ||||
-rw-r--r-- | arch/um/drivers/line.c | 61 | ||||
-rw-r--r-- | arch/um/drivers/xterm.c | 1 | ||||
-rw-r--r-- | arch/um/include/asm/ptrace-generic.h | 4 | ||||
-rw-r--r-- | arch/um/include/shared/line.h | 1 | ||||
-rw-r--r-- | arch/um/include/shared/registers.h | 2 | ||||
-rw-r--r-- | arch/um/kernel/process.c | 2 | ||||
-rw-r--r-- | arch/um/kernel/ptrace.c | 28 | ||||
-rw-r--r-- | arch/um/os-Linux/registers.c | 9 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/mem.c | 2 | ||||
-rw-r--r-- | arch/um/os-Linux/skas/process.c | 19 | ||||
-rw-r--r-- | arch/um/sys-i386/asm/ptrace.h | 5 | ||||
-rw-r--r-- | arch/um/sys-i386/ptrace.c | 28 | ||||
-rw-r--r-- | arch/um/sys-i386/shared/sysdep/ptrace.h | 1 | ||||
-rw-r--r-- | arch/um/sys-x86_64/ptrace.c | 12 | ||||
-rw-r--r-- | arch/um/sys-x86_64/shared/sysdep/ptrace.h | 1 |
17 files changed, 105 insertions, 77 deletions
diff --git a/arch/um/Kconfig.x86 b/arch/um/Kconfig.x86 index d31ecf346b4e..21bebe63df66 100644 --- a/arch/um/Kconfig.x86 +++ b/arch/um/Kconfig.x86 | |||
@@ -10,6 +10,10 @@ config CMPXCHG_LOCAL | |||
10 | bool | 10 | bool |
11 | default n | 11 | default n |
12 | 12 | ||
13 | config CMPXCHG_DOUBLE | ||
14 | bool | ||
15 | default n | ||
16 | |||
13 | source "arch/x86/Kconfig.cpu" | 17 | source "arch/x86/Kconfig.cpu" |
14 | 18 | ||
15 | endmenu | 19 | endmenu |
diff --git a/arch/um/Makefile b/arch/um/Makefile index fab8121d2b32..c0f712cc7c5f 100644 --- a/arch/um/Makefile +++ b/arch/um/Makefile | |||
@@ -41,7 +41,7 @@ KBUILD_CPPFLAGS += -I$(srctree)/$(ARCH_DIR)/sys-$(SUBARCH) | |||
41 | KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ | 41 | KBUILD_CFLAGS += $(CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ |
42 | $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ | 42 | $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap \ |
43 | -Din6addr_loopback=kernel_in6addr_loopback \ | 43 | -Din6addr_loopback=kernel_in6addr_loopback \ |
44 | -Din6addr_any=kernel_in6addr_any | 44 | -Din6addr_any=kernel_in6addr_any -Dstrrchr=kernel_strrchr |
45 | 45 | ||
46 | KBUILD_AFLAGS += $(ARCH_INCLUDE) | 46 | KBUILD_AFLAGS += $(ARCH_INCLUDE) |
47 | 47 | ||
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index d51c404239a8..364c8a15c4c3 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -399,8 +399,8 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data) | |||
399 | * is done under a spinlock. Checking whether the device is in use is | 399 | * is done under a spinlock. Checking whether the device is in use is |
400 | * line->tty->count > 1, also under the spinlock. | 400 | * line->tty->count > 1, also under the spinlock. |
401 | * | 401 | * |
402 | * tty->count serves to decide whether the device should be enabled or | 402 | * line->count serves to decide whether the device should be enabled or |
403 | * disabled on the host. If it's equal to 1, then we are doing the | 403 | * disabled on the host. If it's equal to 0, then we are doing the |
404 | * first open or last close. Otherwise, open and close just return. | 404 | * first open or last close. Otherwise, open and close just return. |
405 | */ | 405 | */ |
406 | 406 | ||
@@ -414,16 +414,16 @@ int line_open(struct line *lines, struct tty_struct *tty) | |||
414 | goto out_unlock; | 414 | goto out_unlock; |
415 | 415 | ||
416 | err = 0; | 416 | err = 0; |
417 | if (tty->count > 1) | 417 | if (line->count++) |
418 | goto out_unlock; | 418 | goto out_unlock; |
419 | 419 | ||
420 | spin_unlock(&line->count_lock); | 420 | BUG_ON(tty->driver_data); |
421 | |||
422 | tty->driver_data = line; | 421 | tty->driver_data = line; |
423 | line->tty = tty; | 422 | line->tty = tty; |
424 | 423 | ||
424 | spin_unlock(&line->count_lock); | ||
425 | err = enable_chan(line); | 425 | err = enable_chan(line); |
426 | if (err) | 426 | if (err) /* line_close() will be called by our caller */ |
427 | return err; | 427 | return err; |
428 | 428 | ||
429 | INIT_DELAYED_WORK(&line->task, line_timer_cb); | 429 | INIT_DELAYED_WORK(&line->task, line_timer_cb); |
@@ -436,7 +436,7 @@ int line_open(struct line *lines, struct tty_struct *tty) | |||
436 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, | 436 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, |
437 | &tty->winsize.ws_col); | 437 | &tty->winsize.ws_col); |
438 | 438 | ||
439 | return err; | 439 | return 0; |
440 | 440 | ||
441 | out_unlock: | 441 | out_unlock: |
442 | spin_unlock(&line->count_lock); | 442 | spin_unlock(&line->count_lock); |
@@ -460,17 +460,16 @@ void line_close(struct tty_struct *tty, struct file * filp) | |||
460 | flush_buffer(line); | 460 | flush_buffer(line); |
461 | 461 | ||
462 | spin_lock(&line->count_lock); | 462 | spin_lock(&line->count_lock); |
463 | if (!line->valid) | 463 | BUG_ON(!line->valid); |
464 | goto out_unlock; | ||
465 | 464 | ||
466 | if (tty->count > 1) | 465 | if (--line->count) |
467 | goto out_unlock; | 466 | goto out_unlock; |
468 | 467 | ||
469 | spin_unlock(&line->count_lock); | ||
470 | |||
471 | line->tty = NULL; | 468 | line->tty = NULL; |
472 | tty->driver_data = NULL; | 469 | tty->driver_data = NULL; |
473 | 470 | ||
471 | spin_unlock(&line->count_lock); | ||
472 | |||
474 | if (line->sigio) { | 473 | if (line->sigio) { |
475 | unregister_winch(tty); | 474 | unregister_winch(tty); |
476 | line->sigio = 0; | 475 | line->sigio = 0; |
@@ -498,7 +497,7 @@ static int setup_one_line(struct line *lines, int n, char *init, int init_prio, | |||
498 | 497 | ||
499 | spin_lock(&line->count_lock); | 498 | spin_lock(&line->count_lock); |
500 | 499 | ||
501 | if (line->tty != NULL) { | 500 | if (line->count) { |
502 | *error_out = "Device is already open"; | 501 | *error_out = "Device is already open"; |
503 | goto out; | 502 | goto out; |
504 | } | 503 | } |
@@ -722,41 +721,53 @@ struct winch { | |||
722 | int pid; | 721 | int pid; |
723 | struct tty_struct *tty; | 722 | struct tty_struct *tty; |
724 | unsigned long stack; | 723 | unsigned long stack; |
724 | struct work_struct work; | ||
725 | }; | 725 | }; |
726 | 726 | ||
727 | static void free_winch(struct winch *winch, int free_irq_ok) | 727 | static void __free_winch(struct work_struct *work) |
728 | { | 728 | { |
729 | if (free_irq_ok) | 729 | struct winch *winch = container_of(work, struct winch, work); |
730 | free_irq(WINCH_IRQ, winch); | 730 | free_irq(WINCH_IRQ, winch); |
731 | |||
732 | list_del(&winch->list); | ||
733 | 731 | ||
734 | if (winch->pid != -1) | 732 | if (winch->pid != -1) |
735 | os_kill_process(winch->pid, 1); | 733 | os_kill_process(winch->pid, 1); |
736 | if (winch->fd != -1) | ||
737 | os_close_file(winch->fd); | ||
738 | if (winch->stack != 0) | 734 | if (winch->stack != 0) |
739 | free_stack(winch->stack, 0); | 735 | free_stack(winch->stack, 0); |
740 | kfree(winch); | 736 | kfree(winch); |
741 | } | 737 | } |
742 | 738 | ||
739 | static void free_winch(struct winch *winch) | ||
740 | { | ||
741 | int fd = winch->fd; | ||
742 | winch->fd = -1; | ||
743 | if (fd != -1) | ||
744 | os_close_file(fd); | ||
745 | list_del(&winch->list); | ||
746 | __free_winch(&winch->work); | ||
747 | } | ||
748 | |||
743 | static irqreturn_t winch_interrupt(int irq, void *data) | 749 | static irqreturn_t winch_interrupt(int irq, void *data) |
744 | { | 750 | { |
745 | struct winch *winch = data; | 751 | struct winch *winch = data; |
746 | struct tty_struct *tty; | 752 | struct tty_struct *tty; |
747 | struct line *line; | 753 | struct line *line; |
754 | int fd = winch->fd; | ||
748 | int err; | 755 | int err; |
749 | char c; | 756 | char c; |
750 | 757 | ||
751 | if (winch->fd != -1) { | 758 | if (fd != -1) { |
752 | err = generic_read(winch->fd, &c, NULL); | 759 | err = generic_read(fd, &c, NULL); |
753 | if (err < 0) { | 760 | if (err < 0) { |
754 | if (err != -EAGAIN) { | 761 | if (err != -EAGAIN) { |
762 | winch->fd = -1; | ||
763 | list_del(&winch->list); | ||
764 | os_close_file(fd); | ||
755 | printk(KERN_ERR "winch_interrupt : " | 765 | printk(KERN_ERR "winch_interrupt : " |
756 | "read failed, errno = %d\n", -err); | 766 | "read failed, errno = %d\n", -err); |
757 | printk(KERN_ERR "fd %d is losing SIGWINCH " | 767 | printk(KERN_ERR "fd %d is losing SIGWINCH " |
758 | "support\n", winch->tty_fd); | 768 | "support\n", winch->tty_fd); |
759 | free_winch(winch, 0); | 769 | INIT_WORK(&winch->work, __free_winch); |
770 | schedule_work(&winch->work); | ||
760 | return IRQ_HANDLED; | 771 | return IRQ_HANDLED; |
761 | } | 772 | } |
762 | goto out; | 773 | goto out; |
@@ -828,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty) | |||
828 | list_for_each_safe(ele, next, &winch_handlers) { | 839 | list_for_each_safe(ele, next, &winch_handlers) { |
829 | winch = list_entry(ele, struct winch, list); | 840 | winch = list_entry(ele, struct winch, list); |
830 | if (winch->tty == tty) { | 841 | if (winch->tty == tty) { |
831 | free_winch(winch, 1); | 842 | free_winch(winch); |
832 | break; | 843 | break; |
833 | } | 844 | } |
834 | } | 845 | } |
@@ -844,7 +855,7 @@ static void winch_cleanup(void) | |||
844 | 855 | ||
845 | list_for_each_safe(ele, next, &winch_handlers) { | 856 | list_for_each_safe(ele, next, &winch_handlers) { |
846 | winch = list_entry(ele, struct winch, list); | 857 | winch = list_entry(ele, struct winch, list); |
847 | free_winch(winch, 1); | 858 | free_winch(winch); |
848 | } | 859 | } |
849 | 860 | ||
850 | spin_unlock(&winch_handler_lock); | 861 | spin_unlock(&winch_handler_lock); |
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 8ac7146c237f..2e1de5728604 100644 --- a/arch/um/drivers/xterm.c +++ b/arch/um/drivers/xterm.c | |||
@@ -123,6 +123,7 @@ static int xterm_open(int input, int output, int primary, void *d, | |||
123 | err = -errno; | 123 | err = -errno; |
124 | printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n", | 124 | printk(UM_KERN_ERR "xterm_open : unlink failed, errno = %d\n", |
125 | errno); | 125 | errno); |
126 | close(fd); | ||
126 | return err; | 127 | return err; |
127 | } | 128 | } |
128 | close(fd); | 129 | close(fd); |
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h index ae084ad1a3a0..1a7d2757fe05 100644 --- a/arch/um/include/asm/ptrace-generic.h +++ b/arch/um/include/asm/ptrace-generic.h | |||
@@ -42,10 +42,6 @@ extern long subarch_ptrace(struct task_struct *child, long request, | |||
42 | unsigned long addr, unsigned long data); | 42 | unsigned long addr, unsigned long data); |
43 | extern unsigned long getreg(struct task_struct *child, int regno); | 43 | extern unsigned long getreg(struct task_struct *child, int regno); |
44 | extern int putreg(struct task_struct *child, int regno, unsigned long value); | 44 | extern int putreg(struct task_struct *child, int regno, unsigned long value); |
45 | extern int get_fpregs(struct user_i387_struct __user *buf, | ||
46 | struct task_struct *child); | ||
47 | extern int set_fpregs(struct user_i387_struct __user *buf, | ||
48 | struct task_struct *child); | ||
49 | 45 | ||
50 | extern int arch_copy_tls(struct task_struct *new); | 46 | extern int arch_copy_tls(struct task_struct *new); |
51 | extern void clear_flushed_tls(struct task_struct *task); | 47 | extern void clear_flushed_tls(struct task_struct *task); |
diff --git a/arch/um/include/shared/line.h b/arch/um/include/shared/line.h index 72f4f25af247..63df3ca02ac2 100644 --- a/arch/um/include/shared/line.h +++ b/arch/um/include/shared/line.h | |||
@@ -33,6 +33,7 @@ struct line_driver { | |||
33 | struct line { | 33 | struct line { |
34 | struct tty_struct *tty; | 34 | struct tty_struct *tty; |
35 | spinlock_t count_lock; | 35 | spinlock_t count_lock; |
36 | unsigned long count; | ||
36 | int valid; | 37 | int valid; |
37 | 38 | ||
38 | char *init_str; | 39 | char *init_str; |
diff --git a/arch/um/include/shared/registers.h b/arch/um/include/shared/registers.h index b0b4589e0ebc..f1e0aa56c52a 100644 --- a/arch/um/include/shared/registers.h +++ b/arch/um/include/shared/registers.h | |||
@@ -16,7 +16,7 @@ extern int restore_fpx_registers(int pid, unsigned long *fp_regs); | |||
16 | extern int save_registers(int pid, struct uml_pt_regs *regs); | 16 | extern int save_registers(int pid, struct uml_pt_regs *regs); |
17 | extern int restore_registers(int pid, struct uml_pt_regs *regs); | 17 | extern int restore_registers(int pid, struct uml_pt_regs *regs); |
18 | extern int init_registers(int pid); | 18 | extern int init_registers(int pid); |
19 | extern void get_safe_registers(unsigned long *regs); | 19 | extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs); |
20 | extern unsigned long get_thread_reg(int reg, jmp_buf *buf); | 20 | extern unsigned long get_thread_reg(int reg, jmp_buf *buf); |
21 | extern int get_fp_registers(int pid, unsigned long *regs); | 21 | extern int get_fp_registers(int pid, unsigned long *regs); |
22 | extern int put_fp_registers(int pid, unsigned long *regs); | 22 | extern int put_fp_registers(int pid, unsigned long *regs); |
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index fab4371184f6..21c1ae7c3d75 100644 --- a/arch/um/kernel/process.c +++ b/arch/um/kernel/process.c | |||
@@ -202,7 +202,7 @@ int copy_thread(unsigned long clone_flags, unsigned long sp, | |||
202 | arch_copy_thread(¤t->thread.arch, &p->thread.arch); | 202 | arch_copy_thread(¤t->thread.arch, &p->thread.arch); |
203 | } | 203 | } |
204 | else { | 204 | else { |
205 | get_safe_registers(p->thread.regs.regs.gp); | 205 | get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp); |
206 | p->thread.request.u.thread = current->thread.request.u.thread; | 206 | p->thread.request.u.thread = current->thread.request.u.thread; |
207 | handler = new_thread_handler; | 207 | handler = new_thread_handler; |
208 | } | 208 | } |
diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 701b672c1122..c9da32b0c707 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c | |||
@@ -50,23 +50,11 @@ long arch_ptrace(struct task_struct *child, long request, | |||
50 | void __user *vp = p; | 50 | void __user *vp = p; |
51 | 51 | ||
52 | switch (request) { | 52 | switch (request) { |
53 | /* read word at location addr. */ | ||
54 | case PTRACE_PEEKTEXT: | ||
55 | case PTRACE_PEEKDATA: | ||
56 | ret = generic_ptrace_peekdata(child, addr, data); | ||
57 | break; | ||
58 | |||
59 | /* read the word at location addr in the USER area. */ | 53 | /* read the word at location addr in the USER area. */ |
60 | case PTRACE_PEEKUSR: | 54 | case PTRACE_PEEKUSR: |
61 | ret = peek_user(child, addr, data); | 55 | ret = peek_user(child, addr, data); |
62 | break; | 56 | break; |
63 | 57 | ||
64 | /* write the word at location addr. */ | ||
65 | case PTRACE_POKETEXT: | ||
66 | case PTRACE_POKEDATA: | ||
67 | ret = generic_ptrace_pokedata(child, addr, data); | ||
68 | break; | ||
69 | |||
70 | /* write the word at location addr in the USER area */ | 58 | /* write the word at location addr in the USER area */ |
71 | case PTRACE_POKEUSR: | 59 | case PTRACE_POKEUSR: |
72 | ret = poke_user(child, addr, data); | 60 | ret = poke_user(child, addr, data); |
@@ -107,16 +95,6 @@ long arch_ptrace(struct task_struct *child, long request, | |||
107 | break; | 95 | break; |
108 | } | 96 | } |
109 | #endif | 97 | #endif |
110 | #ifdef PTRACE_GETFPREGS | ||
111 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ | ||
112 | ret = get_fpregs(vp, child); | ||
113 | break; | ||
114 | #endif | ||
115 | #ifdef PTRACE_SETFPREGS | ||
116 | case PTRACE_SETFPREGS: /* Set the child FPU state. */ | ||
117 | ret = set_fpregs(vp, child); | ||
118 | break; | ||
119 | #endif | ||
120 | case PTRACE_GET_THREAD_AREA: | 98 | case PTRACE_GET_THREAD_AREA: |
121 | ret = ptrace_get_thread_area(child, addr, vp); | 99 | ret = ptrace_get_thread_area(child, addr, vp); |
122 | break; | 100 | break; |
@@ -154,12 +132,6 @@ long arch_ptrace(struct task_struct *child, long request, | |||
154 | break; | 132 | break; |
155 | } | 133 | } |
156 | #endif | 134 | #endif |
157 | #ifdef PTRACE_ARCH_PRCTL | ||
158 | case PTRACE_ARCH_PRCTL: | ||
159 | /* XXX Calls ptrace on the host - needs some SMP thinking */ | ||
160 | ret = arch_prctl(child, data, (void __user *) addr); | ||
161 | break; | ||
162 | #endif | ||
163 | default: | 135 | default: |
164 | ret = ptrace_request(child, request, addr, data); | 136 | ret = ptrace_request(child, request, addr, data); |
165 | if (ret == -EIO) | 137 | if (ret == -EIO) |
diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c index 830fe6a1518a..b866b9e3bef9 100644 --- a/arch/um/os-Linux/registers.c +++ b/arch/um/os-Linux/registers.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include <sys/ptrace.h> | 9 | #include <sys/ptrace.h> |
10 | #include "sysdep/ptrace.h" | 10 | #include "sysdep/ptrace.h" |
11 | #include "sysdep/ptrace_user.h" | ||
12 | #include "registers.h" | ||
11 | 13 | ||
12 | int save_registers(int pid, struct uml_pt_regs *regs) | 14 | int save_registers(int pid, struct uml_pt_regs *regs) |
13 | { | 15 | { |
@@ -32,6 +34,7 @@ int restore_registers(int pid, struct uml_pt_regs *regs) | |||
32 | /* This is set once at boot time and not changed thereafter */ | 34 | /* This is set once at boot time and not changed thereafter */ |
33 | 35 | ||
34 | static unsigned long exec_regs[MAX_REG_NR]; | 36 | static unsigned long exec_regs[MAX_REG_NR]; |
37 | static unsigned long exec_fp_regs[FP_SIZE]; | ||
35 | 38 | ||
36 | int init_registers(int pid) | 39 | int init_registers(int pid) |
37 | { | 40 | { |
@@ -42,10 +45,14 @@ int init_registers(int pid) | |||
42 | return -errno; | 45 | return -errno; |
43 | 46 | ||
44 | arch_init_registers(pid); | 47 | arch_init_registers(pid); |
48 | get_fp_registers(pid, exec_fp_regs); | ||
45 | return 0; | 49 | return 0; |
46 | } | 50 | } |
47 | 51 | ||
48 | void get_safe_registers(unsigned long *regs) | 52 | void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) |
49 | { | 53 | { |
50 | memcpy(regs, exec_regs, sizeof(exec_regs)); | 54 | memcpy(regs, exec_regs, sizeof(exec_regs)); |
55 | |||
56 | if (fp_regs) | ||
57 | memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs)); | ||
51 | } | 58 | } |
diff --git a/arch/um/os-Linux/skas/mem.c b/arch/um/os-Linux/skas/mem.c index d261f170d120..e771398be5f3 100644 --- a/arch/um/os-Linux/skas/mem.c +++ b/arch/um/os-Linux/skas/mem.c | |||
@@ -39,7 +39,7 @@ static unsigned long syscall_regs[MAX_REG_NR]; | |||
39 | 39 | ||
40 | static int __init init_syscall_regs(void) | 40 | static int __init init_syscall_regs(void) |
41 | { | 41 | { |
42 | get_safe_registers(syscall_regs); | 42 | get_safe_registers(syscall_regs, NULL); |
43 | syscall_regs[REGS_IP_INDEX] = STUB_CODE + | 43 | syscall_regs[REGS_IP_INDEX] = STUB_CODE + |
44 | ((unsigned long) &batch_syscall_stub - | 44 | ((unsigned long) &batch_syscall_stub - |
45 | (unsigned long) &__syscall_stub_start); | 45 | (unsigned long) &__syscall_stub_start); |
diff --git a/arch/um/os-Linux/skas/process.c b/arch/um/os-Linux/skas/process.c index d6e0a2234b86..dee0e8cf8ad0 100644 --- a/arch/um/os-Linux/skas/process.c +++ b/arch/um/os-Linux/skas/process.c | |||
@@ -373,6 +373,9 @@ void userspace(struct uml_pt_regs *regs) | |||
373 | if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) | 373 | if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) |
374 | fatal_sigsegv(); | 374 | fatal_sigsegv(); |
375 | 375 | ||
376 | if (put_fp_registers(pid, regs->fp)) | ||
377 | fatal_sigsegv(); | ||
378 | |||
376 | /* Now we set local_using_sysemu to be used for one loop */ | 379 | /* Now we set local_using_sysemu to be used for one loop */ |
377 | local_using_sysemu = get_using_sysemu(); | 380 | local_using_sysemu = get_using_sysemu(); |
378 | 381 | ||
@@ -399,6 +402,12 @@ void userspace(struct uml_pt_regs *regs) | |||
399 | fatal_sigsegv(); | 402 | fatal_sigsegv(); |
400 | } | 403 | } |
401 | 404 | ||
405 | if (get_fp_registers(pid, regs->fp)) { | ||
406 | printk(UM_KERN_ERR "userspace - get_fp_registers failed, " | ||
407 | "errno = %d\n", errno); | ||
408 | fatal_sigsegv(); | ||
409 | } | ||
410 | |||
402 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ | 411 | UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ |
403 | 412 | ||
404 | if (WIFSTOPPED(status)) { | 413 | if (WIFSTOPPED(status)) { |
@@ -457,10 +466,11 @@ void userspace(struct uml_pt_regs *regs) | |||
457 | } | 466 | } |
458 | 467 | ||
459 | static unsigned long thread_regs[MAX_REG_NR]; | 468 | static unsigned long thread_regs[MAX_REG_NR]; |
469 | static unsigned long thread_fp_regs[FP_SIZE]; | ||
460 | 470 | ||
461 | static int __init init_thread_regs(void) | 471 | static int __init init_thread_regs(void) |
462 | { | 472 | { |
463 | get_safe_registers(thread_regs); | 473 | get_safe_registers(thread_regs, thread_fp_regs); |
464 | /* Set parent's instruction pointer to start of clone-stub */ | 474 | /* Set parent's instruction pointer to start of clone-stub */ |
465 | thread_regs[REGS_IP_INDEX] = STUB_CODE + | 475 | thread_regs[REGS_IP_INDEX] = STUB_CODE + |
466 | (unsigned long) stub_clone_handler - | 476 | (unsigned long) stub_clone_handler - |
@@ -503,6 +513,13 @@ int copy_context_skas0(unsigned long new_stack, int pid) | |||
503 | return err; | 513 | return err; |
504 | } | 514 | } |
505 | 515 | ||
516 | err = put_fp_registers(pid, thread_fp_regs); | ||
517 | if (err < 0) { | ||
518 | printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers " | ||
519 | "failed, pid = %d, err = %d\n", pid, err); | ||
520 | return err; | ||
521 | } | ||
522 | |||
506 | /* set a well known return code for detection of child write failure */ | 523 | /* set a well known return code for detection of child write failure */ |
507 | child_data->err = 12345678; | 524 | child_data->err = 12345678; |
508 | 525 | ||
diff --git a/arch/um/sys-i386/asm/ptrace.h b/arch/um/sys-i386/asm/ptrace.h index 0273e4d09af7..5d2a59112537 100644 --- a/arch/um/sys-i386/asm/ptrace.h +++ b/arch/um/sys-i386/asm/ptrace.h | |||
@@ -42,11 +42,6 @@ | |||
42 | */ | 42 | */ |
43 | struct user_desc; | 43 | struct user_desc; |
44 | 44 | ||
45 | extern int get_fpxregs(struct user_fxsr_struct __user *buf, | ||
46 | struct task_struct *child); | ||
47 | extern int set_fpxregs(struct user_fxsr_struct __user *buf, | ||
48 | struct task_struct *tsk); | ||
49 | |||
50 | extern int ptrace_get_thread_area(struct task_struct *child, int idx, | 45 | extern int ptrace_get_thread_area(struct task_struct *child, int idx, |
51 | struct user_desc __user *user_desc); | 46 | struct user_desc __user *user_desc); |
52 | 47 | ||
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index d23b2d3ea384..3375c2717851 100644 --- a/arch/um/sys-i386/ptrace.c +++ b/arch/um/sys-i386/ptrace.c | |||
@@ -145,7 +145,7 @@ int peek_user(struct task_struct *child, long addr, long data) | |||
145 | return put_user(tmp, (unsigned long __user *) data); | 145 | return put_user(tmp, (unsigned long __user *) data); |
146 | } | 146 | } |
147 | 147 | ||
148 | int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | 148 | static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) |
149 | { | 149 | { |
150 | int err, n, cpu = ((struct thread_info *) child->stack)->cpu; | 150 | int err, n, cpu = ((struct thread_info *) child->stack)->cpu; |
151 | struct user_i387_struct fpregs; | 151 | struct user_i387_struct fpregs; |
@@ -161,7 +161,7 @@ int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | |||
161 | return n; | 161 | return n; |
162 | } | 162 | } |
163 | 163 | ||
164 | int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | 164 | static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) |
165 | { | 165 | { |
166 | int n, cpu = ((struct thread_info *) child->stack)->cpu; | 166 | int n, cpu = ((struct thread_info *) child->stack)->cpu; |
167 | struct user_i387_struct fpregs; | 167 | struct user_i387_struct fpregs; |
@@ -174,7 +174,7 @@ int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | |||
174 | (unsigned long *) &fpregs); | 174 | (unsigned long *) &fpregs); |
175 | } | 175 | } |
176 | 176 | ||
177 | int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) | 177 | static int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) |
178 | { | 178 | { |
179 | int err, n, cpu = ((struct thread_info *) child->stack)->cpu; | 179 | int err, n, cpu = ((struct thread_info *) child->stack)->cpu; |
180 | struct user_fxsr_struct fpregs; | 180 | struct user_fxsr_struct fpregs; |
@@ -190,7 +190,7 @@ int get_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) | |||
190 | return n; | 190 | return n; |
191 | } | 191 | } |
192 | 192 | ||
193 | int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) | 193 | static int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) |
194 | { | 194 | { |
195 | int n, cpu = ((struct thread_info *) child->stack)->cpu; | 195 | int n, cpu = ((struct thread_info *) child->stack)->cpu; |
196 | struct user_fxsr_struct fpregs; | 196 | struct user_fxsr_struct fpregs; |
@@ -206,5 +206,23 @@ int set_fpxregs(struct user_fxsr_struct __user *buf, struct task_struct *child) | |||
206 | long subarch_ptrace(struct task_struct *child, long request, | 206 | long subarch_ptrace(struct task_struct *child, long request, |
207 | unsigned long addr, unsigned long data) | 207 | unsigned long addr, unsigned long data) |
208 | { | 208 | { |
209 | return -EIO; | 209 | int ret = -EIO; |
210 | void __user *datap = (void __user *) data; | ||
211 | switch (request) { | ||
212 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ | ||
213 | ret = get_fpregs(datap, child); | ||
214 | break; | ||
215 | case PTRACE_SETFPREGS: /* Set the child FPU state. */ | ||
216 | ret = set_fpregs(datap, child); | ||
217 | break; | ||
218 | case PTRACE_GETFPXREGS: /* Get the child FPU state. */ | ||
219 | ret = get_fpxregs(datap, child); | ||
220 | break; | ||
221 | case PTRACE_SETFPXREGS: /* Set the child FPU state. */ | ||
222 | ret = set_fpxregs(datap, child); | ||
223 | break; | ||
224 | default: | ||
225 | ret = -EIO; | ||
226 | } | ||
227 | return ret; | ||
210 | } | 228 | } |
diff --git a/arch/um/sys-i386/shared/sysdep/ptrace.h b/arch/um/sys-i386/shared/sysdep/ptrace.h index d50e62e07070..c398a5076111 100644 --- a/arch/um/sys-i386/shared/sysdep/ptrace.h +++ b/arch/um/sys-i386/shared/sysdep/ptrace.h | |||
@@ -53,6 +53,7 @@ extern int sysemu_supported; | |||
53 | 53 | ||
54 | struct uml_pt_regs { | 54 | struct uml_pt_regs { |
55 | unsigned long gp[MAX_REG_NR]; | 55 | unsigned long gp[MAX_REG_NR]; |
56 | unsigned long fp[HOST_FPX_SIZE]; | ||
56 | struct faultinfo faultinfo; | 57 | struct faultinfo faultinfo; |
57 | long syscall; | 58 | long syscall; |
58 | int is_user; | 59 | int is_user; |
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index f43613643cdb..4005506834fd 100644 --- a/arch/um/sys-x86_64/ptrace.c +++ b/arch/um/sys-x86_64/ptrace.c | |||
@@ -145,7 +145,7 @@ int is_syscall(unsigned long addr) | |||
145 | return instr == 0x050f; | 145 | return instr == 0x050f; |
146 | } | 146 | } |
147 | 147 | ||
148 | int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | 148 | static int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) |
149 | { | 149 | { |
150 | int err, n, cpu = ((struct thread_info *) child->stack)->cpu; | 150 | int err, n, cpu = ((struct thread_info *) child->stack)->cpu; |
151 | long fpregs[HOST_FP_SIZE]; | 151 | long fpregs[HOST_FP_SIZE]; |
@@ -162,7 +162,7 @@ int get_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | |||
162 | return n; | 162 | return n; |
163 | } | 163 | } |
164 | 164 | ||
165 | int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) | 165 | static int set_fpregs(struct user_i387_struct __user *buf, struct task_struct *child) |
166 | { | 166 | { |
167 | int n, cpu = ((struct thread_info *) child->stack)->cpu; | 167 | int n, cpu = ((struct thread_info *) child->stack)->cpu; |
168 | long fpregs[HOST_FP_SIZE]; | 168 | long fpregs[HOST_FP_SIZE]; |
@@ -182,12 +182,16 @@ long subarch_ptrace(struct task_struct *child, long request, | |||
182 | void __user *datap = (void __user *) data; | 182 | void __user *datap = (void __user *) data; |
183 | 183 | ||
184 | switch (request) { | 184 | switch (request) { |
185 | case PTRACE_GETFPXREGS: /* Get the child FPU state. */ | 185 | case PTRACE_GETFPREGS: /* Get the child FPU state. */ |
186 | ret = get_fpregs(datap, child); | 186 | ret = get_fpregs(datap, child); |
187 | break; | 187 | break; |
188 | case PTRACE_SETFPXREGS: /* Set the child FPU state. */ | 188 | case PTRACE_SETFPREGS: /* Set the child FPU state. */ |
189 | ret = set_fpregs(datap, child); | 189 | ret = set_fpregs(datap, child); |
190 | break; | 190 | break; |
191 | case PTRACE_ARCH_PRCTL: | ||
192 | /* XXX Calls ptrace on the host - needs some SMP thinking */ | ||
193 | ret = arch_prctl(child, data, (void __user *) addr); | ||
194 | break; | ||
191 | } | 195 | } |
192 | 196 | ||
193 | return ret; | 197 | return ret; |
diff --git a/arch/um/sys-x86_64/shared/sysdep/ptrace.h b/arch/um/sys-x86_64/shared/sysdep/ptrace.h index fdba5457947a..8ee8f8e12af1 100644 --- a/arch/um/sys-x86_64/shared/sysdep/ptrace.h +++ b/arch/um/sys-x86_64/shared/sysdep/ptrace.h | |||
@@ -85,6 +85,7 @@ | |||
85 | 85 | ||
86 | struct uml_pt_regs { | 86 | struct uml_pt_regs { |
87 | unsigned long gp[MAX_REG_NR]; | 87 | unsigned long gp[MAX_REG_NR]; |
88 | unsigned long fp[HOST_FP_SIZE]; | ||
88 | struct faultinfo faultinfo; | 89 | struct faultinfo faultinfo; |
89 | long syscall; | 90 | long syscall; |
90 | int is_user; | 91 | int is_user; |