source: trunk/softs/tsar_boot/src/reset_elf_loader.c @ 1064

Last change on this file since 1064 was 992, checked in by alain, 9 years ago

Introduce a new driver for SD Card using the 4bits wide SD bus.
THere is now 5 supported block device peripherals, and the driver names
have been re-organised: reset_ioc_xxx with xxx in (bdv, hba, rdk, spi, sdc)

File size: 4.2 KB
RevLine 
[292]1/**
[586]2 * \file    : reset_elf_loader.c
[292]3 * \date    : August 2012
4 * \author  : Cesar Fuguet
5 *
[586]6 * This file defines an elf file loader which reads an executable .elf file
7 * starting at a sector passed as argument on a disk and copy the different
[292]8 * ELF program segments in the appropriate memory address using as information
[586]9 * the virtual address read from the .elf file.
[292]10 */
11
[586]12#include <reset_ioc.h>
[292]13#include <elf-types.h>
[586]14#include <reset_tty.h>
15#include <reset_utils.h>
[292]16#include <defs.h>
17
[930]18extern int blk_buf_idx;
[949]19extern int dtb_start, dtb_end;
[930]20
[949]21addr_t dtb_addr;
22
[701]23///////////////////////////////////////////////////////////////////////////////
24void * reset_elf_loader(size_t lba)
25///////////////////////////////////////////////////////////////////////////////
[586]26{
[701]27    size_t file_offset = lba * BLOCK_SIZE;
[425]28
[701]29    reset_puts("\n[RESET] Start reset_elf_loader at cycle ");
30    reset_putd( proctime() );
31    reset_puts("\n");
[570]32
[425]33    /*
[930]34     * Init the cache block index
35     */
36    blk_buf_idx = -1;
37
38    /*
[701]39     * Load ELF HEADER
[292]40     */
[701]41    Elf32_Ehdr elf_header;
42    if (pread(file_offset, (void*)&elf_header, sizeof(Elf32_Ehdr), 0) < 0) {
43        goto error;
44    }
[962]45
[992]46#if (RESET_DEBUG > 1)
[962]47    reset_display_block( (char*)&elf_header );
48#endif
49
[701]50    check_elf_header(&elf_header);
[292]51
[701]52    /*
53     * Load ELF PROGRAM HEADER TABLE
54     */
[758]55    Elf32_Phdr elf_pht[RESET_PHDR_ARRAY_SIZE];
[701]56    size_t phdr_nbyte = sizeof(Elf32_Phdr) * elf_header.e_phnum;
57    size_t phdr_off = elf_header.e_phoff;
58    if (pread(file_offset, (void*)&elf_pht, phdr_nbyte, phdr_off) < 0) {
59        goto error;
60    }
[292]61
62    /*
[701]63     * Search for loadable segments in the ELF file
[412]64     */
[701]65    int pseg;
[949]66    for (pseg = 0; pseg < elf_header.e_phnum; pseg++) {
[701]67        if(elf_pht[pseg].p_type != PT_LOAD) continue;
[292]68
[586]69#if (RESET_DEBUG == 1)
[992]70        reset_puts("\n[RESET DEBUG] Loadable segment found:\n");
[701]71        reset_print_elf_phdr(&elf_pht[pseg]);
[412]72#endif
73
[701]74        addr_t p_paddr = elf_pht[pseg].p_paddr;
75        size_t p_filesz = elf_pht[pseg].p_filesz;
76        size_t p_memsz = elf_pht[pseg].p_memsz;
77        size_t p_offset = elf_pht[pseg].p_offset;
[292]78
[701]79        /*
80         * Copy program segment from ELF executable into corresponding physical
81         * address
82         */
83        if (pread(file_offset, (void*)p_paddr, p_filesz, p_offset) < 0) {
84            goto error;
[292]85        }
86
[701]87        /*
88         * Fill remaining bytes with zero (filesz < memsz)
89         */
90        char* pseg_ptr = (char*)p_paddr;
91        memset((void*)&pseg_ptr[p_filesz], 0, (p_memsz - p_filesz));
[292]92
[701]93        reset_puts("\n[RESET] Segment loaded : address = ");
94        reset_putx(p_paddr);
95        reset_puts(" / size = ");
96        reset_putx(p_filesz);
97        reset_puts("\n");
[292]98    }
99
[949]100    if (pseg == 0) {
101        reset_puts("\n[RESET ERROR] No loadable segments");
102        goto error;
103    }
104
105    /* By default, the used device tree is the one in the ROM */
106    dtb_addr = (addr_t)&dtb_start;
107
108#if OS_LINUX
109    /* When loading a Linux kernel, the device tree should be located in low
110     * memory addresses before the kernel itself.
111     * - When the ROM-contained DTB is located before the kernel no need to copy
112     *   the DTB elsewhere.
113     * - When the ROM-contained DTB is located after the kernel the DTB is
114     *   copied before the kernel. */
115    const int copy_dtb = ((addr_t)&dtb_start > elf_pht[0].p_paddr);
116    if (copy_dtb) {
117        size_t dtb_size = (size_t)&dtb_end - (size_t)&dtb_start;
118        dtb_addr = SEG_RAM_BASE;
119        if ((dtb_addr + (addr_t)dtb_size) >= elf_pht[0].p_paddr) {
120            reset_puts("\n[RESET ERROR] Insufficient space to copy the DTB");
121            goto error;
122        }
123
124        memcpy((void*)dtb_addr, (void*)&dtb_start, dtb_size);
125        reset_puts("\n[RESET] Device tree blob copied / address = ");
126        reset_putx(dtb_addr);
127        reset_puts(" / size = ");
128        reset_putx(dtb_size);
129    }
130#endif
131
[586]132    reset_puts("\n[RESET] Complete reset_elf_loader at cycle ");
[949]133    reset_putd(proctime());
[586]134    reset_puts(" / boot entry = ");
[949]135    reset_putx((addr_t)elf_header.e_entry);
[586]136    reset_puts("\n");
[425]137
[949]138    return ((void*)elf_header.e_entry);
[701]139
140error:
141    reset_puts("\n[RESET ERROR] Error while loading ELF file");
142    reset_exit();
143    return 0;
[292]144}
[425]145
146// vim: tabstop=4 : softtabstop=4 : shiftwidth=4 : expandtab
Note: See TracBrowser for help on using the repository browser.