@@ -24,8 +24,10 @@ void flush_thread(void)
{
arch_flush_thread(¤t->thread.arch);
+#ifdef CONFIG_MMU
get_safe_registers(current_pt_regs()->regs.gp,
current_pt_regs()->regs.fp);
+#endif
__switch_mm(¤t->mm->context.id);
}
@@ -35,5 +37,11 @@ void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp)
PT_REGS_IP(regs) = eip;
PT_REGS_SP(regs) = esp;
clear_thread_flag(TIF_SINGLESTEP);
+#ifndef CONFIG_MMU
+ current->thread.regs.regs.gp[REGS_IP_INDEX] = eip;
+ current->thread.regs.regs.gp[REGS_SP_INDEX] = esp;
+ new_thread(task_stack_page(current), ¤t->thread.switch_buf,
+ (void *)eip);
+#endif
}
EXPORT_SYMBOL(start_thread);
@@ -117,13 +117,17 @@ void new_thread_handler(void)
* callback returns only if the kernel thread execs a process
*/
fn(arg);
+#ifndef CONFIG_MMU
+ arch_switch_to(current);
+#endif
userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs);
}
/* Called magically, see new_thread_handler above */
static void fork_handler(void)
{
- schedule_tail(current->thread.prev_sched);
+ if (current->thread.prev_sched != NULL)
+ schedule_tail(current->thread.prev_sched);
/*
* XXX: if interrupt_end() calls schedule, this call to
@@ -134,6 +138,21 @@ static void fork_handler(void)
current->thread.prev_sched = NULL;
+#ifndef CONFIG_MMU
+ /*
+ * This fork can only come from libc's vfork, which
+ * does this:
+ * popq %%rdx;
+ * call *%0; // vsyscall
+ * pushq %%rdx;
+ * %rdx stores the return address which is stored
+ * at pt_regs[HOST_IP] at the moment. We still
+ * need to pop the pushed address by "call" though,
+ * so this is what this next line does.
+ */
+ if (current->thread.regs.regs.gp[HOST_ORIG_AX] == __NR_vfork)
+ current->thread.regs.regs.gp[REGS_SP_INDEX] += 8;
+#endif
userspace(¤t->thread.regs.regs, current_thread_info()->aux_fp_regs);
}
@@ -92,7 +92,10 @@ int os_process_parent(int pid)
void os_alarm_process(int pid)
{
+/* !CONFIG_MMU doesn't send alarm signal to other processes */
+#ifdef UML_CONFIG_MMU
kill(pid, SIGALRM);
+#endif
}
void os_stop_process(int pid)
@@ -114,11 +117,14 @@ void os_kill_process(int pid, int reap_child)
void os_kill_ptraced_process(int pid, int reap_child)
{
+/* !CONFIG_MMU doesn't have ptraced process */
+#ifdef UML_CONFIG_MMU
kill(pid, SIGKILL);
ptrace(PTRACE_KILL, pid);
ptrace(PTRACE_CONT, pid);
if (reap_child)
CATCH_EINTR(waitpid(pid, NULL, __WALL));
+#endif
}
/* Don't use the glibc version, which caches the result in TLS. It misses some
@@ -141,6 +141,7 @@ void wait_stub_done(int pid)
extern unsigned long current_stub_stack(void);
+#ifdef UML_CONFIG_MMU
static void get_skas_faultinfo(int pid, struct faultinfo *fi, unsigned long *aux_fp_regs)
{
int err;
@@ -186,6 +187,7 @@ static void handle_trap(int pid, struct uml_pt_regs *regs)
handle_syscall(regs);
}
+#endif
extern char __syscall_stub_start[];
@@ -336,6 +338,7 @@ int start_userspace(unsigned long stub_stack)
return err;
}
+#ifdef UML_CONFIG_MMU
void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
{
int err, status, op, pid = userspace_pid[0];
@@ -472,6 +475,7 @@ void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
}
}
}
+#endif /* UML_CONFIG_MMU */
void new_thread(void *stack, jmp_buf *buf, void (*handler)(void))
{
@@ -38,6 +38,18 @@ static __always_inline void cpu_relax(void)
#define task_pt_regs(t) (&(t)->thread.regs)
+#ifndef CONFIG_MMU
+#define task_top_of_stack(task) \
+({ \
+ unsigned long __ptr = (unsigned long)task->stack; \
+ __ptr += THREAD_SIZE; \
+ __ptr; \
+})
+
+extern long current_top_of_stack;
+extern long current_ptregs;
+#endif
+
#include <asm/processor-generic.h>
#endif
@@ -86,3 +86,25 @@ ENTRY(__kernel_vsyscall)
ret
END(__kernel_vsyscall)
+
+// void userspace(struct uml_pt_regs *regs, unsigned long *aux_fp_regs)
+ENTRY(userspace)
+ /* align the stack for x86_64 ABI */
+ and $-0x10, %rsp
+ /* Handle any immediate reschedules or signals */
+ call interrupt_end
+
+ movq current_ptregs, %rsp
+
+ POP_REGS
+
+ addq $8, %rsp /* skip orig_ax */
+ popq %r11 /* pt_regs->ip */
+ addq $8, %rsp /* skip cs */
+ addq $8, %rsp /* skip flags */
+ popq %rsp
+
+ jmp *%r11
+
+END(userspace)
+#endif // !CONFIG_MMU
@@ -51,6 +51,18 @@ void arch_switch_to(struct task_struct *to)
* Nothing needs to be done on x86_64.
* The FS_BASE/GS_BASE registers are saved in the ptrace register set.
*/
+#ifndef CONFIG_MMU
+ current_top_of_stack = task_top_of_stack(to);
+ current_ptregs = (long)task_pt_regs(to);
+
+ if ((to->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)] == 0)
+ || (to->mm == NULL))
+ return;
+
+ // rkj: this changes the FS on every context switch
+ arch_prctl(to, ARCH_SET_FS,
+ (void __user *) to->thread.regs.regs.gp[FS_BASE / sizeof(unsigned long)]);
+#endif
}
SYSCALL_DEFINE6(mmap, unsigned long, addr, unsigned long, len,