aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-08-03 14:12:09 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-08-03 14:12:09 -0400
commit9250d9047d99e8175cdf9b8e84952d2c69f3ed6d (patch)
tree8ce1ff8f0e2c9b268a3afe1476cfe65962147aa4
parentabe0308070d23d4b68db093683b7dbc1396b1fbd (diff)
parente35ac62d2202e31307c0f9b278a61e484c4727f2 (diff)
Merge branch 'fixes' of git://git.linaro.org/people/rmk/linux-arm
Pull arm fixes fixes from Russell King: "This fixes a couple of problems with commit 48be69a026b2 ("ARM: move signal handlers into a vdso-like page"), one of which was originally discovered via my testing originally, but the fix for it was never actually committed. The other shows up on noMMU builds, and such platforms are extremely rare and as such are not part of my nightly testing" * 'fixes' of git://git.linaro.org/people/rmk/linux-arm: ARM: fix nommu builds with 48be69a02 (ARM: move signal handlers into a vdso-like page) ARM: fix a cockup in 48be69a02 (ARM: move signal handlers into a vdso-like page)
-rw-r--r--arch/arm/include/asm/elf.h2
-rw-r--r--arch/arm/kernel/process.c9
-rw-r--r--arch/arm/kernel/signal.c48
3 files changed, 31 insertions, 28 deletions
diff --git a/arch/arm/include/asm/elf.h b/arch/arm/include/asm/elf.h
index 9c9b30717fda..56211f2084ef 100644
--- a/arch/arm/include/asm/elf.h
+++ b/arch/arm/include/asm/elf.h
@@ -130,8 +130,10 @@ struct mm_struct;
130extern unsigned long arch_randomize_brk(struct mm_struct *mm); 130extern unsigned long arch_randomize_brk(struct mm_struct *mm);
131#define arch_randomize_brk arch_randomize_brk 131#define arch_randomize_brk arch_randomize_brk
132 132
133#ifdef CONFIG_MMU
133#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1 134#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
134struct linux_binprm; 135struct linux_binprm;
135int arch_setup_additional_pages(struct linux_binprm *, int); 136int arch_setup_additional_pages(struct linux_binprm *, int);
137#endif
136 138
137#endif 139#endif
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 16ed3f7c4980..536c85fe72a8 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -474,17 +474,18 @@ const char *arch_vma_name(struct vm_area_struct *vma)
474 "[sigpage]" : NULL; 474 "[sigpage]" : NULL;
475} 475}
476 476
477static struct page *signal_page;
477extern struct page *get_signal_page(void); 478extern struct page *get_signal_page(void);
478 479
479int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp) 480int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
480{ 481{
481 struct mm_struct *mm = current->mm; 482 struct mm_struct *mm = current->mm;
482 struct page *page;
483 unsigned long addr; 483 unsigned long addr;
484 int ret; 484 int ret;
485 485
486 page = get_signal_page(); 486 if (!signal_page)
487 if (!page) 487 signal_page = get_signal_page();
488 if (!signal_page)
488 return -ENOMEM; 489 return -ENOMEM;
489 490
490 down_write(&mm->mmap_sem); 491 down_write(&mm->mmap_sem);
@@ -496,7 +497,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
496 497
497 ret = install_special_mapping(mm, addr, PAGE_SIZE, 498 ret = install_special_mapping(mm, addr, PAGE_SIZE,
498 VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC, 499 VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
499 &page); 500 &signal_page);
500 501
501 if (ret == 0) 502 if (ret == 0)
502 mm->context.sigpage = addr; 503 mm->context.sigpage = addr;
diff --git a/arch/arm/kernel/signal.c b/arch/arm/kernel/signal.c
index 0f17e06d51e6..ab3304225272 100644
--- a/arch/arm/kernel/signal.c
+++ b/arch/arm/kernel/signal.c
@@ -402,7 +402,8 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
402 __put_user(sigreturn_codes[idx+1], rc+1)) 402 __put_user(sigreturn_codes[idx+1], rc+1))
403 return 1; 403 return 1;
404 404
405 if ((cpsr & MODE32_BIT) && !IS_ENABLED(CONFIG_ARM_MPU)) { 405#ifdef CONFIG_MMU
406 if (cpsr & MODE32_BIT) {
406 struct mm_struct *mm = current->mm; 407 struct mm_struct *mm = current->mm;
407 408
408 /* 409 /*
@@ -412,7 +413,9 @@ setup_return(struct pt_regs *regs, struct ksignal *ksig,
412 */ 413 */
413 retcode = mm->context.sigpage + signal_return_offset + 414 retcode = mm->context.sigpage + signal_return_offset +
414 (idx << 2) + thumb; 415 (idx << 2) + thumb;
415 } else { 416 } else
417#endif
418 {
416 /* 419 /*
417 * Ensure that the instruction cache sees 420 * Ensure that the instruction cache sees
418 * the return code written onto the stack. 421 * the return code written onto the stack.
@@ -614,35 +617,32 @@ do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
614 return 0; 617 return 0;
615} 618}
616 619
617static struct page *signal_page;
618
619struct page *get_signal_page(void) 620struct page *get_signal_page(void)
620{ 621{
621 if (!signal_page) { 622 unsigned long ptr;
622 unsigned long ptr; 623 unsigned offset;
623 unsigned offset; 624 struct page *page;
624 void *addr; 625 void *addr;
625 626
626 signal_page = alloc_pages(GFP_KERNEL, 0); 627 page = alloc_pages(GFP_KERNEL, 0);
627 628
628 if (!signal_page) 629 if (!page)
629 return NULL; 630 return NULL;
630 631
631 addr = page_address(signal_page); 632 addr = page_address(page);
632 633
633 /* Give the signal return code some randomness */ 634 /* Give the signal return code some randomness */
634 offset = 0x200 + (get_random_int() & 0x7fc); 635 offset = 0x200 + (get_random_int() & 0x7fc);
635 signal_return_offset = offset; 636 signal_return_offset = offset;
636 637
637 /* 638 /*
638 * Copy signal return handlers into the vector page, and 639 * Copy signal return handlers into the vector page, and
639 * set sigreturn to be a pointer to these. 640 * set sigreturn to be a pointer to these.
640 */ 641 */
641 memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes)); 642 memcpy(addr + offset, sigreturn_codes, sizeof(sigreturn_codes));
642 643
643 ptr = (unsigned long)addr + offset; 644 ptr = (unsigned long)addr + offset;
644 flush_icache_range(ptr, ptr + sizeof(sigreturn_codes)); 645 flush_icache_range(ptr, ptr + sizeof(sigreturn_codes));
645 }
646 646
647 return signal_page; 647 return page;
648} 648}