Franck Bui-Huu wrote: > > I started to add vdso support for MIPS a couple months ago, but > it's in a very early stage and I unfortunately haven't time to finish > it. I can send it to you if you want. > Here it is. As I said it far from complete but it might help. Franck --- 8< --- diff --git a/arch/mips/kernel/Makefile b/arch/mips/kernel/Makefile index 2fd96d9..01d700c 100644 --- a/arch/mips/kernel/Makefile +++ b/arch/mips/kernel/Makefile @@ -6,11 +6,13 @@ 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 semaphore.o setup.o signal.o syscall.o \ - time.o topology.o traps.o unaligned.o + time.o topology.o traps.o unaligned.o vdso.o binfmt_irix-objs := irixelf.o irixinv.o irixioctl.o irixsig.o \ irix5sys.o sysirix.o +obj-$(CONFIG_32BIT) += vdso32/ + obj-$(CONFIG_STACKTRACE) += stacktrace.o obj-$(CONFIG_MODULES) += mips_ksyms.o module.o diff --git a/arch/mips/kernel/vdso.c b/arch/mips/kernel/vdso.c new file mode 100644 index 0000000..281b7ce --- /dev/null +++ b/arch/mips/kernel/vdso.c @@ -0,0 +1,52 @@ +#include <linux/init.h> + +typedef struct { + unsigned long id; + unsigned long vdso_base; +} mm_context_t; + + +static int vdso_enabled __read_mostly = 1; + +static int __init vdso_setup(char *s) +{ + vdso_enabled = simple_strtol(s, NULL, 0); + return 1; +} +__setup("vdso=", vdso_setup); + + +int arch_setup_additional_pages(struct linux_binprm *bprm, int exec_stack) +{ + struct mm_struct *mm = current->mm; + unsigned long vdso_pages; + unsigned long vdso_base; + int rv; + + if (!vdso_enabled) + return 0; + + down_write(&mm->mmap_sem); + + rv = get_unmapped_area(NULL, vdso_base, vdso_pages << PAGE_SHIFT, 0, 0); + if (IS_ERR_VALUE(rv)) + goto out; + vdso_base = rv; + + rv = install_special_mapping(mm, vdso_base, vdso_pages << PAGE_SHIFT, + VM_READ|VM_EXEC| + VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| + VM_ALWAYSDUMP, + vdso_pagelist); + if (rv) + goto out; +out: + up_write(&mm->mmap_sem); + return rv; +} + +static int __init vdso_init(void) +{ + return 0; +} +arch_initcall(vdso_init); diff --git a/arch/mips/kernel/vdso32/.gitignore b/arch/mips/kernel/vdso32/.gitignore new file mode 100644 index 0000000..e45fba9 --- /dev/null +++ b/arch/mips/kernel/vdso32/.gitignore @@ -0,0 +1 @@ +vdso32.lds diff --git a/arch/mips/kernel/vdso32/Makefile b/arch/mips/kernel/vdso32/Makefile new file mode 100644 index 0000000..b1ea645 --- /dev/null +++ b/arch/mips/kernel/vdso32/Makefile @@ -0,0 +1,35 @@ +# List of files in the vdso +obj-vdso32 = sigtramp.o + +# Build rules +targets := $(obj-vdso32) vdso32.so +obj-vdso32 := $(addprefix $(obj)/, $(obj-vdso32)) + + +EXTRA_CFLAGS := -shared -s -fno-common -fno-builtin +EXTRA_CFLAGS += -nostdlib -Wl,-soname=linux-vdso32.so.1 +EXTRA_CFLAGS += $(call ld-option, -Wl$(comma)--hash-style=sysv) + +EXTRA_AFLAGS := -D__VDSO32__ -s + +obj-y += vdso32.o +extra-y += vdso32.lds +CPPFLAGS_vdso32.lds += -P -C -U$(ARCH) + +# kbuild does not track this dependency due to usage of .incbin +$(obj)/vdso32.o : $(obj)/vdso32.so + +# link rule for the .so file, .lds has to be first +$(obj)/vdso32.so: $(src)/vdso32.lds $(obj-vdso32) + $(call if_changed,vdso32ld) + +# assembly rules for the .S files +$(obj-vdso32): %.o: %.S + $(call if_changed_dep,vdso32as) + +# actual build commands +quiet_cmd_vdso32ld = VDSO32_LD $@ + cmd_vdso32ld = $(CC) $(c_flags) -Wl,-T $^ -o $@ +quiet_cmd_vdso32as = VDSO32_AS $@ + cmd_vdso32as = $(CC) $(a_flags) -c -o $@ $< + diff --git a/arch/mips/kernel/vdso32/sigtramp.S b/arch/mips/kernel/vdso32/sigtramp.S new file mode 100644 index 0000000..4f83203 --- /dev/null +++ b/arch/mips/kernel/vdso32/sigtramp.S @@ -0,0 +1,13 @@ +#include <asm/asm.h> +#include <asm/regdef.h> +#include <asm/unistd.h> + +LEAF(__kernel_sigtramp_32) + li v0, __NR_sigreturn + syscall +END(__kernel_sigtramp_32) + +LEAF(__kernel_sigtramp_rt32) + li v0, __NR_rt_sigreturn + syscall +END(__kernel_sigtramp_rt32) diff --git a/arch/mips/kernel/vdso32/vdso32.S b/arch/mips/kernel/vdso32/vdso32.S new file mode 100644 index 0000000..9548930 --- /dev/null +++ b/arch/mips/kernel/vdso32/vdso32.S @@ -0,0 +1,11 @@ +#include <linux/init.h> + +__INITDATA + + .globl vdso32_start + .globl vdso32_end +vdso32_start: + .incbin "arch/mips/kernel/vdso32/vdso32.so" +vdso32_end: + +__FINIT diff --git a/arch/mips/kernel/vdso32/vdso32.lds.S b/arch/mips/kernel/vdso32/vdso32.lds.S new file mode 100644 index 0000000..250a03d --- /dev/null +++ b/arch/mips/kernel/vdso32/vdso32.lds.S @@ -0,0 +1,73 @@ +/* + * Linker script for vsyscall DSO. The vsyscall page is an ELF shared + * object prelinked to its virtual address, and with only one read-only + * segment (that fits in one page). This script controls its layout. + */ +#include <asm/asm-offsets.h> + +/* Default link addresses for the vDSOs */ +#define VDSO32_LBASE 0x100000 +#define VDSO64_LBASE 0x100000 + +/* Default map addresses */ +#define VDSO32_MBASE VDSO32_LBASE +#define VDSO64_MBASE VDSO64_LBASE + +OUTPUT_ARCH(mips) +ENTRY(__kernel_sigtramp_32); + +SECTIONS +{ + . = VDSO32_LBASE + SIZEOF_HEADERS; + + .hash : { *(.hash) } :text + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + + . = ALIGN(16); + + .text : { *(.text) } :text + .note : { *(.note.*) } :text :note + .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr + .eh_frame : { KEEP (*(.eh_frame)) } :text + + .dynamic : { *(.dynamic) } :text :dynamic + .got : { *(.got) } + .plt : { *(.plt) } + + /DISCARD/ : { + *(.got.plt) *(.got) + *(.data .data.* .gnu.linkonce.d.*) + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + } :text +} + +/* + * We must supply the ELF program headers explicitly to get just one + * PT_LOAD segment, and set the flags explicitly to make segments read-only. + */ +PHDRS +{ + text PT_LOAD FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */ + dynamic PT_DYNAMIC FLAGS(4); /* PF_R */ + note PT_NOTE FLAGS(4); /* PF_R */ + eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */ +} + +/* + * This controls what symbols we export from the DSO. + */ +VERSION +{ + LINUX_2.6.24 { + global: + __kernel_sigtramp_32; + __kernel_sigtramp_rt32; + local: *; + }; +}