source: trunk/softs/tsar_boot/boot_loader_entry.c @ 276

Last change on this file since 276 was 276, checked in by bouyer, 12 years ago

A boot loader to be stored in ROM of a TSAR platform.
Based on Cesar FUGUET's work.
Platform-specific files are in a subdirectory, e.g. platform_fpga_de2-115,
so the same code can be targetted to different platforms.
The platform is selected with the PLATFORM_DIR environnement variable.
The supported variant are soclib and fpga, the later being the default
and the former selected by defining the SOCLIB environnement variable.
The boot loader embeds a binary device tree describing the platform,
to be used by the loaded software.

File size: 7.7 KB
Line 
1/**
2 * \file    : boot_loader_entry.c
3 * \date    : August 2012
4 * \author  : Cesar Fuguet
5 *
6 * This file defines a boot loader which reads an elf file starting in the sector
7 * 0 of the BLOCK DEVICE and copy the different program segments in the appropriate
8 * memory address using as information the virtual address read from the elf file.
9 */
10
11#include <ioc.h>
12#include <elf-types.h>
13#include <boot_tty.h>
14
15#define in_reset       __attribute__((section (".reset")))
16#define in_reset_data __attribute__((section (".reset_data")))
17
18struct base_addresses;
19extern struct base_addresses seg_reset_heap_base;
20
21in_reset static void *boot_memcpy(void *_dst, const void *_src, unsigned int size)
22{
23    unsigned int *dst = _dst;
24    const unsigned int *src = _src;
25    if ( ! ((unsigned int)dst & 3) && ! ((unsigned int)src & 3) )
26        while (size > 3) {
27            *dst++ = *src++;
28            size -= 4;
29        }
30
31    unsigned char *cdst = (unsigned char*)dst;
32    unsigned char *csrc = (unsigned char*)src;
33
34    while (size--) {
35        *cdst++ = *csrc++;
36    }
37    return _dst;
38}
39
40in_reset void * _boot_loader_entry()
41{
42    in_reset_data static const char start_boot_str[] = "Starting bootstrap stage...\n\r";
43    in_reset_data static const char start_boot_str_err[] = "ioc failed\n";
44    in_reset_data static const char copied_str[]     = "Copied segment at address ";
45    in_reset_data static const char finishing_str[]  = "Finishing bootstrap stage, entry point ";
46    in_reset_data static const char end_line[]         = "\n\r";
47   
48    const unsigned int boot_loader_buffer_base = (unsigned int) &seg_reset_heap_base;
49    const unsigned int elf_header_base         = boot_loader_buffer_base + 512;
50    const unsigned int elf_pht_base            = elf_header_base + sizeof(Elf32_Ehdr);
51
52    /**
53     * Temporary variables used by the boot loader
54     */
55    unsigned char * boot_loader_buffer;
56    Elf32_Ehdr    * elf_header;
57    Elf32_Phdr    * elf_pht;
58
59    unsigned int nb_available;
60    unsigned int nb_rest;
61    unsigned int nb_read;
62    unsigned int nb_block;
63    unsigned int offset;
64    unsigned int pseg;
65    unsigned int init_pseg;
66    unsigned int i;
67    unsigned int segment_req;
68   
69    /*
70     * Loader state machine definition
71     */ 
72    enum
73    {
74        ELF_HEADER_STATE,
75        ELF_PROGRAM_HEADER_STATE,
76        ELF_OFFSET_STATE,
77        ELF_SEGMENT_STATE,
78        ELF_END_STATE
79    } init_state;
80
81    boot_puts(start_boot_str);
82
83    /* Initialize the block device */
84    if (_ioc_init() != 0) {
85        boot_puts(start_boot_str_err);
86        while (1);
87    }
88
89    boot_loader_buffer = 0;
90    pseg               = 0;
91    init_pseg          = 0;
92    nb_block           = 2;
93    nb_available       = 0;
94    nb_rest            = sizeof(Elf32_Ehdr);
95    offset                  = 0;
96
97    elf_header         = (Elf32_Ehdr *) elf_header_base;
98    elf_pht            = (Elf32_Phdr *) elf_pht_base;
99
100    init_state         = ELF_HEADER_STATE;
101
102    while(init_state != ELF_END_STATE)
103    {
104        if (nb_available == 0)
105        {
106            boot_loader_buffer = (unsigned char *) boot_loader_buffer_base;
107
108            if ( _ioc_read(nb_block , boot_loader_buffer, 1) )
109            {
110                boot_puts(start_boot_str_err);
111                while (1);
112            }
113           
114            nb_block    += 1;
115            nb_available = 512;
116        }
117
118        nb_read  = (nb_rest <= nb_available) ? nb_rest : nb_available;
119        offset  += nb_read;
120
121        switch(init_state)
122        {
123            /**
124             * Reading ELF executable header
125             */
126            case ELF_HEADER_STATE:
127                boot_memcpy(elf_header, boot_loader_buffer, nb_read);
128
129                nb_rest -= nb_read;
130
131                if(nb_rest == 0)
132                {
133                    nb_rest = elf_header->e_phnum * elf_header->e_phentsize;
134
135                    init_state = ELF_PROGRAM_HEADER_STATE;
136                }
137
138                break;
139
140            /**
141             * Reading ELF program headers
142             */ 
143            case ELF_PROGRAM_HEADER_STATE:
144                boot_memcpy(elf_pht, boot_loader_buffer, nb_read);
145
146                elf_pht  = (Elf32_Phdr *)((unsigned char *) elf_pht + nb_read);
147                nb_rest -= nb_read;
148
149                if(nb_rest == 0)
150                {
151                    elf_pht = (Elf32_Phdr *) elf_pht_base;
152
153                    /*
154                     * Search the first not NULL segment in the ELF file
155                     */
156                    for (pseg = 0; pseg < elf_header->e_phnum; pseg++)
157                    {
158                        if(elf_pht[pseg].p_type == PT_LOAD)
159                        {
160                            nb_rest = elf_pht[pseg].p_offset - offset;
161                            break;
162                        }
163                    }
164
165                    init_state = ELF_OFFSET_STATE;
166                }
167
168                break;
169
170            /**
171             * Go to the offset of the first not null program segment in the ELF file
172             */
173            case ELF_OFFSET_STATE:
174                nb_rest -= nb_read;
175
176                if (nb_rest == 0)
177                {
178                    nb_rest    = elf_pht[pseg].p_filesz;
179                    init_state = ELF_SEGMENT_STATE;
180                }
181
182                break;
183
184            /**
185             * Reading ELF segments
186             */
187            case ELF_SEGMENT_STATE:
188                /**
189                 * Copying ELF segment data in memory segments using the virtual
190                 * address got from the ELF file
191                 */ 
192                segment_req = ((elf_pht[pseg].p_vaddr & 0xBFC00000) != 0xBFC00000);
193
194                if ( segment_req )
195                {
196                    boot_memcpy((unsigned char *) elf_pht[pseg].p_vaddr +
197                                (elf_pht[pseg].p_filesz - nb_rest),
198                                boot_loader_buffer,
199                                nb_read);
200                }
201   
202                nb_rest -= nb_read;
203
204                if ( nb_rest == 0 )
205                {
206                    if ( segment_req )
207                    {
208                        boot_puts(copied_str);
209                        boot_putx(elf_pht[pseg].p_vaddr);
210                        boot_puts(end_line);
211
212                        /*
213                         * Fill remaining bytes with zeros (filesz < memsz)
214                         */
215                        for ( i = 0                                                ;
216                              i < (elf_pht[pseg].p_memsz - elf_pht[pseg].p_filesz) ;
217                              i--                                                  )
218                        {
219                            *(unsigned char *)
220                            (elf_pht[pseg].p_vaddr + elf_pht[pseg].p_filesz + i) = 0;
221                        }
222                    }
223
224                    /*
225                     * Search the first not NULL segment in the ELF file
226                     */
227                    for ( pseg = pseg + 1; pseg < elf_header->e_phnum; pseg++) {
228                        if(elf_pht[pseg].p_type == PT_LOAD)
229                        {
230                            nb_rest = elf_pht[pseg].p_offset - offset;
231                            break;
232                        }
233                    }
234
235                    /*
236                     * Program loading finished
237                     */ 
238                    if(pseg == elf_header->e_phnum)
239                    {
240                        init_state = ELF_END_STATE;
241                        break;
242                    }
243
244                    init_state = ELF_OFFSET_STATE;
245                }
246                break;
247
248            default:
249                break;
250        }
251
252        boot_loader_buffer += nb_read;
253        nb_available       -= nb_read;
254    }
255    boot_puts(finishing_str);
256    boot_putx(elf_header->e_entry);
257    boot_puts(end_line);
258    return (void*)elf_header->e_entry;
259}
Note: See TracBrowser for help on using the repository browser.