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