aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/sys-x86_64
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/sys-x86_64')
-rw-r--r--arch/um/sys-x86_64/syscalls.c73
-rw-r--r--arch/um/sys-x86_64/tls.c11
2 files changed, 62 insertions, 22 deletions
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}