Allocate a separate structure for the vm86 fields.

Signed-off-by: Brian Gerst <brge...@gmail.com>
---
 arch/x86/include/asm/processor.h | 11 ++------
 arch/x86/include/asm/vm86.h      | 10 ++++++++
 arch/x86/kernel/process.c        |  7 +++++
 arch/x86/kernel/vm86_32.c        | 55 +++++++++++++++++++++++-----------------
 arch/x86/mm/fault.c              |  4 +--
 5 files changed, 53 insertions(+), 34 deletions(-)

diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index 43e6519..8085463 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -403,15 +403,9 @@ struct thread_struct {
        unsigned long           cr2;
        unsigned long           trap_nr;
        unsigned long           error_code;
-#ifdef CONFIG_X86_32
+#ifdef CONFIG_VM86
        /* Virtual 86 mode info */
-       struct vm86_struct __user *vm86_info;
-       unsigned long           screen_bitmap;
-       unsigned long           v86flags;
-       unsigned long           v86mask;
-       unsigned long           saved_sp0;
-       unsigned int            saved_fs;
-       unsigned int            saved_gs;
+       struct kernel_vm86_info *vm86;
 #endif
        /* IO permissions: */
        unsigned long           *io_bitmap_ptr;
@@ -716,7 +710,6 @@ static inline void spin_lock_prefetch(const void *x)
 
 #define INIT_THREAD  {                                                   \
        .sp0                    = TOP_OF_INIT_STACK,                      \
-       .vm86_info              = NULL,                                   \
        .sysenter_cs            = __KERNEL_CS,                            \
        .io_bitmap_ptr          = NULL,                                   \
 }
diff --git a/arch/x86/include/asm/vm86.h b/arch/x86/include/asm/vm86.h
index 1d8de3f..88f14e3 100644
--- a/arch/x86/include/asm/vm86.h
+++ b/arch/x86/include/asm/vm86.h
@@ -58,6 +58,16 @@ struct kernel_vm86_struct {
  */
 };
 
+struct kernel_vm86_info {
+       struct vm86_struct __user *vm86_info;
+       unsigned long screen_bitmap;
+       unsigned long v86flags;
+       unsigned long v86mask;
+       unsigned long saved_sp0;
+       unsigned int saved_fs;
+       unsigned int saved_gs;
+};
+
 #ifdef CONFIG_VM86
 
 void handle_vm86_fault(struct kernel_vm86_regs *, long);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index 9cad694..5dcd037 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -110,6 +110,13 @@ void exit_thread(void)
                kfree(bp);
        }
 
+#ifdef CONFIG_VM86
+       if (t->vm86) {
+               kfree(t->vm86);
+               t->vm86 = NULL;
+       }
+#endif
+
        fpu__drop(fpu);
 }
 
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c
index 71a8b0a..8b29c9b 100644
--- a/arch/x86/kernel/vm86_32.c
+++ b/arch/x86/kernel/vm86_32.c
@@ -44,6 +44,7 @@
 #include <linux/ptrace.h>
 #include <linux/audit.h>
 #include <linux/stddef.h>
+#include <linux/slab.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -81,8 +82,8 @@
 /*
  * virtual flags (16 and 32-bit versions)
  */
-#define VFLAGS (*(unsigned short *)&(current->thread.v86flags))
-#define VEFLAGS        (current->thread.v86flags)
+#define VFLAGS (*(unsigned short *)&(current->thread.vm86->v86flags))
+#define VEFLAGS        (current->thread.vm86->v86flags)
 
 #define set_flags(X, new, mask) \
 ((X) = ((X) & ~(mask)) | ((new) & (mask)))
@@ -130,6 +131,7 @@ struct pt_regs *save_v86_state(struct kernel_vm86_regs 
*regs)
        struct tss_struct *tss;
        struct pt_regs *ret;
        unsigned long tmp;
+       struct kernel_vm86_info *vm86 = current->thread.vm86;
 
        /*
         * This gets called from entry.S with interrupts disabled, but
@@ -138,29 +140,29 @@ struct pt_regs *save_v86_state(struct kernel_vm86_regs 
*regs)
         */
        local_irq_enable();
 
-       if (!current->thread.vm86_info) {
+       if (!vm86 || !vm86->vm86_info) {
                pr_alert("no vm86_info: BAD\n");
                do_exit(SIGSEGV);
        }
-       set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | 
current->thread.v86mask);
-       tmp = copy_vm86_regs_to_user(&current->thread.vm86_info->regs, regs);
-       tmp += put_user(current->thread.screen_bitmap, 
&current->thread.vm86_info->screen_bitmap);
+       set_flags(regs->pt.flags, VEFLAGS, X86_EFLAGS_VIF | vm86->v86mask);
+       tmp = copy_vm86_regs_to_user(&vm86->vm86_info->regs, regs);
+       tmp += put_user(vm86->screen_bitmap, &vm86->vm86_info->screen_bitmap);
        if (tmp) {
                pr_alert("could not access userspace vm86_info\n");
                do_exit(SIGSEGV);
        }
 
        tss = &per_cpu(cpu_tss, get_cpu());
-       current->thread.sp0 = current->thread.saved_sp0;
+       current->thread.sp0 = vm86->saved_sp0;
        current->thread.sysenter_cs = __KERNEL_CS;
        load_sp0(tss, &current->thread);
-       current->thread.saved_sp0 = 0;
+       vm86->saved_sp0 = 0;
        put_cpu();
 
        ret = KVM86->regs32;
 
-       ret->fs = current->thread.saved_fs;
-       set_user_gs(ret, current->thread.saved_gs);
+       ret->fs = vm86->saved_fs;
+       set_user_gs(ret, vm86->saved_gs);
 
        return ret;
 }
