mirror of
https://github.com/adulau/aha.git
synced 2025-01-04 07:03:38 +00:00
x86: pass in pt_regs pointer for syscalls that need it
Some syscalls need to access the pt_regs structure, either to copy user register state or to modifiy it. This patch adds stubs to load the address of the pt_regs struct into the %eax register, and changes the syscalls to regparm(1) to receive the pt_regs pointer as the first argument. Signed-off-by: Brian Gerst <brgerst@gmail.com> Acked-by: Tejun Heo <tj@kernel.org> Signed-off-by: Ingo Molnar <mingo@elte.hu>
This commit is contained in:
parent
aa78bcfa01
commit
253f29a4ae
8 changed files with 81 additions and 80 deletions
|
@ -17,6 +17,13 @@
|
||||||
*/
|
*/
|
||||||
#define asmregparm __attribute__((regparm(3)))
|
#define asmregparm __attribute__((regparm(3)))
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For syscalls that need a pointer to the pt_regs struct (ie. fork).
|
||||||
|
* The regs pointer is passed in %eax as the first argument. The
|
||||||
|
* remaining function arguments remain on the stack.
|
||||||
|
*/
|
||||||
|
#define ptregscall __attribute__((regparm(1)))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure the compiler doesn't do anything stupid with the
|
* Make sure the compiler doesn't do anything stupid with the
|
||||||
* arguments on the stack - they are owned by the *caller*, not
|
* arguments on the stack - they are owned by the *caller*, not
|
||||||
|
|
|
@ -29,21 +29,26 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *);
|
||||||
/* X86_32 only */
|
/* X86_32 only */
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
/* kernel/process_32.c */
|
/* kernel/process_32.c */
|
||||||
asmlinkage int sys_fork(struct pt_regs);
|
ptregscall int sys_fork(struct pt_regs *);
|
||||||
asmlinkage int sys_clone(struct pt_regs);
|
ptregscall int sys_clone(struct pt_regs *, unsigned long,
|
||||||
asmlinkage int sys_vfork(struct pt_regs);
|
unsigned long, int __user *,
|
||||||
asmlinkage int sys_execve(struct pt_regs);
|
unsigned long, int __user *);
|
||||||
|
ptregscall int sys_vfork(struct pt_regs *);
|
||||||
|
ptregscall int sys_execve(struct pt_regs *, char __user *,
|
||||||
|
char __user * __user *,
|
||||||
|
char __user * __user *);
|
||||||
|
|
||||||
/* kernel/signal_32.c */
|
/* kernel/signal_32.c */
|
||||||
asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
|
asmlinkage int sys_sigsuspend(int, int, old_sigset_t);
|
||||||
asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
|
asmlinkage int sys_sigaction(int, const struct old_sigaction __user *,
|
||||||
struct old_sigaction __user *);
|
struct old_sigaction __user *);
|
||||||
asmlinkage int sys_sigaltstack(unsigned long);
|
ptregscall int sys_sigaltstack(struct pt_regs *, const stack_t __user *,
|
||||||
asmlinkage unsigned long sys_sigreturn(unsigned long);
|
stack_t __user *);
|
||||||
asmlinkage int sys_rt_sigreturn(unsigned long);
|
ptregscall unsigned long sys_sigreturn(struct pt_regs *);
|
||||||
|
ptregscall int sys_rt_sigreturn(struct pt_regs *);
|
||||||
|
|
||||||
/* kernel/ioport.c */
|
/* kernel/ioport.c */
|
||||||
asmlinkage long sys_iopl(unsigned long);
|
ptregscall long sys_iopl(struct pt_regs *, unsigned int);
|
||||||
|
|
||||||
/* kernel/sys_i386_32.c */
|
/* kernel/sys_i386_32.c */
|
||||||
asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
|
asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long,
|
||||||
|
@ -59,8 +64,8 @@ struct oldold_utsname;
|
||||||
asmlinkage int sys_olduname(struct oldold_utsname __user *);
|
asmlinkage int sys_olduname(struct oldold_utsname __user *);
|
||||||
|
|
||||||
/* kernel/vm86_32.c */
|
/* kernel/vm86_32.c */
|
||||||
asmlinkage int sys_vm86old(struct pt_regs);
|
ptregscall int sys_vm86old(struct pt_regs *, struct vm86_struct __user *);
|
||||||
asmlinkage int sys_vm86(struct pt_regs);
|
ptregscall int sys_vm86(struct pt_regs *, unsigned long, unsigned long);
|
||||||
|
|
||||||
#else /* CONFIG_X86_32 */
|
#else /* CONFIG_X86_32 */
|
||||||
|
|
||||||
|
|
|
@ -697,6 +697,26 @@ syscall_badsys:
|
||||||
END(syscall_badsys)
|
END(syscall_badsys)
|
||||||
CFI_ENDPROC
|
CFI_ENDPROC
|
||||||
|
|
||||||
|
/*
|
||||||
|
* System calls that need a pt_regs pointer.
|
||||||
|
*/
|
||||||
|
#define PTREGSCALL(name) \
|
||||||
|
ALIGN; \
|
||||||
|
ptregs_##name: \
|
||||||
|
leal 4(%esp),%eax; \
|
||||||
|
jmp sys_##name;
|
||||||
|
|
||||||
|
PTREGSCALL(iopl)
|
||||||
|
PTREGSCALL(fork)
|
||||||
|
PTREGSCALL(clone)
|
||||||
|
PTREGSCALL(vfork)
|
||||||
|
PTREGSCALL(execve)
|
||||||
|
PTREGSCALL(sigaltstack)
|
||||||
|
PTREGSCALL(sigreturn)
|
||||||
|
PTREGSCALL(rt_sigreturn)
|
||||||
|
PTREGSCALL(vm86)
|
||||||
|
PTREGSCALL(vm86old)
|
||||||
|
|
||||||
.macro FIXUP_ESPFIX_STACK
|
.macro FIXUP_ESPFIX_STACK
|
||||||
/* since we are on a wrong stack, we cant make it a C code :( */
|
/* since we are on a wrong stack, we cant make it a C code :( */
|
||||||
PER_CPU(gdt_page, %ebx)
|
PER_CPU(gdt_page, %ebx)
|
||||||
|
|
|
@ -131,10 +131,8 @@ static int do_iopl(unsigned int level, struct pt_regs *regs)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
asmlinkage long sys_iopl(unsigned long regsp)
|
ptregscall long sys_iopl(struct pt_regs *regs, unsigned int level)
|
||||||
{
|
{
|
||||||
struct pt_regs *regs = (struct pt_regs *)®sp;
|
|
||||||
unsigned int level = regs->bx;
|
|
||||||
struct thread_struct *t = ¤t->thread;
|
struct thread_struct *t = ¤t->thread;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
|
|
@ -603,24 +603,18 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p)
|
||||||
return prev_p;
|
return prev_p;
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage int sys_fork(struct pt_regs regs)
|
ptregscall int sys_fork(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
return do_fork(SIGCHLD, regs.sp, ®s, 0, NULL, NULL);
|
return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
asmlinkage int sys_clone(struct pt_regs regs)
|
ptregscall int sys_clone(struct pt_regs *regs, unsigned long clone_flags,
|
||||||
|
unsigned long newsp, int __user *parent_tidptr,
|
||||||
|
unsigned long unused, int __user *child_tidptr)
|
||||||
{
|
{
|
||||||
unsigned long clone_flags;
|
|
||||||
unsigned long newsp;
|
|
||||||
int __user *parent_tidptr, *child_tidptr;
|
|
||||||
|
|
||||||
clone_flags = regs.bx;
|
|
||||||
newsp = regs.cx;
|
|
||||||
parent_tidptr = (int __user *)regs.dx;
|
|
||||||
child_tidptr = (int __user *)regs.di;
|
|
||||||
if (!newsp)
|
if (!newsp)
|
||||||
newsp = regs.sp;
|
newsp = regs->sp;
|
||||||
return do_fork(clone_flags, newsp, ®s, 0, parent_tidptr, child_tidptr);
|
return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -633,27 +627,26 @@ asmlinkage int sys_clone(struct pt_regs regs)
|
||||||
* do not have enough call-clobbered registers to hold all
|
* do not have enough call-clobbered registers to hold all
|
||||||
* the information you need.
|
* the information you need.
|
||||||
*/
|
*/
|
||||||
asmlinkage int sys_vfork(struct pt_regs regs)
|
ptregscall int sys_vfork(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs.sp, ®s, 0, NULL, NULL);
|
return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* sys_execve() executes a new program.
|
* sys_execve() executes a new program.
|
||||||
*/
|
*/
|
||||||
asmlinkage int sys_execve(struct pt_regs regs)
|
ptregscall int sys_execve(struct pt_regs *regs, char __user *u_filename,
|
||||||
|
char __user * __user *argv,
|
||||||
|
char __user * __user *envp)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
char *filename;
|
char *filename;
|
||||||
|
|
||||||
filename = getname((char __user *) regs.bx);
|
filename = getname(u_filename);
|
||||||
error = PTR_ERR(filename);
|
error = PTR_ERR(filename);
|
||||||
if (IS_ERR(filename))
|
if (IS_ERR(filename))
|
||||||
goto out;
|
goto out;
|
||||||
error = do_execve(filename,
|
error = do_execve(filename, argv, envp, regs);
|
||||||
(char __user * __user *) regs.cx,
|
|
||||||
(char __user * __user *) regs.dx,
|
|
||||||
®s);
|
|
||||||
if (error == 0) {
|
if (error == 0) {
|
||||||
/* Make sure we don't return using sysenter.. */
|
/* Make sure we don't return using sysenter.. */
|
||||||
set_thread_flag(TIF_IRET);
|
set_thread_flag(TIF_IRET);
|
||||||
|
|
|
@ -549,39 +549,28 @@ sys_sigaction(int sig, const struct old_sigaction __user *act,
|
||||||
#endif /* CONFIG_X86_32 */
|
#endif /* CONFIG_X86_32 */
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
asmlinkage int sys_sigaltstack(unsigned long bx)
|
ptregscall int
|
||||||
{
|
sys_sigaltstack(struct pt_regs *regs, const stack_t __user *uss,
|
||||||
/*
|
stack_t __user *uoss)
|
||||||
* This is needed to make gcc realize it doesn't own the
|
|
||||||
* "struct pt_regs"
|
|
||||||
*/
|
|
||||||
struct pt_regs *regs = (struct pt_regs *)&bx;
|
|
||||||
const stack_t __user *uss = (const stack_t __user *)bx;
|
|
||||||
stack_t __user *uoss = (stack_t __user *)regs->cx;
|
|
||||||
|
|
||||||
return do_sigaltstack(uss, uoss, regs->sp);
|
|
||||||
}
|
|
||||||
#else /* !CONFIG_X86_32 */
|
#else /* !CONFIG_X86_32 */
|
||||||
asmlinkage long
|
asmlinkage long
|
||||||
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
|
sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
|
||||||
struct pt_regs *regs)
|
struct pt_regs *regs)
|
||||||
|
#endif /* CONFIG_X86_32 */
|
||||||
{
|
{
|
||||||
return do_sigaltstack(uss, uoss, regs->sp);
|
return do_sigaltstack(uss, uoss, regs->sp);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_X86_32 */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do a signal return; undo the signal stack.
|
* Do a signal return; undo the signal stack.
|
||||||
*/
|
*/
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
asmlinkage unsigned long sys_sigreturn(unsigned long __unused)
|
ptregscall unsigned long sys_sigreturn(struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
struct sigframe __user *frame;
|
struct sigframe __user *frame;
|
||||||
struct pt_regs *regs;
|
|
||||||
unsigned long ax;
|
unsigned long ax;
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
|
||||||
regs = (struct pt_regs *) &__unused;
|
|
||||||
frame = (struct sigframe __user *)(regs->sp - 8);
|
frame = (struct sigframe __user *)(regs->sp - 8);
|
||||||
|
|
||||||
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
|
||||||
|
@ -640,23 +629,13 @@ badframe:
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_X86_32
|
#ifdef CONFIG_X86_32
|
||||||
/*
|
ptregscall int sys_rt_sigreturn(struct pt_regs *regs)
|
||||||
* Note: do not pass in pt_regs directly as with tail-call optimization
|
|
||||||
* GCC will incorrectly stomp on the caller's frame and corrupt user-space
|
|
||||||
* register state:
|
|
||||||
*/
|
|
||||||
asmlinkage int sys_rt_sigreturn(unsigned long __unused)
|
|
||||||
{
|
|
||||||
struct pt_regs *regs = (struct pt_regs *)&__unused;
|
|
||||||
|
|
||||||
return do_rt_sigreturn(regs);
|
|
||||||
}
|
|
||||||
#else /* !CONFIG_X86_32 */
|
#else /* !CONFIG_X86_32 */
|
||||||
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
|
asmlinkage long sys_rt_sigreturn(struct pt_regs *regs)
|
||||||
|
#endif /* CONFIG_X86_32 */
|
||||||
{
|
{
|
||||||
return do_rt_sigreturn(regs);
|
return do_rt_sigreturn(regs);
|
||||||
}
|
}
|
||||||
#endif /* CONFIG_X86_32 */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OK, we're invoking a handler:
|
* OK, we're invoking a handler:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
ENTRY(sys_call_table)
|
ENTRY(sys_call_table)
|
||||||
.long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
|
.long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */
|
||||||
.long sys_exit
|
.long sys_exit
|
||||||
.long sys_fork
|
.long ptregs_fork
|
||||||
.long sys_read
|
.long sys_read
|
||||||
.long sys_write
|
.long sys_write
|
||||||
.long sys_open /* 5 */
|
.long sys_open /* 5 */
|
||||||
|
@ -10,7 +10,7 @@ ENTRY(sys_call_table)
|
||||||
.long sys_creat
|
.long sys_creat
|
||||||
.long sys_link
|
.long sys_link
|
||||||
.long sys_unlink /* 10 */
|
.long sys_unlink /* 10 */
|
||||||
.long sys_execve
|
.long ptregs_execve
|
||||||
.long sys_chdir
|
.long sys_chdir
|
||||||
.long sys_time
|
.long sys_time
|
||||||
.long sys_mknod
|
.long sys_mknod
|
||||||
|
@ -109,17 +109,17 @@ ENTRY(sys_call_table)
|
||||||
.long sys_newlstat
|
.long sys_newlstat
|
||||||
.long sys_newfstat
|
.long sys_newfstat
|
||||||
.long sys_uname
|
.long sys_uname
|
||||||
.long sys_iopl /* 110 */
|
.long ptregs_iopl /* 110 */
|
||||||
.long sys_vhangup
|
.long sys_vhangup
|
||||||
.long sys_ni_syscall /* old "idle" system call */
|
.long sys_ni_syscall /* old "idle" system call */
|
||||||
.long sys_vm86old
|
.long ptregs_vm86old
|
||||||
.long sys_wait4
|
.long sys_wait4
|
||||||
.long sys_swapoff /* 115 */
|
.long sys_swapoff /* 115 */
|
||||||
.long sys_sysinfo
|
.long sys_sysinfo
|
||||||
.long sys_ipc
|
.long sys_ipc
|
||||||
.long sys_fsync
|
.long sys_fsync
|
||||||
.long sys_sigreturn
|
.long ptregs_sigreturn
|
||||||
.long sys_clone /* 120 */
|
.long ptregs_clone /* 120 */
|
||||||
.long sys_setdomainname
|
.long sys_setdomainname
|
||||||
.long sys_newuname
|
.long sys_newuname
|
||||||
.long sys_modify_ldt
|
.long sys_modify_ldt
|
||||||
|
@ -165,14 +165,14 @@ ENTRY(sys_call_table)
|
||||||
.long sys_mremap
|
.long sys_mremap
|
||||||
.long sys_setresuid16
|
.long sys_setresuid16
|
||||||
.long sys_getresuid16 /* 165 */
|
.long sys_getresuid16 /* 165 */
|
||||||
.long sys_vm86
|
.long ptregs_vm86
|
||||||
.long sys_ni_syscall /* Old sys_query_module */
|
.long sys_ni_syscall /* Old sys_query_module */
|
||||||
.long sys_poll
|
.long sys_poll
|
||||||
.long sys_nfsservctl
|
.long sys_nfsservctl
|
||||||
.long sys_setresgid16 /* 170 */
|
.long sys_setresgid16 /* 170 */
|
||||||
.long sys_getresgid16
|
.long sys_getresgid16
|
||||||
.long sys_prctl
|
.long sys_prctl
|
||||||
.long sys_rt_sigreturn
|
.long ptregs_rt_sigreturn
|
||||||
.long sys_rt_sigaction
|
.long sys_rt_sigaction
|
||||||
.long sys_rt_sigprocmask /* 175 */
|
.long sys_rt_sigprocmask /* 175 */
|
||||||
.long sys_rt_sigpending
|
.long sys_rt_sigpending
|
||||||
|
@ -185,11 +185,11 @@ ENTRY(sys_call_table)
|
||||||
.long sys_getcwd
|
.long sys_getcwd
|
||||||
.long sys_capget
|
.long sys_capget
|
||||||
.long sys_capset /* 185 */
|
.long sys_capset /* 185 */
|
||||||
.long sys_sigaltstack
|
.long ptregs_sigaltstack
|
||||||
.long sys_sendfile
|
.long sys_sendfile
|
||||||
.long sys_ni_syscall /* reserved for streams1 */
|
.long sys_ni_syscall /* reserved for streams1 */
|
||||||
.long sys_ni_syscall /* reserved for streams2 */
|
.long sys_ni_syscall /* reserved for streams2 */
|
||||||
.long sys_vfork /* 190 */
|
.long ptregs_vfork /* 190 */
|
||||||
.long sys_getrlimit
|
.long sys_getrlimit
|
||||||
.long sys_mmap2
|
.long sys_mmap2
|
||||||
.long sys_truncate64
|
.long sys_truncate64
|
||||||
|
|
|
@ -197,9 +197,8 @@ out:
|
||||||
static int do_vm86_irq_handling(int subfunction, int irqnumber);
|
static int do_vm86_irq_handling(int subfunction, int irqnumber);
|
||||||
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk);
|
static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk);
|
||||||
|
|
||||||
asmlinkage int sys_vm86old(struct pt_regs regs)
|
ptregscall int sys_vm86old(struct pt_regs *regs, struct vm86_struct __user *v86)
|
||||||
{
|
{
|
||||||
struct vm86_struct __user *v86 = (struct vm86_struct __user *)regs.bx;
|
|
||||||
struct kernel_vm86_struct info; /* declare this _on top_,
|
struct kernel_vm86_struct info; /* declare this _on top_,
|
||||||
* this avoids wasting of stack space.
|
* this avoids wasting of stack space.
|
||||||
* This remains on the stack until we
|
* This remains on the stack until we
|
||||||
|
@ -218,7 +217,7 @@ asmlinkage int sys_vm86old(struct pt_regs regs)
|
||||||
if (tmp)
|
if (tmp)
|
||||||
goto out;
|
goto out;
|
||||||
memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
|
memset(&info.vm86plus, 0, (int)&info.regs32 - (int)&info.vm86plus);
|
||||||
info.regs32 = ®s;
|
info.regs32 = regs;
|
||||||
tsk->thread.vm86_info = v86;
|
tsk->thread.vm86_info = v86;
|
||||||
do_sys_vm86(&info, tsk);
|
do_sys_vm86(&info, tsk);
|
||||||
ret = 0; /* we never return here */
|
ret = 0; /* we never return here */
|
||||||
|
@ -227,7 +226,7 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
asmlinkage int sys_vm86(struct pt_regs regs)
|
ptregscall int sys_vm86(struct pt_regs *regs, unsigned long cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
struct kernel_vm86_struct info; /* declare this _on top_,
|
struct kernel_vm86_struct info; /* declare this _on top_,
|
||||||
* this avoids wasting of stack space.
|
* this avoids wasting of stack space.
|
||||||
|
@ -239,12 +238,12 @@ asmlinkage int sys_vm86(struct pt_regs regs)
|
||||||
struct vm86plus_struct __user *v86;
|
struct vm86plus_struct __user *v86;
|
||||||
|
|
||||||
tsk = current;
|
tsk = current;
|
||||||
switch (regs.bx) {
|
switch (cmd) {
|
||||||
case VM86_REQUEST_IRQ:
|
case VM86_REQUEST_IRQ:
|
||||||
case VM86_FREE_IRQ:
|
case VM86_FREE_IRQ:
|
||||||
case VM86_GET_IRQ_BITS:
|
case VM86_GET_IRQ_BITS:
|
||||||
case VM86_GET_AND_RESET_IRQ:
|
case VM86_GET_AND_RESET_IRQ:
|
||||||
ret = do_vm86_irq_handling(regs.bx, (int)regs.cx);
|
ret = do_vm86_irq_handling(cmd, (int)arg);
|
||||||
goto out;
|
goto out;
|
||||||
case VM86_PLUS_INSTALL_CHECK:
|
case VM86_PLUS_INSTALL_CHECK:
|
||||||
/*
|
/*
|
||||||
|
@ -261,14 +260,14 @@ asmlinkage int sys_vm86(struct pt_regs regs)
|
||||||
ret = -EPERM;
|
ret = -EPERM;
|
||||||
if (tsk->thread.saved_sp0)
|
if (tsk->thread.saved_sp0)
|
||||||
goto out;
|
goto out;
|
||||||
v86 = (struct vm86plus_struct __user *)regs.cx;
|
v86 = (struct vm86plus_struct __user *)arg;
|
||||||
tmp = copy_vm86_regs_from_user(&info.regs, &v86->regs,
|
tmp = copy_vm86_regs_from_user(&info.regs, &v86->regs,
|
||||||
offsetof(struct kernel_vm86_struct, regs32) -
|
offsetof(struct kernel_vm86_struct, regs32) -
|
||||||
sizeof(info.regs));
|
sizeof(info.regs));
|
||||||
ret = -EFAULT;
|
ret = -EFAULT;
|
||||||
if (tmp)
|
if (tmp)
|
||||||
goto out;
|
goto out;
|
||||||
info.regs32 = ®s;
|
info.regs32 = regs;
|
||||||
info.vm86plus.is_vm86pus = 1;
|
info.vm86plus.is_vm86pus = 1;
|
||||||
tsk->thread.vm86_info = (struct vm86_struct __user *)v86;
|
tsk->thread.vm86_info = (struct vm86_struct __user *)v86;
|
||||||
do_sys_vm86(&info, tsk);
|
do_sys_vm86(&info, tsk);
|
||||||
|
|
Loading…
Reference in a new issue