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

Last change on this file since 691 was 687, checked in by cfuguet, 10 years ago

Modification in tsar_boot:
Replacing p_vaddr by p_paddr while loading ELF file.

File size: 10.7 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
[586]18#if (RESET_DEBUG == 1)
19static char const * const init_state_str[] = 
20{
[425]21    "ELF_HEADER_STATE",
22    "ELF_PROGRAM_HEADER_STATE",
23    "ELF_OFFSET_STATE",
24    "ELF_SEGMENT_STATE",
25    "ELF_END_STATE"
26};
27#endif
28
[586]29unsigned char reset_elf_loader_buffer[512] __attribute__((aligned(CACHE_LINE_SIZE)));
[570]30
[586]31/////////////////////////////////////////////////////////////////////////////////////
32void * reset_elf_loader(unsigned int lba)
33/////////////////////////////////////////////////////////////////////////////////////
[292]34{
[425]35    /*
[586]36     * Temporary variables used by the loader
[292]37     */
38    Elf32_Ehdr      elf_header;
39    Elf32_Phdr      elf_pht[PHDR_ARRAY_SIZE];
40
41    unsigned char * buffer_ptr;
[425]42    Elf32_Ehdr    * elf_ehdr_ptr;
43    Elf32_Phdr    * elf_phdr_ptr;
[292]44
45    unsigned int nb_available;
46    unsigned int nb_rest;
47    unsigned int nb_read;
48    unsigned int nb_block;
49    unsigned int offset;
[425]50
51    unsigned char * pseg_ptr;
52    unsigned int pseg_start;
53    unsigned int pseg_end;
54    unsigned int pseg_remainder;
[292]55    unsigned int pseg;
[412]56
[292]57    /*
58     * Loader state machine definition
[412]59     */
[425]60    typedef enum
[292]61    {
62        ELF_HEADER_STATE,
63        ELF_PROGRAM_HEADER_STATE,
64        ELF_OFFSET_STATE,
65        ELF_SEGMENT_STATE,
66        ELF_END_STATE
[425]67    } elf_loader_t;
[292]68
[425]69    elf_loader_t init_state;
70    init_state = ELF_HEADER_STATE;
71
[586]72#if (RESET_DEBUG == 1)
[425]73    elf_loader_t init_state_debug;
74    init_state_debug = ELF_END_STATE;
[412]75#endif
76
[586]77    reset_puts("\n[RESET] Start reset_elf_loader at cycle ");
78    reset_putd( proctime() );
79    reset_puts("\n");
[292]80
[425]81    nb_block     = lba;
82    nb_available = 0;
83    nb_rest      = sizeof(Elf32_Ehdr);
84    pseg         = 0;
85    offset       = 0;
86    elf_ehdr_ptr = (Elf32_Ehdr *) &elf_header;
87    elf_phdr_ptr = (Elf32_Phdr *) &elf_pht[0];
[292]88
89    while(init_state != ELF_END_STATE)
90    {
[425]91        if (nb_available == 0 )
[292]92        {
[586]93            buffer_ptr = &reset_elf_loader_buffer[0];
[292]94
[586]95            if (reset_ioc_read(nb_block , buffer_ptr, 1))
[292]96            {
[586]97                reset_puts ("[RESET ERROR] reset_ioc_read() failed\n");
98                reset_exit();
[292]99            }
[388]100
[292]101            nb_block    += 1;
102            nb_available = 512;
103        }
104
105        nb_read  = (nb_rest <= nb_available) ? nb_rest : nb_available;
106        offset  +=  nb_read;
107
[586]108#if (RESET_DEBUG == 1)
[412]109        if (init_state != init_state_debug)
110        {
[586]111            reset_puts("\ninit_state = ");
112            reset_puts(init_state_str[init_state]);
113            reset_puts("\n");
[412]114            init_state_debug = init_state;
115        }
116#endif
117
[292]118        switch(init_state)
119        {
[425]120            /*
[292]121             * Reading ELF executable header
122             */
123            case ELF_HEADER_STATE:
[425]124                memcpy(elf_ehdr_ptr, buffer_ptr, nb_read);
[292]125
126                nb_rest -= nb_read;
127
128                if(nb_rest == 0)
129                {
[425]130                    nb_rest = elf_ehdr_ptr->e_phnum * elf_ehdr_ptr->e_phentsize;
131                    /*
132                     * Verification of ELF Magic Number
133                     */
134                    if ( (elf_ehdr_ptr->e_ident[EI_MAG0] != ELFMAG0) ||
135                         (elf_ehdr_ptr->e_ident[EI_MAG1] != ELFMAG1) ||
136                         (elf_ehdr_ptr->e_ident[EI_MAG2] != ELFMAG2) ||
137                         (elf_ehdr_ptr->e_ident[EI_MAG3] != ELFMAG3) )
[388]138                    {
[586]139                        reset_puts("[RESET ERROR] boot-loader file is not an ELF format\n");
140                        reset_exit();
[388]141                    }
[292]142
[412]143                    /*
[388]144                     * Verification of Program Headers table size. It must be
[412]145                     * smaller than the work size allocated for the
[388]146                     * elf_pht[PHDR_ARRAY_SIZE] array
[425]147                     */
148                    if (elf_ehdr_ptr->e_phnum > PHDR_ARRAY_SIZE)
[292]149                    {
[586]150                        reset_puts("[RESET ERROR] ELF PHDR table size too large\n");
151                        reset_exit();
[292]152                    }
153
154                    init_state = ELF_PROGRAM_HEADER_STATE;
155                }
156
157                break;
158
[425]159            /*
[292]160             * Reading ELF program headers
[412]161             */
[292]162            case ELF_PROGRAM_HEADER_STATE:
[425]163                memcpy(elf_phdr_ptr, buffer_ptr, nb_read);
[292]164
[425]165                elf_phdr_ptr = 
166                    (Elf32_Phdr *)((unsigned char *) elf_phdr_ptr + nb_read);
[292]167
[425]168                nb_rest -= nb_read;
169
[292]170                if(nb_rest == 0)
171                {
[425]172                    elf_phdr_ptr = (Elf32_Phdr *) &elf_pht[0];
[292]173
174                    /*
175                     * Search the first not NULL segment in the ELF file
176                     */
[425]177                    for (pseg = 0; pseg < elf_ehdr_ptr->e_phnum; pseg++)
[292]178                    {
[425]179                        if(elf_phdr_ptr[pseg].p_type == PT_LOAD)
[292]180                        {
[586]181#if (RESET_DEBUG == 1)
182                            reset_puts("loadable segment found:\n");
183                            reset_print_elf_phdr(&elf_phdr_ptr[pseg]);
[412]184#endif
[425]185                            if (elf_phdr_ptr[pseg].p_offset < offset)
[412]186                            {
[415]187                                /*
[425]188                                 * Case where the segment to load includes the
189                                 * elf and program headers
190                                 */
191                                nb_rest = elf_phdr_ptr[pseg].p_filesz - offset;
[412]192                                init_state = ELF_SEGMENT_STATE;
193                            }
194                            else
195                            {
[415]196                                /*
197                                 * Segment to load is further away in ELF file
[425]198                                 */
199                                nb_rest = elf_phdr_ptr[pseg].p_offset - offset;
[412]200                                init_state = ELF_OFFSET_STATE;
201                            }
[292]202                            break;
203                        }
204                    }
205
[425]206                    if (pseg == elf_ehdr_ptr->e_phnum)
[412]207                    {
[586]208                        reset_puts("[RESET ERROR] No PT_LOAD found\n");
209                        reset_exit();
[412]210                    }
211
[292]212                }
213
214                break;
215
[425]216            /*
[415]217             * Go to the offset of the first not null program segment in the
218             * ELF file
[425]219             *
220             * TODO:
221             * No need to read from the disk the useless bytes. Try to compute
222             * the next usefull lba
[292]223             */
224            case ELF_OFFSET_STATE:
225                nb_rest -= nb_read;
226
227                if (nb_rest == 0)
228                {
[425]229                    nb_rest    = elf_phdr_ptr[pseg].p_filesz;
[292]230                    init_state = ELF_SEGMENT_STATE;
231                }
232
233                break;
234
[425]235            /*
[292]236             * Reading ELF segments
[425]237             *
238             * TODO:
239             * Do not pass by block buffer but write directly in target memory
240             * address
[292]241             */
242            case ELF_SEGMENT_STATE:
[425]243                /*
244                 * Verify that loadable segment does not conflict with
245                 * pre-loader memory space
[412]246                 */
[687]247                pseg_start = elf_phdr_ptr[pseg].p_paddr;
[292]248
[687]249                pseg_end   = elf_phdr_ptr[pseg].p_paddr +
[425]250                             elf_phdr_ptr[pseg].p_memsz;
251
252                if ((pseg_start >= 0xBFC00000 && pseg_start <= 0xBFC10000) ||
253                    (pseg_end   >= 0xBFC00000 && pseg_end   <= 0xBFC10000) ||
254                    (pseg_start <  0xBFC00000 && pseg_end   >  0xBFC10000))
[292]255                {
[586]256                    reset_puts("[RESET ERROR] conflict with pre-loader memory space\n");
257                    reset_exit();
[292]258                }
[412]259
[425]260                /*
261                 * Copy the ELF segment data in memory using the
262                 * virtual address obtained from the ELF file
263                 */
264                pseg_ptr = (unsigned char *)
[687]265                    elf_phdr_ptr[pseg].p_paddr  +
[425]266                    elf_phdr_ptr[pseg].p_filesz -
267                    nb_rest;
268
269                memcpy(pseg_ptr, buffer_ptr, nb_read);
270
[292]271                nb_rest -= nb_read;
272
[425]273                if (nb_rest == 0)
[292]274                {
[425]275                    /*
276                     * Fill remaining bytes with zeros (filesz < memsz)
277                     */
278                    pseg_remainder =
279                        elf_phdr_ptr[pseg].p_memsz  -
280                        elf_phdr_ptr[pseg].p_filesz ;
[292]281
[425]282                    pseg_ptr = (unsigned char *)
[687]283                        elf_phdr_ptr[pseg].p_paddr  +
[425]284                        elf_phdr_ptr[pseg].p_filesz ;
[292]285
[591]286                    memset(pseg_ptr, 0, pseg_remainder);
[425]287
[586]288                    reset_puts("\n[RESET] Segment loaded : address = ");
[687]289                    reset_putx(elf_phdr_ptr[pseg].p_paddr);
[586]290                    reset_puts(" / size = ");
291                    reset_putx(elf_phdr_ptr[pseg].p_filesz);
292                    reset_puts("\n");
[425]293
[292]294                    /*
[425]295                     * Search the next first not NULL segment in the ELF file
[292]296                     */
[425]297                    for (pseg += 1; pseg < elf_ehdr_ptr->e_phnum; pseg++)
298                    {
299                        if(elf_phdr_ptr[pseg].p_type == PT_LOAD)
[292]300                        {
[586]301#if (RESET_DEBUG == 1)
302                            reset_puts("loadable segment found:\n");
303                            reset_print_elf_phdr(&elf_phdr_ptr[pseg]);
[425]304#endif
305                            nb_rest = elf_phdr_ptr[pseg].p_offset - offset;
[292]306                            break;
307                        }
308                    }
309
310                    /*
311                     * Program loading finished
[412]312                     */
[425]313                    if(pseg == elf_ehdr_ptr->e_phnum)
[292]314                    {
315                        init_state = ELF_END_STATE;
316                        break;
317                    }
318
319                    init_state = ELF_OFFSET_STATE;
320                }
321                break;
322
323            default:
324                break;
325        }
326
[425]327        buffer_ptr   += nb_read;
328        nb_available -= nb_read;
[292]329    }
330
[586]331    reset_puts("\n[RESET] Complete reset_elf_loader at cycle ");
332    reset_putd( proctime() );
333    reset_puts(" / boot entry = ");
334    reset_putx( (unsigned int)(elf_ehdr_ptr->e_entry) );
335    reset_puts("\n");
[425]336
337    return ((void *) elf_ehdr_ptr->e_entry);
[292]338}
[425]339
340// vim: tabstop=4 : softtabstop=4 : shiftwidth=4 : expandtab
Note: See TracBrowser for help on using the repository browser.