aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/include/os.h2
-rw-r--r--arch/um/os-Linux/sys-x86_64/Makefile2
-rw-r--r--arch/um/os-Linux/sys-x86_64/prctl.c12
-rw-r--r--arch/um/sys-x86_64/syscalls.c73
-rw-r--r--arch/um/sys-x86_64/tls.c11
-rw-r--r--include/asm-um/processor-x86_64.h6
-rw-r--r--include/asm-um/ptrace-x86_64.h6
7 files changed, 83 insertions, 29 deletions
diff --git a/arch/um/include/os.h b/arch/um/include/os.h
index 8f602667296d..8629bd191492 100644
--- a/arch/um/include/os.h
+++ b/arch/um/include/os.h
@@ -340,4 +340,6 @@ extern void maybe_sigio_broken(int fd, int read);
340extern void sig_handler_common_skas(int sig, void *sc_ptr); 340extern void sig_handler_common_skas(int sig, void *sc_ptr);
341extern void user_signal(int sig, union uml_pt_regs *regs, int pid); 341extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
342 342
343extern int os_arch_prctl(int pid, int code, unsigned long *addr);
344
343#endif 345#endif
diff --git a/arch/um/os-Linux/sys-x86_64/Makefile b/arch/um/os-Linux/sys-x86_64/Makefile
index f67842a7735b..7955e061a678 100644
--- a/arch/um/os-Linux/sys-x86_64/Makefile
+++ b/arch/um/os-Linux/sys-x86_64/Makefile
@@ -3,7 +3,7 @@
3# Licensed under the GPL 3# Licensed under the GPL
4# 4#
5 5
6obj-$(CONFIG_MODE_SKAS) = registers.o signal.o 6obj-$(CONFIG_MODE_SKAS) = registers.o prctl.o signal.o
7 7
8USER_OBJS := $(obj-y) 8USER_OBJS := $(obj-y)
9 9
diff --git a/arch/um/os-Linux/sys-x86_64/prctl.c b/arch/um/os-Linux/sys-x86_64/prctl.c
new file mode 100644
index 000000000000..9d34eddb517f
--- /dev/null
+++ b/arch/um/os-Linux/sys-x86_64/prctl.c
@@ -0,0 +1,12 @@
1/*
2 * Copyright (C) 2007 Jeff Dike (jdike@{addtoit.com,linux.intel.com})
3 * Licensed under the GPL
4 */
5
6#include <sys/ptrace.h>
7#include <linux/ptrace.h>
8
9int os_arch_prctl(int pid, int code, unsigned long *addr)
10{
11 return ptrace(PTRACE_ARCH_PRCTL, pid, (unsigned long) addr, code);
12}
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
index 73ce4463f70c..f309fa9bc232 100644
--- a/arch/um/sys-x86_64/syscalls.c
+++ b/arch/um/sys-x86_64/syscalls.c
@@ -16,6 +16,7 @@
16#include "asm/prctl.h" /* XXX This should get the constants from libc */ 16#include "asm/prctl.h" /* XXX This should get the constants from libc */
17#include "choose-mode.h" 17#include "choose-mode.h"
18#include "kern.h" 18#include "kern.h"
19#include "os.h"
19 20
20asmlinkage long sys_uname64(struct new_utsname __user * name) 21asmlinkage long sys_uname64(struct new_utsname __user * name)
21{ 22{
@@ -58,40 +59,67 @@ static long arch_prctl_tt(int code, unsigned long addr)
58 59
59#ifdef CONFIG_MODE_SKAS 60#ifdef CONFIG_MODE_SKAS
60 61
61/* XXX: Must also call arch_prctl in the host, beside saving the segment bases! */ 62static long arch_prctl_skas(int code, unsigned long __user *addr)
62static long arch_prctl_skas(int code, unsigned long addr)
63{ 63{
64 long ret = 0; 64 unsigned long *ptr = addr, tmp;
65 long ret;
66 int pid = current->mm->context.skas.id.u.pid;
65 67
68 /*
69 * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to
70 * be safe), we need to call arch_prctl on the host because
71 * setting %fs may result in something else happening (like a
72 * GDT being set instead). So, we let the host fiddle the
73 * registers and restore them afterwards.
74 *
75 * So, the saved registers are stored to the process (this
76 * needed because a stub may have been the last thing to run),
77 * arch_prctl is run on the host, then the registers are read
78 * back.
79 */
66 switch(code){ 80 switch(code){
67 case ARCH_SET_FS: 81 case ARCH_SET_FS:
68 current->thread.regs.regs.skas.regs[FS_BASE / sizeof(unsigned long)] = addr;
69 break;
70 case ARCH_SET_GS: 82 case ARCH_SET_GS:
71 current->thread.regs.regs.skas.regs[GS_BASE / sizeof(unsigned long)] = addr; 83 restore_registers(pid, &current->thread.regs.regs);
84 break;
85 case ARCH_GET_FS:
86 case ARCH_GET_GS:
87 /*
88 * With these two, we read to a local pointer and
89 * put_user it to the userspace pointer that we were
90 * given. If addr isn't valid (because it hasn't been
91 * faulted in or is just bogus), we want put_user to
92 * fault it in (or return -EFAULT) instead of having
93 * the host return -EFAULT.
94 */
95 ptr = &tmp;
96 }
97
98 ret = os_arch_prctl(pid, code, ptr);
99 if(ret)
100 return ret;
101
102 switch(code){
103 case ARCH_SET_FS:
104 case ARCH_SET_GS:
105 save_registers(pid, &current->thread.regs.regs);
72 break; 106 break;
73 case ARCH_GET_FS: 107 case ARCH_GET_FS:
74 ret = put_user(current->thread.regs.regs.skas. 108 ret = put_user(tmp, addr);
75 regs[FS_BASE / sizeof(unsigned long)],
76 (unsigned long __user *)addr);
77 break; 109 break;
78 case ARCH_GET_GS: 110 case ARCH_GET_GS:
79 ret = put_user(current->thread.regs.regs.skas. 111 ret = put_user(tmp, addr);
80 regs[GS_BASE / sizeof(unsigned long)],
81 (unsigned long __user *)addr);
82 break; 112 break;
83 default:
84 ret = -EINVAL;
85 break;
86 } 113 }
87 114
88 return(ret); 115 return ret;
89} 116}
90#endif 117#endif
91 118
92long sys_arch_prctl(int code, unsigned long addr) 119long sys_arch_prctl(int code, unsigned long addr)
93{ 120{
94 return(CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code, addr)); 121 return CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, code,
122 (unsigned long __user *) addr);
95} 123}
96 124
97long sys_clone(unsigned long clone_flags, unsigned long newsp, 125long sys_clone(unsigned long clone_flags, unsigned long newsp,
@@ -105,5 +133,14 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
105 ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid, 133 ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
106 child_tid); 134 child_tid);
107 current->thread.forking = 0; 135 current->thread.forking = 0;
108 return(ret); 136 return ret;
137}
138
139void arch_switch_to_skas(struct task_struct *from, struct task_struct *to)
140{
141 if(to->thread.arch.fs == 0)
142 return;
143
144 arch_prctl_skas(ARCH_SET_FS, (void __user *) to->thread.arch.fs);
109} 145}
146
diff --git a/arch/um/sys-x86_64/tls.c b/arch/um/sys-x86_64/tls.c
index ce1bf1b81c43..febbc94be25f 100644
--- a/arch/um/sys-x86_64/tls.c
+++ b/arch/um/sys-x86_64/tls.c
@@ -1,14 +1,17 @@
1#include "linux/sched.h" 1#include "linux/sched.h"
2 2
3void debug_arch_force_load_TLS(void)
4{
5}
6
7void clear_flushed_tls(struct task_struct *task) 3void clear_flushed_tls(struct task_struct *task)
8{ 4{
9} 5}
10 6
11int arch_copy_tls(struct task_struct *t) 7int arch_copy_tls(struct task_struct *t)
12{ 8{
9 /*
10 * If CLONE_SETTLS is set, we need to save the thread id
11 * (which is argument 5, child_tid, of clone) so it can be set
12 * during context switches.
13 */
14 t->thread.arch.fs = t->thread.regs.regs.skas.regs[R8 / sizeof(long)];
15
13 return 0; 16 return 0;
14} 17}
diff --git a/include/asm-um/processor-x86_64.h b/include/asm-um/processor-x86_64.h
index 10609af376c0..31c2d4d685bd 100644
--- a/include/asm-um/processor-x86_64.h
+++ b/include/asm-um/processor-x86_64.h
@@ -13,6 +13,7 @@
13struct arch_thread { 13struct arch_thread {
14 unsigned long debugregs[8]; 14 unsigned long debugregs[8];
15 int debugregs_seq; 15 int debugregs_seq;
16 unsigned long fs;
16 struct faultinfo faultinfo; 17 struct faultinfo faultinfo;
17}; 18};
18 19
@@ -25,8 +26,9 @@ extern inline void rep_nop(void)
25#define cpu_relax() rep_nop() 26#define cpu_relax() rep_nop()
26 27
27#define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \ 28#define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \
28 .debugregs_seq = 0, \ 29 .debugregs_seq = 0, \
29 .faultinfo = { 0, 0, 0 } } 30 .fs = 0, \
31 .faultinfo = { 0, 0, 0 } }
30 32
31static inline void arch_flush_thread(struct arch_thread *thread) 33static inline void arch_flush_thread(struct arch_thread *thread)
32{ 34{
diff --git a/include/asm-um/ptrace-x86_64.h b/include/asm-um/ptrace-x86_64.h
index 03b4af4ac09a..a927450ce401 100644
--- a/include/asm-um/ptrace-x86_64.h
+++ b/include/asm-um/ptrace-x86_64.h
@@ -81,9 +81,7 @@ static inline void arch_switch_to_tt(struct task_struct *from,
81{ 81{
82} 82}
83 83
84static inline void arch_switch_to_skas(struct task_struct *from, 84extern void arch_switch_to_skas(struct task_struct *from,
85 struct task_struct *to) 85 struct task_struct *to);
86{
87}
88 86
89#endif 87#endif