at v4.0 154 lines 3.8 kB view raw
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#include <asm/vdso.h> 25#include <arch/sim.h> 26 27/* Notify a running simulator, if any, that an exec just occurred. */ 28static void sim_notify_exec(const char *binary_name) 29{ 30 unsigned char c; 31 do { 32 c = *binary_name++; 33 __insn_mtspr(SPR_SIM_CONTROL, 34 (SIM_CONTROL_OS_EXEC 35 | (c << _SIM_CONTROL_OPERATOR_BITS))); 36 37 } while (c); 38} 39 40static int notify_exec(struct mm_struct *mm) 41{ 42 char *buf, *path; 43 struct vm_area_struct *vma; 44 45 if (!sim_is_simulator()) 46 return 1; 47 48 if (mm->exe_file == NULL) 49 return 0; 50 51 for (vma = current->mm->mmap; ; vma = vma->vm_next) { 52 if (vma == NULL) 53 return 0; 54 if (vma->vm_file == mm->exe_file) 55 break; 56 } 57 58 buf = (char *) __get_free_page(GFP_KERNEL); 59 if (buf == NULL) 60 return 0; 61 62 path = d_path(&mm->exe_file->f_path, buf, PAGE_SIZE); 63 if (IS_ERR(path)) { 64 free_page((unsigned long)buf); 65 return 0; 66 } 67 68 /* 69 * Notify simulator of an ET_DYN object so we know the load address. 70 * The somewhat cryptic overuse of SIM_CONTROL_DLOPEN allows us 71 * to be backward-compatible with older simulator releases. 72 */ 73 if (vma->vm_start == (ELF_ET_DYN_BASE & PAGE_MASK)) { 74 char buf[64]; 75 int i; 76 77 snprintf(buf, sizeof(buf), "0x%lx:@", vma->vm_start); 78 for (i = 0; ; ++i) { 79 char c = buf[i]; 80 __insn_mtspr(SPR_SIM_CONTROL, 81 (SIM_CONTROL_DLOPEN 82 | (c << _SIM_CONTROL_OPERATOR_BITS))); 83 if (c == '\0') 84 break; 85 } 86 } 87 88 sim_notify_exec(path); 89 free_page((unsigned long)buf); 90 return 1; 91} 92 93/* Notify a running simulator, if any, that we loaded an interpreter. */ 94static void sim_notify_interp(unsigned long load_addr) 95{ 96 size_t i; 97 for (i = 0; i < sizeof(load_addr); i++) { 98 unsigned char c = load_addr >> (i * 8); 99 __insn_mtspr(SPR_SIM_CONTROL, 100 (SIM_CONTROL_OS_INTERP 101 | (c << _SIM_CONTROL_OPERATOR_BITS))); 102 } 103} 104 105 106int arch_setup_additional_pages(struct linux_binprm *bprm, 107 int executable_stack) 108{ 109 struct mm_struct *mm = current->mm; 110 int retval = 0; 111 112 down_write(&mm->mmap_sem); 113 114 /* 115 * Notify the simulator that an exec just occurred. 116 * If we can't find the filename of the mapping, just use 117 * whatever was passed as the linux_binprm filename. 118 */ 119 if (!notify_exec(mm)) 120 sim_notify_exec(bprm->filename); 121 122 retval = setup_vdso_pages(); 123 124#ifndef __tilegx__ 125 /* 126 * Set up a user-interrupt mapping here; the user can't 127 * create one themselves since it is above TASK_SIZE. 128 * We make it unwritable by default, so the model for adding 129 * interrupt vectors always involves an mprotect. 130 */ 131 if (!retval) { 132 unsigned long addr = MEM_USER_INTRPT; 133 addr = mmap_region(NULL, addr, INTRPT_SIZE, 134 VM_READ|VM_EXEC| 135 VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC, 0); 136 if (addr > (unsigned long) -PAGE_SIZE) 137 retval = (int) addr; 138 } 139#endif 140 141 up_write(&mm->mmap_sem); 142 143 return retval; 144} 145 146 147void elf_plat_init(struct pt_regs *regs, unsigned long load_addr) 148{ 149 /* Zero all registers. */ 150 memset(regs, 0, sizeof(*regs)); 151 152 /* Report the interpreter's load address. */ 153 sim_notify_interp(load_addr); 154}