@@ -249,8 +251,15 @@ 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;
 
-       if (tsk->thread.saved_sp0)
+       if (!vm86)
+       {
+               if (!(vm86 = kzalloc(sizeof(*vm86), GFP_KERNEL)))
+                       return -ENOMEM;
+               tsk->thread.vm86 = vm86;
+       }
+       if (vm86->saved_sp0)
                return -EPERM;
        if (plus) {
                if (copy_vm86_regs_from_user(&info->regs, &v86->regs,
@@ -266,7 +275,7 @@ static long do_sys_vm86(struct vm86plus_struct __user *v86, 
bool plus,
                memset(&info->vm86plus, 0, sizeof(struct vm86plus_info_struct));
        }
        info->regs32 = current_pt_regs();
-       tsk->thread.vm86_info = (struct vm86_struct __user *) v86;
+       vm86->vm86_info = (struct vm86_struct __user *) v86;
 
 /*
  * make sure the vm86() system call doesn't try to do anything silly
@@ -290,16 +299,16 @@ static long do_sys_vm86(struct vm86plus_struct __user 
*v86, bool plus,
 
        switch (info->cpu_type) {
        case CPU_286:
-               tsk->thread.v86mask = 0;
+               vm86->v86mask = 0;
                break;
        case CPU_386:
-               tsk->thread.v86mask = X86_EFLAGS_NT | X86_EFLAGS_IOPL;
+               vm86->v86mask = X86_EFLAGS_NT | X86_EFLAGS_IOPL;
                break;
        case CPU_486:
-               tsk->thread.v86mask = X86_EFLAGS_AC | X86_EFLAGS_NT | 
X86_EFLAGS_IOPL;
+               vm86->v86mask = X86_EFLAGS_AC | X86_EFLAGS_NT | X86_EFLAGS_IOPL;
                break;
        default:
-               tsk->thread.v86mask = X86_EFLAGS_ID | X86_EFLAGS_AC | 
X86_EFLAGS_NT | X86_EFLAGS_IOPL;
+               vm86->v86mask = X86_EFLAGS_ID | X86_EFLAGS_AC | X86_EFLAGS_NT | 
X86_EFLAGS_IOPL;
                break;
        }
 
@@ -307,9 +316,9 @@ 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;
-       tsk->thread.saved_sp0 = tsk->thread.sp0;
-       tsk->thread.saved_fs = info->regs32->fs;
-       tsk->thread.saved_gs = get_user_gs(info->regs32);
+       vm86->saved_sp0 = tsk->thread.sp0;
+       vm86->saved_fs = info->regs32->fs;
+       vm86->saved_gs = get_user_gs(info->regs32);
 
        tss = &per_cpu(cpu_tss, get_cpu());
        tsk->thread.sp0 = (unsigned long) &info->VM86_TSS_ESP0;
@@ -318,7 +327,7 @@ static long do_sys_vm86(struct vm86plus_struct __user *v86, 
bool plus,
        load_sp0(tss, &tsk->thread);
        put_cpu();
 
-       tsk->thread.screen_bitmap = info->screen_bitmap;
+       vm86->screen_bitmap = info->screen_bitmap;
        if (info->flags & VM86_SCREEN_BITMAP)
                mark_screen_rdonly(tsk->mm);
 
@@ -388,7 +397,7 @@ static inline void clear_AC(struct kernel_vm86_regs *regs)
 
 static inline void set_vflags_long(unsigned long flags, struct 
kernel_vm86_regs *regs)
 {
-       set_flags(VEFLAGS, flags, current->thread.v86mask);
+       set_flags(VEFLAGS, flags, current->thread.vm86->v86mask);
        set_flags(regs->pt.flags, flags, SAFE_MASK);
        if (flags & X86_EFLAGS_IF)
                set_IF(regs);
@@ -398,7 +407,7 @@ static inline void set_vflags_long(unsigned long flags, 
struct kernel_vm86_regs
 
 static inline void set_vflags_short(unsigned short flags, struct 
kernel_vm86_regs *regs)
 {
-       set_flags(VFLAGS, flags, current->thread.v86mask);
+       set_flags(VFLAGS, flags, current->thread.vm86->v86mask);
        set_flags(regs->pt.flags, flags, SAFE_MASK);
        if (flags & X86_EFLAGS_IF)
                set_IF(regs);
@@ -413,7 +422,7 @@ static inline unsigned long get_vflags(struct 
kernel_vm86_regs *regs)
        if (VEFLAGS & X86_EFLAGS_VIF)
                flags |= X86_EFLAGS_IF;
        flags |= X86_EFLAGS_IOPL;
-       return flags | (VEFLAGS & current->thread.v86mask);
+       return flags | (VEFLAGS & current->thread.vm86->v86mask);
 }
 
 static inline int is_revectored(int nr, struct revectored_struct *bitmap)
diff --git a/arch/x86/mm/fault.c b/arch/x86/mm/fault.c
index 81dcebf..5196ac4 100644
--- a/arch/x86/mm/fault.c
+++ b/arch/x86/mm/fault.c
@@ -315,12 +315,12 @@ check_v8086_mode(struct pt_regs *regs, unsigned long 
address,
 {
        unsigned long bit;
 
-       if (!v8086_mode(regs))
+       if (!v8086_mode(regs) || !tsk->thread.vm86)
                return;
 
        bit = (address - 0xA0000) >> PAGE_SHIFT;
        if (bit < 32)
-               tsk->thread.screen_bitmap |= 1 << bit;
+               tsk->thread.vm86->screen_bitmap |= 1 << bit;
 }
 
 static bool low_pfn(unsigned long pfn)
-- 
2.4.3

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to