Annotation of qemu/roms/SLOF/lib/libelf/elf.c, revision 1.1.1.1

1.1       root        1: /******************************************************************************
                      2:  * Copyright (c) 2004, 2008 IBM Corporation
                      3:  * All rights reserved.
                      4:  * This program and the accompanying materials
                      5:  * are made available under the terms of the BSD License
                      6:  * which accompanies this distribution, and is available at
                      7:  * http://www.opensource.org/licenses/bsd-license.php
                      8:  *
                      9:  * Contributors:
                     10:  *     IBM Corporation - initial implementation
                     11:  *****************************************************************************/
                     12: 
                     13: /* this is elf.fs rewritten in C */
                     14: 
                     15: #include <string.h>
                     16: #include <cpu.h>
                     17: #include <libelf.h>
                     18: 
                     19: struct ehdr {
                     20:        unsigned int ei_ident;
                     21:        unsigned char ei_class;
                     22:        unsigned char ei_data;
                     23:        unsigned char ei_version;
                     24:        unsigned char ei_pad[9];
                     25:        unsigned short e_type;
                     26:        unsigned short e_machine;
                     27:        unsigned int e_version;
                     28:        unsigned int e_entry;
                     29:        unsigned int e_phoff;
                     30:        unsigned int e_shoff;
                     31:        unsigned int e_flags;
                     32:        unsigned short e_ehsize;
                     33:        unsigned short e_phentsize;
                     34:        unsigned short e_phnum;
                     35:        unsigned short e_shentsize;
                     36:        unsigned short e_shnum;
                     37:        unsigned short e_shstrndx;
                     38: };
                     39: 
                     40: struct phdr {
                     41:        unsigned int p_type;
                     42:        unsigned int p_offset;
                     43:        unsigned int p_vaddr;
                     44:        unsigned int p_paddr;
                     45:        unsigned int p_filesz;
                     46:        unsigned int p_memsz;
                     47:        unsigned int p_flags;
                     48:        unsigned int p_align;
                     49: };
                     50: 
                     51: struct ehdr64 {
                     52:        unsigned int ei_ident;
                     53:        unsigned char ei_class;
                     54:        unsigned char ei_data;
                     55:        unsigned char ei_version;
                     56:        unsigned char ei_pad[9];
                     57:        unsigned short e_type;
                     58:        unsigned short e_machine;
                     59:        unsigned int e_version;
                     60:        unsigned long e_entry;
                     61:        unsigned long e_phoff;
                     62:        unsigned long e_shoff;
                     63:        unsigned int e_flags;
                     64:        unsigned short e_ehsize;
                     65:        unsigned short e_phentsize;
                     66:        unsigned short e_phnum;
                     67:        unsigned short e_shentsize;
                     68:        unsigned short e_shnum;
                     69:        unsigned short e_shstrndx;
                     70: };
                     71: 
                     72: struct phdr64 {
                     73:        unsigned int p_type;
                     74:        unsigned int p_flags;
                     75:        unsigned long p_offset;
                     76:        unsigned long p_vaddr;
                     77:        unsigned long p_paddr;
                     78:        unsigned long p_filesz;
                     79:        unsigned long p_memsz;
                     80:        unsigned long p_align;
                     81: };
                     82: 
                     83: #define VOID(x) (void *)((unsigned long)x)
                     84: 
                     85: static void
                     86: load_segment(unsigned long *file_addr, struct phdr *phdr)
                     87: {
                     88:        unsigned long src = phdr->p_offset + (unsigned long) file_addr;
                     89:        /* copy into storage */
                     90:        memmove(VOID(phdr->p_vaddr), VOID(src), phdr->p_filesz);
                     91: 
                     92:        /* clear bss */
                     93:        memset(VOID(phdr->p_vaddr + phdr->p_filesz), 0,
                     94:               phdr->p_memsz - phdr->p_filesz);
                     95: 
                     96:        if (phdr->p_memsz) {
                     97:                flush_cache(VOID(phdr->p_vaddr), phdr->p_memsz);
                     98:        }
                     99: }
                    100: 
                    101: static unsigned int
                    102: load_segments(unsigned long *file_addr)
                    103: {
                    104:        struct ehdr *ehdr = (struct ehdr *) file_addr;
                    105:        /* Calculate program header address */
                    106:        struct phdr *phdr =
                    107:            (struct phdr *) (((unsigned char *) file_addr) + ehdr->e_phoff);
                    108:        int i;
                    109:        /* loop e_phnum times */
                    110:        for (i = 0; i <= ehdr->e_phnum; i++) {
                    111:                /* PT_LOAD ? */
                    112:                if (phdr->p_type == 1) {
                    113:                        /* copy segment */
                    114:                        load_segment(file_addr, phdr);
                    115:                }
                    116:                /* step to next header */
                    117:                phdr =
                    118:                    (struct phdr *) (((unsigned char *) phdr) +
                    119:                                     ehdr->e_phentsize);
                    120:        }
                    121:        return ehdr->e_entry;
                    122: }
                    123: 
                    124: static void
                    125: load_segment64(unsigned long *file_addr, struct phdr64 *phdr64)
                    126: {
                    127:        unsigned long src = phdr64->p_offset + (unsigned long) file_addr;
                    128:        /* copy into storage */
                    129:        memmove(VOID(phdr64->p_vaddr), VOID(src), phdr64->p_filesz);
                    130: 
                    131:        /* clear bss */
                    132:        memset(VOID(phdr64->p_vaddr + phdr64->p_filesz), 0,
                    133:               phdr64->p_memsz - phdr64->p_filesz);
                    134: 
                    135:        if (phdr64->p_memsz) {
                    136:                flush_cache(VOID(phdr64->p_vaddr), phdr64->p_memsz);
                    137:        }
                    138: }
                    139: 
                    140: static unsigned long
                    141: load_segments64(unsigned long *file_addr)
                    142: {
                    143:        struct ehdr64 *ehdr64 = (struct ehdr64 *) file_addr;
                    144:        /* Calculate program header address */
                    145:        struct phdr64 *phdr64 =
                    146:            (struct phdr64 *) (((unsigned char *) file_addr) + ehdr64->e_phoff);
                    147:        int i;
                    148:        /* loop e_phnum times */
                    149:        for (i = 0; i <= ehdr64->e_phnum; i++) {
                    150:                /* PT_LOAD ? */
                    151:                if (phdr64->p_type == 1) {
                    152:                        /* copy segment */
                    153:                        load_segment64(file_addr, phdr64);
                    154:                }
                    155:                /* step to next header */
                    156:                phdr64 =
                    157:                    (struct phdr64 *) (((unsigned char *) phdr64) +
                    158:                                       ehdr64->e_phentsize);
                    159:        }
                    160:        return ehdr64->e_entry;
                    161: }
                    162: 
                    163: #if __BYTE_ORDER == __BIG_ENDIAN
                    164: #define cpu_to_be32(x)  (x)
                    165: #else
                    166: #define cpu_to_be32(x)  bswap_32(x)
                    167: #endif
                    168: 
                    169: /**
                    170:  * elf_check_file tests if the file at file_addr is
                    171:  * a correct endian, ELF PPC executable
                    172:  * @param file_addr  pointer to the start of the ELF file
                    173:  * @return           the class (1 for 32 bit, 2 for 64 bit)
                    174:  *                   -1 if it is not an ELF file
                    175:  *                   -2 if it has the wrong endianess
                    176:  *                   -3 if it is not an ELF executable
                    177:  *                   -4 if it is not for PPC
                    178:  */
                    179: static int
                    180: elf_check_file(unsigned long *file_addr)
                    181: {
                    182:        struct ehdr *ehdr = (struct ehdr *) file_addr;
                    183:        /* check if it is an ELF image at all */
                    184:        if (cpu_to_be32(ehdr->ei_ident) != 0x7f454c46)
                    185:                return -1;
                    186: 
                    187:        /* endian check */
                    188: #if __BYTE_ORDER == __BIG_ENDIAN
                    189:        if (ehdr->ei_data != 2)
                    190:                /* not a big endian image */
                    191: #else
                    192:        if (ehdr->ei_data == 2)
                    193:                /* not a little endian image */
                    194: #endif
                    195:                return -2;
                    196: 
                    197:        /* check if it is an ELF executable */
                    198:        if (ehdr->e_type != 2)
                    199:                return -3;
                    200: 
                    201:        /* check if it is a PPC ELF executable */
                    202:        if (ehdr->e_machine != 0x14 && ehdr->e_machine != 0x15)
                    203:                return -4;
                    204: 
                    205:        return ehdr->ei_class;
                    206: }
                    207: 
                    208: /**
                    209:  * load_elf_file tries to load the ELF file specified in file_addr
                    210:  *
                    211:  * it first checks if the file is a PPC ELF executable and then loads
                    212:  * the segments depending if it is a 64bit or 32 bit ELF file
                    213:  *
                    214:  * @param file_addr  pointer to the start of the elf file
                    215:  * @param entry      pointer where the ELF loader will store
                    216:  *                   the entry point
                    217:  * @return           1 for a 32 bit file
                    218:  *                   2 for a 64 bit file
                    219:  *                   anything else means an error during load
                    220:  */
                    221: int
                    222: load_elf_file(unsigned long *file_addr, unsigned long *entry)
                    223: {
                    224:        int type = elf_check_file(file_addr);
                    225:        switch (type) {
                    226:        case 1:
                    227:                *entry = load_segments(file_addr);
                    228:                break;
                    229:        case 2:
                    230:                *entry = load_segments64(file_addr);
                    231:                break;
                    232:        }
                    233:        return type;
                    234: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.