1/* 2 * linux/fs/binfmt_som.c 3 * 4 * These are the functions used to load SOM format executables as used 5 * by HP-UX. 6 * 7 * Copyright 1999 Matthew Wilcox <willy@bofh.ai> 8 * based on binfmt_elf which is 9 * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). 10 */ 11 12#include <linux/module.h> 13 14#include <linux/fs.h> 15#include <linux/stat.h> 16#include <linux/sched.h> 17#include <linux/mm.h> 18#include <linux/mman.h> 19#include <linux/errno.h> 20#include <linux/signal.h> 21#include <linux/binfmts.h> 22#include <linux/som.h> 23#include <linux/string.h> 24#include <linux/file.h> 25#include <linux/fcntl.h> 26#include <linux/ptrace.h> 27#include <linux/slab.h> 28#include <linux/shm.h> 29#include <linux/personality.h> 30#include <linux/init.h> 31 32#include <asm/a.out.h> 33#include <asm/uaccess.h> 34#include <asm/pgtable.h> 35 36 37#include <linux/elf.h> 38 39static int load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs); 40static int load_som_library(struct file *); 41 42/* 43 * If we don't support core dumping, then supply a NULL so we 44 * don't even try. 45 */ 46#define som_core_dump NULL 47 48#define SOM_PAGESTART(_v) ((_v) & ~(unsigned long)(SOM_PAGESIZE-1)) 49#define SOM_PAGEOFFSET(_v) ((_v) & (SOM_PAGESIZE-1)) 50#define SOM_PAGEALIGN(_v) (((_v) + SOM_PAGESIZE - 1) & ~(SOM_PAGESIZE - 1)) 51 52static struct linux_binfmt som_format = { 53 .module = THIS_MODULE, 54 .load_binary = load_som_binary, 55 .load_shlib = load_som_library, 56 .core_dump = som_core_dump, 57 .min_coredump = SOM_PAGESIZE 58}; 59 60/* 61 * create_som_tables() parses the env- and arg-strings in new user 62 * memory and creates the pointer tables from them, and puts their 63 * addresses on the "stack", returning the new stack pointer value. 64 */ 65static void create_som_tables(struct linux_binprm *bprm) 66{ 67 char **argv, **envp; 68 int argc = bprm->argc; 69 int envc = bprm->envc; 70 unsigned long p; 71 unsigned long *sp; 72 73 /* Word-align the stack pointer */ 74 sp = (unsigned long *)((bprm->p + 3) & ~3); 75 76 envp = (char **) sp; 77 sp += envc + 1; 78 argv = (char **) sp; 79 sp += argc + 1; 80 81 __put_user((unsigned long) envp,++sp); 82 __put_user((unsigned long) argv,++sp); 83 84 __put_user(argc, ++sp); 85 86 bprm->p = (unsigned long) sp; 87 88 p = current->mm->arg_start; 89 while (argc-- > 0) { 90 __put_user((char *)p,argv++); 91 p += strlen_user((char *)p); 92 } 93 __put_user(NULL, argv); 94 current->mm->arg_end = current->mm->env_start = p; 95 while (envc-- > 0) { 96 __put_user((char *)p,envp++); 97 p += strlen_user((char *)p); 98 } 99 __put_user(NULL, envp); 100 current->mm->env_end = p; 101} 102 103static int check_som_header(struct som_hdr *som_ex) 104{ 105 int *buf = (int *)som_ex; 106 int i, ck; 107 108 if (som_ex->system_id != SOM_SID_PARISC_1_0 && 109 som_ex->system_id != SOM_SID_PARISC_1_1 && 110 som_ex->system_id != SOM_SID_PARISC_2_0) 111 return -ENOEXEC; 112 113 if (som_ex->a_magic != SOM_EXEC_NONSHARE && 114 som_ex->a_magic != SOM_EXEC_SHARE && 115 som_ex->a_magic != SOM_EXEC_DEMAND) 116 return -ENOEXEC; 117 118 if (som_ex->version_id != SOM_ID_OLD && 119 som_ex->version_id != SOM_ID_NEW) 120 return -ENOEXEC; 121 122 ck = 0; 123 for (i=0; i<32; i++) 124 ck ^= buf[i]; 125 if (ck != 0) 126 return -ENOEXEC; 127 128 return 0; 129} 130 131static int map_som_binary(struct file *file, 132 const struct som_exec_auxhdr *hpuxhdr) 133{ 134 unsigned long code_start, code_size, data_start, data_size; 135 unsigned long bss_start, som_brk; 136 int retval; 137 int prot = PROT_READ | PROT_EXEC; 138 int flags = MAP_FIXED|MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; 139 140 mm_segment_t old_fs = get_fs(); 141 set_fs(get_ds()); 142 143 code_start = SOM_PAGESTART(hpuxhdr->exec_tmem); 144 code_size = SOM_PAGEALIGN(hpuxhdr->exec_tsize); 145 current->mm->start_code = code_start; 146 current->mm->end_code = code_start + code_size; 147 down_write(¤t->mm->mmap_sem); 148 retval = do_mmap(file, code_start, code_size, prot, 149 flags, SOM_PAGESTART(hpuxhdr->exec_tfile)); 150 up_write(¤t->mm->mmap_sem); 151 if (retval < 0 && retval > -1024) 152 goto out; 153 154 data_start = SOM_PAGESTART(hpuxhdr->exec_dmem); 155 data_size = SOM_PAGEALIGN(hpuxhdr->exec_dsize); 156 current->mm->start_data = data_start; 157 current->mm->end_data = bss_start = data_start + data_size; 158 down_write(¤t->mm->mmap_sem); 159 retval = do_mmap(file, data_start, data_size, 160 prot | PROT_WRITE, flags, 161 SOM_PAGESTART(hpuxhdr->exec_dfile)); 162 up_write(¤t->mm->mmap_sem); 163 if (retval < 0 && retval > -1024) 164 goto out; 165 166 som_brk = bss_start + SOM_PAGEALIGN(hpuxhdr->exec_bsize); 167 current->mm->start_brk = current->mm->brk = som_brk; 168 down_write(¤t->mm->mmap_sem); 169 retval = do_mmap(NULL, bss_start, som_brk - bss_start, 170 prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, 0); 171 up_write(¤t->mm->mmap_sem); 172 if (retval > 0 || retval < -1024) 173 retval = 0; 174out: 175 set_fs(old_fs); 176 return retval; 177} 178 179 180/* 181 * These are the functions used to load SOM executables and shared 182 * libraries. There is no binary dependent code anywhere else. 183 */ 184 185static int 186load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) 187{ 188 int som_exec_fileno; 189 int retval; 190 unsigned int size; 191 unsigned long som_entry; 192 struct som_hdr *som_ex; 193 struct som_exec_auxhdr *hpuxhdr; 194 struct files_struct *files; 195 196 /* Get the exec-header */ 197 som_ex = (struct som_hdr *) bprm->buf; 198 199 retval = check_som_header(som_ex); 200 if (retval != 0) 201 goto out; 202 203 /* Now read in the auxiliary header information */ 204 205 retval = -ENOMEM; 206 size = som_ex->aux_header_size; 207 if (size > SOM_PAGESIZE) 208 goto out; 209 hpuxhdr = kmalloc(size, GFP_KERNEL); 210 if (!hpuxhdr) 211 goto out; 212 213 retval = kernel_read(bprm->file, som_ex->aux_header_location, 214 (char *) hpuxhdr, size); 215 if (retval != size) { 216 if (retval >= 0) 217 retval = -EIO; 218 goto out_free; 219 } 220 221 files = current->files; /* Refcounted so ok */ 222 retval = unshare_files(); 223 if (retval < 0) 224 goto out_free; 225 if (files == current->files) { 226 put_files_struct(files); 227 files = NULL; 228 } 229 230 retval = get_unused_fd(); 231 if (retval < 0) 232 goto out_free; 233 get_file(bprm->file); 234 fd_install(som_exec_fileno = retval, bprm->file); 235 236 /* Flush all traces of the currently running executable */ 237 retval = flush_old_exec(bprm); 238 if (retval) 239 goto out_free; 240 241 /* OK, This is the point of no return */ 242 current->flags &= ~PF_FORKNOEXEC; 243 current->personality = PER_HPUX; 244 245 /* Set the task size for HP-UX processes such that 246 * the gateway page is outside the address space. 247 * This can be fixed later, but for now, this is much 248 * easier. 249 */ 250 251 current->thread.task_size = 0xc0000000; 252 253 /* Set map base to allow enough room for hp-ux heap growth */ 254 255 current->thread.map_base = 0x80000000; 256 257 retval = map_som_binary(bprm->file, hpuxhdr); 258 if (retval < 0) 259 goto out_free; 260 261 som_entry = hpuxhdr->exec_entry; 262 kfree(hpuxhdr); 263 264 set_binfmt(&som_format); 265 compute_creds(bprm); 266 setup_arg_pages(bprm, STACK_TOP, EXSTACK_DEFAULT); 267 268 create_som_tables(bprm); 269 270 current->mm->start_stack = bprm->p; 271 272 273 map_hpux_gateway_page(current,current->mm); 274 275 start_thread_som(regs, som_entry, bprm->p); 276 if (current->ptrace & PT_PTRACED) 277 send_sig(SIGTRAP, current, 0); 278 return 0; 279 280 /* error cleanup */ 281out_free: 282 kfree(hpuxhdr); 283out: 284 return retval; 285} 286 287static int load_som_library(struct file *f) 288{ 289/* No lib support in SOM yet. gizza chance.. */ 290 return -ENOEXEC; 291} 292 /* Install the SOM loader. 293 * N.B. We *rely* on the table being the right size with the 294 * right number of free slots... 295 */ 296 297static int __init init_som_binfmt(void) 298{ 299 return register_binfmt(&som_format); 300} 301 302static void __exit exit_som_binfmt(void) 303{ 304 /* Remove the SOM loader. */ 305 unregister_binfmt(&som_format); 306} 307 308core_initcall(init_som_binfmt); 309module_exit(exit_som_binfmt); 310