aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/Kconfig.x862
-rw-r--r--arch/um/drivers/chan_kern.c3
-rw-r--r--arch/um/drivers/cow_user.c6
-rw-r--r--arch/um/drivers/harddog_user.c2
-rw-r--r--arch/um/drivers/line.c3
-rw-r--r--arch/um/drivers/net_kern.c12
-rw-r--r--arch/um/drivers/net_user.c5
-rw-r--r--arch/um/drivers/slip_user.c3
-rw-r--r--arch/um/include/asm/delay.h10
-rw-r--r--arch/um/include/asm/ptrace-generic.h2
-rw-r--r--arch/um/kernel/exec.c1
-rw-r--r--arch/um/kernel/reboot.c3
-rw-r--r--arch/um/os-Linux/Makefile4
-rw-r--r--arch/um/os-Linux/elf_aux.c7
-rw-r--r--arch/um/os-Linux/helper.c4
-rw-r--r--arch/um/os-Linux/main.c4
-rw-r--r--arch/um/os-Linux/mem.c6
-rw-r--r--arch/um/os-Linux/user_syms.c5
-rw-r--r--arch/um/sys-i386/Makefile2
-rw-r--r--arch/um/sys-i386/asm/elf.h2
-rw-r--r--arch/um/sys-i386/delay.c59
-rw-r--r--arch/um/sys-i386/mem.c62
-rw-r--r--arch/um/sys-i386/signal.c2
-rw-r--r--arch/um/sys-x86_64/Makefile4
-rw-r--r--arch/um/sys-x86_64/asm/elf.h10
-rw-r--r--arch/um/sys-x86_64/delay.c54
-rw-r--r--arch/um/sys-x86_64/mem.c32
-rw-r--r--arch/um/sys-x86_64/shared/sysdep/vm-flags.h26
-rw-r--r--arch/um/sys-x86_64/vdso/Makefile90
-rw-r--r--arch/um/sys-x86_64/vdso/checkundef.sh10
-rw-r--r--arch/um/sys-x86_64/vdso/um_vdso.c71
-rw-r--r--arch/um/sys-x86_64/vdso/vdso-layout.lds.S64
-rw-r--r--arch/um/sys-x86_64/vdso/vdso-note.S12
-rw-r--r--arch/um/sys-x86_64/vdso/vdso.S10
-rw-r--r--arch/um/sys-x86_64/vdso/vdso.lds.S32
-rw-r--r--arch/um/sys-x86_64/vdso/vma.c74
36 files changed, 605 insertions, 93 deletions
diff --git a/arch/um/Kconfig.x86 b/arch/um/Kconfig.x86
index 8aae429a56e..d31ecf346b4 100644
--- a/arch/um/Kconfig.x86
+++ b/arch/um/Kconfig.x86
@@ -1,3 +1,5 @@
1mainmenu "User Mode Linux/$SUBARCH $KERNELVERSION Kernel Configuration"
2
1source "arch/um/Kconfig.common" 3source "arch/um/Kconfig.common"
2 4
3menu "UML-specific options" 5menu "UML-specific options"
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..d51c404239a 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 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
266static 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
265static void uml_net_get_drvinfo(struct net_device *dev, 274static 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
115out_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 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 */
7extern void __bad_udelay(void); 5extern void __bad_udelay(void);
6extern void __bad_ndelay(void);
8 7
9extern void __udelay(unsigned long usecs); 8extern void __udelay(unsigned long usecs);
9extern void __ndelay(unsigned long usecs);
10extern void __delay(unsigned long loops); 10extern 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))
17extern 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..ae084ad1a3a 100644
--- a/arch/um/include/asm/ptrace-generic.h
+++ b/arch/um/include/asm/ptrace-generic.h
@@ -47,8 +47,6 @@ extern int get_fpregs(struct user_i387_struct __user *buf,
47extern int set_fpregs(struct user_i387_struct __user *buf, 47extern int set_fpregs(struct user_i387_struct __user *buf,
48 struct task_struct *child); 48 struct task_struct *child);
49 49
50extern void show_regs(struct pt_regs *regs);
51
52extern int arch_copy_tls(struct task_struct *new); 50extern int arch_copy_tls(struct task_struct *new);
53extern void clear_flushed_tls(struct task_struct *task); 51extern void clear_flushed_tls(struct task_struct *task);
54 52
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
39void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) 39void 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 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
6obj-y = aio.o elf_aux.o execvp.o file.o helper.o irq.o main.o mem.o process.o \ 6obj-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
10obj-$(CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA) += elf_aux.o
11
10USER_OBJS := $(user-objs-y) aio.o elf_aux.o execvp.o file.o helper.o irq.o \ 12USER_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
19typedef Elf32_auxv_t elf_auxv_t; 17typedef Elf32_auxv_t elf_auxv_t;
20#else
21typedef 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 */
25char * elf_aux_platform; 20char * elf_aux_platform;
26long elf_aux_hwcap; 21extern long elf_aux_hwcap;
27unsigned long vsyscall_ehdr; 22unsigned long vsyscall_ehdr;
28unsigned long vsyscall_end; 23unsigned long vsyscall_end;
29unsigned long __kernel_vsyscall; 24unsigned 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
24long elf_aux_hwcap;
25
24static void set_stklim(void) 26static 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;
201close:
202 close(fd);
201out: 203out:
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 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
114extern long __guard __attribute__((weak)); 114extern long __guard __attribute__((weak));
115EXPORT_SYMBOL(__guard); 115EXPORT_SYMBOL(__guard);
116
117#ifdef _FORTIFY_SOURCE
118extern int __sprintf_chk(char *str, int flag, size_t strlen, const char *format);
119EXPORT_SYMBOL(__sprintf_chk);
120#endif
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 87b659dadf3..3923cfb8764 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -4,7 +4,7 @@
4 4
5obj-y = bug.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ 5obj-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
9obj-$(CONFIG_BINFMT_ELF) += elfcore.o 9obj-$(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 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/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
6void __delay(unsigned long time) 15void __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}
34EXPORT_SYMBOL(__delay);
19 35
20void __udelay(unsigned long usecs) 36inline 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}
48EXPORT_SYMBOL(__const_udelay);
28 49
50void __udelay(unsigned long usecs)
51{
52 __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */
53}
29EXPORT_SYMBOL(__udelay); 54EXPORT_SYMBOL(__udelay);
55
56void __ndelay(unsigned long nsecs)
57{
58 __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */
59}
60EXPORT_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
13static struct vm_area_struct gate_vma;
14
15static 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
38struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
39{
40 return FIXADDR_USER_START ? &gate_vma : NULL;
41}
42
43int 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
54int 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/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 61fc99a42e1..bd4d1d3ba91 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
7obj-y = bug.o bugs.o delay.o fault.o ldt.o mem.o ptrace.o ptrace_user.o \ 7obj-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
11obj-y += vdso/
12
11subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \ 13subarch-obj-y = lib/csum-partial_64.o lib/memcpy_64.o lib/thunk_64.o \
12 lib/rwsem.o 14 lib/rwsem.o
13subarch-obj-$(CONFIG_MODULES) += kernel/module.o 15subarch-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 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
124struct linux_binprm;
125extern int arch_setup_additional_pages(struct linux_binprm *bprm,
126 int uses_interp);
127
128extern 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
13void __delay(unsigned long loops) 15void __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}
34EXPORT_SYMBOL(__delay);
20 35
21void __udelay(unsigned long usecs) 36inline 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}
48EXPORT_SYMBOL(__const_udelay);
29 49
50void __udelay(unsigned long usecs)
51{
52 __const_udelay(usecs * 0x000010c7); /* 2**32 / 1000000 (rounded up) */
53}
30EXPORT_SYMBOL(__udelay); 54EXPORT_SYMBOL(__udelay);
55
56void __ndelay(unsigned long nsecs)
57{
58 __const_udelay(nsecs * 0x00005); /* 2**32 / 1000000000 (rounded up) */
59}
60EXPORT_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
11unsigned long vm_stack_flags = __VM_STACK_FLAGS; 5const char *arch_vma_name(struct vm_area_struct *vma)
12unsigned long vm_stack_flags32 = __VM_STACK_FLAGS; 6{
13unsigned long vm_data_default_flags = __VM_DATA_DEFAULT_FLAGS; 7 if (vma->vm_mm && vma->vm_start == um_vdso_addr)
14unsigned long vm_data_default_flags32 = __VM_DATA_DEFAULT_FLAGS; 8 return "[vdso]";
15unsigned long vm_force_exec32 = PROT_EXEC; 9
10 return NULL;
11}
12
13struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
14{
15 return NULL;
16}
17
18int in_gate_area(struct mm_struct *mm, unsigned long addr)
19{
20 return 0;
21}
16 22
23int 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 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
16extern unsigned long vm_stack_flags, vm_stack_flags32;
17extern unsigned long vm_data_default_flags, vm_data_default_flags32;
18extern 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
5VDSO64-y := y
6
7vdso-install-$(VDSO64-y) += vdso.so
8
9
10# files to link into the vdso
11vobjs-y := vdso-note.o um_vdso.o
12
13# files to link into kernel
14obj-$(VDSO64-y) += vdso.o vma.o
15
16vobjs := $(foreach F,$(vobjs-y),$(obj)/$F)
17
18$(obj)/vdso.o: $(obj)/vdso.so
19
20targets += vdso.so vdso.so.dbg vdso.lds $(vobjs-y)
21
22export CPPFLAGS_vdso.lds += -P -C
23
24VDSO_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#
40CFL := $(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#
49CFLAGS_REMOVE_vdso-note.o = -pg
50CFLAGS_REMOVE_um_vdso.o = -pg
51
52targets += vdso-syms.lds
53obj-$(VDSO64-y) += vdso-syms.lds
54
55#
56# Match symbols in the DSO that look like VDSO*; produce a file of constants.
57#
58sed-vdsosym := -e 's/^00*/0/' \
59 -e 's/^\([0-9a-fA-F]*\) . \(VDSO[a-zA-Z0-9_]*\)$$/\2 = 0x\1;/p'
60quiet_cmd_vdsosym = VDSOSYM $@
61define cmd_vdsosym
62 $(NM) $< | LC_ALL=C sed -n $(sed-vdsosym) | LC_ALL=C sort > $@
63endef
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#
71quiet_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
77VDSO_LDFLAGS = -fPIC -shared $(call cc-ldoption, -Wl$(comma)--hash-style=sysv)
78GCOV_PROFILE := n
79
80#
81# Install the unstripped copy of vdso*.so listed in $(vdso-install-y).
82#
83quiet_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
89PHONY += vdso_install $(vdso-install-y)
90vdso_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
2nm="$1"
3file="$2"
4$nm "$file" | grep '^ *U' > /dev/null 2>&1
5if [ $? -eq 1 ]; then
6 exit 0
7else
8 echo "$file: undefined symbols found" >&2
9 exit 1
10fi
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
19int __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}
28int clock_gettime(clockid_t, struct timespec *)
29 __attribute__((weak, alias("__vdso_clock_gettime")));
30
31int __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}
40int gettimeofday(struct timeval *, struct timezone *)
41 __attribute__((weak, alias("__vdso_gettimeofday")));
42
43time_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}
53int time(time_t *t) __attribute__((weak, alias("__vdso_time")));
54
55long
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
70long 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
7SECTIONS
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 */
58PHDRS
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
10ELFNOTE_START(Linux, 0, "a")
11 .long LINUX_VERSION_CODE
12ELFNOTE_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
6vdso_start:
7 .incbin "arch/um/sys-x86_64/vdso/vdso.so"
8vdso_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 */
17VERSION {
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
32VDSO64_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..9495c8d0ce3
--- /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
15unsigned int __read_mostly vdso_enabled = 1;
16unsigned long um_vdso_addr;
17
18extern unsigned long task_size;
19extern char vdso_start[], vdso_end[];
20
21static struct page **vdsop;
22
23static 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
47oom:
48 printk(KERN_ERR "Cannot allocate vdso\n");
49 vdso_enabled = 0;
50
51 return -ENOMEM;
52}
53subsys_initcall(init_vdso);
54
55int 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}