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

Last change on this file since 377 was 292, checked in by cfuguet, 12 years ago

Changing directory structure of the TSAR boot loader.
A README.txt file has been included to explain the new structure
and the MAKEFILE parameters.

Erasing the heap segment for the boot elf loader. All the work space
is allocated in the stack.

The stack size is defined in the include/defs.h.

Important modification in the reset.S file. The non-boot
processors (processor id != 0) wait in a low comsumption energy
mode to be wake up by processor 0 using an IPI. Each processor
has a private mailbox in the local XICU. The value written in
the mailbox will be used as address to jump by the processors.

The waking up of non-boot processors is not done in this boot loader
so it must be done in the application loaded.

The boot_loader_elf function loads into memory an executable .elf file
which must be placed in the BOOT_LOADER_LBA block of the disk. This
constant can be defined in the include/defs.h file.

File size: 7.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
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.