Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752607AbbGKGRO (ORCPT ); Sat, 11 Jul 2015 02:17:14 -0400 Received: from mail-yk0-f179.google.com ([209.85.160.179]:35256 "EHLO mail-yk0-f179.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751649AbbGKGRN (ORCPT ); Sat, 11 Jul 2015 02:17:13 -0400 From: Brian Gerst To: x86@kernel.org, linux-kernel@vger.kernel.org Cc: Ingo Molnar , "H. Peter Anvin" , Denys Vlasenko , Andy Lutomirski , Linus Torvalds Subject: [PATCH 4/5] x86/vm86: Eliminate kernel_vm86_struct Date: Sat, 11 Jul 2015 01:09:19 -0400 Message-Id: <1436591360-16210-5-git-send-email-brgerst@gmail.com> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1436591360-16210-1-git-send-email-brgerst@gmail.com> References: <1436591360-16210-1-git-send-email-brgerst@gmail.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7463 Lines: 224 Now there is no vm86-specific data left on the kernel stack while in userspace, except for the 32-bit regs. Signed-off-by: Brian Gerst --- arch/x86/include/asm/vm86.h | 25 +---------------- arch/x86/kernel/vm86_32.c | 68 +++++++++++++++++++-------------------------- 2 files changed, 29 insertions(+), 64 deletions(-) diff --git a/arch/x86/include/asm/vm86.h b/arch/x86/include/asm/vm86.h index bc28a40..84d4bda 100644 --- a/arch/x86/include/asm/vm86.h +++ b/arch/x86/include/asm/vm86.h @@ -28,32 +28,9 @@ struct kernel_vm86_regs { unsigned short gs, __gsh; }; -struct kernel_vm86_struct { - struct kernel_vm86_regs regs; -/* - * the below part remains on the kernel stack while we are in VM86 mode. - * 'tss.esp0' then contains the address of VM86_TSS_ESP0 below, and when we - * get forced back from VM86, the CPU and "SAVE_ALL" will restore the above - * 'struct kernel_vm86_regs' with the then actual values. - * Therefore, pt_regs in fact points to a complete 'kernel_vm86_struct' - * in kernelspace, hence we need not reget the data from userspace. - */ -#define VM86_TSS_ESP0 regs32 - struct pt_regs *regs32; /* here we save the pointer to the old regs */ -/* - * The below is not part of the structure, but the stack layout continues - * this way. In front of 'return-eip' may be some data, depending on - * compilation, so we don't rely on this and save the pointer to 'oldregs' - * in 'regs32' above. - * However, with GCC-2.7.2 and the current CFLAGS you see exactly this: - - long return-eip; from call to vm86() - struct pt_regs oldregs; user space registers as saved by syscall - */ -}; - struct kernel_vm86_info { struct vm86_struct __user *vm86_info; + struct pt_regs *regs32; unsigned long v86flags; unsigned long v86mask; unsigned long saved_sp0; diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index f174602..d7aae93 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c @@ -67,9 +67,6 @@ */ -#define KVM86 ((struct kernel_vm86_struct *)regs) - - /* * 8- and 16-bit register defines.. */ @@ -156,7 +153,7 @@ struct pt_regs *save_v86_state(struct kernel_vm86_regs *regs) vm86->saved_sp0 = 0; put_cpu(); - ret = KVM86->regs32; + ret = vm86->regs32; ret->fs = vm86->saved_fs; set_user_gs(ret, vm86->saved_gs); @@ -199,29 +196,16 @@ out: static int do_vm86_irq_handling(int subfunction, int irqnumber); -static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus, - struct kernel_vm86_struct *info); +static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus); SYSCALL_DEFINE1(vm86old, struct vm86_struct __user *, v86) { - struct kernel_vm86_struct info; /* declare this _on top_, - * this avoids wasting of stack space. - * This remains on the stack until we - * return to 32 bit user space. - */ - - return do_sys_vm86((struct vm86plus_struct __user *) v86, false, &info); + return do_sys_vm86((struct vm86plus_struct __user *) v86, false); } SYSCALL_DEFINE2(vm86, unsigned long, cmd, unsigned long, arg) { - struct kernel_vm86_struct info; /* declare this _on top_, - * this avoids wasting of stack space. - * This remains on the stack until we - * return to 32 bit user space. - */ - switch (cmd) { case VM86_REQUEST_IRQ: case VM86_FREE_IRQ: @@ -239,16 +223,17 @@ SYSCALL_DEFINE2(vm86, unsigned long, cmd, unsigned long, arg) } /* we come here only for functions VM86_ENTER, VM86_ENTER_NO_BYPASS */ - return do_sys_vm86((struct vm86plus_struct __user *) arg, true, &info); + return do_sys_vm86((struct vm86plus_struct __user *) arg, true); } -static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus, - struct kernel_vm86_struct *info) +static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus) { struct tss_struct *tss; struct task_struct *tsk = current; struct kernel_vm86_info *vm86 = tsk->thread.vm86; + struct kernel_vm86_regs regs; + struct pt_regs *regs32 = current_pt_regs(); if (!vm86) { @@ -258,7 +243,7 @@ static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus, } if (vm86->saved_sp0) return -EPERM; - if (copy_vm86_regs_from_user(&info->regs, &v86->regs)) + if (copy_vm86_regs_from_user(®s, &v86->regs)) return -EFAULT; if (plus) { if (copy_from_user(&vm86->flags, &v86->flags, @@ -273,17 +258,17 @@ static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus, return -EFAULT; memset(&vm86->vm86plus, 0, sizeof(struct vm86plus_info_struct)); } - info->regs32 = current_pt_regs(); + vm86->regs32 = regs32; vm86->vm86_info = (struct vm86_struct __user *) v86; /* * make sure the vm86() system call doesn't try to do anything silly */ - info->regs.pt.ds = 0; - info->regs.pt.es = 0; - info->regs.pt.fs = 0; + regs.pt.ds = 0; + regs.pt.es = 0; + regs.pt.fs = 0; #ifndef CONFIG_X86_32_LAZY_GS - info->regs.pt.gs = 0; + regs.pt.gs = 0; #endif /* @@ -291,10 +276,10 @@ static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus, * has set it up safely, so this makes sure interrupt etc flags are * inherited from protected mode. */ - VEFLAGS = info->regs.pt.flags; - info->regs.pt.flags &= SAFE_MASK; - info->regs.pt.flags |= info->regs32->flags & ~SAFE_MASK; - info->regs.pt.flags |= X86_VM_MASK; + VEFLAGS = regs.pt.flags; + regs.pt.flags &= SAFE_MASK; + regs.pt.flags |= regs32->flags & ~SAFE_MASK; + regs.pt.flags |= X86_VM_MASK; switch (vm86->cpu_type) { case CPU_286: @@ -314,13 +299,14 @@ static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus, /* * Save old state, set default return value (%ax) to 0 (VM86_SIGNAL) */ - info->regs32->ax = VM86_SIGNAL; + regs32->ax = VM86_SIGNAL; vm86->saved_sp0 = tsk->thread.sp0; - vm86->saved_fs = info->regs32->fs; - vm86->saved_gs = get_user_gs(info->regs32); + vm86->saved_fs = regs32->fs; + vm86->saved_gs = get_user_gs(regs32); tss = &per_cpu(cpu_tss, get_cpu()); - tsk->thread.sp0 = (unsigned long) &info->VM86_TSS_ESP0; + /* Set new sp0 right below 32-bit regs */ + tsk->thread.sp0 = (unsigned long) regs32; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; load_sp0(tss, &tsk->thread); @@ -343,7 +329,7 @@ static long do_sys_vm86(struct vm86plus_struct __user *v86, bool plus, #endif "jmp resume_userspace" : /* no outputs */ - :"r" (&info->regs), "r" (task_thread_info(tsk)), "r" (0)); + :"r" (®s), "r" (task_thread_info(tsk)), "r" (0)); return 0; /* we never return here */ } @@ -548,12 +534,14 @@ cannot_handle: int handle_vm86_trap(struct kernel_vm86_regs *regs, long error_code, int trapno) { - if (current->thread.vm86->vm86plus.is_vm86pus) { + struct kernel_vm86_info *vm86 = current->thread.vm86; + + if (vm86->vm86plus.is_vm86pus) { if ((trapno == 3) || (trapno == 1)) { - KVM86->regs32->ax = VM86_TRAP + (trapno << 8); + vm86->regs32->ax = VM86_TRAP + (trapno << 8); /* setting this flag forces the code in entry_32.S to the path where we call save_v86_state() and change - the stack pointer to KVM86->regs32 */ + the stack pointer to regs32 */ set_thread_flag(TIF_NOTIFY_RESUME); return 0; } -- 2.4.3 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/