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

Last change on this file since 394 was 388, checked in by cfuguet, 12 years ago

Modifications in tsar/trunk/softs/tsar_boot:

  • Improving the boot_ioc_read when using a SD card in FPGA platform.
  • Adding some instrumentation on the SD card driver (under preprocessor conditional directives).
  • Including Doxyfile for generate documentation using doxygen.
  • Improving the Makefile to include doc generation.
File size: 8.0 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
52    boot_puts("Starting boot_elf_loader function...\n\r");
53
54    nb_block           = lba;
55
56    pseg               = 0;
57    nb_available       = 0;
58    nb_rest            = sizeof(Elf32_Ehdr);
59    offset             = 0;
60
61    elf_header_ptr     = (Elf32_Ehdr *) &elf_header;
62    elf_pht_ptr        = (Elf32_Phdr *) &elf_pht[0];
63
64    init_state         = ELF_HEADER_STATE;
65
66    while(init_state != ELF_END_STATE)
67    {
68        if (nb_available == 0)
69        {
70            buffer_ptr = &boot_elf_loader_buffer[0];
71
72            if ( boot_ioc_read(nb_block , buffer_ptr, 1) )
73            {
74                boot_puts (
75                    "ERROR: "
76                    "IOC_FAILED"
77                    "\n"
78                );
79
80                boot_exit();
81            }
82
83            nb_block    += 1;
84            nb_available = 512;
85        }
86
87        nb_read  = (nb_rest <= nb_available) ? nb_rest : nb_available;
88        offset  +=  nb_read;
89
90        switch(init_state)
91        {
92            /**
93             * Reading ELF executable header
94             */
95            case ELF_HEADER_STATE:
96                boot_memcpy(elf_header_ptr, buffer_ptr, nb_read);
97
98                nb_rest -= nb_read;
99
100                if(nb_rest == 0)
101                {
102                    nb_rest = elf_header_ptr->e_phnum * elf_header_ptr->e_phentsize;
103
104                    /* Verification of ELF Magic Number */
105                    if (
106                        (elf_header_ptr->e_ident[EI_MAG0] != ELFMAG0) ||
107                        (elf_header_ptr->e_ident[EI_MAG1] != ELFMAG1) ||
108                        (elf_header_ptr->e_ident[EI_MAG2] != ELFMAG2) ||
109                        (elf_header_ptr->e_ident[EI_MAG3] != ELFMAG3) )
110                    {
111                        boot_puts(
112                            "ERROR: "
113                            "Input file does not use ELF format"
114                            "\n"
115                        ); 
116
117                        boot_exit();
118                    }
119
120                    /*
121                     * Verification of Program Headers table size. It must be
122                     * smaller than the work size allocated for the
123                     * elf_pht[PHDR_ARRAY_SIZE] array
124                     **/
125                    if (elf_header_ptr->e_phnum > PHDR_ARRAY_SIZE)
126                    {
127                        boot_puts(
128                            "ERROR: "
129                            "ELF PHDR table size is bigger than "
130                            "the allocated work space"
131                            "\n"
132                        );
133
134                        boot_exit();
135                    }
136
137                    init_state = ELF_PROGRAM_HEADER_STATE;
138                }
139
140                break;
141
142            /**
143             * Reading ELF program headers
144             */ 
145            case ELF_PROGRAM_HEADER_STATE:
146                boot_memcpy(elf_pht_ptr, buffer_ptr, nb_read);
147
148                elf_pht_ptr = (Elf32_Phdr *)((unsigned char *) elf_pht_ptr + nb_read);
149                nb_rest    -= nb_read;
150
151                if(nb_rest == 0)
152                {
153                    elf_pht_ptr = (Elf32_Phdr *) &elf_pht[0];
154
155                    /*
156                     * Search the first not NULL segment in the ELF file
157                     */
158                    for (pseg = 0; pseg < elf_header_ptr->e_phnum; pseg++)
159                    {
160                        if(elf_pht_ptr[pseg].p_type == PT_LOAD)
161                        {
162                            nb_rest = elf_pht_ptr[pseg].p_offset - offset;
163                            break;
164                        }
165                    }
166
167                    init_state = ELF_OFFSET_STATE;
168                }
169
170                break;
171
172            /**
173             * Go to the offset of the first not null program segment in the ELF file
174             */
175            case ELF_OFFSET_STATE:
176                nb_rest -= nb_read;
177
178                if (nb_rest == 0)
179                {
180                    nb_rest    = elf_pht_ptr[pseg].p_filesz;
181                    init_state = ELF_SEGMENT_STATE;
182                }
183
184                break;
185
186            /**
187             * Reading ELF segments
188             */
189            case ELF_SEGMENT_STATE:
190                /**
191                 * Copying ELF segment data in memory segments using the virtual
192                 * address got from the ELF file
193                 */ 
194                segment_req = ((elf_pht_ptr[pseg].p_vaddr & 0xBFC00000) != 0xBFC00000);
195
196                if ( segment_req )
197                {
198                    boot_memcpy((unsigned char *) elf_pht_ptr[pseg].p_vaddr +
199                                (elf_pht_ptr[pseg].p_filesz - nb_rest),
200                                buffer_ptr,
201                                nb_read);
202                }
203   
204                nb_rest -= nb_read;
205
206                if ( nb_rest == 0 )
207                {
208                    if ( segment_req )
209                    {
210                        boot_puts("Copied segment at address ");
211                        boot_putx(elf_pht_ptr[pseg].p_vaddr);
212                        boot_puts("\n");
213
214                        /*
215                         * Fill remaining bytes with zeros (filesz < memsz)
216                         */
217                        for ( i = 0                                                        ;
218                              i < (elf_pht_ptr[pseg].p_memsz - elf_pht_ptr[pseg].p_filesz) ;
219                              i--                                                          )
220                        {
221                            *(unsigned char *)
222                            (elf_pht_ptr[pseg].p_vaddr + elf_pht_ptr[pseg].p_filesz + i) = 0;
223                        }
224                    }
225
226                    /*
227                     * Search the first not NULL segment in the ELF file
228                     */
229                    for ( pseg = pseg + 1; pseg < elf_header_ptr->e_phnum; pseg++) {
230                        if(elf_pht_ptr[pseg].p_type == PT_LOAD)
231                        {
232                            nb_rest = elf_pht_ptr[pseg].p_offset - offset;
233                            break;
234                        }
235                    }
236
237                    /*
238                     * Program loading finished
239                     */ 
240                    if(pseg == elf_header_ptr->e_phnum)
241                    {
242                        init_state = ELF_END_STATE;
243                        break;
244                    }
245
246                    init_state = ELF_OFFSET_STATE;
247                }
248                break;
249
250            default:
251                break;
252        }
253
254        buffer_ptr              += nb_read;
255        nb_available            -= nb_read;
256    }
257
258    boot_puts (
259        "Finishing boot_elf_loader function.\n"
260        "Entry point address: "
261    );
262    boot_putx(elf_header_ptr->e_entry);
263    boot_puts("\n");
264
265    return ((void *) elf_header_ptr->e_entry);
266}
Note: See TracBrowser for help on using the repository browser.