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

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

Modifications in soft/tsar_boot:

  • Fixing indentation problems in spi.c code
  • Erasing useless print in boot_elf_loader.c
File size: 10.5 KB
Line 
1/**
2 * \file    : boot_loader_entry.c
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>
15#include <boot_memcpy.h>
16#include <defs.h>
17
18void * boot_elf_loader(unsigned int lba)
19{
20    /**
21     * Temporary variables used by the boot loader
22     */
23    unsigned char   boot_elf_loader_buffer[512];
24    Elf32_Ehdr      elf_header;
25    Elf32_Phdr      elf_pht[PHDR_ARRAY_SIZE];
26
27    unsigned char * buffer_ptr;
28    Elf32_Ehdr    * elf_header_ptr;
29    Elf32_Phdr    * elf_pht_ptr;
30
31    unsigned int nb_available;
32    unsigned int nb_rest;
33    unsigned int nb_read;
34    unsigned int nb_block;
35    unsigned int offset;
36    unsigned int pseg;
37    unsigned int i;
38    unsigned int segment_req;
39
40    /*
41     * Loader state machine definition
42     */
43    enum
44    {
45        ELF_HEADER_STATE,
46        ELF_PROGRAM_HEADER_STATE,
47        ELF_OFFSET_STATE,
48        ELF_SEGMENT_STATE,
49        ELF_END_STATE
50    } init_state
51#if (BOOT_DEBUG ==1)
52    , init_state_debug
53#endif
54        ;
55
56#if (BOOT_DEBUG == 1)
57    char* init_state_str[] = {
58        "ELF_HEADER_STATE",
59        "ELF_PROGRAM_HEADER_STATE",
60        "ELF_OFFSET_STATE",
61        "ELF_SEGMENT_STATE",
62        "ELF_END_STATE"
63    };
64#endif
65
66
67    boot_puts("Starting boot_elf_loader function...\n\r");
68
69    nb_block           = lba;
70
71    pseg               = 0;
72    nb_available       = 0;
73    nb_rest            = sizeof(Elf32_Ehdr);
74    offset             = 0;
75
76    elf_header_ptr     = (Elf32_Ehdr *) &elf_header;
77    elf_pht_ptr        = (Elf32_Phdr *) &elf_pht[0];
78
79    init_state         = ELF_HEADER_STATE;
80#if (BOOT_DEBUG == 1)
81    init_state_debug   = ELF_END_STATE;
82#endif
83
84    while(init_state != ELF_END_STATE)
85    {
86        if (nb_available == 0)
87        {
88            buffer_ptr = &boot_elf_loader_buffer[0];
89
90            if ( boot_ioc_read(nb_block , buffer_ptr, 1) )
91            {
92                boot_puts (
93                    "ERROR: "
94                    "IOC_FAILED"
95                    "\n"
96                );
97
98                boot_exit();
99            }
100
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
108#if (BOOT_DEBUG == 1)
109        if (init_state != init_state_debug)
110        {
111            boot_puts("\ninit_state = ");
112            boot_puts(init_state_str[init_state]);
113            boot_puts("\n");
114            init_state_debug = init_state;
115        }
116#endif
117
118        switch(init_state)
119        {
120            /**
121             * Reading ELF executable header
122             */
123            case ELF_HEADER_STATE:
124                boot_memcpy(elf_header_ptr, buffer_ptr, nb_read);
125
126                nb_rest -= nb_read;
127
128                if(nb_rest == 0)
129                {
130                    nb_rest = elf_header_ptr->e_phnum * elf_header_ptr->e_phentsize;
131
132                    /* Verification of ELF Magic Number */
133                    if (
134                        (elf_header_ptr->e_ident[EI_MAG0] != ELFMAG0) ||
135                        (elf_header_ptr->e_ident[EI_MAG1] != ELFMAG1) ||
136                        (elf_header_ptr->e_ident[EI_MAG2] != ELFMAG2) ||
137                        (elf_header_ptr->e_ident[EI_MAG3] != ELFMAG3) )
138                    {
139                        boot_puts(
140                            "ERROR: "
141                            "Input file does not use ELF format"
142                            "\n"
143                        );
144
145                        boot_exit();
146                    }
147
148                    /*
149                     * Verification of Program Headers table size. It must be
150                     * smaller than the work size allocated for the
151                     * elf_pht[PHDR_ARRAY_SIZE] array
152                     **/
153                    if (elf_header_ptr->e_phnum > PHDR_ARRAY_SIZE)
154                    {
155                        boot_puts(
156                            "ERROR: "
157                            "ELF PHDR table size is bigger than "
158                            "the allocated work space"
159                            "\n"
160                        );
161
162                        boot_exit();
163                    }
164
165                    init_state = ELF_PROGRAM_HEADER_STATE;
166                }
167
168                break;
169
170            /**
171             * Reading ELF program headers
172             */
173            case ELF_PROGRAM_HEADER_STATE:
174                boot_memcpy(elf_pht_ptr, buffer_ptr, nb_read);
175
176                elf_pht_ptr = (Elf32_Phdr *)((unsigned char *) elf_pht_ptr + nb_read);
177                nb_rest    -= nb_read;
178
179                if(nb_rest == 0)
180                {
181                    elf_pht_ptr = (Elf32_Phdr *) &elf_pht[0];
182
183                    /*
184                     * Search the first not NULL segment in the ELF file
185                     */
186                    for (pseg = 0; pseg < elf_header_ptr->e_phnum; pseg++)
187                    {
188                        if(elf_pht_ptr[pseg].p_type == PT_LOAD)
189                        {
190#if (BOOT_DEBUG == 1)
191                            boot_puts("found a loadable segment:");
192                            boot_puts("\n- type   : "); boot_putx(elf_pht_ptr[pseg].p_type);
193                            boot_puts("\n- offset : "); boot_putx(elf_pht_ptr[pseg].p_offset);
194                            boot_puts("\n- vaddr  : "); boot_putx(elf_pht_ptr[pseg].p_vaddr);
195                            boot_puts("\n- paddr  : "); boot_putx(elf_pht_ptr[pseg].p_paddr);
196                            boot_puts("\n- filesz : "); boot_putx(elf_pht_ptr[pseg].p_filesz);
197                            boot_puts("\n- memsz  : "); boot_putx(elf_pht_ptr[pseg].p_memsz);
198                            boot_puts("\n- flags  : "); boot_putx(elf_pht_ptr[pseg].p_flags);
199                            boot_puts("\n- align  : "); boot_putx(elf_pht_ptr[pseg].p_align);
200#endif
201                            if (elf_pht_ptr[pseg].p_offset < offset)
202                            {
203                                /*
204                                 * Case where the segment to load includes the elf
205                                 * and program headers
206                                 * */
207                                nb_rest = elf_pht_ptr[pseg].p_filesz - offset;
208                                init_state = ELF_SEGMENT_STATE;
209                            }
210                            else
211                            {
212                                /*
213                                 * Segment to load is further away in ELF file
214                                 * */
215                                nb_rest = elf_pht_ptr[pseg].p_offset - offset;
216                                init_state = ELF_OFFSET_STATE;
217                            }
218                            break;
219                        }
220                    }
221
222                    if (pseg == elf_header_ptr->e_phnum)
223                    {
224                        boot_puts(
225                            "ERROR: "
226                            "No PT_LOAD found"
227                            "\n"
228                        );
229                        boot_exit();
230                    }
231
232                }
233
234                break;
235
236            /**
237             * Go to the offset of the first not null program segment in the
238             * ELF file
239             */
240            case ELF_OFFSET_STATE:
241                nb_rest -= nb_read;
242
243                if (nb_rest == 0)
244                {
245                    nb_rest    = elf_pht_ptr[pseg].p_filesz;
246                    init_state = ELF_SEGMENT_STATE;
247                }
248
249                break;
250
251            /**
252             * Reading ELF segments
253             */
254            case ELF_SEGMENT_STATE:
255                /**
256                 * Copying ELF segment data in memory segments using the virtual
257                 * address got from the ELF file
258                 */
259                segment_req = ((elf_pht_ptr[pseg].p_vaddr & 0xBFC00000) != 0xBFC00000);
260
261                if ( segment_req )
262                {
263                    boot_memcpy((unsigned char *) elf_pht_ptr[pseg].p_vaddr +
264                                (elf_pht_ptr[pseg].p_filesz - nb_rest),
265                                buffer_ptr,
266                                nb_read);
267                }
268
269                nb_rest -= nb_read;
270
271                if ( nb_rest == 0 )
272                {
273                    if ( segment_req )
274                    {
275                        boot_puts("Copied segment at address ");
276                        boot_putx(elf_pht_ptr[pseg].p_vaddr);
277                        boot_puts("\n");
278
279                        /*
280                         * Fill remaining bytes with zeros (filesz < memsz)
281                         */
282                        for ( i = 0                                                        ;
283                              i < (elf_pht_ptr[pseg].p_memsz - elf_pht_ptr[pseg].p_filesz) ;
284                              i--                                                          )
285                        {
286                            *(unsigned char *)
287                            (elf_pht_ptr[pseg].p_vaddr + elf_pht_ptr[pseg].p_filesz + i) = 0;
288                        }
289                    }
290
291                    /*
292                     * Search the first not NULL segment in the ELF file
293                     */
294                    for ( pseg = pseg + 1; pseg < elf_header_ptr->e_phnum; pseg++) {
295                        if(elf_pht_ptr[pseg].p_type == PT_LOAD)
296                        {
297                            nb_rest = elf_pht_ptr[pseg].p_offset - offset;
298                            break;
299                        }
300                    }
301
302                    /*
303                     * Program loading finished
304                     */
305                    if(pseg == elf_header_ptr->e_phnum)
306                    {
307                        init_state = ELF_END_STATE;
308                        break;
309                    }
310
311                    init_state = ELF_OFFSET_STATE;
312                }
313                break;
314
315            default:
316                break;
317        }
318
319        buffer_ptr              += nb_read;
320        nb_available            -= nb_read;
321    }
322
323    boot_puts (
324        "Finishing boot_elf_loader function.\n"
325        "Entry point address: "
326    );
327    boot_putx(elf_header_ptr->e_entry);
328    boot_puts("\n");
329
330    return ((void *) elf_header_ptr->e_entry);
331}
Note: See TracBrowser for help on using the repository browser.