aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/process.c')
-rw-r--r--arch/x86/kernel/process.c114
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
21unsigned long idle_halt; 26unsigned long idle_halt;
22EXPORT_SYMBOL(idle_halt); 27EXPORT_SYMBOL(idle_halt);
@@ -87,6 +92,25 @@ void exit_thread(void)
87 } 92 }
88} 93}
89 94
95void 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
90void flush_thread(void) 114void 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
229int sys_fork(struct pt_regs *regs) 237int 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
258long
259sys_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 */
272extern void kernel_thread_helper(void);
273
274/*
275 * Create a kernel thread
276 */
277int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
278{
279 struct pt_regs regs;
280
281 memset(&regs, 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, &regs, 0, NULL, NULL);
300}
301EXPORT_SYMBOL(kernel_thread);
302
303/*
304 * sys_execve() executes a new program.
305 */
306long 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