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

Last change on this file since 577 was 570, checked in by cfuguet, 11 years ago

Modifications in tsar_boot:

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