From aa6758d4867cd07bd76105ade6177fe6148e559a Mon Sep 17 00:00:00 2001 From: Paolo 'Blaisorblade' Giarrusso Date: Fri, 31 Mar 2006 02:30:22 -0800 Subject: [PATCH] uml: implement {get,set}_thread_area for i386 Implement sys_[gs]et_thread_area and the corresponding ptrace operations for UML. This is the main chunk, additional parts follow. This implementation is now well tested and has run reliably for some time, and we've understood all the previously existing problems. Their implementation saves the new GDT content and then forwards the call to the host when appropriate, i.e. immediately when the target process is running or on context switch otherwise (i.e. on fork and on ptrace() calls). In SKAS mode, we must switch registers on each context switch (because SKAS does not switches tls_array together with current->mm). Also, added get_cpu() locking; this has been done for SKAS mode, since TT does not need it (it does not use smp_processor_id()). Signed-off-by: Paolo 'Blaisorblade' Giarrusso Acked-by: Jeff Dike Signed-off-by: Andrew Morton Signed-off-by: Linus Torvalds --- arch/um/kernel/exec_kern.c | 12 +----------- arch/um/kernel/process_kern.c | 20 ++++++++++++++++++-- arch/um/kernel/ptrace.c | 10 ++++++++++ arch/um/kernel/skas/process_kern.c | 2 ++ 4 files changed, 31 insertions(+), 13 deletions(-) (limited to 'arch/um/kernel') diff --git a/arch/um/kernel/exec_kern.c b/arch/um/kernel/exec_kern.c index f9b346e05b0..c0cb627bf59 100644 --- a/arch/um/kernel/exec_kern.c +++ b/arch/um/kernel/exec_kern.c @@ -22,6 +22,7 @@ void flush_thread(void) { + arch_flush_thread(¤t->thread.arch); CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); } @@ -74,14 +75,3 @@ long sys_execve(char __user *file, char __user *__user *argv, unlock_kernel(); return(error); } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-file-style: "linux" - * End: - */ diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c index ba8a52c1f7a..f6a5a502120 100644 --- a/arch/um/kernel/process_kern.c +++ b/arch/um/kernel/process_kern.c @@ -156,9 +156,25 @@ int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, unsigned long stack_top, struct task_struct * p, struct pt_regs *regs) { + int ret; + p->thread = (struct thread_struct) INIT_THREAD; - return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, - clone_flags, sp, stack_top, p, regs)); + ret = CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, + clone_flags, sp, stack_top, p, regs); + + if (ret || !current->thread.forking) + goto out; + + clear_flushed_tls(p); + + /* + * Set a new TLS for the child thread? + */ + if (clone_flags & CLONE_SETTLS) + ret = arch_copy_tls(p); + +out: + return ret; } void initial_thread_cb(void (*proc)(void *), void *arg) diff --git a/arch/um/kernel/ptrace.c b/arch/um/kernel/ptrace.c index 394582202ce..60d2eda995c 100644 --- a/arch/um/kernel/ptrace.c +++ b/arch/um/kernel/ptrace.c @@ -185,6 +185,16 @@ long arch_ptrace(struct task_struct *child, long request, long addr, long data) ret = set_fpxregs(data, child); break; #endif + case PTRACE_GET_THREAD_AREA: + ret = ptrace_get_thread_area(child, addr, + (struct user_desc __user *) data); + break; + + case PTRACE_SET_THREAD_AREA: + ret = ptrace_set_thread_area(child, addr, + (struct user_desc __user *) data); + break; + case PTRACE_FAULTINFO: { /* Take the info from thread->arch->faultinfo, * but transfer max. sizeof(struct ptrace_faultinfo). diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c index 14360ac17f0..38b185370c4 100644 --- a/arch/um/kernel/skas/process_kern.c +++ b/arch/um/kernel/skas/process_kern.c @@ -111,6 +111,8 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; handler = fork_handler; + + arch_copy_thread(¤t->thread.arch, &p->thread.arch); } else { init_thread_registers(&p->thread.regs.regs); -- cgit v1.2.3