Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * Copyright 2003 PathScale, Inc. | |
3 | * | |
4 | * Licensed under the GPL | |
5 | */ | |
6 | ||
7 | #include "linux/linkage.h" | |
8 | #include "linux/slab.h" | |
9 | #include "linux/shm.h" | |
f7fe8781 PBG |
10 | #include "linux/utsname.h" |
11 | #include "linux/personality.h" | |
1da177e4 LT |
12 | #include "asm/uaccess.h" |
13 | #define __FRAME_OFFSETS | |
14 | #include "asm/ptrace.h" | |
15 | #include "asm/unistd.h" | |
16 | #include "asm/prctl.h" /* XXX This should get the constants from libc */ | |
17 | #include "choose-mode.h" | |
ba9950c8 | 18 | #include "kern.h" |
f355559c | 19 | #include "os.h" |
1da177e4 | 20 | |
80f95078 PBG |
21 | asmlinkage long sys_uname64(struct new_utsname __user * name) |
22 | { | |
23 | int err; | |
24 | down_read(&uts_sem); | |
e9ff3990 | 25 | err = copy_to_user(name, utsname(), sizeof (*name)); |
80f95078 PBG |
26 | up_read(&uts_sem); |
27 | if (personality(current->personality) == PER_LINUX32) | |
28 | err |= copy_to_user(&name->machine, "i686", 5); | |
29 | return err ? -EFAULT : 0; | |
30 | } | |
31 | ||
1da177e4 LT |
32 | #ifdef CONFIG_MODE_TT |
33 | extern long arch_prctl(int code, unsigned long addr); | |
34 | ||
35 | static long arch_prctl_tt(int code, unsigned long addr) | |
36 | { | |
37 | unsigned long tmp; | |
38 | long ret; | |
39 | ||
40 | switch(code){ | |
41 | case ARCH_SET_GS: | |
42 | case ARCH_SET_FS: | |
43 | ret = arch_prctl(code, addr); | |
44 | break; | |
45 | case ARCH_GET_FS: | |
46 | case ARCH_GET_GS: | |
47 | ret = arch_prctl(code, (unsigned long) &tmp); | |
48 | if(!ret) | |
ca34fb1a | 49 | ret = put_user(tmp, (long __user *)addr); |
1da177e4 LT |
50 | break; |
51 | default: | |
52 | ret = -EINVAL; | |
53 | break; | |
54 | } | |
55 | ||
56 | return(ret); | |
57 | } | |
58 | #endif | |
59 | ||
60 | #ifdef CONFIG_MODE_SKAS | |
61 | ||
6e6d74cf JD |
62 | long arch_prctl_skas(struct task_struct *task, int code, |
63 | unsigned long __user *addr) | |
1da177e4 | 64 | { |
f355559c JD |
65 | unsigned long *ptr = addr, tmp; |
66 | long ret; | |
6e6d74cf | 67 | int pid = task->mm->context.skas.id.u.pid; |
1da177e4 | 68 | |
f355559c JD |
69 | /* |
70 | * With ARCH_SET_FS (and ARCH_SET_GS is treated similarly to | |
71 | * be safe), we need to call arch_prctl on the host because | |
72 | * setting %fs may result in something else happening (like a | |
6e6d74cf JD |
73 | * GDT or thread.fs being set instead). So, we let the host |
74 | * fiddle the registers and thread struct and restore the | |
75 | * registers afterwards. | |
f355559c JD |
76 | * |
77 | * So, the saved registers are stored to the process (this | |
78 | * needed because a stub may have been the last thing to run), | |
79 | * arch_prctl is run on the host, then the registers are read | |
80 | * back. | |
81 | */ | |
1da177e4 | 82 | switch(code){ |
1da177e4 | 83 | case ARCH_SET_FS: |
f767b02f | 84 | case ARCH_SET_GS: |
f355559c JD |
85 | restore_registers(pid, ¤t->thread.regs.regs); |
86 | break; | |
87 | case ARCH_GET_FS: | |
88 | case ARCH_GET_GS: | |
89 | /* | |
90 | * With these two, we read to a local pointer and | |
91 | * put_user it to the userspace pointer that we were | |
92 | * given. If addr isn't valid (because it hasn't been | |
93 | * faulted in or is just bogus), we want put_user to | |
94 | * fault it in (or return -EFAULT) instead of having | |
95 | * the host return -EFAULT. | |
96 | */ | |
97 | ptr = &tmp; | |
98 | } | |
99 | ||
100 | ret = os_arch_prctl(pid, code, ptr); | |
101 | if(ret) | |
102 | return ret; | |
103 | ||
104 | switch(code){ | |
105 | case ARCH_SET_FS: | |
44f5c4ce JD |
106 | current->thread.arch.fs = (unsigned long) ptr; |
107 | save_registers(pid, ¤t->thread.regs.regs); | |
108 | break; | |
f355559c JD |
109 | case ARCH_SET_GS: |
110 | save_registers(pid, ¤t->thread.regs.regs); | |
f767b02f | 111 | break; |
1da177e4 | 112 | case ARCH_GET_FS: |
f355559c | 113 | ret = put_user(tmp, addr); |
1da177e4 LT |
114 | break; |
115 | case ARCH_GET_GS: | |
f355559c | 116 | ret = put_user(tmp, addr); |
1da177e4 | 117 | break; |
1da177e4 LT |
118 | } |
119 | ||
f355559c | 120 | return ret; |
1da177e4 LT |
121 | } |
122 | #endif | |
123 | ||
124 | long sys_arch_prctl(int code, unsigned long addr) | |
125 | { | |
6e6d74cf | 126 | return CHOOSE_MODE_PROC(arch_prctl_tt, arch_prctl_skas, current, code, |
f355559c | 127 | (unsigned long __user *) addr); |
1da177e4 LT |
128 | } |
129 | ||
130 | long sys_clone(unsigned long clone_flags, unsigned long newsp, | |
131 | void __user *parent_tid, void __user *child_tid) | |
132 | { | |
133 | long ret; | |
134 | ||
e0877f07 JD |
135 | if (!newsp) |
136 | newsp = UPT_SP(¤t->thread.regs.regs); | |
1da177e4 | 137 | current->thread.forking = 1; |
e0877f07 JD |
138 | ret = do_fork(clone_flags, newsp, ¤t->thread.regs, 0, parent_tid, |
139 | child_tid); | |
1da177e4 | 140 | current->thread.forking = 0; |
f355559c JD |
141 | return ret; |
142 | } | |
143 | ||
144 | void arch_switch_to_skas(struct task_struct *from, struct task_struct *to) | |
145 | { | |
44f5c4ce | 146 | if((to->thread.arch.fs == 0) || (to->mm == NULL)) |
f355559c JD |
147 | return; |
148 | ||
6e6d74cf | 149 | arch_prctl_skas(to, ARCH_SET_FS, (void __user *) to->thread.arch.fs); |
1da177e4 | 150 | } |