diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-26 00:00:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-07-26 00:00:19 -0400 |
commit | 45b583b10a8b438b970e95a7d1d4db22c9e35004 (patch) | |
tree | 14fa481598289df0459580c582b48a9d95db51f6 /arch/um | |
parent | 154dd78d30b56ffb8b447f629bfcceb14150e5c4 (diff) | |
parent | f19da2ce8ef5e49b8b8ea199c3601dd45d71b262 (diff) |
Merge 'akpm' patch series
* Merge akpm patch series: (122 commits)
drivers/connector/cn_proc.c: remove unused local
Documentation/SubmitChecklist: add RCU debug config options
reiserfs: use hweight_long()
reiserfs: use proper little-endian bitops
pnpacpi: register disabled resources
drivers/rtc/rtc-tegra.c: properly initialize spinlock
drivers/rtc/rtc-twl.c: check return value of twl_rtc_write_u8() in twl_rtc_set_time()
drivers/rtc: add support for Qualcomm PMIC8xxx RTC
drivers/rtc/rtc-s3c.c: support clock gating
drivers/rtc/rtc-mpc5121.c: add support for RTC on MPC5200
init: skip calibration delay if previously done
misc/eeprom: add eeprom access driver for digsy_mtc board
misc/eeprom: add driver for microwire 93xx46 EEPROMs
checkpatch.pl: update $logFunctions
checkpatch: make utf-8 test --strict
checkpatch.pl: add ability to ignore various messages
checkpatch: add a "prefer __aligned" check
checkpatch: validate signature styles and To: and Cc: lines
checkpatch: add __rcu as a sparse modifier
checkpatch: suggest using min_t or max_t
...
Did this as a merge because of (trivial) conflicts in
- Documentation/feature-removal-schedule.txt
- arch/xtensa/include/asm/uaccess.h
that were just easier to fix up in the merge than in the patch series.
Diffstat (limited to 'arch/um')
34 files changed, 604 insertions, 90 deletions
diff --git a/arch/um/Kconfig.x86 b/arch/um/Kconfig.x86 index 8aae429a56e2..d31ecf346b4e 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" |
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c index 25e1965df7ce..d4191fe1cede 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 93f227a25ba4..9cbb426c0b91 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 b56f8e0196a9..84dce3fc590c 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 35dd0b86401a..d51c404239a8 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 | ||
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 47d0c37897d5..22745b47c829 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 9415dd9e63ef..520118888f16 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 a1c2d2c98a94..cbacfc4e63e6 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/include/asm/delay.h b/arch/um/include/asm/delay.h index c71e32b6741e..8a5576d8eda5 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/kernel/exec.c b/arch/um/kernel/exec.c index 09bd7b585726..939a4a67f0fd 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/reboot.c b/arch/um/kernel/reboot.c index 869bec9f2516..4d93dff6b371 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 d66f0388f091..b33f4dfe7ae5 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 608784d4ec57..953323799381 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 b6b1096152aa..feff22d64672 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 fb2a97a75fb1..8471b817d94f 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 e696144d2be3..62878cf1d33f 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/user_syms.c b/arch/um/os-Linux/user_syms.c index 05f5ea8e83d2..45ffe46871e0 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 87b659dadf3f..3923cfb87649 100644 --- a/arch/um/sys-i386/Makefile +++ b/arch/um/sys-i386/Makefile | |||
@@ -4,7 +4,7 @@ | |||
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 | ||
diff --git a/arch/um/sys-i386/asm/elf.h b/arch/um/sys-i386/asm/elf.h index d964a4111ac6..42305551d204 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/delay.c b/arch/um/sys-i386/delay.c index d623e074f41d..f3fe1a688f7e 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 000000000000..639900a6fde9 --- /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-x86_64/Makefile b/arch/um/sys-x86_64/Makefile index 61fc99a42e10..bd4d1d3ba919 100644 --- a/arch/um/sys-x86_64/Makefile +++ b/arch/um/sys-x86_64/Makefile | |||
@@ -4,10 +4,12 @@ | |||
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.o | 14 | lib/rwsem.o |
13 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o | 15 | subarch-obj-$(CONFIG_MODULES) += kernel/module.o |
diff --git a/arch/um/sys-x86_64/asm/elf.h b/arch/um/sys-x86_64/asm/elf.h index d6d5af376251..11a2bfb38859 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 dee5be66da82..f3fe1a688f7e 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 3f8df8abf347..546518727a73 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/shared/sysdep/vm-flags.h b/arch/um/sys-x86_64/shared/sysdep/vm-flags.h index 3213edfa7888..3978e55132d2 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 000000000000..5dffe6d46686 --- /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 000000000000..7ee90a9b549d --- /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 000000000000..7c441b59d375 --- /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 000000000000..634a2cf62046 --- /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 000000000000..79a071e4357e --- /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 000000000000..ec82c1686bd6 --- /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 000000000000..b96b2677cad8 --- /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 000000000000..9495c8d0ce37 --- /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(GFP_KERNEL, sizeof(struct page *)); | ||
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 | } | ||