|
@@ -243,6 +243,41 @@ sys_clone(unsigned long clone_flags, unsigned long newsp,
|
|
|
return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This gets run with %si containing the
|
|
|
+ * function to call, and %di containing
|
|
|
+ * the "args".
|
|
|
+ */
|
|
|
+extern void kernel_thread_helper(void);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create a kernel thread
|
|
|
+ */
|
|
|
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
|
|
|
+{
|
|
|
+ struct pt_regs regs;
|
|
|
+
|
|
|
+ memset(®s, 0, sizeof(regs));
|
|
|
+
|
|
|
+ regs.si = (unsigned long) fn;
|
|
|
+ regs.di = (unsigned long) arg;
|
|
|
+
|
|
|
+#ifdef CONFIG_X86_32
|
|
|
+ regs.ds = __USER_DS;
|
|
|
+ regs.es = __USER_DS;
|
|
|
+ regs.fs = __KERNEL_PERCPU;
|
|
|
+ regs.gs = __KERNEL_STACK_CANARY;
|
|
|
+#endif
|
|
|
+
|
|
|
+ regs.orig_ax = -1;
|
|
|
+ regs.ip = (unsigned long) kernel_thread_helper;
|
|
|
+ regs.cs = __KERNEL_CS | get_kernel_rpl();
|
|
|
+ regs.flags = X86_EFLAGS_IF | 0x2;
|
|
|
+
|
|
|
+ /* Ok, create the new process.. */
|
|
|
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(kernel_thread);
|
|
|
|
|
|
/*
|
|
|
* sys_execve() executes a new program.
|