source: trunk/softs/tsar_boot/src/boot_elf_loader.c @ 513

Last change on this file since 513 was 425, checked in by cfuguet, 11 years ago

Modifications in tsar_boot:

  • Creating new files boot_utils.[c h] containing the memcpy, memset and some ELF format debug functions
  • Introducing assert in the boot_elf_loader to show an error when some of segments to load conflicts with some of the pre-loader segments
  • Cosmetic changes in boot_elf_loader to improve code readibility
  • Fixing bug in dcache_buf_invalidate function used by boot_ioc_read when cache coherence not supported. The condition in the for loop was erroneous.
  • Modification in Makefile: The SYSCLK_FREQ parameter is not passed anymore

as a Makefile parameter but it is definesd in the defs_platform.h file

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