diff options
| author | Matthew Wilcox <willy@debian.org> | 2002-11-03 00:21:26 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@penguin.transmeta.com> | 2002-11-03 00:21:26 -0800 |
| commit | 6d92ffb3c8a71204d1a4b8ea8d77cdfa022d5927 (patch) | |
| tree | a7935a4ba6b9f7c268d785a98bbcf1c7ba70a60c | |
| parent | 136e336b78507b5f43dcfce7b989162e574e201c (diff) | |
[PATCH] binfmt_som
SOM is the file format used for HPUX binaries.
| -rw-r--r-- | fs/Makefile | 1 | ||||
| -rw-r--r-- | fs/binfmt_som.c | 329 | ||||
| -rw-r--r-- | include/linux/som.h | 154 |
3 files changed, 484 insertions, 0 deletions
diff --git a/fs/Makefile b/fs/Makefile index ff4413cc812f..fd711af1104d 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -29,6 +29,7 @@ obj-$(CONFIG_BINFMT_MISC) += binfmt_misc.o obj-y += binfmt_script.o obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o +obj-$(CONFIG_BINFMT_SOM) += binfmt_som.o obj-$(CONFIG_QUOTA) += dquot.o obj-$(CONFIG_QFMT_V1) += quota_v1.o diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c new file mode 100644 index 000000000000..b9ea2556e5b0 --- /dev/null +++ b/fs/binfmt_som.c @@ -0,0 +1,329 @@ +/* + * linux/fs/binfmt_som.c + * + * These are the functions used to load SOM format executables as used + * by HP-UX. + * + * Copyright 1999 Matthew Wilcox <willy@bofh.ai> + * based on binfmt_elf which is + * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com). + */ + +#include <linux/module.h> + +#include <linux/fs.h> +#include <linux/stat.h> +#include <linux/sched.h> +#include <linux/mm.h> +#include <linux/mman.h> +#include <linux/errno.h> +#include <linux/signal.h> +#include <linux/binfmts.h> +#include <linux/som.h> +#include <linux/string.h> +#include <linux/file.h> +#include <linux/fcntl.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/shm.h> +#include <linux/personality.h> +#include <linux/init.h> + +#include <asm/uaccess.h> +#include <asm/pgtable.h> + +#include <linux/config.h> + +#include <linux/elf.h> + +static int load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs); +static int load_som_library(struct file *); + +/* + * If we don't support core dumping, then supply a NULL so we + * don't even try. + */ +#if 0 +static int som_core_dump(long signr, struct pt_regs * regs); +#else +#define som_core_dump NULL +#endif + +#define SOM_PAGESTART(_v) ((_v) & ~(unsigned long)(SOM_PAGESIZE-1)) +#define SOM_PAGEOFFSET(_v) ((_v) & (SOM_PAGESIZE-1)) +#define SOM_PAGEALIGN(_v) (((_v) + SOM_PAGESIZE - 1) & ~(SOM_PAGESIZE - 1)) + +static struct linux_binfmt som_format = { + NULL, THIS_MODULE, load_som_binary, load_som_library, som_core_dump, SOM_PAGESIZE +}; + +/* + * create_som_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +static void create_som_tables(struct linux_binprm *bprm) +{ + char **argv, **envp; + int argc = bprm->argc; + int envc = bprm->envc; + unsigned long p; + unsigned long *sp; + + /* Word-align the stack pointer */ + sp = (unsigned long *)((bprm->p + 3) & ~3); + + envp = (char **) sp; + sp += envc + 1; + argv = (char **) sp; + sp += argc + 1; + + __put_user((unsigned long) envp,++sp); + __put_user((unsigned long) argv,++sp); + + __put_user(argc, ++sp); + + bprm->p = (unsigned long) sp; + + p = current->mm->arg_start; + while (argc-- > 0) { + __put_user((char *)p,argv++); + p += strlen_user((char *)p); + } + __put_user(NULL, argv); + current->mm->arg_end = current->mm->env_start = p; + while (envc-- > 0) { + __put_user((char *)p,envp++); + p += strlen_user((char *)p); + } + __put_user(NULL, envp); + current->mm->env_end = p; +} + +static int check_som_header(struct som_hdr *som_ex) +{ + int *buf = (int *)som_ex; + int i, ck; + + if (som_ex->system_id != SOM_SID_PARISC_1_0 && + som_ex->system_id != SOM_SID_PARISC_1_1 && + som_ex->system_id != SOM_SID_PARISC_2_0) + return -ENOEXEC; + + if (som_ex->a_magic != SOM_EXEC_NONSHARE && + som_ex->a_magic != SOM_EXEC_SHARE && + som_ex->a_magic != SOM_EXEC_DEMAND) + return -ENOEXEC; + + if (som_ex->version_id != SOM_ID_OLD && + som_ex->version_id != SOM_ID_NEW) + return -ENOEXEC; + + ck = 0; + for (i=0; i<32; i++) + ck ^= buf[i]; + if (ck != 0) + return -ENOEXEC; + + return 0; +} + +static int map_som_binary(struct file *file, + const struct som_exec_auxhdr *hpuxhdr) +{ + unsigned long code_start, code_size, data_start, data_size; + unsigned long bss_start, som_brk; + int retval; + int prot = PROT_READ | PROT_EXEC; + int flags = MAP_FIXED|MAP_PRIVATE|MAP_DENYWRITE|MAP_EXECUTABLE; + + mm_segment_t old_fs = get_fs(); + set_fs(get_ds()); + + code_start = SOM_PAGESTART(hpuxhdr->exec_tmem); + code_size = SOM_PAGEALIGN(hpuxhdr->exec_tsize); + current->mm->start_code = code_start; + current->mm->end_code = code_start + code_size; + down_write(¤t->mm->mmap_sem); + retval = do_mmap(file, code_start, code_size, prot, + flags, SOM_PAGESTART(hpuxhdr->exec_tfile)); + up_write(¤t->mm->mmap_sem); + if (retval < 0 && retval > -1024) + goto out; + + data_start = SOM_PAGESTART(hpuxhdr->exec_dmem); + data_size = SOM_PAGEALIGN(hpuxhdr->exec_dsize); + current->mm->start_data = data_start; + current->mm->end_data = bss_start = data_start + data_size; + down_write(¤t->mm->mmap_sem); + retval = do_mmap(file, data_start, data_size, + prot | PROT_WRITE, flags, + SOM_PAGESTART(hpuxhdr->exec_dfile)); + up_write(¤t->mm->mmap_sem); + if (retval < 0 && retval > -1024) + goto out; + + som_brk = bss_start + SOM_PAGEALIGN(hpuxhdr->exec_bsize); + current->mm->start_brk = current->mm->brk = som_brk; + down_write(¤t->mm->mmap_sem); + retval = do_mmap(NULL, bss_start, som_brk - bss_start, + prot | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, 0); + up_write(¤t->mm->mmap_sem); + if (retval > 0 || retval < -1024) + retval = 0; +out: + set_fs(old_fs); + return retval; +} + + +/* + * These are the functions used to load SOM executables and shared + * libraries. There is no binary dependent code anywhere else. + */ + +static inline int +do_load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + int som_exec_fileno; + int retval; + unsigned int size; + unsigned long som_entry; + struct som_hdr *som_ex; + struct som_exec_auxhdr *hpuxhdr; + + /* Get the exec-header */ + som_ex = (struct som_hdr *) bprm->buf; + + retval = check_som_header(som_ex); + if (retval != 0) + goto out; + + /* Now read in the auxiliary header information */ + + retval = -ENOMEM; + size = som_ex->aux_header_size; + if (size > SOM_PAGESIZE) + goto out; + hpuxhdr = (struct som_exec_auxhdr *) kmalloc(size, GFP_KERNEL); + if (!hpuxhdr) + goto out; + + retval = kernel_read(bprm->file, som_ex->aux_header_location, + (char *) hpuxhdr, size); + if (retval < 0) + goto out_free; + + retval = get_unused_fd(); + if (retval < 0) + goto out_free; + get_file(bprm->file); + fd_install(som_exec_fileno = retval, bprm->file); + + /* Flush all traces of the currently running executable */ + retval = flush_old_exec(bprm); + if (retval) + goto out_free; + + /* OK, This is the point of no return */ + current->flags &= ~PF_FORKNOEXEC; + current->personality = PER_HPUX; + + /* Set the task size for HP-UX processes such that + * the gateway page is outside the address space. + * This can be fixed later, but for now, this is much + * easier. + */ + + current->thread.task_size = 0xc0000000; + + /* Set map base to allow enough room for hp-ux heap growth */ + + current->thread.map_base = 0x80000000; + + retval = map_som_binary(bprm->file, hpuxhdr); + if (retval < 0) + goto out_free; + + som_entry = hpuxhdr->exec_entry; + kfree(hpuxhdr); + + set_binfmt(&som_format); + compute_creds(bprm); + setup_arg_pages(bprm); + + create_som_tables(bprm); + + current->mm->start_stack = bprm->p; + current->mm->rss = 0; + +#if 0 + printk("(start_brk) %08lx\n" , (unsigned long) current->mm->start_brk); + printk("(end_code) %08lx\n" , (unsigned long) current->mm->end_code); + printk("(start_code) %08lx\n" , (unsigned long) current->mm->start_code); + printk("(end_data) %08lx\n" , (unsigned long) current->mm->end_data); + printk("(start_stack) %08lx\n" , (unsigned long) current->mm->start_stack); + printk("(brk) %08lx\n" , (unsigned long) current->mm->brk); +#endif + + map_hpux_gateway_page(current,current->mm); + + start_thread_som(regs, som_entry, bprm->p); + if (current->ptrace & PT_PTRACED) + send_sig(SIGTRAP, current, 0); + return 0; + + /* error cleanup */ +out_free: + kfree(hpuxhdr); +out: + return retval; +} + +static int +load_som_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_som_binary(bprm, regs); + MOD_DEC_USE_COUNT; + return retval; +} + +static inline int +do_load_som_library(struct file *f) +{ +/* No lib support in SOM yet. gizza chance.. */ + return -ENOEXEC; +} + +static int load_som_library(struct file *f) +{ + int retval; + + MOD_INC_USE_COUNT; + retval = do_load_som_library(f); + MOD_DEC_USE_COUNT; + return retval; +} + + /* Install the SOM loader. + * N.B. We *rely* on the table being the right size with the + * right number of free slots... + */ + +static int __init init_som_binfmt(void) +{ + return register_binfmt(&som_format); +} + +static void __exit exit_som_binfmt(void) +{ + /* Remove the SOM loader. */ + unregister_binfmt(&som_format); +} + +module_init(init_som_binfmt); +module_exit(exit_som_binfmt); + diff --git a/include/linux/som.h b/include/linux/som.h new file mode 100644 index 000000000000..166594e4e7be --- /dev/null +++ b/include/linux/som.h @@ -0,0 +1,154 @@ +#ifndef _LINUX_SOM_H +#define _LINUX_SOM_H + +/* File format definition for SOM executables / shared libraries */ + +/* we need struct timespec */ +#include <linux/time.h> + +#define SOM_PAGESIZE 4096 + +/* this is the SOM header */ +struct som_hdr { + short system_id; /* magic number - system */ + short a_magic; /* magic number - file type */ + unsigned int version_id; /* versiod ID: YYMMDDHH */ + struct timespec file_time; /* system clock */ + unsigned int entry_space; /* space for entry point */ + unsigned int entry_subspace; /* subspace for entry point */ + unsigned int entry_offset; /* offset of entry point */ + unsigned int aux_header_location; /* auxiliary header location */ + unsigned int aux_header_size; /* auxiliary header size */ + unsigned int som_length; /* length of entire SOM */ + unsigned int presumed_dp; /* compiler's DP value */ + unsigned int space_location; /* space dictionary location */ + unsigned int space_total; /* number of space entries */ + unsigned int subspace_location; /* subspace entries location */ + unsigned int subspace_total; /* number of subspace entries */ + unsigned int loader_fixup_location; /* MPE/iX loader fixup */ + unsigned int loader_fixup_total; /* number of fixup records */ + unsigned int space_strings_location; /* (sub)space names */ + unsigned int space_strings_size; /* size of strings area */ + unsigned int init_array_location; /* reserved */ + unsigned int init_array_total; /* reserved */ + unsigned int compiler_location; /* module dictionary */ + unsigned int compiler_total; /* number of modules */ + unsigned int symbol_location; /* symbol dictionary */ + unsigned int symbol_total; /* number of symbols */ + unsigned int fixup_request_location; /* fixup requests */ + unsigned int fixup_request_total; /* number of fixup requests */ + unsigned int symbol_strings_location;/* module & symbol names area */ + unsigned int symbol_strings_size; /* size of strings area */ + unsigned int unloadable_sp_location; /* unloadable spaces location */ + unsigned int unloadable_sp_size; /* size of data */ + unsigned int checksum; +}; + +/* values for system_id */ + +#define SOM_SID_PARISC_1_0 0x020b +#define SOM_SID_PARISC_1_1 0x0210 +#define SOM_SID_PARISC_2_0 0x0214 + +/* values for a_magic */ + +#define SOM_LIB_EXEC 0x0104 +#define SOM_RELOCATABLE 0x0106 +#define SOM_EXEC_NONSHARE 0x0107 +#define SOM_EXEC_SHARE 0x0108 +#define SOM_EXEC_DEMAND 0x010B +#define SOM_LIB_DYN 0x010D +#define SOM_LIB_SHARE 0x010E +#define SOM_LIB_RELOC 0x0619 + +/* values for version_id. Decimal not hex, yes. Grr. */ + +#define SOM_ID_OLD 85082112 +#define SOM_ID_NEW 87102412 + +struct aux_id { + unsigned int mandatory :1; /* the linker must understand this */ + unsigned int copy :1; /* Must be copied by the linker */ + unsigned int append :1; /* Must be merged by the linker */ + unsigned int ignore :1; /* Discard section if unknown */ + unsigned int reserved :12; + unsigned int type :16; /* Header type */ + unsigned int length; /* length of _following_ data */ +}; + +/* The Exec Auxiliary Header. Called The HP-UX Header within HP apparently. */ +struct som_exec_auxhdr { + struct aux_id som_auxhdr; + int exec_tsize; /* Text size in bytes */ + int exec_tmem; /* Address to load text at */ + int exec_tfile; /* Location of text in file */ + int exec_dsize; /* Data size in bytes */ + int exec_dmem; /* Address to load data at */ + int exec_dfile; /* Location of data in file */ + int exec_bsize; /* Uninitialised data (bss) */ + int exec_entry; /* Address to start executing */ + int exec_flags; /* loader flags */ + int exec_bfill; /* initialisation value for bss */ +}; + +/* Oh, the things people do to avoid casts. Shame it'll break with gcc's + * new aliasing rules really. + */ +union name_pt { + char * n_name; + unsigned int n_strx; +}; + +/* The Space Dictionary */ +struct space_dictionary_record { + union name_pt name; /* index to subspace name */ + unsigned int is_loadable :1; /* loadable */ + unsigned int is_defined :1; /* defined within file */ + unsigned int is_private :1; /* not sharable */ + unsigned int has_intermediate_code :1; /* contains intermediate code */ + unsigned int is_tspecific :1; /* thread specific */ + unsigned int reserved :11; /* for future expansion */ + unsigned int sort_key :8; /* for linker */ + unsigned int reserved2 :8; /* for future expansion */ + + int space_number; /* index */ + int subspace_index; /* index into subspace dict */ + unsigned int subspace_quantity; /* number of subspaces */ + int loader_fix_index; /* for loader */ + unsigned int loader_fix_quantity; /* for loader */ + int init_pointer_index; /* data pointer array index */ + unsigned int init_pointer_quantity; /* number of data pointers */ +}; + +/* The Subspace Dictionary */ +struct subspace_dictionary_record { + int space_index; + unsigned int access_control_bits :7; + unsigned int memory_resident :1; + unsigned int dup_common :1; + unsigned int is_common :1; + unsigned int quadrant :2; + unsigned int initially_frozen :1; + unsigned int is_first :1; + unsigned int code_only :1; + unsigned int sort_key :8; + unsigned int replicate_init :1; + unsigned int continuation :1; + unsigned int is_tspecific :1; + unsigned int is_comdat :1; + unsigned int reserved :4; + + int file_loc_init_value; + unsigned int initialization_length; + unsigned int subspace_start; + unsigned int subspace_length; + + unsigned int reserved2 :5; + unsigned int alignment :27; + + union name_pt name; + int fixup_request_index; + unsigned int fixup_request_quantity; +}; + +#endif /* _LINUX_SOM_H */ |
