diff options
author | Jason Wright <jason@cvs.openbsd.org> | 2001-09-18 15:24:19 +0000 |
---|---|---|
committer | Jason Wright <jason@cvs.openbsd.org> | 2001-09-18 15:24:19 +0000 |
commit | 079286ffb014f102173a56f27e66b9330f28afd3 (patch) | |
tree | 3a8c69365c96a949d147ad74e8d3ecf93ee8e2c0 /distrib/common/elfrdsetroot.c | |
parent | c33d767ac74fbc64e451c6af233d439c63310995 (diff) |
copy the alpha/elfrdsetroot to common (for more general use: macppc, sparc64, etc)
Diffstat (limited to 'distrib/common/elfrdsetroot.c')
-rw-r--r-- | distrib/common/elfrdsetroot.c | 223 |
1 files changed, 223 insertions, 0 deletions
diff --git a/distrib/common/elfrdsetroot.c b/distrib/common/elfrdsetroot.c new file mode 100644 index 00000000000..dfa786720f5 --- /dev/null +++ b/distrib/common/elfrdsetroot.c @@ -0,0 +1,223 @@ +/* $OpenBSD: elfrdsetroot.c,v 1.1 2001/09/18 15:24:18 jason Exp $ */ +/* $NetBSD: rdsetroot.c,v 1.2 1995/10/13 16:38:39 gwr Exp $ */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * All rights reserved. + * + * ELF modifications Copyright (c) 1997 Per Fogelstrom. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Copy a ramdisk image into the space reserved for it. + * Kernel variables: rd_root_size, rd_root_image + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/mman.h> + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <nlist.h> + +#ifdef __alpha__ /* XXXXXXX */ +#define ELFSIZE 64 +#else +#define ELFSIZE 32 +#endif + +#include <sys/exec_elf.h> + +extern off_t lseek(); + +char *file; + +/* Virtual addresses of the symbols we frob. */ +long rd_root_image_va, rd_root_size_va; + +/* Offsets relative to start of data segment. */ +long rd_root_image_off, rd_root_size_off; + +/* value in the location at rd_root_size_off */ +off_t rd_root_size_val; + +/* pointers to pieces of mapped file */ +char *dataseg; + +/* parameters to mmap digged out from program header */ +off_t mmap_offs; +size_t mmap_size; + +int find_rd_root_image(char *, Elf_Ehdr *, Elf_Phdr *); + +int +main(argc,argv) + char **argv; +{ + int fd, n; + int found; + int *ip; + Elf_Ehdr eh; + Elf_Phdr *ph; + int phsize; + + if (argc < 2) { + printf("%s: missing file name\n", argv[0]); + exit(1); + } + file = argv[1]; + + fd = open(file, O_RDWR); + if (fd < 0) { + perror(file); + exit(1); + } + + n = read(fd, &eh, sizeof(eh)); + if (n < sizeof(eh)) { + printf("%s: reading header\n", file); + exit(1); + } + + if (!IS_ELF(eh)) { + printf("%s: not elf\n", file); + exit(1); + } + + phsize = eh.e_phnum * sizeof(Elf_Phdr); + ph = (Elf_Phdr *)malloc(phsize); + lseek(fd, eh.e_phoff, 0); + if (read(fd, (char *)ph, phsize) != phsize) { + printf("%s: can't read phdr area\n", file); + exit(1); + } + found = 0; + for(n = 0; n < eh.e_phnum && !found; n++) { + if(ph[n].p_type == PT_LOAD) { + found = find_rd_root_image(file, &eh, &ph[n]); + } + } + if (!found) { + printf("%s: can't locate space for rd_root_image!", file); + exit(1); + } + + /* + * Map in the whole data segment. + * The file offset needs to be page aligned. + */ + dataseg = mmap(NULL, /* any address is ok */ + mmap_size, /* length */ + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, mmap_offs); + if (dataseg == MAP_FAILED) { + printf("%s: can not map data seg\n", file); + perror(file); + exit(1); + } + + /* + * Find value in the location: rd_root_size + */ + ip = (int*) (dataseg + rd_root_size_off); + rd_root_size_val = *ip; +#ifdef DEBUG + printf("rd_root_size val: 0x%08X (%d blocks)\n", + rd_root_size_val, (rd_root_size_val >> 9)); +#endif + + /* + * Copy the symbol table and string table. + */ +#ifdef DEBUG + printf("copying root image...\n"); +#endif + n = read(0, dataseg + rd_root_image_off, + rd_root_size_val); + if (n < 0) { + perror("read"); + exit(1); + } + + msync(dataseg, mmap_size, 0); + +#ifdef DEBUG + printf("...copied %d bytes\n", n); +#endif + close(fd); + exit(0); +} + + +/* + * Find locations of the symbols to patch. + */ +struct nlist wantsyms[] = { + { "_rd_root_size", 0 }, + { "_rd_root_image", 0 }, + { NULL, 0 }, +}; + +int +find_rd_root_image(file, eh, ph) + char *file; + Elf_Ehdr *eh; + Elf_Phdr *ph; +{ + unsigned long kernel_start; + unsigned long kernel_size; + + if (nlist(file, wantsyms)) { + printf("%s: no rd_root_image symbols?\n", file); + exit(1); + } + kernel_start = ph->p_paddr; + kernel_size = ph->p_filesz; + + rd_root_size_off = wantsyms[0].n_value - kernel_start; + rd_root_image_off = wantsyms[1].n_value - kernel_start; + +#ifdef DEBUG + printf("rd_root_size_off = 0x%x\n", rd_root_size_off); + printf("rd_root_image_off = 0x%x\n", rd_root_image_off); +#endif + + /* + * Sanity check locations of db_* symbols + */ + if (rd_root_image_off < 0 || rd_root_image_off >= kernel_size) { + return(0); + } + if (rd_root_size_off < 0 || rd_root_size_off >= kernel_size) { + printf("%s: rd_root_size not in data segment?\n", file); + return(0); + } + mmap_offs = ph->p_offset; + mmap_size = kernel_size; + return(1); +} |