The patch titled um: Save FPU registers between task switches has been removed from the -mm tree. Its filename was um-save-fpu-registers-between-task-switches.patch This patch was dropped because it was merged into mainline or a subsystem tree The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/ ------------------------------------------------------ Subject: um: Save FPU registers between task switches From: Ingo van Lil <inguin@xxxxxx> Some time ago Jeff prepared 42daba3 ("uml: stop saving process FP state") for UML to stop saving the process FP state between task switches. The assumption was that since with SKAS0 every guest process runs inside a host process context the host OS will take care of keeping the proper FP state. Unfortunately this is not true for multi-threaded applications, where all guest threads share a single host process context yet all may use the FPU on their own. Although I haven't verified it I suspect things to be even worse in SKAS3 mode where all guest processes run inside a single host process. The patch reintroduces the saving and restoring of the FP context between task switches. [richard@xxxxxx: Ingo posted this patch in 2009, sadly it was never applied and got lost. Now in 2011 the problem was reported by Gunnar.] Signed-off-by: Ingo van Lil <inguin@xxxxxx> Signed-off-by: Richard Weinberger <richard@xxxxxx> Reported-by: <gunnarlindroth@xxxxxxxxxxx> Tested-by: <gunnarlindroth@xxxxxxxxxxx> Cc: Stanislav Meduna <stano@xxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- arch/um/include/shared/registers.h | 2 +- arch/um/kernel/process.c | 2 +- arch/um/os-Linux/registers.c | 9 ++++++++- arch/um/os-Linux/skas/mem.c | 2 +- arch/um/os-Linux/skas/process.c | 19 ++++++++++++++++++- arch/um/sys-i386/shared/sysdep/ptrace.h | 1 + arch/um/sys-x86_64/shared/sysdep/ptrace.h | 1 + 7 files changed, 31 insertions(+), 5 deletions(-) diff -puN arch/um/include/shared/registers.h~um-save-fpu-registers-between-task-switches arch/um/include/shared/registers.h --- a/arch/um/include/shared/registers.h~um-save-fpu-registers-between-task-switches +++ a/arch/um/include/shared/registers.h @@ -16,7 +16,7 @@ extern int restore_fpx_registers(int pid extern int save_registers(int pid, struct uml_pt_regs *regs); extern int restore_registers(int pid, struct uml_pt_regs *regs); extern int init_registers(int pid); -extern void get_safe_registers(unsigned long *regs); +extern void get_safe_registers(unsigned long *regs, unsigned long *fp_regs); extern unsigned long get_thread_reg(int reg, jmp_buf *buf); extern int get_fp_registers(int pid, unsigned long *regs); extern int put_fp_registers(int pid, unsigned long *regs); diff -puN arch/um/kernel/process.c~um-save-fpu-registers-between-task-switches arch/um/kernel/process.c --- a/arch/um/kernel/process.c~um-save-fpu-registers-between-task-switches +++ a/arch/um/kernel/process.c @@ -202,7 +202,7 @@ int copy_thread(unsigned long clone_flag arch_copy_thread(¤t->thread.arch, &p->thread.arch); } else { - get_safe_registers(p->thread.regs.regs.gp); + get_safe_registers(p->thread.regs.regs.gp, p->thread.regs.regs.fp); p->thread.request.u.thread = current->thread.request.u.thread; handler = new_thread_handler; } diff -puN arch/um/os-Linux/registers.c~um-save-fpu-registers-between-task-switches arch/um/os-Linux/registers.c --- a/arch/um/os-Linux/registers.c~um-save-fpu-registers-between-task-switches +++ a/arch/um/os-Linux/registers.c @@ -8,6 +8,8 @@ #include <string.h> #include <sys/ptrace.h> #include "sysdep/ptrace.h" +#include "sysdep/ptrace_user.h" +#include "registers.h" int save_registers(int pid, struct uml_pt_regs *regs) { @@ -32,6 +34,7 @@ int restore_registers(int pid, struct um /* This is set once at boot time and not changed thereafter */ static unsigned long exec_regs[MAX_REG_NR]; +static unsigned long exec_fp_regs[FP_SIZE]; int init_registers(int pid) { @@ -42,10 +45,14 @@ int init_registers(int pid) return -errno; arch_init_registers(pid); + get_fp_registers(pid, exec_fp_regs); return 0; } -void get_safe_registers(unsigned long *regs) +void get_safe_registers(unsigned long *regs, unsigned long *fp_regs) { memcpy(regs, exec_regs, sizeof(exec_regs)); + + if (fp_regs) + memcpy(fp_regs, exec_fp_regs, sizeof(exec_fp_regs)); } diff -puN arch/um/os-Linux/skas/mem.c~um-save-fpu-registers-between-task-switches arch/um/os-Linux/skas/mem.c --- a/arch/um/os-Linux/skas/mem.c~um-save-fpu-registers-between-task-switches +++ a/arch/um/os-Linux/skas/mem.c @@ -39,7 +39,7 @@ static unsigned long syscall_regs[MAX_RE static int __init init_syscall_regs(void) { - get_safe_registers(syscall_regs); + get_safe_registers(syscall_regs, NULL); syscall_regs[REGS_IP_INDEX] = STUB_CODE + ((unsigned long) &batch_syscall_stub - (unsigned long) &__syscall_stub_start); diff -puN arch/um/os-Linux/skas/process.c~um-save-fpu-registers-between-task-switches arch/um/os-Linux/skas/process.c --- a/arch/um/os-Linux/skas/process.c~um-save-fpu-registers-between-task-switches +++ a/arch/um/os-Linux/skas/process.c @@ -373,6 +373,9 @@ void userspace(struct uml_pt_regs *regs) if (ptrace(PTRACE_SETREGS, pid, 0, regs->gp)) fatal_sigsegv(); + if (put_fp_registers(pid, regs->fp)) + fatal_sigsegv(); + /* Now we set local_using_sysemu to be used for one loop */ local_using_sysemu = get_using_sysemu(); @@ -399,6 +402,12 @@ void userspace(struct uml_pt_regs *regs) fatal_sigsegv(); } + if (get_fp_registers(pid, regs->fp)) { + printk(UM_KERN_ERR "userspace - get_fp_registers failed, " + "errno = %d\n", errno); + fatal_sigsegv(); + } + UPT_SYSCALL_NR(regs) = -1; /* Assume: It's not a syscall */ if (WIFSTOPPED(status)) { @@ -457,10 +466,11 @@ void userspace(struct uml_pt_regs *regs) } static unsigned long thread_regs[MAX_REG_NR]; +static unsigned long thread_fp_regs[FP_SIZE]; static int __init init_thread_regs(void) { - get_safe_registers(thread_regs); + get_safe_registers(thread_regs, thread_fp_regs); /* Set parent's instruction pointer to start of clone-stub */ thread_regs[REGS_IP_INDEX] = STUB_CODE + (unsigned long) stub_clone_handler - @@ -503,6 +513,13 @@ int copy_context_skas0(unsigned long new return err; } + err = put_fp_registers(pid, thread_fp_regs); + if (err < 0) { + printk(UM_KERN_ERR "copy_context_skas0 : put_fp_registers " + "failed, pid = %d, err = %d\n", pid, err); + return err; + } + /* set a well known return code for detection of child write failure */ child_data->err = 12345678; diff -puN arch/um/sys-i386/shared/sysdep/ptrace.h~um-save-fpu-registers-between-task-switches arch/um/sys-i386/shared/sysdep/ptrace.h --- a/arch/um/sys-i386/shared/sysdep/ptrace.h~um-save-fpu-registers-between-task-switches +++ a/arch/um/sys-i386/shared/sysdep/ptrace.h @@ -53,6 +53,7 @@ extern int sysemu_supported; struct uml_pt_regs { unsigned long gp[MAX_REG_NR]; + unsigned long fp[HOST_FPX_SIZE]; struct faultinfo faultinfo; long syscall; int is_user; diff -puN arch/um/sys-x86_64/shared/sysdep/ptrace.h~um-save-fpu-registers-between-task-switches arch/um/sys-x86_64/shared/sysdep/ptrace.h --- a/arch/um/sys-x86_64/shared/sysdep/ptrace.h~um-save-fpu-registers-between-task-switches +++ a/arch/um/sys-x86_64/shared/sysdep/ptrace.h @@ -85,6 +85,7 @@ struct uml_pt_regs { unsigned long gp[MAX_REG_NR]; + unsigned long fp[HOST_FP_SIZE]; struct faultinfo faultinfo; long syscall; int is_user; _ Patches currently in -mm which might be from inguin@xxxxxx are origin.patch -- To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html