diff options
Diffstat (limited to 'arch/um')
52 files changed, 743 insertions, 174 deletions
diff --git a/arch/um/Kconfig.x86 b/arch/um/Kconfig.x86 index 8aae429a56e..21bebe63df6 100644 --- a/arch/um/Kconfig.x86 +++ b/arch/um/Kconfig.x86 | |||
@@ -1,3 +1,5 @@ | |||
1 | mainmenu "User Mode Linux/$SUBARCH $KERNELVERSION Kernel Configuration" | ||
2 | |||
1 | source "arch/um/Kconfig.common" | 3 | source "arch/um/Kconfig.common" |
2 | 4 | ||
3 | menu "UML-specific options" | 5 | menu "UML-specific options" |
@@ -8,6 +10,10 @@ config CMPXCHG_LOCAL | |||
8 | bool | 10 | bool |
9 | default n | 11 | default n |
10 | 12 | ||
13 | config CMPXCHG_DOUBLE | ||
14 | bool | ||
15 | default n | ||
16 | |||
11 | source "arch/x86/Kconfig.cpu" | 17 | source "arch/x86/Kconfig.cpu" |
12 | 18 | ||
13 | endmenu | 19 | endmenu |
diff --git a/arch/um/Makefile b/arch/um/Makefile index fab8121d2b3..c0f712cc7c5 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/chan_kern.c b/arch/um/drivers/chan_kern.c index 25e1965df7c..d4191fe1ced 100644 --- a/arch/um/drivers/chan_kern.c +++ b/arch/um/drivers/chan_kern.c | |||
@@ -543,11 +543,10 @@ int parse_chan_pair(char *str, struct line *line, int device, | |||
543 | const struct chan_opts *opts, char **error_out) | 543 | const struct chan_opts *opts, char **error_out) |
544 | { | 544 | { |
545 | struct list_head *chans = &line->chan_list; | 545 | struct list_head *chans = &line->chan_list; |
546 | struct chan *new, *chan; | 546 | struct chan *new; |
547 | char *in, *out; | 547 | char *in, *out; |
548 | 548 | ||
549 | if (!list_empty(chans)) { | 549 | if (!list_empty(chans)) { |
550 | chan = list_entry(chans->next, struct chan, list); | ||
551 | free_chan(chans, 0); | 550 | free_chan(chans, 0); |
552 | INIT_LIST_HEAD(chans); | 551 | INIT_LIST_HEAD(chans); |
553 | } | 552 | } |
diff --git a/arch/um/drivers/cow_user.c b/arch/um/drivers/cow_user.c index 93f227a25ba..9cbb426c0b9 100644 --- a/arch/um/drivers/cow_user.c +++ b/arch/um/drivers/cow_user.c | |||
@@ -186,7 +186,11 @@ static int absolutize(char *to, int size, char *from) | |||
186 | strcat(to, "/"); | 186 | strcat(to, "/"); |
187 | strcat(to, from); | 187 | strcat(to, from); |
188 | } | 188 | } |
189 | chdir(save_cwd); | 189 | if (chdir(save_cwd)) { |
190 | cow_printf("absolutize : Can't cd to '%s' - " | ||
191 | "errno = %d\n", save_cwd, errno); | ||
192 | return -1; | ||
193 | } | ||
190 | return 0; | 194 | return 0; |
191 | } | 195 | } |
192 | 196 | ||
diff --git a/arch/um/drivers/harddog_user.c b/arch/um/drivers/harddog_user.c index b56f8e0196a..84dce3fc590 100644 --- a/arch/um/drivers/harddog_user.c +++ b/arch/um/drivers/harddog_user.c | |||
@@ -32,7 +32,7 @@ int start_watchdog(int *in_fd_ret, int *out_fd_ret, char *sock) | |||
32 | { | 32 | { |
33 | struct dog_data data; | 33 | struct dog_data data; |
34 | int in_fds[2], out_fds[2], pid, n, err; | 34 | int in_fds[2], out_fds[2], pid, n, err; |
35 | char pid_buf[sizeof("nnnnn\0")], c; | 35 | char pid_buf[sizeof("nnnnnnn\0")], c; |
36 | char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; | 36 | char *pid_args[] = { "/usr/bin/uml_watchdog", "-pid", pid_buf, NULL }; |
37 | char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, | 37 | char *mconsole_args[] = { "/usr/bin/uml_watchdog", "-mconsole", NULL, |
38 | NULL }; | 38 | NULL }; |
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c index 35dd0b86401..364c8a15c4c 100644 --- a/arch/um/drivers/line.c +++ b/arch/um/drivers/line.c | |||
@@ -176,10 +176,9 @@ void line_flush_buffer(struct tty_struct *tty) | |||
176 | { | 176 | { |
177 | struct line *line = tty->driver_data; | 177 | struct line *line = tty->driver_data; |
178 | unsigned long flags; | 178 | unsigned long flags; |
179 | int err; | ||
180 | 179 | ||
181 | spin_lock_irqsave(&line->lock, flags); | 180 | spin_lock_irqsave(&line->lock, flags); |
182 | err = flush_buffer(line); | 181 | flush_buffer(line); |
183 | spin_unlock_irqrestore(&line->lock, flags); | 182 | spin_unlock_irqrestore(&line->lock, flags); |
184 | } | 183 | } |
185 | 184 | ||
@@ -400,8 +399,8 @@ int line_setup_irq(int fd, int input, int output, struct line *line, void *data) | |||
400 | * 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 |
401 | * line->tty->count > 1, also under the spinlock. | 400 | * line->tty->count > 1, also under the spinlock. |
402 | * | 401 | * |
403 | * 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 |
404 | * 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 |
405 | * first open or last close. Otherwise, open and close just return. | 404 | * first open or last close. Otherwise, open and close just return. |
406 | */ | 405 | */ |
407 | 406 | ||
@@ -415,16 +414,16 @@ int line_open(struct line *lines, struct tty_struct *tty) | |||
415 | goto out_unlock; | 414 | goto out_unlock; |
416 | 415 | ||
417 | err = 0; | 416 | err = 0; |
418 | if (tty->count > 1) | 417 | if (line->count++) |
419 | goto out_unlock; | 418 | goto out_unlock; |
420 | 419 | ||
421 | spin_unlock(&line->count_lock); | 420 | BUG_ON(tty->driver_data); |
422 | |||
423 | tty->driver_data = line; | 421 | tty->driver_data = line; |
424 | line->tty = tty; | 422 | line->tty = tty; |
425 | 423 | ||
424 | spin_unlock(&line->count_lock); | ||
426 | err = enable_chan(line); | 425 | err = enable_chan(line); |
427 | if (err) | 426 | if (err) /* line_close() will be called by our caller */ |
428 | return err; | 427 | return err; |
429 | 428 | ||
430 | INIT_DELAYED_WORK(&line->task, line_timer_cb); | 429 | INIT_DELAYED_WORK(&line->task, line_timer_cb); |
@@ -437,7 +436,7 @@ int line_open(struct line *lines, struct tty_struct *tty) | |||
437 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, | 436 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, |
438 | &tty->winsize.ws_col); | 437 | &tty->winsize.ws_col); |
439 | 438 | ||
440 | return err; | 439 | return 0; |
441 | 440 | ||
442 | out_unlock: | 441 | out_unlock: |
443 | spin_unlock(&line->count_lock); | 442 | spin_unlock(&line->count_lock); |
@@ -461,17 +460,16 @@ void line_close(struct tty_struct *tty, struct file * filp) | |||
461 | flush_buffer(line); | 460 | flush_buffer(line); |
462 | 461 | ||
463 | spin_lock(&line->count_lock); | 462 | spin_lock(&line->count_lock); |
464 | if (!line->valid) | 463 | BUG_ON(!line->valid); |
465 | goto out_unlock; | ||
466 | 464 | ||
467 | if (tty->count > 1) | 465 | if (--line->count) |
468 | goto out_unlock; | 466 | goto out_unlock; |
469 | 467 | ||
470 | spin_unlock(&line->count_lock); | ||
471 | |||
472 | line->tty = NULL; | 468 | line->tty = NULL; |
473 | tty->driver_data = NULL; | 469 | tty->driver_data = NULL; |
474 | 470 | ||
471 | spin_unlock(&line->count_lock); | ||
472 | |||
475 | if (line->sigio) { | 473 | if (line->sigio) { |
476 | unregister_winch(tty); | 474 | unregister_winch(tty); |
477 | line->sigio = 0; | 475 | line->sigio = 0; |
@@ -499,7 +497,7 @@ static int setup_one_line(struct line *lines, int n, char *init, int init_prio, | |||
499 | 497 | ||
500 | spin_lock(&line->count_lock); | 498 | spin_lock(&line->count_lock); |
501 | 499 | ||
502 | if (line->tty != NULL) { | 500 | if (line->count) { |
503 | *error_out = "Device is already open"; | 501 | *error_out = "Device is already open"; |
504 | goto out; | 502 | goto out; |
505 | } | 503 | } |
@@ -723,41 +721,53 @@ struct winch { | |||
723 | int pid; | 721 | int pid; |
724 | struct tty_struct *tty; | 722 | struct tty_struct *tty; |
725 | unsigned long stack; | 723 | unsigned long stack; |
724 | struct work_struct work; | ||
726 | }; | 725 | }; |
727 | 726 | ||
728 | static void free_winch(struct winch *winch, int free_irq_ok) | 727 | static void __free_winch(struct work_struct *work) |
729 | { | 728 | { |
730 | if (free_irq_ok) | 729 | struct winch *winch = container_of(work, struct winch, work); |
731 | free_irq(WINCH_IRQ, winch); | 730 | free_irq(WINCH_IRQ, winch); |
732 | |||
733 | list_del(&winch->list); | ||
734 | 731 | ||
735 | if (winch->pid != -1) | 732 | if (winch->pid != -1) |
736 | os_kill_process(winch->pid, 1); | 733 | os_kill_process(winch->pid, 1); |
737 | if (winch->fd != -1) | ||
738 | os_close_file(winch->fd); | ||
739 | if (winch->stack != 0) | 734 | if (winch->stack != 0) |
740 | free_stack(winch->stack, 0); | 735 | free_stack(winch->stack, 0); |
741 | kfree(winch); | 736 | kfree(winch); |
742 | } | 737 | } |
743 | 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 | |||
744 | static irqreturn_t winch_interrupt(int irq, void *data) | 749 | static irqreturn_t winch_interrupt(int irq, void *data) |
745 | { | 750 | { |
746 | struct winch *winch = data; | 751 | struct winch *winch = data; |
747 | struct tty_struct *tty; | 752 | struct tty_struct *tty; |
748 | struct line *line; | 753 | struct line *line; |
754 | int fd = winch->fd; | ||
749 | int err; | 755 | int err; |
750 | char c; | 756 | char c; |
751 | 757 | ||
752 | if (winch->fd != -1) { | 758 | if (fd != -1) { |
753 | err = generic_read(winch->fd, &c, NULL); | 759 | err = generic_read(fd, &c, NULL); |
754 | if (err < 0) { | 760 | if (err < 0) { |
755 | if (err != -EAGAIN) { | 761 | if (err != -EAGAIN) { |
762 | winch->fd = -1; | ||
763 | list_del(&winch->list); | ||
764 | os_close_file(fd); | ||
756 | printk(KERN_ERR "winch_interrupt : " | 765 | printk(KERN_ERR "winch_interrupt : " |
757 | "read failed, errno = %d\n", -err); | 766 | "read failed, errno = %d\n", -err); |
758 | printk(KERN_ERR "fd %d is losing SIGWINCH " | 767 | printk(KERN_ERR "fd %d is losing SIGWINCH " |
759 | "support\n", winch->tty_fd); | 768 | "support\n", winch->tty_fd); |
760 | free_winch(winch, 0); | 769 | INIT_WORK(&winch->work, __free_winch); |
770 | schedule_work(&winch->work); | ||
761 | return IRQ_HANDLED; | 771 | return IRQ_HANDLED; |
762 | } | 772 | } |
763 | goto out; | 773 | goto out; |
@@ -829,7 +839,7 @@ static void unregister_winch(struct tty_struct *tty) | |||
829 | list_for_each_safe(ele, next, &winch_handlers) { | 839 | list_for_each_safe(ele, next, &winch_handlers) { |
830 | winch = list_entry(ele, struct winch, list); | 840 | winch = list_entry(ele, struct winch, list); |
831 | if (winch->tty == tty) { | 841 | if (winch->tty == tty) { |
832 | free_winch(winch, 1); | 842 | free_winch(winch); |
833 | break; | 843 | break; |
834 | } | 844 | } |
835 | } | 845 | } |
@@ -845,7 +855,7 @@ static void winch_cleanup(void) | |||
845 | 855 | ||
846 | list_for_each_safe(ele, next, &winch_handlers) { | 856 | list_for_each_safe(ele, next, &winch_handlers) { |
847 | winch = list_entry(ele, struct winch, list); | 857 | winch = list_entry(ele, struct winch, list); |
848 | free_winch(winch, 1); | 858 | free_winch(winch); |
849 | } | 859 | } |
850 | 860 | ||
851 | spin_unlock(&winch_handler_lock); | 861 | spin_unlock(&winch_handler_lock); |
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 47d0c37897d..22745b47c82 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c | |||
@@ -262,6 +262,15 @@ static int uml_net_change_mtu(struct net_device *dev, int new_mtu) | |||
262 | return 0; | 262 | return 0; |
263 | } | 263 | } |
264 | 264 | ||
265 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
266 | static void uml_net_poll_controller(struct net_device *dev) | ||
267 | { | ||
268 | disable_irq(dev->irq); | ||
269 | uml_net_interrupt(dev->irq, dev); | ||
270 | enable_irq(dev->irq); | ||
271 | } | ||
272 | #endif | ||
273 | |||
265 | static void uml_net_get_drvinfo(struct net_device *dev, | 274 | static void uml_net_get_drvinfo(struct net_device *dev, |
266 | struct ethtool_drvinfo *info) | 275 | struct ethtool_drvinfo *info) |
267 | { | 276 | { |
@@ -364,6 +373,9 @@ static const struct net_device_ops uml_netdev_ops = { | |||
364 | .ndo_set_mac_address = eth_mac_addr, | 373 | .ndo_set_mac_address = eth_mac_addr, |
365 | .ndo_change_mtu = uml_net_change_mtu, | 374 | .ndo_change_mtu = uml_net_change_mtu, |
366 | .ndo_validate_addr = eth_validate_addr, | 375 | .ndo_validate_addr = eth_validate_addr, |
376 | #ifdef CONFIG_NET_POLL_CONTROLLER | ||
377 | .ndo_poll_controller = uml_net_poll_controller, | ||
378 | #endif | ||
367 | }; | 379 | }; |
368 | 380 | ||
369 | /* | 381 | /* |
diff --git a/arch/um/drivers/net_user.c b/arch/um/drivers/net_user.c index 9415dd9e63e..520118888f1 100644 --- a/arch/um/drivers/net_user.c +++ b/arch/um/drivers/net_user.c | |||
@@ -228,7 +228,10 @@ static void change(char *dev, char *what, unsigned char *addr, | |||
228 | "buffer\n"); | 228 | "buffer\n"); |
229 | 229 | ||
230 | pid = change_tramp(argv, output, output_len); | 230 | pid = change_tramp(argv, output, output_len); |
231 | if (pid < 0) return; | 231 | if (pid < 0) { |
232 | kfree(output); | ||
233 | return; | ||
234 | } | ||
232 | 235 | ||
233 | if (output != NULL) { | 236 | if (output != NULL) { |
234 | printk("%s", output); | 237 | printk("%s", output); |
diff --git a/arch/um/drivers/slip_user.c b/arch/um/drivers/slip_user.c index a1c2d2c98a9..cbacfc4e63e 100644 --- a/arch/um/drivers/slip_user.c +++ b/arch/um/drivers/slip_user.c | |||
@@ -102,7 +102,7 @@ static int slip_tramp(char **argv, int fd) | |||
102 | "buffer\n"); | 102 | "buffer\n"); |
103 | os_kill_process(pid, 1); | 103 | os_kill_process(pid, 1); |
104 | err = -ENOMEM; | 104 | err = -ENOMEM; |
105 | goto out_free; | 105 | goto out_close; |
106 | } | 106 | } |
107 | 107 | ||
108 | close(fds[1]); | 108 | close(fds[1]); |
@@ -112,7 +112,6 @@ static int slip_tramp(char **argv, int fd) | |||
112 | err = helper_wait(pid); | 112 | err = helper_wait(pid); |
113 | close(fds[0]); | 113 | close(fds[0]); |
114 | 114 | ||
115 | out_free: | ||
116 | kfree(output); | 115 | kfree(output); |
117 | return err; | 116 | return err; |
118 | 117 | ||
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c index 620f5b70957..0491e40d696 100644 --- a/arch/um/drivers/ubd_kern.c +++ b/arch/um/drivers/ubd_kern.c | |||
@@ -513,8 +513,37 @@ __uml_exitcall(kill_io_thread); | |||
513 | static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) | 513 | static inline int ubd_file_size(struct ubd *ubd_dev, __u64 *size_out) |
514 | { | 514 | { |
515 | char *file; | 515 | char *file; |
516 | int fd; | ||
517 | int err; | ||
518 | |||
519 | __u32 version; | ||
520 | __u32 align; | ||
521 | char *backing_file; | ||
522 | time_t mtime; | ||
523 | unsigned long long size; | ||
524 | int sector_size; | ||
525 | int bitmap_offset; | ||
526 | |||
527 | if (ubd_dev->file && ubd_dev->cow.file) { | ||
528 | file = ubd_dev->cow.file; | ||
529 | |||
530 | goto out; | ||
531 | } | ||
516 | 532 | ||
517 | file = ubd_dev->cow.file ? ubd_dev->cow.file : ubd_dev->file; | 533 | fd = os_open_file(ubd_dev->file, global_openflags, 0); |
534 | if (fd < 0) | ||
535 | return fd; | ||
536 | |||
537 | err = read_cow_header(file_reader, &fd, &version, &backing_file, \ | ||
538 | &mtime, &size, §or_size, &align, &bitmap_offset); | ||
539 | os_close_file(fd); | ||
540 | |||
541 | if(err == -EINVAL) | ||
542 | file = ubd_dev->file; | ||
543 | else | ||
544 | file = backing_file; | ||
545 | |||
546 | out: | ||
518 | return os_file_size(file, size_out); | 547 | return os_file_size(file, size_out); |
519 | } | 548 | } |
520 | 549 | ||
diff --git a/arch/um/drivers/xterm.c b/arch/um/drivers/xterm.c index 8ac7146c237..2e1de572860 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/asm-offsets.h b/arch/um/include/asm/asm-offsets.h deleted file mode 100644 index d370ee36a18..00000000000 --- a/arch/um/include/asm/asm-offsets.h +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | #include <generated/asm-offsets.h> | ||
diff --git a/arch/um/include/asm/delay.h b/arch/um/include/asm/delay.h index c71e32b6741..8a5576d8eda 100644 --- a/arch/um/include/asm/delay.h +++ b/arch/um/include/asm/delay.h | |||
@@ -1,20 +1,18 @@ | |||
1 | #ifndef __UM_DELAY_H | 1 | #ifndef __UM_DELAY_H |
2 | #define __UM_DELAY_H | 2 | #define __UM_DELAY_H |
3 | 3 | ||
4 | #define MILLION 1000000 | ||
5 | |||
6 | /* Undefined on purpose */ | 4 | /* Undefined on purpose */ |
7 | extern void __bad_udelay(void); | 5 | extern void __bad_udelay(void); |
6 | extern void __bad_ndelay(void); | ||
8 | 7 | ||
9 | extern void __udelay(unsigned long usecs); | 8 | extern void __udelay(unsigned long usecs); |
9 | extern void __ndelay(unsigned long usecs); | ||
10 | extern void __delay(unsigned long loops); | 10 | extern void __delay(unsigned long loops); |
11 | 11 | ||
12 | #define udelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \ | 12 | #define udelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \ |
13 | __bad_udelay() : __udelay(n)) | 13 | __bad_udelay() : __udelay(n)) |
14 | 14 | ||
15 | /* It appears that ndelay is not used at all for UML, and has never been | 15 | #define ndelay(n) ((__builtin_constant_p(n) && (n) > 20000) ? \ |
16 | * implemented. */ | 16 | __bad_ndelay() : __ndelay(n)) |
17 | extern void __unimplemented_ndelay(void); | ||
18 | #define ndelay(n) __unimplemented_ndelay() | ||
19 | 17 | ||
20 | #endif | 18 | #endif |
diff --git a/arch/um/include/asm/ptrace-generic.h b/arch/um/include/asm/ptrace-generic.h index b7c5bab9bd7..1a7d2757fe0 100644 --- a/arch/um/include/asm/ptrace-generic.h +++ b/arch/um/include/asm/ptrace-generic.h | |||
@@ -42,12 +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 | |||
50 | extern void show_regs(struct pt_regs *regs); | ||
51 | 45 | ||
52 | extern int arch_copy_tls(struct task_struct *new); | 46 | extern int arch_copy_tls(struct task_struct *new); |
53 | 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 72f4f25af24..63df3ca02ac 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 b0b4589e0eb..f1e0aa56c52 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/exec.c b/arch/um/kernel/exec.c index 09bd7b58572..939a4a67f0f 100644 --- a/arch/um/kernel/exec.c +++ b/arch/um/kernel/exec.c | |||
@@ -38,7 +38,6 @@ void flush_thread(void) | |||
38 | 38 | ||
39 | void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) | 39 | void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) |
40 | { | 40 | { |
41 | set_fs(USER_DS); | ||
42 | PT_REGS_IP(regs) = eip; | 41 | PT_REGS_IP(regs) = eip; |
43 | PT_REGS_SP(regs) = esp; | 42 | PT_REGS_SP(regs) = esp; |
44 | } | 43 | } |
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c index fab4371184f..21c1ae7c3d7 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 701b672c112..c9da32b0c70 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/kernel/reboot.c b/arch/um/kernel/reboot.c index 869bec9f251..4d93dff6b37 100644 --- a/arch/um/kernel/reboot.c +++ b/arch/um/kernel/reboot.c | |||
@@ -20,9 +20,8 @@ static void kill_off_processes(void) | |||
20 | os_kill_ptraced_process(userspace_pid[0], 1); | 20 | os_kill_ptraced_process(userspace_pid[0], 1); |
21 | else { | 21 | else { |
22 | struct task_struct *p; | 22 | struct task_struct *p; |
23 | int pid, me; | 23 | int pid; |
24 | 24 | ||
25 | me = os_getpid(); | ||
26 | for_each_process(p) { | 25 | for_each_process(p) { |
27 | if (p->mm == NULL) | 26 | if (p->mm == NULL) |
28 | continue; | 27 | continue; |
diff --git a/arch/um/os-Linux/Makefile b/arch/um/os-Linux/Makefile index d66f0388f09..b33f4dfe7ae 100644 --- a/arch/um/os-Linux/Makefile +++ b/arch/um/os-Linux/Makefile | |||
@@ -3,10 +3,12 @@ | |||
3 | # Licensed under the GPL | 3 | # Licensed under the GPL |
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ | 6 | obj-y = aio.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ |
7 | registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \ | 7 | registers.o sigio.o signal.o start_up.o time.o tty.o uaccess.o \ |
8 | umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/ | 8 | umid.o tls.o user_syms.o util.o drivers/ sys-$(SUBARCH)/ skas/ |
9 | 9 | ||
10 | obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o | ||
11 | |||
10 | USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ | 12 | USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ |
11 | main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ | 13 | main.o mem.o process.o registers.o sigio.o signal.o start_up.o time.o \ |
12 | tty.o tls.o uaccess.o umid.o util.o | 14 | tty.o tls.o uaccess.o umid.o util.o |
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c index 608784d4ec5..95332379938 100644 --- a/arch/um/os-Linux/elf_aux.c +++ b/arch/um/os-Linux/elf_aux.c | |||
@@ -14,16 +14,11 @@ | |||
14 | #include "mem_user.h" | 14 | #include "mem_user.h" |
15 | #include <kern_constants.h> | 15 | #include <kern_constants.h> |
16 | 16 | ||
17 | /* Use the one from the kernel - the host may miss it, if having old headers. */ | ||
18 | #if UM_ELF_CLASS == UM_ELFCLASS32 | ||
19 | typedef Elf32_auxv_t elf_auxv_t; | 17 | typedef Elf32_auxv_t elf_auxv_t; |
20 | #else | ||
21 | typedef Elf64_auxv_t elf_auxv_t; | ||
22 | #endif | ||
23 | 18 | ||
24 | /* These are initialized very early in boot and never changed */ | 19 | /* These are initialized very early in boot and never changed */ |
25 | char * elf_aux_platform; | 20 | char * elf_aux_platform; |
26 | long elf_aux_hwcap; | 21 | extern long elf_aux_hwcap; |
27 | unsigned long vsyscall_ehdr; | 22 | unsigned long vsyscall_ehdr; |
28 | unsigned long vsyscall_end; | 23 | unsigned long vsyscall_end; |
29 | unsigned long __kernel_vsyscall; | 24 | unsigned long __kernel_vsyscall; |
diff --git a/arch/um/os-Linux/helper.c b/arch/um/os-Linux/helper.c index b6b1096152a..feff22d6467 100644 --- a/arch/um/os-Linux/helper.c +++ b/arch/um/os-Linux/helper.c | |||
@@ -28,14 +28,14 @@ static int helper_child(void *arg) | |||
28 | { | 28 | { |
29 | struct helper_data *data = arg; | 29 | struct helper_data *data = arg; |
30 | char **argv = data->argv; | 30 | char **argv = data->argv; |
31 | int err; | 31 | int err, ret; |
32 | 32 | ||
33 | if (data->pre_exec != NULL) | 33 | if (data->pre_exec != NULL) |
34 | (*data->pre_exec)(data->pre_data); | 34 | (*data->pre_exec)(data->pre_data); |
35 | err = execvp_noalloc(data->buf, argv[0], argv); | 35 | err = execvp_noalloc(data->buf, argv[0], argv); |
36 | 36 | ||
37 | /* If the exec succeeds, we don't get here */ | 37 | /* If the exec succeeds, we don't get here */ |
38 | write(data->fd, &err, sizeof(err)); | 38 | CATCH_EINTR(ret = write(data->fd, &err, sizeof(err))); |
39 | 39 | ||
40 | return 0; | 40 | return 0; |
41 | } | 41 | } |
diff --git a/arch/um/os-Linux/main.c b/arch/um/os-Linux/main.c index fb2a97a75fb..8471b817d94 100644 --- a/arch/um/os-Linux/main.c +++ b/arch/um/os-Linux/main.c | |||
@@ -21,6 +21,8 @@ | |||
21 | #define STACKSIZE (8 * 1024 * 1024) | 21 | #define STACKSIZE (8 * 1024 * 1024) |
22 | #define THREAD_NAME_LEN (256) | 22 | #define THREAD_NAME_LEN (256) |
23 | 23 | ||
24 | long elf_aux_hwcap; | ||
25 | |||
24 | static void set_stklim(void) | 26 | static void set_stklim(void) |
25 | { | 27 | { |
26 | struct rlimit lim; | 28 | struct rlimit lim; |
@@ -143,7 +145,9 @@ int __init main(int argc, char **argv, char **envp) | |||
143 | install_fatal_handler(SIGINT); | 145 | install_fatal_handler(SIGINT); |
144 | install_fatal_handler(SIGTERM); | 146 | install_fatal_handler(SIGTERM); |
145 | 147 | ||
148 | #ifdef CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA | ||
146 | scan_elf_aux(envp); | 149 | scan_elf_aux(envp); |
150 | #endif | ||
147 | 151 | ||
148 | do_uml_initcalls(); | 152 | do_uml_initcalls(); |
149 | ret = linux_main(argc, argv); | 153 | ret = linux_main(argc, argv); |
diff --git a/arch/um/os-Linux/mem.c b/arch/um/os-Linux/mem.c index e696144d2be..62878cf1d33 100644 --- a/arch/um/os-Linux/mem.c +++ b/arch/um/os-Linux/mem.c | |||
@@ -176,7 +176,7 @@ static int __init make_tempfile(const char *template, char **out_tempname, | |||
176 | 176 | ||
177 | find_tempdir(); | 177 | find_tempdir(); |
178 | if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN)) | 178 | if ((tempdir == NULL) || (strlen(tempdir) >= MAXPATHLEN)) |
179 | return -1; | 179 | goto out; |
180 | 180 | ||
181 | if (template[0] != '/') | 181 | if (template[0] != '/') |
182 | strcpy(tempname, tempdir); | 182 | strcpy(tempname, tempdir); |
@@ -191,13 +191,15 @@ static int __init make_tempfile(const char *template, char **out_tempname, | |||
191 | } | 191 | } |
192 | if (do_unlink && (unlink(tempname) < 0)) { | 192 | if (do_unlink && (unlink(tempname) < 0)) { |
193 | perror("unlink"); | 193 | perror("unlink"); |
194 | goto out; | 194 | goto close; |
195 | } | 195 | } |
196 | if (out_tempname) { | 196 | if (out_tempname) { |
197 | *out_tempname = tempname; | 197 | *out_tempname = tempname; |
198 | } else | 198 | } else |
199 | free(tempname); | 199 | free(tempname); |
200 | return fd; | 200 | return fd; |
201 | close: | ||
202 | close(fd); | ||
201 | out: | 203 | out: |
202 | free(tempname); | 204 | free(tempname); |
203 | return -1; | 205 | return -1; |
diff --git a/arch/um/os-Linux/registers.c b/arch/um/os-Linux/registers.c index 830fe6a1518..b866b9e3bef 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 d261f170d12..e771398be5f 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 d6e0a2234b8..dee0e8cf8ad 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/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c index 05f5ea8e83d..45ffe46871e 100644 --- a/arch/um/os-Linux/user_syms.c +++ b/arch/um/os-Linux/user_syms.c | |||
@@ -113,3 +113,8 @@ EXPORT_SYMBOL(__stack_smash_handler); | |||
113 | 113 | ||
114 | extern long __guard __attribute__((weak)); | 114 | extern long __guard __attribute__((weak)); |
115 | EXPORT_SYMBOL(__guard); | 115 | EXPORT_SYMBOL(__guard); |
116 | |||
117 | #ifdef _FORTIFY_SOURCE | ||
118 | extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format); | ||
119 | EXPORT_SYMBOL(__sprintf_chk); | ||
120 | #endif | ||
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile index b1da91c1b20..3923cfb8764 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile | |||
@@ -4,11 +4,12 @@ | |||
4 | 4 | ||
5 | obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ | 5 | obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ |
6 | ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \ | 6 | ptrace_user.o setjmp.o signal.o stub.o stub_segv.o syscalls.o sysrq.o \ |
7 | sys_call_table.o tls.o atomic64_cx8_32.o | 7 | sys_call_table.o tls.o atomic64_cx8_32.o mem.o |
8 | 8 | ||
9 | obj-$(CONFIG_BINFMT_ELF) += elfcore.o | 9 | obj-$(CONFIG_BINFMT_ELF) += elfcore.o |
10 | 10 | ||
11 | subarch-obj-y = lib/semaphore_32.o lib/string_32.o | 11 | subarch-obj-y = lib/string_32.o |
12 | subarch-obj-$(CONFIG_RWSEM_XCHGADD_ALGORITHM) += lib/rwsem.o | ||
12 | subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o | 13 | subarch-obj-$(CONFIG_HIGHMEM) += mm/highmem_32.o |
13 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o | 14 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o |
14 | 15 | ||
diff --git a/arch/um/sys-i386/asm/elf.h b/arch/um/sys-i386/asm/elf.h index d964a4111ac..42305551d20 100644 --- a/arch/um/sys-i386/asm/elf.h +++ b/arch/um/sys-i386/asm/elf.h | |||
@@ -105,6 +105,8 @@ extern unsigned long __kernel_vsyscall; | |||
105 | #define FIXADDR_USER_START VSYSCALL_BASE | 105 | #define FIXADDR_USER_START VSYSCALL_BASE |
106 | #define FIXADDR_USER_END VSYSCALL_END | 106 | #define FIXADDR_USER_END VSYSCALL_END |
107 | 107 | ||
108 | #define __HAVE_ARCH_GATE_AREA 1 | ||
109 | |||
108 | /* | 110 | /* |
109 | * Architecture-neutral AT_ values in 0-17, leave some room | 111 | * Architecture-neutral AT_ values in 0-17, leave some room |
110 | * for more of them, start the x86-specific ones at 32. | 112 | * for more of them, start the x86-specific ones at 32. |
diff --git a/arch/um/sys-i386/asm/ptrace.h b/arch/um/sys-i386/asm/ptrace.h index 0273e4d09af..5d2a5911253 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/delay.c b/arch/um/sys-i386/delay.c index d623e074f41..f3fe1a688f7 100644 --- a/arch/um/sys-i386/delay.c +++ b/arch/um/sys-i386/delay.c | |||
@@ -1,29 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * Mostly copied from arch/x86/lib/delay.c | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
8 | */ | ||
9 | |||
1 | #include <linux/module.h> | 10 | #include <linux/module.h> |
2 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
3 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
4 | #include <asm/param.h> | 13 | #include <asm/param.h> |
5 | 14 | ||
6 | void __delay(unsigned long time) | 15 | void __delay(unsigned long loops) |
7 | { | 16 | { |
8 | /* Stolen from the i386 __loop_delay */ | 17 | asm volatile( |
9 | int d0; | 18 | "test %0,%0\n" |
10 | __asm__ __volatile__( | 19 | "jz 3f\n" |
11 | "\tjmp 1f\n" | 20 | "jmp 1f\n" |
21 | |||
12 | ".align 16\n" | 22 | ".align 16\n" |
13 | "1:\tjmp 2f\n" | 23 | "1: jmp 2f\n" |
24 | |||
14 | ".align 16\n" | 25 | ".align 16\n" |
15 | "2:\tdecl %0\n\tjns 2b" | 26 | "2: dec %0\n" |
16 | :"=&a" (d0) | 27 | " jnz 2b\n" |
17 | :"0" (time)); | 28 | "3: dec %0\n" |
29 | |||
30 | : /* we don't need output */ | ||
31 | : "a" (loops) | ||
32 | ); | ||
18 | } | 33 | } |
34 | EXPORT_SYMBOL(__delay); | ||
19 | 35 | ||
20 | void __udelay(unsigned long usecs) | 36 | inline void __const_udelay(unsigned long xloops) |
21 | { | 37 | { |
22 | int i, n; | 38 | int d0; |
23 | 39 | ||
24 | n = (loops_per_jiffy * HZ * usecs) / MILLION; | 40 | xloops *= 4; |
25 | for(i=0;i<n;i++) | 41 | asm("mull %%edx" |
26 | cpu_relax(); | 42 | : "=d" (xloops), "=&a" (d0) |
43 | : "1" (xloops), "0" | ||
44 | (loops_per_jiffy * (HZ/4))); | ||
45 | |||
46 | __delay(++xloops); | ||
27 | } | 47 | } |
48 | EXPORT_SYMBOL(__const_udelay); | ||
28 | 49 | ||
50 | void __udelay(unsigned long usecs) | ||
51 | { | ||
52 | __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ | ||
53 | } | ||
29 | EXPORT_SYMBOL(__udelay); | 54 | EXPORT_SYMBOL(__udelay); |
55 | |||
56 | void __ndelay(unsigned long nsecs) | ||
57 | { | ||
58 | __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ | ||
59 | } | ||
60 | EXPORT_SYMBOL(__ndelay); | ||
diff --git a/arch/um/sys-i386/mem.c b/arch/um/sys-i386/mem.c new file mode 100644 index 00000000000..639900a6fde --- /dev/null +++ b/arch/um/sys-i386/mem.c | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/mm.h> | ||
10 | #include <asm/page.h> | ||
11 | #include <asm/mman.h> | ||
12 | |||
13 | static struct vm_area_struct gate_vma; | ||
14 | |||
15 | static int __init gate_vma_init(void) | ||
16 | { | ||
17 | if (!FIXADDR_USER_START) | ||
18 | return 0; | ||
19 | |||
20 | gate_vma.vm_mm = NULL; | ||
21 | gate_vma.vm_start = FIXADDR_USER_START; | ||
22 | gate_vma.vm_end = FIXADDR_USER_END; | ||
23 | gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC; | ||
24 | gate_vma.vm_page_prot = __P101; | ||
25 | |||
26 | /* | ||
27 | * Make sure the vDSO gets into every core dump. | ||
28 | * Dumping its contents makes post-mortem fully interpretable later | ||
29 | * without matching up the same kernel and hardware config to see | ||
30 | * what PC values meant. | ||
31 | */ | ||
32 | gate_vma.vm_flags |= VM_ALWAYSDUMP; | ||
33 | |||
34 | return 0; | ||
35 | } | ||
36 | __initcall(gate_vma_init); | ||
37 | |||
38 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) | ||
39 | { | ||
40 | return FIXADDR_USER_START ? &gate_vma : NULL; | ||
41 | } | ||
42 | |||
43 | int in_gate_area_no_mm(unsigned long addr) | ||
44 | { | ||
45 | if (!FIXADDR_USER_START) | ||
46 | return 0; | ||
47 | |||
48 | if ((addr >= FIXADDR_USER_START) && (addr < FIXADDR_USER_END)) | ||
49 | return 1; | ||
50 | |||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | int in_gate_area(struct mm_struct *mm, unsigned long addr) | ||
55 | { | ||
56 | struct vm_area_struct *vma = get_gate_vma(mm); | ||
57 | |||
58 | if (!vma) | ||
59 | return 0; | ||
60 | |||
61 | return (addr >= vma->vm_start) && (addr < vma->vm_end); | ||
62 | } | ||
diff --git a/arch/um/sys-i386/ptrace.c b/arch/um/sys-i386/ptrace.c index d23b2d3ea38..3375c271785 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 d50e62e0707..c398a507611 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-i386/signal.c b/arch/um/sys-i386/signal.c index 129647375a6..89a46626bfd 100644 --- a/arch/um/sys-i386/signal.c +++ b/arch/um/sys-i386/signal.c | |||
@@ -58,7 +58,7 @@ static inline unsigned long twd_fxsr_to_i387(struct user_fxsr_struct *fxsave) | |||
58 | unsigned long ret = 0xffff0000; | 58 | unsigned long ret = 0xffff0000; |
59 | int i; | 59 | int i; |
60 | 60 | ||
61 | #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); | 61 | #define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16) |
62 | 62 | ||
63 | for (i = 0; i < 8; i++) { | 63 | for (i = 0; i < 8; i++) { |
64 | if (twd & 0x1) { | 64 | if (twd & 0x1) { |
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index c1ea9eb0446..bd4d1d3ba91 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile | |||
@@ -4,12 +4,14 @@ | |||
4 | # Licensed under the GPL | 4 | # Licensed under the GPL |
5 | # | 5 | # |
6 | 6 | ||
7 | obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ | 7 | obj-y = bug.o bugs.o delay.o fault.o ldt.o ptrace.o ptrace_user.o mem.o \ |
8 | setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \ | 8 | setjmp.o signal.o stub.o stub_segv.o syscalls.o syscall_table.o \ |
9 | sysrq.o ksyms.o tls.o | 9 | sysrq.o ksyms.o tls.o |
10 | 10 | ||
11 | obj-y += vdso/ | ||
12 | |||
11 | subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \ | 13 | subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \ |
12 | lib/rwsem_64.o | 14 | lib/rwsem.o |
13 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o | 15 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o |
14 | 16 | ||
15 | ldt-y = ../sys-i386/ldt.o | 17 | ldt-y = ../sys-i386/ldt.o |
diff --git a/arch/um/sys-x86_64/asm/elf.h b/arch/um/sys-x86_64/asm/elf.h index d6d5af37625..11a2bfb3885 100644 --- a/arch/um/sys-x86_64/asm/elf.h +++ b/arch/um/sys-x86_64/asm/elf.h | |||
@@ -119,4 +119,14 @@ extern long elf_aux_hwcap; | |||
119 | 119 | ||
120 | #define SET_PERSONALITY(ex) do ; while(0) | 120 | #define SET_PERSONALITY(ex) do ; while(0) |
121 | 121 | ||
122 | #define __HAVE_ARCH_GATE_AREA 1 | ||
123 | #define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 | ||
124 | struct linux_binprm; | ||
125 | extern int arch_setup_additional_pages(struct linux_binprm *bprm, | ||
126 | int uses_interp); | ||
127 | |||
128 | extern unsigned long um_vdso_addr; | ||
129 | #define AT_SYSINFO_EHDR 33 | ||
130 | #define ARCH_DLINFO NEW_AUX_ENT(AT_SYSINFO_EHDR, um_vdso_addr) | ||
131 | |||
122 | #endif | 132 | #endif |
diff --git a/arch/um/sys-x86_64/delay.c b/arch/um/sys-x86_64/delay.c index dee5be66da8..f3fe1a688f7 100644 --- a/arch/um/sys-x86_64/delay.c +++ b/arch/um/sys-x86_64/delay.c | |||
@@ -1,30 +1,60 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright 2003 PathScale, Inc. | 2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> |
3 | * Copied from arch/x86_64 | 3 | * Mostly copied from arch/x86/lib/delay.c |
4 | * | 4 | * |
5 | * Licensed under the GPL | 5 | * This program is free software; you can redistribute it and/or modify |
6 | * it under the terms of the GNU General Public License version 2 as | ||
7 | * published by the Free Software Foundation. | ||
6 | */ | 8 | */ |
7 | 9 | ||
8 | #include <linux/module.h> | 10 | #include <linux/module.h> |
11 | #include <linux/kernel.h> | ||
9 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
10 | #include <asm/processor.h> | ||
11 | #include <asm/param.h> | 13 | #include <asm/param.h> |
12 | 14 | ||
13 | void __delay(unsigned long loops) | 15 | void __delay(unsigned long loops) |
14 | { | 16 | { |
15 | unsigned long i; | 17 | asm volatile( |
18 | "test %0,%0\n" | ||
19 | "jz 3f\n" | ||
20 | "jmp 1f\n" | ||
16 | 21 | ||
17 | for(i = 0; i < loops; i++) | 22 | ".align 16\n" |
18 | cpu_relax(); | 23 | "1: jmp 2f\n" |
24 | |||
25 | ".align 16\n" | ||
26 | "2: dec %0\n" | ||
27 | " jnz 2b\n" | ||
28 | "3: dec %0\n" | ||
29 | |||
30 | : /* we don't need output */ | ||
31 | : "a" (loops) | ||
32 | ); | ||
19 | } | 33 | } |
34 | EXPORT_SYMBOL(__delay); | ||
20 | 35 | ||
21 | void __udelay(unsigned long usecs) | 36 | inline void __const_udelay(unsigned long xloops) |
22 | { | 37 | { |
23 | unsigned long i, n; | 38 | int d0; |
24 | 39 | ||
25 | n = (loops_per_jiffy * HZ * usecs) / MILLION; | 40 | xloops *= 4; |
26 | for(i=0;i<n;i++) | 41 | asm("mull %%edx" |
27 | cpu_relax(); | 42 | : "=d" (xloops), "=&a" (d0) |
43 | : "1" (xloops), "0" | ||
44 | (loops_per_jiffy * (HZ/4))); | ||
45 | |||
46 | __delay(++xloops); | ||
28 | } | 47 | } |
48 | EXPORT_SYMBOL(__const_udelay); | ||
29 | 49 | ||
50 | void __udelay(unsigned long usecs) | ||
51 | { | ||
52 | __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */ | ||
53 | } | ||
30 | EXPORT_SYMBOL(__udelay); | 54 | EXPORT_SYMBOL(__udelay); |
55 | |||
56 | void __ndelay(unsigned long nsecs) | ||
57 | { | ||
58 | __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */ | ||
59 | } | ||
60 | EXPORT_SYMBOL(__ndelay); | ||
diff --git a/arch/um/sys-x86_64/mem.c b/arch/um/sys-x86_64/mem.c index 3f8df8abf34..546518727a7 100644 --- a/arch/um/sys-x86_64/mem.c +++ b/arch/um/sys-x86_64/mem.c | |||
@@ -1,16 +1,26 @@ | |||
1 | /* | ||
2 | * Copyright 2003 PathScale, Inc. | ||
3 | * | ||
4 | * Licensed under the GPL | ||
5 | */ | ||
6 | |||
7 | #include "linux/mm.h" | 1 | #include "linux/mm.h" |
8 | #include "asm/page.h" | 2 | #include "asm/page.h" |
9 | #include "asm/mman.h" | 3 | #include "asm/mman.h" |
10 | 4 | ||
11 | unsigned long vm_stack_flags = __VM_STACK_FLAGS; | 5 | const char *arch_vma_name(struct vm_area_struct *vma) |
12 | unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; | 6 | { |
13 | unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; | 7 | if (vma->vm_mm && vma->vm_start == um_vdso_addr) |
14 | unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; | 8 | return "[vdso]"; |
15 | unsigned long vm_force_exec32 = PROT_EXEC; | 9 | |
10 | return NULL; | ||
11 | } | ||
12 | |||
13 | struct vm_area_struct *get_gate_vma(struct mm_struct *mm) | ||
14 | { | ||
15 | return NULL; | ||
16 | } | ||
17 | |||
18 | int in_gate_area(struct mm_struct *mm, unsigned long addr) | ||
19 | { | ||
20 | return 0; | ||
21 | } | ||
16 | 22 | ||
23 | int in_gate_area_no_mm(unsigned long addr) | ||
24 | { | ||
25 | return 0; | ||
26 | } | ||
diff --git a/arch/um/sys-x86_64/ptrace.c b/arch/um/sys-x86_64/ptrace.c index f43613643cd..4005506834f 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 fdba5457947..8ee8f8e12af 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; |
diff --git a/arch/um/sys-x86_64/shared/sysdep/vm-flags.h b/arch/um/sys-x86_64/shared/sysdep/vm-flags.h index 3213edfa788..3978e55132d 100644 --- a/arch/um/sys-x86_64/shared/sysdep/vm-flags.h +++ b/arch/um/sys-x86_64/shared/sysdep/vm-flags.h | |||
@@ -7,27 +7,9 @@ | |||
7 | #ifndef __VM_FLAGS_X86_64_H | 7 | #ifndef __VM_FLAGS_X86_64_H |
8 | #define __VM_FLAGS_X86_64_H | 8 | #define __VM_FLAGS_X86_64_H |
9 | 9 | ||
10 | #define __VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ | 10 | #define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | VM_EXEC | \ |
11 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) | 11 | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
12 | #define __VM_STACK_FLAGS (VM_GROWSDOWN | VM_READ | VM_WRITE | \ | 12 | #define VM_STACK_DEFAULT_FLAGS (VM_GROWSDOWN | VM_READ | VM_WRITE | \ |
13 | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | \ | 13 | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) |
14 | VM_MAYEXEC) | ||
15 | |||
16 | extern unsigned long vm_stack_flags, vm_stack_flags32; | ||
17 | extern unsigned long vm_data_default_flags, vm_data_default_flags32; | ||
18 | extern unsigned long vm_force_exec32; | ||
19 | |||
20 | #ifdef TIF_IA32 | ||
21 | #define VM_DATA_DEFAULT_FLAGS \ | ||
22 | (test_thread_flag(TIF_IA32) ? vm_data_default_flags32 : \ | ||
23 | vm_data_default_flags) | ||
24 | |||
25 | #define VM_STACK_DEFAULT_FLAGS \ | ||
26 | (test_thread_flag(TIF_IA32) ? vm_stack_flags32 : vm_stack_flags) | ||
27 | #endif | ||
28 | |||
29 | #define VM_DATA_DEFAULT_FLAGS vm_data_default_flags | ||
30 | |||
31 | #define VM_STACK_DEFAULT_FLAGS vm_stack_flags | ||
32 | 14 | ||
33 | #endif | 15 | #endif |
diff --git a/arch/um/sys-x86_64/vdso/Makefile b/arch/um/sys-x86_64/vdso/Makefile new file mode 100644 index 00000000000..5dffe6d4668 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/Makefile | |||
@@ -0,0 +1,90 @@ | |||
1 | # | ||
2 | # Building vDSO images for x86. | ||
3 | # | ||
4 | |||
5 | VDSO64-y := y | ||
6 | |||
7 | vdso-install-$(VDSO64-y) += vdso.so | ||
8 | |||
9 | |||
10 | # files to link into the vdso | ||
11 | vobjs-y := vdso-note.o um_vdso.o | ||
12 | |||
13 | # files to link into kernel | ||
14 | obj-$(VDSO64-y) += vdso.o vma.o | ||
15 | |||
16 | vobjs := $(foreach F,$(vobjs-y),$(obj)/$F) | ||
17 | |||
18 | $(obj)/vdso.o: $(obj)/vdso.so | ||
19 | |||
20 | targets += vdso.so vdso.so.dbg vdso.lds $(vobjs-y) | ||
21 | |||
22 | export CPPFLAGS_vdso.lds += -P -C | ||
23 | |||
24 | VDSO_LDFLAGS_vdso.lds = -m64 -Wl,-soname=linux-vdso.so.1 \ | ||
25 | -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096 | ||
26 | |||
27 | $(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so | ||
28 | |||
29 | $(obj)/vdso.so.dbg: $(src)/vdso.lds $(vobjs) FORCE | ||
30 | $(call if_changed,vdso) | ||
31 | |||
32 | $(obj)/%.so: OBJCOPYFLAGS := -S | ||
33 | $(obj)/%.so: $(obj)/%.so.dbg FORCE | ||
34 | $(call if_changed,objcopy) | ||
35 | |||
36 | # | ||
37 | # Don't omit frame pointers for ease of userspace debugging, but do | ||
38 | # optimize sibling calls. | ||
39 | # | ||
40 | CFL := $(PROFILING) -mcmodel=small -fPIC -O2 -fasynchronous-unwind-tables -m64 \ | ||
41 | $(filter -g%,$(KBUILD_CFLAGS)) $(call cc-option, -fno-stack-protector) \ | ||
42 | -fno-omit-frame-pointer -foptimize-sibling-calls | ||
43 | |||
44 | $(vobjs): KBUILD_CFLAGS += $(CFL) | ||
45 | |||
46 | # | ||
47 | # vDSO code runs in userspace and -pg doesn't help with profiling anyway. | ||
48 | # | ||
49 | CFLAGS_REMOVE_vdso-note.o = -pg | ||
50 | CFLAGS_REMOVE_um_vdso.o = -pg | ||
51 | |||
52 | targets += vdso-syms.lds | ||
53 | obj-$(VDSO64-y) += vdso-syms.lds | ||
54 | |||
55 | # | ||
56 | # Match symbols in the DSO that look like VDSO*; produce a file of constants. | ||
57 | # | ||
58 | sed-vdsosym := -e 's/^00*/0/' \ | ||
59 | -e 's/^\([0-9a-fA-F]*\) . \(VDSO[a-zA-Z0-9_]*\)$$/\2 = 0x\1;/p' | ||
60 | quiet_cmd_vdsosym = VDSOSYM $@ | ||
61 | define cmd_vdsosym | ||
62 | $(NM) $< | LC_ALL=C sed -n $(sed-vdsosym) | LC_ALL=C sort > $@ | ||
63 | endef | ||
64 | |||
65 | $(obj)/%-syms.lds: $(obj)/%.so.dbg FORCE | ||
66 | $(call if_changed,vdsosym) | ||
67 | |||
68 | # | ||
69 | # The DSO images are built using a special linker script. | ||
70 | # | ||
71 | quiet_cmd_vdso = VDSO $@ | ||
72 | cmd_vdso = $(CC) -nostdlib -o $@ \ | ||
73 | $(VDSO_LDFLAGS) $(VDSO_LDFLAGS_$(filter %.lds,$(^F))) \ | ||
74 | -Wl,-T,$(filter %.lds,$^) $(filter %.o,$^) && \ | ||
75 | sh $(srctree)/$(src)/checkundef.sh '$(NM)' '$@' | ||
76 | |||
77 | VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv) | ||
78 | GCOV_PROFILE := n | ||
79 | |||
80 | # | ||
81 | # Install the unstripped copy of vdso*.so listed in $(vdso-install-y). | ||
82 | # | ||
83 | quiet_cmd_vdso_install = INSTALL $@ | ||
84 | cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/$@ | ||
85 | $(vdso-install-y): %.so: $(obj)/%.so.dbg FORCE | ||
86 | @mkdir -p $(MODLIB)/vdso | ||
87 | $(call cmd,vdso_install) | ||
88 | |||
89 | PHONY += vdso_install $(vdso-install-y) | ||
90 | vdso_install: $(vdso-install-y) | ||
diff --git a/arch/um/sys-x86_64/vdso/checkundef.sh b/arch/um/sys-x86_64/vdso/checkundef.sh new file mode 100644 index 00000000000..7ee90a9b549 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/checkundef.sh | |||
@@ -0,0 +1,10 @@ | |||
1 | #!/bin/sh | ||
2 | nm="$1" | ||
3 | file="$2" | ||
4 | $nm "$file" | grep '^ *U' > /dev/null 2>&1 | ||
5 | if [ $? -eq 1 ]; then | ||
6 | exit 0 | ||
7 | else | ||
8 | echo "$file: undefined symbols found" >&2 | ||
9 | exit 1 | ||
10 | fi | ||
diff --git a/arch/um/sys-x86_64/vdso/um_vdso.c b/arch/um/sys-x86_64/vdso/um_vdso.c new file mode 100644 index 00000000000..7c441b59d37 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/um_vdso.c | |||
@@ -0,0 +1,71 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * This vDSO turns all calls into a syscall so that UML can trap them. | ||
9 | */ | ||
10 | |||
11 | |||
12 | /* Disable profiling for userspace code */ | ||
13 | #define DISABLE_BRANCH_PROFILING | ||
14 | |||
15 | #include <linux/time.h> | ||
16 | #include <linux/getcpu.h> | ||
17 | #include <asm/unistd.h> | ||
18 | |||
19 | int __vdso_clock_gettime(clockid_t clock, struct timespec *ts) | ||
20 | { | ||
21 | long ret; | ||
22 | |||
23 | asm("syscall" : "=a" (ret) : | ||
24 | "0" (__NR_clock_gettime), "D" (clock), "S" (ts) : "memory"); | ||
25 | |||
26 | return ret; | ||
27 | } | ||
28 | int clock_gettime(clockid_t, struct timespec *) | ||
29 | __attribute__((weak, alias("__vdso_clock_gettime"))); | ||
30 | |||
31 | int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz) | ||
32 | { | ||
33 | long ret; | ||
34 | |||
35 | asm("syscall" : "=a" (ret) : | ||
36 | "0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory"); | ||
37 | |||
38 | return ret; | ||
39 | } | ||
40 | int gettimeofday(struct timeval *, struct timezone *) | ||
41 | __attribute__((weak, alias("__vdso_gettimeofday"))); | ||
42 | |||
43 | time_t __vdso_time(time_t *t) | ||
44 | { | ||
45 | long secs; | ||
46 | |||
47 | asm volatile("syscall" | ||
48 | : "=a" (secs) | ||
49 | : "0" (__NR_time), "D" (t) : "cc", "r11", "cx", "memory"); | ||
50 | |||
51 | return secs; | ||
52 | } | ||
53 | int time(time_t *t) __attribute__((weak, alias("__vdso_time"))); | ||
54 | |||
55 | long | ||
56 | __vdso_getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *unused) | ||
57 | { | ||
58 | /* | ||
59 | * UML does not support SMP, we can cheat here. :) | ||
60 | */ | ||
61 | |||
62 | if (cpu) | ||
63 | *cpu = 0; | ||
64 | if (node) | ||
65 | *node = 0; | ||
66 | |||
67 | return 0; | ||
68 | } | ||
69 | |||
70 | long getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache) | ||
71 | __attribute__((weak, alias("__vdso_getcpu"))); | ||
diff --git a/arch/um/sys-x86_64/vdso/vdso-layout.lds.S b/arch/um/sys-x86_64/vdso/vdso-layout.lds.S new file mode 100644 index 00000000000..634a2cf6204 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vdso-layout.lds.S | |||
@@ -0,0 +1,64 @@ | |||
1 | /* | ||
2 | * Linker script for vDSO. This is an ELF shared object prelinked to | ||
3 | * its virtual address, and with only one read-only segment. | ||
4 | * This script controls its layout. | ||
5 | */ | ||
6 | |||
7 | SECTIONS | ||
8 | { | ||
9 | . = VDSO_PRELINK + SIZEOF_HEADERS; | ||
10 | |||
11 | .hash : { *(.hash) } :text | ||
12 | .gnu.hash : { *(.gnu.hash) } | ||
13 | .dynsym : { *(.dynsym) } | ||
14 | .dynstr : { *(.dynstr) } | ||
15 | .gnu.version : { *(.gnu.version) } | ||
16 | .gnu.version_d : { *(.gnu.version_d) } | ||
17 | .gnu.version_r : { *(.gnu.version_r) } | ||
18 | |||
19 | .note : { *(.note.*) } :text :note | ||
20 | |||
21 | .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr | ||
22 | .eh_frame : { KEEP (*(.eh_frame)) } :text | ||
23 | |||
24 | .dynamic : { *(.dynamic) } :text :dynamic | ||
25 | |||
26 | .rodata : { *(.rodata*) } :text | ||
27 | .data : { | ||
28 | *(.data*) | ||
29 | *(.sdata*) | ||
30 | *(.got.plt) *(.got) | ||
31 | *(.gnu.linkonce.d.*) | ||
32 | *(.bss*) | ||
33 | *(.dynbss*) | ||
34 | *(.gnu.linkonce.b.*) | ||
35 | } | ||
36 | |||
37 | .altinstructions : { *(.altinstructions) } | ||
38 | .altinstr_replacement : { *(.altinstr_replacement) } | ||
39 | |||
40 | /* | ||
41 | * Align the actual code well away from the non-instruction data. | ||
42 | * This is the best thing for the I-cache. | ||
43 | */ | ||
44 | . = ALIGN(0x100); | ||
45 | |||
46 | .text : { *(.text*) } :text =0x90909090 | ||
47 | } | ||
48 | |||
49 | /* | ||
50 | * Very old versions of ld do not recognize this name token; use the constant. | ||
51 | */ | ||
52 | #define PT_GNU_EH_FRAME 0x6474e550 | ||
53 | |||
54 | /* | ||
55 | * We must supply the ELF program headers explicitly to get just one | ||
56 | * PT_LOAD segment, and set the flags explicitly to make segments read-only. | ||
57 | */ | ||
58 | PHDRS | ||
59 | { | ||
60 | text PT_LOAD FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */ | ||
61 | dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ | ||
62 | note PT_NOTE FLAGS(4); /* PF_R */ | ||
63 | eh_frame_hdr PT_GNU_EH_FRAME; | ||
64 | } | ||
diff --git a/arch/um/sys-x86_64/vdso/vdso-note.S b/arch/um/sys-x86_64/vdso/vdso-note.S new file mode 100644 index 00000000000..79a071e4357 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vdso-note.S | |||
@@ -0,0 +1,12 @@ | |||
1 | /* | ||
2 | * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. | ||
3 | * Here we can supply some information useful to userland. | ||
4 | */ | ||
5 | |||
6 | #include <linux/uts.h> | ||
7 | #include <linux/version.h> | ||
8 | #include <linux/elfnote.h> | ||
9 | |||
10 | ELFNOTE_START(Linux, 0, "a") | ||
11 | .long LINUX_VERSION_CODE | ||
12 | ELFNOTE_END | ||
diff --git a/arch/um/sys-x86_64/vdso/vdso.S b/arch/um/sys-x86_64/vdso/vdso.S new file mode 100644 index 00000000000..ec82c1686bd --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vdso.S | |||
@@ -0,0 +1,10 @@ | |||
1 | #include <linux/init.h> | ||
2 | |||
3 | __INITDATA | ||
4 | |||
5 | .globl vdso_start, vdso_end | ||
6 | vdso_start: | ||
7 | .incbin "arch/um/sys-x86_64/vdso/vdso.so" | ||
8 | vdso_end: | ||
9 | |||
10 | __FINIT | ||
diff --git a/arch/um/sys-x86_64/vdso/vdso.lds.S b/arch/um/sys-x86_64/vdso/vdso.lds.S new file mode 100644 index 00000000000..b96b2677cad --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vdso.lds.S | |||
@@ -0,0 +1,32 @@ | |||
1 | /* | ||
2 | * Linker script for 64-bit vDSO. | ||
3 | * We #include the file to define the layout details. | ||
4 | * Here we only choose the prelinked virtual address. | ||
5 | * | ||
6 | * This file defines the version script giving the user-exported symbols in | ||
7 | * the DSO. We can define local symbols here called VDSO* to make their | ||
8 | * values visible using the asm-x86/vdso.h macros from the kernel proper. | ||
9 | */ | ||
10 | |||
11 | #define VDSO_PRELINK 0xffffffffff700000 | ||
12 | #include "vdso-layout.lds.S" | ||
13 | |||
14 | /* | ||
15 | * This controls what userland symbols we export from the vDSO. | ||
16 | */ | ||
17 | VERSION { | ||
18 | LINUX_2.6 { | ||
19 | global: | ||
20 | clock_gettime; | ||
21 | __vdso_clock_gettime; | ||
22 | gettimeofday; | ||
23 | __vdso_gettimeofday; | ||
24 | getcpu; | ||
25 | __vdso_getcpu; | ||
26 | time; | ||
27 | __vdso_time; | ||
28 | local: *; | ||
29 | }; | ||
30 | } | ||
31 | |||
32 | VDSO64_PRELINK = VDSO_PRELINK; | ||
diff --git a/arch/um/sys-x86_64/vdso/vma.c b/arch/um/sys-x86_64/vdso/vma.c new file mode 100644 index 00000000000..91f4ec9a0a5 --- /dev/null +++ b/arch/um/sys-x86_64/vdso/vma.c | |||
@@ -0,0 +1,74 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011 Richard Weinberger <richrd@nod.at> | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License version 2 as | ||
6 | * published by the Free Software Foundation. | ||
7 | */ | ||
8 | |||
9 | #include <linux/slab.h> | ||
10 | #include <linux/sched.h> | ||
11 | #include <linux/mm.h> | ||
12 | #include <asm/page.h> | ||
13 | #include <linux/init.h> | ||
14 | |||
15 | unsigned int __read_mostly vdso_enabled = 1; | ||
16 | unsigned long um_vdso_addr; | ||
17 | |||
18 | extern unsigned long task_size; | ||
19 | extern char vdso_start[], vdso_end[]; | ||
20 | |||
21 | static struct page **vdsop; | ||
22 | |||
23 | static int __init init_vdso(void) | ||
24 | { | ||
25 | struct page *um_vdso; | ||
26 | |||
27 | BUG_ON(vdso_end - vdso_start > PAGE_SIZE); | ||
28 | |||
29 | um_vdso_addr = task_size - PAGE_SIZE; | ||
30 | |||
31 | vdsop = kmalloc(sizeof(struct page *), GFP_KERNEL); | ||
32 | if (!vdsop) | ||
33 | goto oom; | ||
34 | |||
35 | um_vdso = alloc_page(GFP_KERNEL); | ||
36 | if (!um_vdso) { | ||
37 | kfree(vdsop); | ||
38 | |||
39 | goto oom; | ||
40 | } | ||
41 | |||
42 | copy_page(page_address(um_vdso), vdso_start); | ||
43 | *vdsop = um_vdso; | ||
44 | |||
45 | return 0; | ||
46 | |||
47 | oom: | ||
48 | printk(KERN_ERR "Cannot allocate vdso\n"); | ||
49 | vdso_enabled = 0; | ||
50 | |||
51 | return -ENOMEM; | ||
52 | } | ||
53 | subsys_initcall(init_vdso); | ||
54 | |||
55 | int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) | ||
56 | { | ||
57 | int err; | ||
58 | struct mm_struct *mm = current->mm; | ||
59 | |||
60 | if (!vdso_enabled) | ||
61 | return 0; | ||
62 | |||
63 | down_write(&mm->mmap_sem); | ||
64 | |||
65 | err = install_special_mapping(mm, um_vdso_addr, PAGE_SIZE, | ||
66 | VM_READ|VM_EXEC| | ||
67 | VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| | ||
68 | VM_ALWAYSDUMP, | ||
69 | vdsop); | ||
70 | |||
71 | up_write(&mm->mmap_sem); | ||
72 | |||
73 | return err; | ||
74 | } | ||