This is a preliminary patch to add a vdso to all user processes.
Still missing are ELF headers and .eh_frame information. But it is
enough to allow us to move signal trampolines off of the stack.
We allocate a single page (the vdso) and write all possible signal
trampolines into it. The stack is moved down by one page and the vdso
is mapped into this space.
Signed-off-by: David Daney <ddaney@caviumnetworks.com>
---
arch/mips/include/asm/elf.h | 4 +
arch/mips/include/asm/mmu.h | 5 +-
arch/mips/include/asm/mmu_context.h | 2 +-
arch/mips/include/asm/processor.h | 5 +-
arch/mips/include/asm/vdso.h | 29 ++++++++++
arch/mips/kernel/Makefile | 2 +-
arch/mips/kernel/syscall.c | 2 +-
arch/mips/kernel/vdso.c | 104 +++++++++++++++++++++++++++++++++++
8 files changed, 147 insertions(+), 6 deletions(-)
create mode 100644 arch/mips/include/asm/vdso.h
create mode 100644 arch/mips/kernel/vdso.c
diff --git a/arch/mips/include/asm/elf.h b/arch/mips/include/asm/elf.h
index d58f128..08b3bc5 100644
--- a/arch/mips/include/asm/elf.h
+++ b/arch/mips/include/asm/elf.h
@@ -364,4 +364,8 @@ extern int dump_task_fpu(struct task_struct *,
elf_fpregset_t *);
#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2)
#endif
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int uses_interp);
#endif /* _ASM_ELF_H */
diff --git a/arch/mips/include/asm/mmu.h b/arch/mips/include/asm/mmu.h
index 4063edd..c436138 100644
--- a/arch/mips/include/asm/mmu.h
+++ b/arch/mips/include/asm/mmu.h
@@ -1,6 +1,9 @@
#ifndef __ASM_MMU_H
#define __ASM_MMU_H
-typedef unsigned long mm_context_t[NR_CPUS];
+typedef struct {
+ unsigned long asid[NR_CPUS];
+ void *vdso;
+} mm_context_t;
#endif /* __ASM_MMU_H */
diff --git a/arch/mips/include/asm/mmu_context.h
b/arch/mips/include/asm/mmu_context.h
index d7f3eb0..62bcf13 100644
--- a/arch/mips/include/asm/mmu_context.h
+++ b/arch/mips/include/asm/mmu_context.h
@@ -73,7 +73,7 @@ extern unsigned long smtc_asid_mask;
#endif
-#define cpu_context(cpu, mm) ((mm)->context[cpu])
+#define cpu_context(cpu, mm) ((mm)->context.asid[cpu])
#define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK)
#define asid_cache(cpu) (cpu_data[cpu].asid_cache)
diff --git a/arch/mips/include/asm/processor.h
b/arch/mips/include/asm/processor.h
index 0f926aa..530b01f 100644
--- a/arch/mips/include/asm/processor.h
+++ b/arch/mips/include/asm/processor.h
@@ -39,7 +39,7 @@ extern unsigned int vced_count, vcei_count;
* so don't change it unless you know what you are doing.
*/
#define TASK_SIZE 0x7fff8000UL
-#define STACK_TOP TASK_SIZE
+#define STACK_TOP (TASK_SIZE - PAGE_SIZE)
/*
* This decides where the kernel will search for a free chunk of vm
@@ -59,7 +59,8 @@ extern unsigned int vced_count, vcei_count;
#define TASK_SIZE32 0x7fff8000UL
#define TASK_SIZE 0x10000000000UL
#define STACK_TOP \
- (test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE)
+ ((test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE) - \
+ PAGE_SIZE)
/*
* This decides where the kernel will search for a free chunk of vm
diff --git a/arch/mips/include/asm/vdso.h b/arch/mips/include/asm/vdso.h
new file mode 100644
index 0000000..cca56aa
--- /dev/null
+++ b/arch/mips/include/asm/vdso.h
@@ -0,0 +1,29 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Cavium Networks
+ */
+
+#ifndef __ASM_VDSO_H
+#define __ASM_VDSO_H
+
+#include <linux/types.h>
+
+
+#ifdef CONFIG_32BIT
+struct mips_vdso {
+ u32 signal_trampoline[2];
+ u32 rt_signal_trampoline[2];
+};
+#else /* !CONFIG_32BIT */
+struct mips_vdso {
+ u32 o32_signal_trampoline[2];
+ u32 o32_rt_signal_trampoline[2];
+ u32 rt_signal_trampoline[2];
+ u32 n32_rt_signal_trampoline[2];
+};
+#endif /* CONFIG_32BIT */
+
+#endif /* __ASM_VDSO_H */
diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile
index e961221..b8158b5 100644
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -6,7 +6,7 @@ extra-y := head.o init_task.o vmlinux.lds
obj-y += cpu-probe.o branch.o entry.o genex.o irq.o process.o \
ptrace.o reset.o setup.o signal.o syscall.o \
- time.o topology.o traps.o unaligned.o watch.o
+ time.o topology.o traps.o unaligned.o watch.o vdso.o
obj-$(CONFIG_CEVT_BCM1480) += cevt-bcm1480.o
obj-$(CONFIG_CEVT_R4K_LIB) += cevt-r4k.o
diff --git a/arch/mips/kernel/syscall.c b/arch/mips/kernel/syscall.c
index 955c5f0..491e5be 100644
--- a/arch/mips/kernel/syscall.c
+++ b/arch/mips/kernel/syscall.c
@@ -77,7 +77,7 @@ unsigned long arch_get_unmapped_area(struct file *filp,
unsigned long addr,
int do_color_align;
unsigned long task_size;
- task_size = STACK_TOP;
+ task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE;
if (len > task_size)
return -ENOMEM;
diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c
new file mode 100644
index 0000000..a1f38a6
--- /dev/null
+++ b/arch/mips/kernel/vdso.c
@@ -0,0 +1,104 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2009 Cavium Networks
+ */
+
+
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/binfmts.h>
+#include <linux/elf.h>
+#include <linux/vmalloc.h>
+#include <linux/unistd.h>
+
+#include <asm/vdso.h>
+
+/*
+ * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
+ */
+#define __NR_O32_sigreturn 4119
+#define __NR_O32_rt_sigreturn 4193
+#define __NR_N32_rt_sigreturn 6211
+
+static struct page *vdso_page;
+
+static void __init install_trampoline(u32 *tramp, unsigned int sigreturn)
+{
+ tramp[0] = 0x24020000 + sigreturn; /* li v0, sigreturn */
+ tramp[1] = 0x0000000c; /* syscall */
+}
+
+static int __init init_vdso(void)
+{
+ struct mips_vdso *vdso;
+
+ vdso_page = alloc_page(GFP_KERNEL);
+ if (!vdso_page)
+ panic("Cannot allocate vdso");
+
+ vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL);
+ if (!vdso)
+ panic("Cannot map vdso");
+ clear_page(vdso);
+
+ install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn);
+#ifdef CONFIG_32BIT
+ install_trampoline(vdso->signal_trampoline, __NR_sigreturn);
+#else
+ install_trampoline(vdso->n32_rt_signal_trampoline,
+ __NR_N32_rt_sigreturn);
+ install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn);
+ install_trampoline(vdso->o32_rt_signal_trampoline,
+ __NR_O32_rt_sigreturn);
+#endif
+
+ vunmap(vdso);
+
+ pr_notice("init_vdso successfull\n");
+
+ return 0;
+}
+device_initcall(init_vdso);
+
+static unsigned long vdso_addr(unsigned long start)
+{
+ return STACK_TOP;
+}
+
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+ int ret;
+ unsigned long addr;
+ struct mm_struct *mm = current->mm;
+
+ down_write(&mm->mmap_sem);
+
+ addr = vdso_addr(mm->start_stack);
+
+ addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0);
+ if (IS_ERR_VALUE(addr)) {
+ ret = addr;
+ goto up_fail;
+ }
+
+ ret = install_special_mapping(mm, addr, PAGE_SIZE,
+ VM_READ|VM_EXEC|
+ VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC|
+ VM_ALWAYSDUMP,
+ &vdso_page);
+
+ if (ret)
+ goto up_fail;
+
+ mm->context.vdso = (void *)addr;
+
+up_fail:
+ up_write(&mm->mmap_sem);
+ return ret;
+}
--
1.6.0.6
|