diff options
author | Brian Gerst <brgerst@gmail.com> | 2009-02-11 16:43:58 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2009-02-11 17:00:56 -0500 |
commit | b12bdaf11f935d7be030207e3c77faeaeab8ded3 (patch) | |
tree | e41f325f01614f7cf2eb78350fbd7440afe39cf8 | |
parent | 1c0040047d5499599cc231ca3f105be3ceff8562 (diff) |
x86: use regparm(3) for passed-in pt_regs pointer
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 take the pointer as an argument instead of relying on
the assumption that the pt_regs structure overlaps the function
arguments.
Drop the use of regparm(1) due to concern about gcc bugs, and to move
in the direction of the eventual removal of regparm(0) for asmlinkage.
Signed-off-by: Brian Gerst <brgerst@gmail.com>
Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
-rw-r--r-- | arch/x86/include/asm/linkage.h | 7 | ||||
-rw-r--r-- | arch/x86/include/asm/syscalls.h | 25 | ||||
-rw-r--r-- | arch/x86/kernel/ioport.c | 3 | ||||
-rw-r--r-- | arch/x86/kernel/process_32.c | 27 | ||||
-rw-r--r-- | arch/x86/kernel/signal.c | 21 | ||||
-rw-r--r-- | arch/x86/kernel/vm86_32.c | 11 |
6 files changed, 49 insertions, 45 deletions
diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h index 2fd5926fb97d..5d98d0b68ffc 100644 --- a/arch/x86/include/asm/linkage.h +++ b/arch/x86/include/asm/linkage.h | |||
@@ -18,13 +18,6 @@ | |||
18 | #define asmregparm __attribute__((regparm(3))) | 18 | #define asmregparm __attribute__((regparm(3))) |
19 | 19 | ||
20 | /* | 20 | /* |
21 | * For syscalls that need a pointer to the pt_regs struct (ie. fork). | ||
22 | * The regs pointer is passed in %eax as the first argument. The | ||
23 | * remaining function arguments remain on the stack. | ||
24 | */ | ||
25 | #define ptregscall __attribute__((regparm(1))) | ||
26 | |||
27 | /* | ||
28 | * Make sure the compiler doesn't do anything stupid with the | 21 | * Make sure the compiler doesn't do anything stupid with the |
29 | * arguments on the stack - they are owned by the *caller*, not | 22 | * arguments on the stack - they are owned by the *caller*, not |
30 | * the callee. This just fools gcc into not spilling into them, | 23 | * the callee. This just fools gcc into not spilling into them, |
diff --git a/arch/x86/include/asm/syscalls.h b/arch/x86/include/asm/syscalls.h index 617295255a17..77bb31a88ba8 100644 --- a/arch/x86/include/asm/syscalls.h +++ b/arch/x86/include/asm/syscalls.h | |||
@@ -29,26 +29,21 @@ asmlinkage int sys_get_thread_area(struct user_desc __user *); | |||
29 | /* X86_32 only */ | 29 | /* X86_32 only */ |
30 | #ifdef CONFIG_X86_32 | 30 | #ifdef CONFIG_X86_32 |
31 | /* kernel/process_32.c */ | 31 | /* kernel/process_32.c */ |
32 | ptregscall int sys_fork(struct pt_regs *); | 32 | int sys_fork(struct pt_regs *); |
33 | ptregscall int sys_clone(struct pt_regs *, unsigned long, | 33 | int sys_clone(struct pt_regs *); |
34 | unsigned long, int __user *, | 34 | int sys_vfork(struct pt_regs *); |
35 | unsigned long, int __user *); | 35 | int sys_execve(struct pt_regs *); |
36 | ptregscall int sys_vfork(struct pt_regs *); | ||
37 | ptregscall int sys_execve(struct pt_regs *, char __user *, | ||
38 | char __user * __user *, | ||
39 | char __user * __user *); | ||
40 | 36 | ||
41 | /* kernel/signal_32.c */ | 37 | /* kernel/signal_32.c */ |
42 | asmlinkage int sys_sigsuspend(int, int, old_sigset_t); | 38 | asmlinkage int sys_sigsuspend(int, int, old_sigset_t); |
43 | asmlinkage int sys_sigaction(int, const struct old_sigaction __user *, | 39 | asmlinkage int sys_sigaction(int, const struct old_sigaction __user *, |
44 | struct old_sigaction __user *); | 40 | struct old_sigaction __user *); |
45 | ptregscall int sys_sigaltstack(struct pt_regs *, const stack_t __user *, | 41 | int sys_sigaltstack(struct pt_regs *); |
46 | stack_t __user *); | 42 | unsigned long sys_sigreturn(struct pt_regs *); |
47 | ptregscall unsigned long sys_sigreturn(struct pt_regs *); | 43 | int sys_rt_sigreturn(struct pt_regs *); |
48 | ptregscall int sys_rt_sigreturn(struct pt_regs *); | ||
49 | 44 | ||
50 | /* kernel/ioport.c */ | 45 | /* kernel/ioport.c */ |
51 | ptregscall long sys_iopl(struct pt_regs *, unsigned int); | 46 | long sys_iopl(struct pt_regs *); |
52 | 47 | ||
53 | /* kernel/sys_i386_32.c */ | 48 | /* kernel/sys_i386_32.c */ |
54 | asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, | 49 | asmlinkage long sys_mmap2(unsigned long, unsigned long, unsigned long, |
@@ -64,8 +59,8 @@ struct oldold_utsname; | |||
64 | asmlinkage int sys_olduname(struct oldold_utsname __user *); | 59 | asmlinkage int sys_olduname(struct oldold_utsname __user *); |
65 | 60 | ||
66 | /* kernel/vm86_32.c */ | 61 | /* kernel/vm86_32.c */ |
67 | ptregscall int sys_vm86old(struct pt_regs *, struct vm86_struct __user *); | 62 | int sys_vm86old(struct pt_regs *); |
68 | ptregscall int sys_vm86(struct pt_regs *, unsigned long, unsigned long); | 63 | int sys_vm86(struct pt_regs *); |
69 | 64 | ||
70 | #else /* CONFIG_X86_32 */ | 65 | #else /* CONFIG_X86_32 */ |
71 | 66 | ||
diff --git a/arch/x86/kernel/ioport.c b/arch/x86/kernel/ioport.c index 7ec148646312..e41980a373ab 100644 --- a/arch/x86/kernel/ioport.c +++ b/arch/x86/kernel/ioport.c | |||
@@ -131,8 +131,9 @@ static int do_iopl(unsigned int level, struct pt_regs *regs) | |||
131 | } | 131 | } |
132 | 132 | ||
133 | #ifdef CONFIG_X86_32 | 133 | #ifdef CONFIG_X86_32 |
134 | ptregscall long sys_iopl(struct pt_regs *regs, unsigned int level) | 134 | long sys_iopl(struct pt_regs *regs) |
135 | { | 135 | { |
136 | unsigned int level = regs->bx; | ||
136 | struct thread_struct *t = ¤t->thread; | 137 | struct thread_struct *t = ¤t->thread; |
137 | int rc; | 138 | int rc; |
138 | 139 | ||
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c index 5a9dcfb01f71..fec79ad85dc6 100644 --- a/arch/x86/kernel/process_32.c +++ b/arch/x86/kernel/process_32.c | |||
@@ -603,15 +603,21 @@ __switch_to(struct task_struct *prev_p, struct task_struct *next_p) | |||
603 | return prev_p; | 603 | return prev_p; |
604 | } | 604 | } |
605 | 605 | ||
606 | ptregscall int sys_fork(struct pt_regs *regs) | 606 | int sys_fork(struct pt_regs *regs) |
607 | { | 607 | { |
608 | return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); | 608 | return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); |
609 | } | 609 | } |
610 | 610 | ||
611 | ptregscall int sys_clone(struct pt_regs *regs, unsigned long clone_flags, | 611 | int sys_clone(struct pt_regs *regs) |
612 | unsigned long newsp, int __user *parent_tidptr, | ||
613 | unsigned long unused, int __user *child_tidptr) | ||
614 | { | 612 | { |
613 | unsigned long clone_flags; | ||
614 | unsigned long newsp; | ||
615 | int __user *parent_tidptr, *child_tidptr; | ||
616 | |||
617 | clone_flags = regs->bx; | ||
618 | newsp = regs->cx; | ||
619 | parent_tidptr = (int __user *)regs->dx; | ||
620 | child_tidptr = (int __user *)regs->di; | ||
615 | if (!newsp) | 621 | if (!newsp) |
616 | newsp = regs->sp; | 622 | newsp = regs->sp; |
617 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); | 623 | return do_fork(clone_flags, newsp, regs, 0, parent_tidptr, child_tidptr); |
@@ -627,7 +633,7 @@ ptregscall int sys_clone(struct pt_regs *regs, unsigned long clone_flags, | |||
627 | * do not have enough call-clobbered registers to hold all | 633 | * do not have enough call-clobbered registers to hold all |
628 | * the information you need. | 634 | * the information you need. |
629 | */ | 635 | */ |
630 | ptregscall int sys_vfork(struct pt_regs *regs) | 636 | int sys_vfork(struct pt_regs *regs) |
631 | { | 637 | { |
632 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL); | 638 | return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, NULL, NULL); |
633 | } | 639 | } |
@@ -635,18 +641,19 @@ ptregscall int sys_vfork(struct pt_regs *regs) | |||
635 | /* | 641 | /* |
636 | * sys_execve() executes a new program. | 642 | * sys_execve() executes a new program. |
637 | */ | 643 | */ |
638 | ptregscall int sys_execve(struct pt_regs *regs, char __user *u_filename, | 644 | int sys_execve(struct pt_regs *regs) |
639 | char __user * __user *argv, | ||
640 | char __user * __user *envp) | ||
641 | { | 645 | { |
642 | int error; | 646 | int error; |
643 | char *filename; | 647 | char *filename; |
644 | 648 | ||
645 | filename = getname(u_filename); | 649 | filename = getname((char __user *) regs->bx); |
646 | error = PTR_ERR(filename); | 650 | error = PTR_ERR(filename); |
647 | if (IS_ERR(filename)) | 651 | if (IS_ERR(filename)) |
648 | goto out; | 652 | goto out; |
649 | error = do_execve(filename, argv, envp, regs); | 653 | error = do_execve(filename, |
654 | (char __user * __user *) regs->cx, | ||
655 | (char __user * __user *) regs->dx, | ||
656 | regs); | ||
650 | if (error == 0) { | 657 | if (error == 0) { |
651 | /* Make sure we don't return using sysenter.. */ | 658 | /* Make sure we don't return using sysenter.. */ |
652 | set_thread_flag(TIF_IRET); | 659 | set_thread_flag(TIF_IRET); |
diff --git a/arch/x86/kernel/signal.c b/arch/x86/kernel/signal.c index d7a158367e38..ccfb27412f0f 100644 --- a/arch/x86/kernel/signal.c +++ b/arch/x86/kernel/signal.c | |||
@@ -549,23 +549,27 @@ sys_sigaction(int sig, const struct old_sigaction __user *act, | |||
549 | #endif /* CONFIG_X86_32 */ | 549 | #endif /* CONFIG_X86_32 */ |
550 | 550 | ||
551 | #ifdef CONFIG_X86_32 | 551 | #ifdef CONFIG_X86_32 |
552 | ptregscall int | 552 | int sys_sigaltstack(struct pt_regs *regs) |
553 | sys_sigaltstack(struct pt_regs *regs, const stack_t __user *uss, | 553 | { |
554 | stack_t __user *uoss) | 554 | const stack_t __user *uss = (const stack_t __user *)regs->bx; |
555 | stack_t __user *uoss = (stack_t __user *)regs->cx; | ||
556 | |||
557 | return do_sigaltstack(uss, uoss, regs->sp); | ||
558 | } | ||
555 | #else /* !CONFIG_X86_32 */ | 559 | #else /* !CONFIG_X86_32 */ |
556 | asmlinkage long | 560 | asmlinkage long |
557 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, | 561 | sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss, |
558 | struct pt_regs *regs) | 562 | struct pt_regs *regs) |
559 | #endif /* CONFIG_X86_32 */ | ||
560 | { | 563 | { |
561 | return do_sigaltstack(uss, uoss, regs->sp); | 564 | return do_sigaltstack(uss, uoss, regs->sp); |
562 | } | 565 | } |
566 | #endif /* CONFIG_X86_32 */ | ||
563 | 567 | ||
564 | /* | 568 | /* |
565 | * Do a signal return; undo the signal stack. | 569 | * Do a signal return; undo the signal stack. |
566 | */ | 570 | */ |
567 | #ifdef CONFIG_X86_32 | 571 | #ifdef CONFIG_X86_32 |
568 | ptregscall unsigned long sys_sigreturn(struct pt_regs *regs) | 572 | unsigned long sys_sigreturn(struct pt_regs *regs) |
569 | { | 573 | { |
570 | struct sigframe __user *frame; | 574 | struct sigframe __user *frame; |
571 | unsigned long ax; | 575 | unsigned long ax; |
@@ -629,13 +633,16 @@ badframe: | |||
629 | } | 633 | } |
630 | 634 | ||
631 | #ifdef CONFIG_X86_32 | 635 | #ifdef CONFIG_X86_32 |
632 | ptregscall int sys_rt_sigreturn(struct pt_regs *regs) | 636 | int sys_rt_sigreturn(struct pt_regs *regs) |
637 | { | ||
638 | return do_rt_sigreturn(regs); | ||
639 | } | ||
633 | #else /* !CONFIG_X86_32 */ | 640 | #else /* !CONFIG_X86_32 */ |
634 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) | 641 | asmlinkage long sys_rt_sigreturn(struct pt_regs *regs) |
635 | #endif /* CONFIG_X86_32 */ | ||
636 | { | 642 | { |
637 | return do_rt_sigreturn(regs); | 643 | return do_rt_sigreturn(regs); |
638 | } | 644 | } |
645 | #endif /* CONFIG_X86_32 */ | ||
639 | 646 | ||
640 | /* | 647 | /* |
641 | * OK, we're invoking a handler: | 648 | * OK, we're invoking a handler: |
diff --git a/arch/x86/kernel/vm86_32.c b/arch/x86/kernel/vm86_32.c index 8fa6ba7c9233..d7ac84e7fc1c 100644 --- a/arch/x86/kernel/vm86_32.c +++ b/arch/x86/kernel/vm86_32.c | |||
@@ -197,8 +197,9 @@ out: | |||
197 | static int do_vm86_irq_handling(int subfunction, int irqnumber); | 197 | static int do_vm86_irq_handling(int subfunction, int irqnumber); |
198 | static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk); | 198 | static void do_sys_vm86(struct kernel_vm86_struct *info, struct task_struct *tsk); |
199 | 199 | ||
200 | ptregscall int sys_vm86old(struct pt_regs *regs, struct vm86_struct __user *v86) | 200 | int sys_vm86old(struct pt_regs *regs) |
201 | { | 201 | { |
202 | struct vm86_struct __user *v86 = (struct vm86_struct __user *)regs->bx; | ||
202 | struct kernel_vm86_struct info; /* declare this _on top_, | 203 | struct kernel_vm86_struct info; /* declare this _on top_, |
203 | * this avoids wasting of stack space. | 204 | * this avoids wasting of stack space. |
204 | * This remains on the stack until we | 205 | * This remains on the stack until we |
@@ -226,7 +227,7 @@ out: | |||
226 | } | 227 | } |
227 | 228 | ||
228 | 229 | ||
229 | ptregscall int sys_vm86(struct pt_regs *regs, unsigned long cmd, unsigned long arg) | 230 | int sys_vm86(struct pt_regs *regs) |
230 | { | 231 | { |
231 | struct kernel_vm86_struct info; /* declare this _on top_, | 232 | struct kernel_vm86_struct info; /* declare this _on top_, |
232 | * this avoids wasting of stack space. | 233 | * this avoids wasting of stack space. |
@@ -238,12 +239,12 @@ ptregscall int sys_vm86(struct pt_regs *regs, unsigned long cmd, unsigned long a | |||
238 | struct vm86plus_struct __user *v86; | 239 | struct vm86plus_struct __user *v86; |
239 | 240 | ||
240 | tsk = current; | 241 | tsk = current; |
241 | switch (cmd) { | 242 | switch (regs->bx) { |
242 | case VM86_REQUEST_IRQ: | 243 | case VM86_REQUEST_IRQ: |
243 | case VM86_FREE_IRQ: | 244 | case VM86_FREE_IRQ: |
244 | case VM86_GET_IRQ_BITS: | 245 | case VM86_GET_IRQ_BITS: |
245 | case VM86_GET_AND_RESET_IRQ: | 246 | case VM86_GET_AND_RESET_IRQ: |
246 | ret = do_vm86_irq_handling(cmd, (int)arg); | 247 | ret = do_vm86_irq_handling(regs->bx, (int)regs->cx); |
247 | goto out; | 248 | goto out; |
248 | case VM86_PLUS_INSTALL_CHECK: | 249 | case VM86_PLUS_INSTALL_CHECK: |
249 | /* | 250 | /* |
@@ -260,7 +261,7 @@ ptregscall int sys_vm86(struct pt_regs *regs, unsigned long cmd, unsigned long a | |||
260 | ret = -EPERM; | 261 | ret = -EPERM; |
261 | if (tsk->thread.saved_sp0) | 262 | if (tsk->thread.saved_sp0) |
262 | goto out; | 263 | goto out; |
263 | v86 = (struct vm86plus_struct __user *)arg; | 264 | v86 = (struct vm86plus_struct __user *)regs->cx; |
264 | tmp = copy_vm86_regs_from_user(&info.regs, &v86->regs, | 265 | tmp = copy_vm86_regs_from_user(&info.regs, &v86->regs, |
265 | offsetof(struct kernel_vm86_struct, regs32) - | 266 | offsetof(struct kernel_vm86_struct, regs32) - |
266 | sizeof(info.regs)); | 267 | sizeof(info.regs)); |