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

Last change on this file since 412 was 412, checked in by porquet, 11 years ago

boot_tsar: bug fix and more debug

File size: 10.4 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("init_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:\n");
192                            boot_puts("- type   : "); boot_putx(elf_pht_ptr[pseg].p_type);    boot_puts("\n");
193                            boot_puts("- offset : "); boot_putx(elf_pht_ptr[pseg].p_offset);  boot_puts("\n");
194                            boot_puts("- vaddr  : "); boot_putx(elf_pht_ptr[pseg].p_vaddr);   boot_puts("\n");
195                            boot_puts("- paddr  : "); boot_putx(elf_pht_ptr[pseg].p_paddr);   boot_puts("\n");
196                            boot_puts("- filesz : "); boot_putx(elf_pht_ptr[pseg].p_filesz);  boot_puts("\n");
197                            boot_puts("- memsz  : "); boot_putx(elf_pht_ptr[pseg].p_memsz);   boot_puts("\n");
198                            boot_puts("- flags  : "); boot_putx(elf_pht_ptr[pseg].p_flags);   boot_puts("\n");
199                            boot_puts("- align  : "); boot_putx(elf_pht_ptr[pseg].p_align);   boot_puts("\n");
200#endif
201                            if (elf_pht_ptr[pseg].p_offset < offset)
202                            {
203                                /* case where the segment to load includes the elf and program headers */
204                                nb_rest = elf_pht_ptr[pseg].p_filesz - offset;
205                                init_state = ELF_SEGMENT_STATE;
206                            }
207                            else
208                            {
209                                /* segment to load is further away in memory */
210                                nb_rest = elf_pht_ptr[pseg].p_offset - offset;
211                                init_state = ELF_OFFSET_STATE;
212                            }
213                            break;
214                        }
215                    }
216
217                    if (pseg == elf_header_ptr->e_phnum)
218                    {
219                        boot_puts(
220                            "ERROR: "
221                            "No PT_LOAD found"
222                            "\n"
223                        );
224                        boot_exit();
225                    }
226
227                }
228
229                break;
230
231            /**
232             * Go to the offset of the first not null program segment in the ELF file
233             */
234            case ELF_OFFSET_STATE:
235                nb_rest -= nb_read;
236
237                if (nb_rest == 0)
238                {
239                    nb_rest    = elf_pht_ptr[pseg].p_filesz;
240                    init_state = ELF_SEGMENT_STATE;
241                }
242
243                break;
244
245            /**
246             * Reading ELF segments
247             */
248            case ELF_SEGMENT_STATE:
249                /**
250                 * Copying ELF segment data in memory segments using the virtual
251                 * address got from the ELF file
252                 */
253                segment_req = ((elf_pht_ptr[pseg].p_vaddr & 0xBFC00000) != 0xBFC00000);
254
255                if ( segment_req )
256                {
257                    boot_memcpy((unsigned char *) elf_pht_ptr[pseg].p_vaddr +
258                                (elf_pht_ptr[pseg].p_filesz - nb_rest),
259                                buffer_ptr,
260                                nb_read);
261                }
262
263                nb_rest -= nb_read;
264
265                if ( nb_rest == 0 )
266                {
267                    if ( segment_req )
268                    {
269                        boot_puts("Copied segment at address ");
270                        boot_putx(elf_pht_ptr[pseg].p_vaddr);
271                        boot_puts("\n");
272
273                        /*
274                         * Fill remaining bytes with zeros (filesz < memsz)
275                         */
276                        for ( i = 0                                                        ;
277                              i < (elf_pht_ptr[pseg].p_memsz - elf_pht_ptr[pseg].p_filesz) ;
278                              i--                                                          )
279                        {
280                            *(unsigned char *)
281                            (elf_pht_ptr[pseg].p_vaddr + elf_pht_ptr[pseg].p_filesz + i) = 0;
282                        }
283                    }
284
285                    /*
286                     * Search the first not NULL segment in the ELF file
287                     */
288                    for ( pseg = pseg + 1; pseg < elf_header_ptr->e_phnum; pseg++) {
289                        if(elf_pht_ptr[pseg].p_type == PT_LOAD)
290                        {
291                            nb_rest = elf_pht_ptr[pseg].p_offset - offset;
292                            break;
293                        }
294                    }
295
296                    /*
297                     * Program loading finished
298                     */
299                    if(pseg == elf_header_ptr->e_phnum)
300                    {
301                        init_state = ELF_END_STATE;
302                        break;
303                    }
304
305                    init_state = ELF_OFFSET_STATE;
306                }
307                break;
308
309            default:
310                break;
311        }
312
313        buffer_ptr              += nb_read;
314        nb_available            -= nb_read;
315    }
316
317    boot_puts (
318        "Finishing boot_elf_loader function.\n"
319        "Entry point address: "
320    );
321    boot_putx(elf_header_ptr->e_entry);
322    boot_puts("\n");
323
324    return ((void *) elf_header_ptr->e_entry);
325}
Note: See TracBrowser for help on using the repository browser.