Skip to content

Commit

Permalink
MIPS: Preliminary VDSO
Browse files Browse the repository at this point in the history
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.  Note that emulation
of branch delay slots in the FPU emulator still requires 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>
To: linux-mips@linux-mips.org
Patchwork: http://patchwork.linux-mips.org/patch/975/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
  • Loading branch information
David Daney authored and Ralf Baechle committed Apr 12, 2010
1 parent 58b9e22 commit c52d0d3
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 6 deletions.
4 changes: 4 additions & 0 deletions arch/mips/include/asm/elf.h
Original file line number Diff line number Diff line change
Expand Up @@ -368,4 +368,8 @@ extern const char *__elf_platform;
#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 */
5 changes: 4 additions & 1 deletion arch/mips/include/asm/mmu.h
Original file line number Diff line number Diff line change
@@ -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 */
2 changes: 1 addition & 1 deletion arch/mips/include/asm/mmu_context.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,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)

Expand Down
11 changes: 9 additions & 2 deletions arch/mips/include/asm/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,19 @@ extern void (*cpu_wait)(void);

extern unsigned int vced_count, vcei_count;

/*
* A special page (the vdso) is mapped into all processes at the very
* top of the virtual memory space.
*/
#define SPECIAL_PAGES_SIZE PAGE_SIZE

#ifdef CONFIG_32BIT
/*
* User space process size: 2GB. This is hardcoded into a few places,
* 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_MASK) - SPECIAL_PAGES_SIZE)

/*
* This decides where the kernel will search for a free chunk of vm
Expand All @@ -59,7 +65,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_MASK) - SPECIAL_PAGES_SIZE)

/*
* This decides where the kernel will search for a free chunk of vm
Expand Down
29 changes: 29 additions & 0 deletions arch/mips/include/asm/vdso.h
Original file line number Diff line number Diff line change
@@ -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 */
2 changes: 1 addition & 1 deletion arch/mips/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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

ifdef CONFIG_FUNCTION_TRACER
CFLAGS_REMOVE_ftrace.o = -pg
Expand Down
6 changes: 5 additions & 1 deletion arch/mips/kernel/syscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,11 @@ unsigned long arch_get_unmapped_area(struct file *filp, unsigned long addr,
int do_color_align;
unsigned long task_size;

task_size = STACK_TOP;
#ifdef CONFIG_32BIT
task_size = TASK_SIZE;
#else /* Must be CONFIG_64BIT*/
task_size = test_thread_flag(TIF_32BIT_ADDR) ? TASK_SIZE32 : TASK_SIZE;
#endif

if (len > task_size)
return -ENOMEM;
Expand Down
112 changes: 112 additions & 0 deletions arch/mips/kernel/vdso.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/*
* 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, 2010 Cavium Networks, Inc.
*/


#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>
#include <asm/uasm.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)
{
uasm_i_addiu(&tramp, 2, 0, sigreturn); /* li v0, sigreturn */
uasm_i_syscall(&tramp, 0);
}

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;
}

const char *arch_vma_name(struct vm_area_struct *vma)
{
if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
return "[vdso]";
return NULL;
}

0 comments on commit c52d0d3

Please sign in to comment.