Annotation of qemu/roms/openbios/libopenbios/elf_load.c, revision 1.1.1.1

1.1       root        1: /* ELF Boot loader
                      2:  * As we have seek, this implementation can be straightforward.
                      3:  * 2003-07 by SONE Takeshi
                      4:  */
                      5: 
                      6: #include "config.h"
                      7: #include "kernel/kernel.h"
                      8: #include "libc/diskio.h"
                      9: #include "arch/common/elf_boot.h"
                     10: #include "libopenbios/elf_load.h"
                     11: #include "libopenbios/sys_info.h"
                     12: #include "libopenbios/ipchecksum.h"
                     13: #include "libopenbios/bindings.h"
                     14: #include "libopenbios/ofmem.h"
                     15: #define printf printk
                     16: #define debug printk
                     17: 
                     18: #define DEBUG          0
                     19: 
                     20: #define MAX_HEADERS    0x20
                     21: #define BS             0x100   /* smallest step used when looking for the ELF header */
                     22: 
                     23: #ifdef CONFIG_PPC
                     24: extern void             flush_icache_range( char *start, char *stop );
                     25: #endif
                     26: 
                     27: /* FreeBSD and possibly others mask the high 8 bits */
                     28: #define addr_fixup(addr) ((addr) & 0x00ffffff)
                     29: 
                     30: static char *image_name, *image_version;
                     31: static int fd;
                     32: 
                     33: /* Note: avoid name collision with platforms which have their own version of calloc() */
                     34: static void *ob_calloc(size_t nmemb, size_t size)
                     35: {
                     36:     size_t alloc_size = nmemb * size;
                     37:     void *mem;
                     38: 
                     39:     if (alloc_size < nmemb || alloc_size < size) {
                     40:         printf("calloc overflow: %u, %u\n", nmemb, size);
                     41:         return NULL;
                     42:     }
                     43: 
                     44:     mem = malloc(alloc_size);
                     45:     memset(mem, 0, alloc_size);
                     46: 
                     47:     return mem;
                     48: }
                     49: 
                     50: static int check_mem_ranges(struct sys_info *info,
                     51:        Elf_phdr *phdr, int phnum)
                     52: {
                     53:     int i, j;
                     54:     unsigned long start, end;
                     55:     unsigned long prog_start, prog_end;
                     56:     struct memrange *mem;
                     57: 
                     58:     prog_start = virt_to_phys(&_start);
                     59:     prog_end = virt_to_phys(&_end);
                     60: 
                     61:     for (i = 0; i < phnum; i++) {
                     62:        if (phdr[i].p_type != PT_LOAD)
                     63:            continue;
                     64:        start = addr_fixup(phdr[i].p_paddr);
                     65:        end = start + phdr[i].p_memsz;
                     66:        if (start < prog_start && end > prog_start)
                     67:            goto conflict;
                     68:        if (start < prog_end && end > prog_end)
                     69:            goto conflict;
                     70:        mem=info->memrange;
                     71:        for (j = 0; j < info->n_memranges; j++) {
                     72:            if (mem[j].base <= start && mem[j].base + mem[j].size >= end)
                     73:                break;
                     74:        }
                     75:        if (j >= info->n_memranges)
                     76:            goto badseg;
                     77:     }
                     78:     return 1;
                     79: 
                     80: conflict:
                     81:     printf("%s occupies [%#lx-%#lx]\n", program_name, prog_start, prog_end);
                     82: 
                     83: badseg:
                     84:     printf("Segment %d [%#lx-%#lx] doesn't fit into memory\n", i, start, end-1);
                     85:     return 0;
                     86: }
                     87: 
                     88: static unsigned long process_image_notes(Elf_phdr *phdr, int phnum,
                     89:                                          unsigned short *sum_ptr,
                     90:                                          unsigned int offset)
                     91: {
                     92:     int i;
                     93:     char *buf = NULL;
                     94:     int retval = 0;
                     95:     unsigned long addr, end;
                     96:     Elf_Nhdr *nhdr;
                     97:     const char *name;
                     98:     void *desc;
                     99: 
                    100:     for (i = 0; i < phnum; i++) {
                    101:        if (phdr[i].p_type != PT_NOTE)
                    102:            continue;
                    103:        buf = malloc(phdr[i].p_filesz);
                    104:        seek_io(fd, offset + phdr[i].p_offset);
                    105:        if ((size_t)read_io(fd, buf, phdr[i].p_filesz) != phdr[i].p_filesz) {
                    106:            printf("Can't read note segment\n");
                    107:            goto out;
                    108:        }
                    109:        addr = (unsigned long) buf;
                    110:        end = addr + phdr[i].p_filesz;
                    111:        while (addr < end) {
                    112:            nhdr = (Elf_Nhdr *) addr;
                    113:            addr += sizeof(Elf_Nhdr);
                    114:            name = (const char *) addr;
                    115:            addr += (nhdr->n_namesz+3) & ~3;
                    116:            desc = (void *) addr;
                    117:            addr += (nhdr->n_descsz+3) & ~3;
                    118: 
                    119:            if (nhdr->n_namesz==sizeof(ELF_NOTE_BOOT)
                    120:                    && memcmp(name, ELF_NOTE_BOOT, sizeof(ELF_NOTE_BOOT))==0) {
                    121:                if (nhdr->n_type == EIN_PROGRAM_NAME) {
                    122:                    image_name = ob_calloc(1, nhdr->n_descsz + 1);
                    123:                    memcpy(image_name, desc, nhdr->n_descsz);
                    124:                }
                    125:                if (nhdr->n_type == EIN_PROGRAM_VERSION) {
                    126:                    image_version = ob_calloc(1, nhdr->n_descsz + 1);
                    127:                    memcpy(image_version, desc, nhdr->n_descsz);
                    128:                }
                    129:                if (nhdr->n_type == EIN_PROGRAM_CHECKSUM) {
                    130:                    *sum_ptr = *(unsigned short *) desc;
                    131:                    debug("Image checksum: %#04x\n", *sum_ptr);
                    132:                    /* Where in the file */
                    133:                    retval = phdr[i].p_offset
                    134:                        + (unsigned long) desc - (unsigned long) buf;
                    135:                }
                    136:            }
                    137:        }
                    138:     }
                    139: out:
                    140:     close_io(fd);
                    141:     if (buf)
                    142:        free(buf);
                    143:     return retval;
                    144: }
                    145: 
                    146: static int load_segments(Elf_phdr *phdr, int phnum,
                    147:                          unsigned long checksum_offset,
                    148:                          unsigned int offset, unsigned long *bytes)
                    149: {
                    150:     //unsigned int start_time, time;
                    151:     int i;
                    152: 
                    153:     *bytes = 0;
                    154:     // start_time = currticks();
                    155:     for (i = 0; i < phnum; i++) {
                    156:        if (phdr[i].p_type != PT_LOAD)
                    157:            continue;
                    158:        debug("segment %d addr:" FMT_elf " file:" FMT_elf " mem:" FMT_elf " ",
                    159:               i, addr_fixup(phdr[i].p_paddr), phdr[i].p_filesz, phdr[i].p_memsz);
                    160:        seek_io(fd, offset + phdr[i].p_offset);
                    161:        debug("loading... ");
                    162:        if ((size_t)read_io(fd, phys_to_virt(addr_fixup(phdr[i].p_paddr)), phdr[i].p_filesz)
                    163:                != phdr[i].p_filesz) {
                    164:            printf("Can't read program segment %d\n", i);
                    165:            return 0;
                    166:        }
                    167:        bytes += phdr[i].p_filesz;
                    168:        debug("clearing... ");
                    169:        memset(phys_to_virt(addr_fixup(phdr[i].p_paddr) + phdr[i].p_filesz), 0,
                    170:                phdr[i].p_memsz - phdr[i].p_filesz);
                    171:        if (phdr[i].p_offset <= checksum_offset
                    172:                && phdr[i].p_offset + phdr[i].p_filesz >= checksum_offset+2) {
                    173:            debug("clearing checksum... ");
                    174:            memset(phys_to_virt(addr_fixup(phdr[i].p_paddr) + checksum_offset
                    175:                        - phdr[i].p_offset), 0, 2);
                    176:        }
                    177:        debug("ok\n");
                    178: 
                    179:     }
                    180:     // time = currticks() - start_time;
                    181:     //debug("Loaded %lu bytes in %ums (%luKB/s)\n", bytes, time,
                    182:     //     time? bytes/time : 0);
                    183:     debug("Loaded %lu bytes \n", *bytes);
                    184: 
                    185:     return 1;
                    186: }
                    187: 
                    188: static int verify_image(Elf_ehdr *ehdr, Elf_phdr *phdr, int phnum,
                    189:        unsigned short image_sum)
                    190: {
                    191:     unsigned short sum, part_sum;
                    192:     unsigned long offset;
                    193:     int i;
                    194: 
                    195:     sum = 0;
                    196:     offset = 0;
                    197: 
                    198:     part_sum = ipchksum(ehdr, sizeof *ehdr);
                    199:     sum = add_ipchksums(offset, sum, part_sum);
                    200:     offset += sizeof *ehdr;
                    201: 
                    202:     part_sum = ipchksum(phdr, phnum * sizeof(*phdr));
                    203:     sum = add_ipchksums(offset, sum, part_sum);
                    204:     offset += phnum * sizeof(*phdr);
                    205: 
                    206:     for (i = 0; i < phnum; i++) {
                    207:        if (phdr[i].p_type != PT_LOAD)
                    208:            continue;
                    209:        part_sum = ipchksum(phys_to_virt(addr_fixup(phdr[i].p_paddr)), phdr[i].p_memsz);
                    210:        sum = add_ipchksums(offset, sum, part_sum);
                    211:        offset += phdr[i].p_memsz;
                    212:     }
                    213: 
                    214:     if (sum != image_sum) {
                    215:        printf("Verify FAILED (image:%#04x vs computed:%#04x)\n",
                    216:                image_sum, sum);
                    217:        return 0;
                    218:     }
                    219:     return 1;
                    220: }
                    221: 
                    222: static inline unsigned padded(unsigned s)
                    223: {
                    224:     return (s + 3) & ~3;
                    225: }
                    226: 
                    227: static Elf_Bhdr *add_boot_note(Elf_Bhdr *bhdr, const char *name,
                    228:        unsigned type, const char *desc, unsigned descsz)
                    229: {
                    230:     Elf_Nhdr nhdr;
                    231:     unsigned ent_size, new_size, pad;
                    232:     char *addr;
                    233: 
                    234:     if (!bhdr)
                    235:        return NULL;
                    236: 
                    237:     nhdr.n_namesz = name? strlen(name)+1 : 0;
                    238:     nhdr.n_descsz = descsz;
                    239:     nhdr.n_type = type;
                    240:     ent_size = sizeof(nhdr) + padded(nhdr.n_namesz) + padded(nhdr.n_descsz);
                    241:     if (bhdr->b_size + ent_size > 0xffff) {
                    242:        printf("Boot notes too big\n");
                    243:        free(bhdr);
                    244:        return NULL;
                    245:     }
                    246:     if (bhdr->b_size + ent_size > bhdr->b_checksum) {
                    247:        do {
                    248:            new_size = bhdr->b_checksum * 2;
                    249:        } while (new_size < bhdr->b_size + ent_size);
                    250:        if (new_size > 0xffff)
                    251:            new_size = 0xffff;
                    252:        debug("expanding boot note size to %u\n", new_size);
                    253: #ifdef HAVE_REALLOC
                    254:        bhdr = realloc(bhdr, new_size);
                    255:        bhdr->b_checksum = new_size;
                    256: #else
                    257:        printf("Boot notes too big\n");
                    258:        free(bhdr);
                    259:        return NULL;
                    260: #endif
                    261:     }
                    262: 
                    263:     addr = (char *) bhdr;
                    264:     addr += bhdr->b_size;
                    265:     memcpy(addr, &nhdr, sizeof(nhdr));
                    266:     addr += sizeof(nhdr);
                    267: 
                    268:     if (name && nhdr.n_namesz) {
                    269:         memcpy(addr, name, nhdr.n_namesz);
                    270:         addr += nhdr.n_namesz;
                    271:         pad = padded(nhdr.n_namesz) - nhdr.n_namesz;
                    272:         memset(addr, 0, pad);
                    273:         addr += pad;
                    274:     }
                    275: 
                    276:     memcpy(addr, desc, nhdr.n_descsz);
                    277:     addr += nhdr.n_descsz;
                    278:     pad = padded(nhdr.n_descsz) - nhdr.n_descsz;
                    279:     memset(addr, 0, pad);
                    280: 
                    281:     bhdr->b_size += ent_size;
                    282:     bhdr->b_records++;
                    283:     return bhdr;
                    284: }
                    285: 
                    286: static inline Elf_Bhdr *add_note_string(Elf_Bhdr *bhdr, const char *name,
                    287:        unsigned type, const char *desc)
                    288: {
                    289:     return add_boot_note(bhdr, name, type, desc, strlen(desc) + 1);
                    290: }
                    291: 
                    292: static Elf_Bhdr *build_boot_notes(struct sys_info *info, const char *cmdline)
                    293: {
                    294:     Elf_Bhdr *bhdr;
                    295: 
                    296:     bhdr = malloc(256);
                    297:     bhdr->b_signature = ELF_BHDR_MAGIC;
                    298:     bhdr->b_size = sizeof *bhdr;
                    299:     bhdr->b_checksum = 256; /* XXX cache the current buffer size here */
                    300:     bhdr->b_records = 0;
                    301: 
                    302:     if (info->firmware)
                    303:        bhdr = add_note_string(bhdr, NULL, EBN_FIRMWARE_TYPE, info->firmware);
                    304:     bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_NAME, program_name);
                    305:     bhdr = add_note_string(bhdr, NULL, EBN_BOOTLOADER_VERSION, program_version);
                    306:     if (cmdline)
                    307:        bhdr = add_note_string(bhdr, NULL, EBN_COMMAND_LINE, cmdline);
                    308:     if (!bhdr)
                    309:        return bhdr;
                    310:     bhdr->b_checksum = 0;
                    311:     bhdr->b_checksum = ipchksum(bhdr, bhdr->b_size);
                    312:     return bhdr;
                    313: }
                    314: 
                    315: int
                    316: is_elf(Elf_ehdr *ehdr)
                    317: {
                    318:     return (ehdr->e_ident[EI_MAG0] == ELFMAG0
                    319:         && ehdr->e_ident[EI_MAG1] == ELFMAG1
                    320:         && ehdr->e_ident[EI_MAG2] == ELFMAG2
                    321:         && ehdr->e_ident[EI_MAG3] == ELFMAG3
                    322:         && ehdr->e_ident[EI_CLASS] == ARCH_ELF_CLASS
                    323:         && ehdr->e_ident[EI_DATA] == ARCH_ELF_DATA
                    324:         && ehdr->e_ident[EI_VERSION] == EV_CURRENT
                    325:         && ehdr->e_type == ET_EXEC
                    326:         && ARCH_ELF_MACHINE_OK(ehdr->e_machine)
                    327:         && ehdr->e_version == EV_CURRENT
                    328:         && ehdr->e_phentsize == sizeof(Elf_phdr));
                    329: }
                    330: 
                    331: int
                    332: find_elf(Elf_ehdr *ehdr)
                    333: {
                    334:    int offset;
                    335: 
                    336:    for (offset = 0; offset < MAX_HEADERS * BS; offset += BS) {
                    337:         if ((size_t)read_io(fd, ehdr, sizeof ehdr) != sizeof ehdr) {
                    338:             debug("Can't read ELF header\n");
                    339:             return 0;
                    340:         }
                    341: 
                    342:         if (is_elf(ehdr)) {
                    343:             debug("Found ELF header at offset %d\n", offset);
                    344:            return offset;
                    345:         }
                    346: 
                    347:         seek_io(fd, offset);
                    348:     }
                    349: 
                    350:     debug("Not a bootable ELF image\n");
                    351:     return 0;
                    352: }
                    353: 
                    354: Elf_phdr *
                    355: elf_readhdrs(int offset, Elf_ehdr *ehdr)
                    356: {
                    357:     unsigned long phdr_size;
                    358:     Elf_phdr *phdr;
                    359: 
                    360:     phdr_size = ehdr->e_phnum * sizeof(Elf_phdr);
                    361:     phdr = malloc(phdr_size);
                    362:     seek_io(fd, offset + ehdr->e_phoff);
                    363:     if ((size_t)read_io(fd, phdr, phdr_size) != phdr_size) {
                    364:        printf("Can't read program header\n");
                    365:        return NULL;
                    366:     }
                    367: 
                    368:     return phdr;
                    369: }
                    370: 
                    371: int 
                    372: elf_load(struct sys_info *info, ihandle_t dev, const char *cmdline, void **boot_notes)
                    373: {
                    374:     Elf_ehdr ehdr;
                    375:     Elf_phdr *phdr = NULL;
                    376:     unsigned long checksum_offset, file_size;
                    377:     unsigned short checksum = 0;
                    378:     int retval = -1;
                    379:     unsigned int offset;
                    380: 
                    381:     image_name = image_version = NULL;
                    382: 
                    383:     /* Mark the saved-program-state as invalid */
                    384:     feval("0 state-valid !");
                    385: 
                    386:     fd = open_ih(dev);
                    387:     if (fd == -1) {
                    388:        goto out;
                    389:     }
                    390: 
                    391:     offset = find_elf(&ehdr);
                    392:     if (!offset) {
                    393:        retval = LOADER_NOT_SUPPORT;
                    394:         goto out;
                    395:     }
                    396: 
                    397: #if DEBUG
                    398:        printk("ELF header:\n");
                    399:        printk(" ehdr.e_type    = %d\n", (int)ehdr.e_type);
                    400:        printk(" ehdr.e_machine = %d\n", (int)ehdr.e_machine);
                    401:        printk(" ehdr.e_version = %d\n", (int)ehdr.e_version);
                    402:        printk(" ehdr.e_entry   = 0x%08x\n", (int)ehdr.e_entry);
                    403:        printk(" ehdr.e_phoff   = 0x%08x\n", (int)ehdr.e_phoff);
                    404:        printk(" ehdr.e_shoff   = 0x%08x\n", (int)ehdr.e_shoff);
                    405:        printk(" ehdr.e_flags   = %d\n", (int)ehdr.e_flags);
                    406:        printk(" ehdr.e_ehsize  = 0x%08x\n", (int)ehdr.e_ehsize);
                    407:        printk(" ehdr.e_phentsize = 0x%08x\n", (int)ehdr.e_phentsize);
                    408:        printk(" ehdr.e_phnum   = %d\n", (int)ehdr.e_phnum);
                    409: #endif
                    410: 
                    411:     if (ehdr.e_phnum > MAX_HEADERS) {
                    412:         printk ("elfload: too many program headers (MAX_HEADERS)\n");
                    413:         retval = 0;
                    414:        goto out;
                    415:     }
                    416: 
                    417:     phdr = elf_readhdrs(offset, &ehdr);
                    418:     if (!phdr)
                    419:         goto out;
                    420: 
                    421:     if (!check_mem_ranges(info, phdr, ehdr.e_phnum))
                    422:        goto out;
                    423: 
                    424:     checksum_offset = process_image_notes(phdr, ehdr.e_phnum, &checksum, offset);
                    425: 
                    426:     printf("Loading %s", image_name ? image_name : "image");
                    427:     if (image_version)
                    428:        printf(" version %s", image_version);
                    429:     printf("...\n");
                    430: 
                    431:     if (!load_segments(phdr, ehdr.e_phnum, checksum_offset, offset, &file_size))
                    432:        goto out;
                    433: 
                    434:     if (checksum_offset) {
                    435:        if (!verify_image(&ehdr, phdr, ehdr.e_phnum, checksum))
                    436:            goto out;
                    437:     }
                    438: 
                    439:     /* If we are attempting an ELF boot image, we pass a non-NULL pointer
                    440:        into boot_notes and mark the image as elf-boot rather than standard
                    441:        ELF */
                    442:     if (boot_notes) {
                    443:         *boot_notes = (void *)virt_to_phys(build_boot_notes(info, cmdline));
                    444:         feval("elf-boot saved-program-state >sps.file-type !");
                    445:     } else {
                    446:         feval("elf saved-program-state >sps.file-type !");
                    447:     }
                    448: 
                    449:     //debug("current time: %lu\n", currticks());
                    450: 
                    451:     debug("entry point is " FMT_elf "\n", addr_fixup(ehdr.e_entry));
                    452: 
                    453:     // Initialise saved-program-state
                    454:     PUSH(addr_fixup(ehdr.e_entry));
                    455:     feval("saved-program-state >sps.entry !");
                    456:     PUSH(file_size);
                    457:     feval("saved-program-state >sps.file-size !");
                    458: 
                    459:     feval("-1 state-valid !");
                    460: 
                    461: out:
                    462:     close_io(fd);
                    463:     if (phdr)
                    464:        free(phdr);
                    465:     if (image_name)
                    466:        free(image_name);
                    467:     if (image_version)
                    468:        free(image_version);
                    469:     return retval;
                    470: }
                    471: 
                    472: void 
                    473: elf_init_program(void)
                    474: {
                    475:        char *base;
                    476:        int i;
                    477:        Elf_ehdr *ehdr;
                    478:        Elf_phdr *phdr;
                    479:        size_t size, total_size = 0;
                    480:        char *addr;
                    481:        uintptr_t tmp;
                    482: 
                    483:        /* TODO: manage ELF notes section */
                    484:        feval("0 state-valid !");
                    485:        feval("load-base");
                    486:        base = (char*)cell2pointer(POP());
                    487: 
                    488:        ehdr = (Elf_ehdr *)base;
                    489: 
                    490:        if (!is_elf(ehdr)) {
                    491:                debug("Not a valid ELF memory image\n");
                    492:                return;
                    493:        }
                    494: 
                    495:        phdr = (Elf_phdr *)(base + ehdr->e_phoff);
                    496: 
                    497:        for (i = 0; i < ehdr->e_phnum; i++) {
                    498: 
                    499: #if DEBUG
                    500:                debug("filesz: %08lX memsz: %08lX p_offset: %08lX "
                    501:                         "p_vaddr %08lX\n",
                    502:                        (unsigned long)phdr[i].p_filesz, (unsigned long)phdr[i].p_memsz,
                    503:                        (unsigned long)phdr[i].p_offset, (unsigned long)phdr[i].p_vaddr );
                    504: #endif
                    505: 
                    506:                size = MIN(phdr[i].p_filesz, phdr[i].p_memsz);
                    507:                if (!size)
                    508:                        continue;
                    509: #if !defined(CONFIG_SPARC32) && !defined(CONFIG_X86)
                    510:                if( ofmem_claim( phdr[i].p_vaddr, phdr[i].p_memsz, 0 ) == -1 ) {
                    511:                         printk("Ignoring failed claim for va %lx memsz %lx!\n",
                    512:                                (unsigned long)phdr[i].p_vaddr,
                    513:                                (unsigned long)phdr[i].p_memsz);
                    514:                }
                    515: #endif
                    516:                /* Workaround for archs where sizeof(int) != pointer size */
                    517:                tmp = phdr[i].p_vaddr;
                    518:                addr = (char *)tmp;
                    519: 
                    520:                memcpy(addr, base + phdr[i].p_offset, size);
                    521: 
                    522:                total_size += size;
                    523: 
                    524: #ifdef CONFIG_PPC
                    525:                flush_icache_range( addr, addr + size );
                    526: #endif
                    527:        }
                    528: 
                    529:        // Initialise saved-program-state
                    530:        PUSH(ehdr->e_entry);
                    531:        feval("saved-program-state >sps.entry !");
                    532:        PUSH(total_size);
                    533:        feval("saved-program-state >sps.file-size !");
                    534:        feval("elf saved-program-state >sps.file-type !");
                    535: 
                    536:        feval("-1 state-valid !");
                    537: }

unix.superglobalmegacorp.com

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