Update of /cvsroot/linuxsh/linux/arch/sh/kernel/vsyscall In directory sc8-pr-cvs6.sourceforge.net:/tmp/cvs-serv25403/arch/sh/kernel/vsyscall Added Files: Makefile vsyscall-note.S vsyscall-sigreturn.S vsyscall-syscall.S vsyscall-trapa.S vsyscall.c vsyscall.lds.S Log Message: Initial configurable vsyscall page support, only used for the signal trampoline return code at the moment.. --- NEW FILE: Makefile --- obj-y += vsyscall.o vsyscall-syscall.o $(obj)/vsyscall-syscall.o: \ $(foreach F,trapa,$(obj)/vsyscall-$F.so) # Teach kbuild about targets targets += $(foreach F,trapa,vsyscall-$F.o vsyscall-$F.so) targets += vsyscall-note.o vsyscall.lds # The DSO images are built using a special linker script quiet_cmd_syscall = SYSCALL $@ cmd_syscall = $(CC) -nostdlib $(SYSCFLAGS_$(@F)) \ -Wl,-T,$(filter-out FORCE,$^) -o $@ export CPPFLAGS_vsyscall.lds += -P -C -Ush vsyscall-flags = -shared -s -Wl,-soname=linux-gate.so.1 \ $(call ld-option, -Wl$(comma)--hash-style=sysv) SYSCFLAGS_vsyscall-trapa.so = $(vsyscall-flags) $(obj)/vsyscall-trapa.so: \ $(obj)/vsyscall-%.so: $(src)/vsyscall.lds $(obj)/vsyscall-%.o FORCE $(call if_changed,syscall) # We also create a special relocatable object that should mirror the symbol # table and layout of the linked DSO. With ld -R we can then refer to # these symbols in the kernel code rather than hand-coded addresses. extra-y += vsyscall-syms.o $(obj)/built-in.o: $(obj)/vsyscall-syms.o $(obj)/built-in.o: ld_flags += -R $(obj)/vsyscall-syms.o SYSCFLAGS_vsyscall-syms.o = -r $(obj)/vsyscall-syms.o: $(src)/vsyscall.lds \ $(obj)/vsyscall-trapa.o $(obj)/vsyscall-note.o FORCE $(call if_changed,syscall) --- NEW FILE: vsyscall-note.S --- /* * This supplies .note.* sections to go into the PT_NOTE inside the vDSO text. * Here we can supply some information useful to userland. */ #include <linux/uts.h> #include <linux/version.h> #define ASM_ELF_NOTE_BEGIN(name, flags, vendor, type) \ .section name, flags; \ .balign 4; \ .long 1f - 0f; /* name length */ \ .long 3f - 2f; /* data length */ \ .long type; /* note type */ \ 0: .asciz vendor; /* vendor name */ \ 1: .balign 4; \ 2: #define ASM_ELF_NOTE_END \ 3: .balign 4; /* pad out section */ \ .previous ASM_ELF_NOTE_BEGIN(".note.kernel-version", "a", UTS_SYSNAME, 0) .long LINUX_VERSION_CODE ASM_ELF_NOTE_END --- NEW FILE: vsyscall-sigreturn.S --- #include <asm/unistd.h> .text .balign 32 .globl __kernel_sigreturn .type __kernel_sigreturn,@function __kernel_sigreturn: .LSTART_sigreturn: mov.w 1f, r3 trapa #0x10 or r0, r0 or r0, r0 or r0, r0 or r0, r0 or r0, r0 1: .short __NR_sigreturn .LEND_sigreturn: .size __kernel_sigreturn,.-.LSTART_sigreturn .balign 32 .globl __kernel_rt_sigreturn .type __kernel_rt_sigreturn,@function __kernel_rt_sigreturn: .LSTART_rt_sigreturn: mov.w 1f, r3 trapa #0x10 or r0, r0 or r0, r0 or r0, r0 or r0, r0 or r0, r0 1: .short __NR_rt_sigreturn .LEND_rt_sigreturn: .size __kernel_rt_sigreturn,.-.LSTART_rt_sigreturn .section .eh_frame,"a",@progbits .previous --- NEW FILE: vsyscall-syscall.S --- #include <linux/init.h> __INITDATA .globl vsyscall_trapa_start, vsyscall_trapa_end vsyscall_trapa_start: .incbin "arch/sh/kernel/vsyscall-trapa.so" vsyscall_trapa_end: __FINIT --- NEW FILE: vsyscall-trapa.S --- .text .globl __kernel_vsyscall .type __kernel_vsyscall,@function __kernel_vsyscall: .LSTART_vsyscall: /* XXX: We'll have to do something here once we opt to use the vDSO * page for something other than the signal trampoline.. as well as * fill out .eh_frame -- PFM. */ .LEND_vsyscall: .size __kernel_vsyscall,.-.LSTART_vsyscall .previous .section .eh_frame,"a",@progbits .LCIE: .ualong .LCIE_end - .LCIE_start .LCIE_start: .ualong 0 /* CIE ID */ .byte 0x1 /* Version number */ .string "zRS" /* NUL-terminated augmentation string */ .uleb128 0x1 /* Code alignment factor */ .sleb128 -4 /* Data alignment factor */ .byte 0x11 /* Return address register column */ /* Augmentation length and data (none) */ .byte 0xc /* DW_CFA_def_cfa */ .uleb128 0xf /* r15 */ .uleb128 0x0 /* offset 0 */ .align 2 .LCIE_end: .ualong .LFDE_end-.LFDE_start /* Length FDE */ .LFDE_start: .ualong .LCIE /* CIE pointer */ .ualong .LSTART_vsyscall-. /* start address */ .ualong .LEND_vsyscall-.LSTART_vsyscall .uleb128 0 .align 2 .LFDE_end: .previous /* Get the common code for the sigreturn entry points */ #include "vsyscall-sigreturn.S" --- NEW FILE: vsyscall.c --- /* * arch/sh/kernel/vsyscall.c * * Copyright (C) 2006 Paul Mundt * * vDSO randomization * Copyright(C) 2005-2006, Red Hat, Inc., Ingo Molnar * * 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. */ #include <linux/mm.h> #include <linux/slab.h> #include <linux/kernel.h> #include <linux/init.h> #include <linux/gfp.h> #include <linux/module.h> #include <linux/elf.h> /* * Should the kernel map a VDSO page into processes and pass its * address down to glibc upon exec()? */ unsigned int __read_mostly vdso_enabled = 1; EXPORT_SYMBOL_GPL(vdso_enabled); static int __init vdso_setup(char *s) { vdso_enabled = simple_strtoul(s, NULL, 0); return 1; } __setup("vdso=", vdso_setup); /* * These symbols are defined by vsyscall.o to mark the bounds * of the ELF DSO images included therein. */ extern const char vsyscall_trapa_start, vsyscall_trapa_end; static void *syscall_page; int __init vsyscall_init(void) { syscall_page = (void *)get_zeroed_page(GFP_ATOMIC); /* * XXX: Map this page to a fixmap entry if we get around * to adding the page to ELF core dumps */ memcpy(syscall_page, &vsyscall_trapa_start, &vsyscall_trapa_end - &vsyscall_trapa_start); return 0; } static struct page *syscall_vma_nopage(struct vm_area_struct *vma, unsigned long address, int *type) { unsigned long offset = address - vma->vm_start; struct page *page; if (address < vma->vm_start || address > vma->vm_end) return NOPAGE_SIGBUS; page = virt_to_page(syscall_page + offset); get_page(page); return page; } /* Prevent VMA merging */ static void syscall_vma_close(struct vm_area_struct *vma) { } static struct vm_operations_struct syscall_vm_ops = { .nopage = syscall_vma_nopage, .close = syscall_vma_close, }; /* Setup a VMA at program startup for the vsyscall page */ int arch_setup_additional_pages(struct linux_binprm *bprm, int executable_stack) { struct vm_area_struct *vma; struct mm_struct *mm = current->mm; unsigned long addr; int ret; down_write(&mm->mmap_sem); addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; } vma = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); if (!vma) { ret = -ENOMEM; goto up_fail; } vma->vm_start = addr; vma->vm_end = addr + PAGE_SIZE; /* MAYWRITE to allow gdb to COW and set breakpoints */ vma->vm_flags = VM_READ|VM_EXEC|VM_MAYREAD|VM_MAYEXEC|VM_MAYWRITE; vma->vm_flags |= mm->def_flags; vma->vm_page_prot = protection_map[vma->vm_flags & 7]; vma->vm_ops = &syscall_vm_ops; vma->vm_mm = mm; ret = insert_vm_struct(mm, vma); if (unlikely(ret)) { kmem_cache_free(vm_area_cachep, vma); goto up_fail; } current->mm->context.vdso = (void *)addr; mm->total_vm++; 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; } struct vm_area_struct *get_gate_vma(struct task_struct *task) { return NULL; } int in_gate_area(struct task_struct *task, unsigned long address) { return 0; } int in_gate_area_no_task(unsigned long address) { return 0; } --- NEW FILE: vsyscall.lds.S --- /* * 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> #ifdef CONFIG_CPU_LITTLE_ENDIAN OUTPUT_FORMAT("elf32-sh-linux", "elf32-sh-linux", "elf32-sh-linux") #else OUTPUT_FORMAT("elf32-shbig-linux", "elf32-shbig-linux", "elf32-shbig-linux") #endif OUTPUT_ARCH(sh) /* The ELF entry point can be used to set the AT_SYSINFO value. */ ENTRY(__kernel_vsyscall); SECTIONS { . = 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) } /* This linker script is used both with -r and with -shared. For the layouts to match, we need to skip more than enough space for the dynamic symbol table et al. If this amount is insufficient, ld -shared will barf. Just increase it here. */ . = 0x400; .text : { *(.text) } :text =0x90909090 .note : { *(.note.*) } :text :note .eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr .eh_frame : { KEEP (*(.eh_frame)) } :text .dynamic : { *(.dynamic) } :text :dynamic .useless : { *(.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 { global: __kernel_vsyscall; __kernel_sigreturn; __kernel_rt_sigreturn; local: *; }; } |