diff options
Diffstat (limited to 'arch/x86/kernel/process.c')
-rw-r--r-- | arch/x86/kernel/process.c | 114 |
1 files changed, 96 insertions, 18 deletions
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 5284cd2b5776..c6ee241c8a98 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c | |||
@@ -9,7 +9,11 @@ | |||
9 | #include <linux/pm.h> | 9 | #include <linux/pm.h> |
10 | #include <linux/clockchips.h> | 10 | #include <linux/clockchips.h> |
11 | #include <linux/random.h> | 11 | #include <linux/random.h> |
12 | #include <linux/user-return-notifier.h> | ||
13 | #include <linux/dmi.h> | ||
14 | #include <linux/utsname.h> | ||
12 | #include <trace/events/power.h> | 15 | #include <trace/events/power.h> |
16 | #include <linux/hw_breakpoint.h> | ||
13 | #include <asm/system.h> | 17 | #include <asm/system.h> |
14 | #include <asm/apic.h> | 18 | #include <asm/apic.h> |
15 | #include <asm/syscalls.h> | 19 | #include <asm/syscalls.h> |
@@ -17,6 +21,7 @@ | |||
17 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
18 | #include <asm/i387.h> | 22 | #include <asm/i387.h> |
19 | #include <asm/ds.h> | 23 | #include <asm/ds.h> |
24 | #include <asm/debugreg.h> | ||
20 | 25 | ||
21 | unsigned long idle_halt; | 26 | unsigned long idle_halt; |
22 | EXPORT_SYMBOL(idle_halt); | 27 | EXPORT_SYMBOL(idle_halt); |
@@ -87,6 +92,25 @@ void exit_thread(void) | |||
87 | } | 92 | } |
88 | } | 93 | } |
89 | 94 | ||
95 | void show_regs_common(void) | ||
96 | { | ||
97 | const char *board, *product; | ||
98 | |||
99 | board = dmi_get_system_info(DMI_BOARD_NAME); | ||
100 | if (!board) | ||
101 | board = ""; | ||
102 | product = dmi_get_system_info(DMI_PRODUCT_NAME); | ||
103 | if (!product) | ||
104 | product = ""; | ||
105 | |||
106 | printk(KERN_CONT "\n"); | ||
107 | printk(KERN_DEFAULT "Pid: %d, comm: %.20s %s %s %.*s %s/%s\n", | ||
108 | current->pid, current->comm, print_tainted(), | ||
109 | init_utsname()->release, | ||
110 | (int)strcspn(init_utsname()->version, " "), | ||
111 | init_utsname()->version, board, product); | ||
112 | } | ||
113 | |||
90 | void flush_thread(void) | 114 | void flush_thread(void) |
91 | { | 115 | { |
92 | struct task_struct *tsk = current; | 116 | struct task_struct *tsk = current; |
@@ -103,14 +127,7 @@ void flush_thread(void) | |||
103 | } | 127 | } |
104 | #endif | 128 | #endif |
105 | 129 | ||
106 | clear_tsk_thread_flag(tsk, TIF_DEBUG); | 130 | flush_ptrace_hw_breakpoint(tsk); |
107 | |||
108 | tsk->thread.debugreg0 = 0; | ||
109 | tsk->thread.debugreg1 = 0; | ||
110 | tsk->thread.debugreg2 = 0; | ||
111 | tsk->thread.debugreg3 = 0; | ||
112 | tsk->thread.debugreg6 = 0; | ||
113 | tsk->thread.debugreg7 = 0; | ||
114 | memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); | 131 | memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); |
115 | /* | 132 | /* |
116 | * Forget coprocessor state.. | 133 | * Forget coprocessor state.. |
@@ -192,16 +209,6 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, | |||
192 | else if (next->debugctlmsr != prev->debugctlmsr) | 209 | else if (next->debugctlmsr != prev->debugctlmsr) |
193 | update_debugctlmsr(next->debugctlmsr); | 210 | update_debugctlmsr(next->debugctlmsr); |
194 | 211 | ||
195 | if (test_tsk_thread_flag(next_p, TIF_DEBUG)) { | ||
196 | set_debugreg(next->debugreg0, 0); | ||
197 | set_debugreg(next->debugreg1, 1); | ||
198 | set_debugreg(next->debugreg2, 2); | ||
199 | set_debugreg(next->debugreg3, 3); | ||
200 | /* no 4 and 5 */ | ||
201 | set_debugreg(next->debugreg6, 6); | ||
202 | set_debugreg(next->debugreg7, 7); | ||
203 | } | ||
204 | |||
205 | if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ | 212 | if (test_tsk_thread_flag(prev_p, TIF_NOTSC) ^ |
206 | test_tsk_thread_flag(next_p, TIF_NOTSC)) { | 213 | test_tsk_thread_flag(next_p, TIF_NOTSC)) { |
207 | /* prev and next are different */ | 214 | /* prev and next are different */ |
@@ -224,6 +231,7 @@ void __switch_to_xtra(struct task_struct *prev_p, struct task_struct *next_p, | |||
224 | */ | 231 | */ |
225 | memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); | 232 | memset(tss->io_bitmap, 0xff, prev->io_bitmap_max); |
226 | } | 233 | } |
234 | propagate_user_return_notify(prev_p, next_p); | ||
227 | } | 235 | } |
228 | 236 | ||
229 | int sys_fork(struct pt_regs *regs) | 237 | int sys_fork(struct pt_regs *regs) |
@@ -247,6 +255,76 @@ int sys_vfork(struct pt_regs *regs) | |||
247 | NULL, NULL); | 255 | NULL, NULL); |
248 | } | 256 | } |
249 | 257 | ||
258 | long | ||
259 | sys_clone(unsigned long clone_flags, unsigned long newsp, | ||
260 | void __user *parent_tid, void __user *child_tid, struct pt_regs *regs) | ||
261 | { | ||
262 | if (!newsp) | ||
263 | newsp = regs->sp; | ||
264 | return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); | ||
265 | } | ||
266 | |||
267 | /* | ||
268 | * This gets run with %si containing the | ||
269 | * function to call, and %di containing | ||
270 | * the "args". | ||
271 | */ | ||
272 | extern void kernel_thread_helper(void); | ||
273 | |||
274 | /* | ||
275 | * Create a kernel thread | ||
276 | */ | ||
277 | int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) | ||
278 | { | ||
279 | struct pt_regs regs; | ||
280 | |||
281 | memset(®s, 0, sizeof(regs)); | ||
282 | |||
283 | regs.si = (unsigned long) fn; | ||
284 | regs.di = (unsigned long) arg; | ||
285 | |||
286 | #ifdef CONFIG_X86_32 | ||
287 | regs.ds = __USER_DS; | ||
288 | regs.es = __USER_DS; | ||
289 | regs.fs = __KERNEL_PERCPU; | ||
290 | regs.gs = __KERNEL_STACK_CANARY; | ||
291 | #endif | ||
292 | |||
293 | regs.orig_ax = -1; | ||
294 | regs.ip = (unsigned long) kernel_thread_helper; | ||
295 | regs.cs = __KERNEL_CS | get_kernel_rpl(); | ||
296 | regs.flags = X86_EFLAGS_IF | 0x2; | ||
297 | |||
298 | /* Ok, create the new process.. */ | ||
299 | return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); | ||
300 | } | ||
301 | EXPORT_SYMBOL(kernel_thread); | ||
302 | |||
303 | /* | ||
304 | * sys_execve() executes a new program. | ||
305 | */ | ||
306 | long sys_execve(char __user *name, char __user * __user *argv, | ||
307 | char __user * __user *envp, struct pt_regs *regs) | ||
308 | { | ||
309 | long error; | ||
310 | char *filename; | ||
311 | |||
312 | filename = getname(name); | ||
313 | error = PTR_ERR(filename); | ||
314 | if (IS_ERR(filename)) | ||
315 | return error; | ||
316 | error = do_execve(filename, argv, envp, regs); | ||
317 | |||
318 | #ifdef CONFIG_X86_32 | ||
319 | if (error == 0) { | ||
320 | /* Make sure we don't return using sysenter.. */ | ||
321 | set_thread_flag(TIF_IRET); | ||
322 | } | ||
323 | #endif | ||
324 | |||
325 | putname(filename); | ||
326 | return error; | ||
327 | } | ||
250 | 328 | ||
251 | /* | 329 | /* |
252 | * Idle related variables and functions | 330 | * Idle related variables and functions |