1/* 2 * Copyright 2010 Tilera Corporation. All Rights Reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation, version 2. 7 * 8 * This program is distributed in the hope that it will be useful, but 9 * WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or 11 * NON INFRINGEMENT. See the GNU General Public License for 12 * more details. 13 */ 14 15#include <linux/mm.h> 16#include <linux/pagemap.h> 17#include <linux/binfmts.h> 18#include <linux/compat.h> 19#include <linux/mman.h> 20#include <linux/elf.h> 21#include <asm/pgtable.h> 22#include <asm/pgalloc.h> 23#include <asm/sections.h> 24 25/* Notify a running simulator, if any, that an exec just occurred. */ 26static void sim_notify_exec(const char *binary_name) 27{ 28 unsigned char c; 29 do { 30 c = *binary_name++; 31 __insn_mtspr(SPR_SIM_CONTROL, 32 (SIM_CONTROL_OS_EXEC 33 | (c << _SIM_CONTROL_OPERATOR_BITS))); 34 35 } while (c); 36} 37 38static int notify_exec(void) 39{ 40 int retval = 0; /* failure */ 41 struct vm_area_struct *vma = current->mm->mmap; 42 while (vma) { 43 if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) 44 break; 45 vma = vma->vm_next; 46 } 47 if (vma) { 48 char *buf = (char *) __get_free_page(GFP_KERNEL); 49 if (buf) { 50 char *path = d_path(&vma->vm_file->f_path, 51 buf, PAGE_SIZE); 52 if (!IS_ERR(path)) { 53 sim_notify_exec(path); 54 retval = 1; 55 } 56 free_page((unsigned long)buf); 57 } 58 } 59 return retval; 60} 61 62/* Notify a running simulator, if any, that we loaded an interpreter. */ 63static void sim_notify_interp(unsigned long load_addr) 64{ 65 size_t i; 66 for (i = 0; i < sizeof(load_addr); i++) { 67 unsigned char c = load_addr >> (i * 8); 68 __insn_mtspr(SPR_SIM_CONTROL, 69 (SIM_CONTROL_OS_INTERP 70 | (c << _SIM_CONTROL_OPERATOR_BITS))); 71 } 72} 73 74 75/* Kernel address of page used to map read-only kernel data into userspace. */ 76static void *vdso_page; 77 78/* One-entry array used for install_special_mapping. */ 79static struct page *vdso_pages[1]; 80 81static int __init vdso_setup(void) 82{ 83 vdso_page = (void *)get_zeroed_page(GFP_ATOMIC); 84 memcpy(vdso_page, __rt_sigreturn, __rt_sigreturn_end - __rt_sigreturn); 85 vdso_pages[0] = virt_to_page(vdso_page); 86 return 0; 87} 88device_initcall(vdso_setup); 89 90const char *arch_vma_name(struct vm_area_struct *vma) 91{ 92 if (vma->vm_private_data == vdso_pages) 93 return "[vdso]"; 94#ifndef __tilegx__ 95 if (vma->vm_start == MEM_USER_INTRPT) 96 return "[intrpt]"; 97#endif 98 return NULL; 99} 100 101int arch_setup_additional_pages(struct linux_binprm *bprm, 102 int executable_stack) 103{ 104 struct mm_struct *mm = current->mm; 105 unsigned long vdso_base; 106 int retval = 0; 107 108 /* 109 * Notify the simulator that an exec just occurred. 110 * If we can't find the filename of the mapping, just use 111 * whatever was passed as the linux_binprm filename. 112 */ 113 if (!notify_exec()) 114 sim_notify_exec(bprm->filename); 115 116 down_write(&mm->mmap_sem); 117 118 /* 119 * MAYWRITE to allow gdb to COW and set breakpoints 120 * 121 * Make sure the vDSO gets into every core dump. Dumping its 122 * contents makes post-mortem fully interpretable later 123 * without matching up the same kernel and hardware config to 124 * see what PC values meant. 125 */ 126 vdso_base = VDSO_BASE; 127 retval = install_special_mapping(mm, vdso_base, PAGE_SIZE, 128 VM_READ|VM_EXEC| 129 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC| 130 VM_ALWAYSDUMP, 131 vdso_pages); 132 133#ifndef __tilegx__ 134 /* 135 * Set up a user-interrupt mapping here; the user can't 136 * create one themselves since it is above TASK_SIZE. 137 * We make it unwritable by default, so the model for adding 138 * interrupt vectors always involves an mprotect. 139 */ 140 if (!retval) { 141 unsigned long addr = MEM_USER_INTRPT; 142 addr = mmap_region(NULL, addr, INTRPT_SIZE, 143 MAP_FIXED|MAP_ANONYMOUS|MAP_PRIVATE, 144 VM_READ|VM_EXEC| 145 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 0); 146 if (addr > (unsigned long) -PAGE_SIZE) 147 retval = (int) addr; 148 } 149#endif 150 151 up_write(&mm->mmap_sem); 152 153 return retval; 154} 155 156 157void elf_plat_init(struct pt_regs *regs, unsigned long load_addr) 158{ 159 /* Zero all registers. */ 160 memset(regs, 0, sizeof(*regs)); 161 162 /* Report the interpreter's load address. */ 163 sim_notify_interp(load_addr); 164} 165