Changeset 701 for trunk/softs/tsar_boot/src/reset_elf_loader.c
- Timestamp:
- May 25, 2014, 5:35:37 PM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/softs/tsar_boot/src/reset_elf_loader.c
r694 r701 16 16 #include <defs.h> 17 17 18 #if (RESET_DEBUG == 1) 19 static char const * const init_state_str[] = 18 /////////////////////////////////////////////////////////////////////////////// 19 void * reset_elf_loader(size_t lba) 20 /////////////////////////////////////////////////////////////////////////////// 20 21 { 21 "ELF_HEADER_STATE", 22 "ELF_PROGRAM_HEADER_STATE", 23 "ELF_OFFSET_STATE", 24 "ELF_SEGMENT_STATE", 25 "ELF_END_STATE" 26 }; 27 #endif 28 29 unsigned char reset_elf_loader_buffer[512] __attribute__((aligned(CACHE_LINE_SIZE))); 30 31 ///////////////////////////////////////////////////////////////////////////////////// 32 void * reset_elf_loader(unsigned int lba) 33 ///////////////////////////////////////////////////////////////////////////////////// 34 { 35 /* 36 * Temporary variables used by the loader 37 */ 38 Elf32_Ehdr elf_header; 39 Elf32_Phdr elf_pht[PHDR_ARRAY_SIZE]; 40 41 unsigned char * buffer_ptr = 0; 42 Elf32_Ehdr * elf_ehdr_ptr; 43 Elf32_Phdr * elf_phdr_ptr; 44 45 unsigned int nb_available; 46 unsigned int nb_rest; 47 unsigned int nb_read; 48 unsigned int nb_block; 49 unsigned int offset; 50 51 unsigned char * pseg_ptr; 52 unsigned int pseg_start; 53 unsigned int pseg_end; 54 unsigned int pseg_remainder; 55 unsigned int pseg; 56 57 /* 58 * Loader state machine definition 59 */ 60 typedef enum 61 { 62 ELF_HEADER_STATE, 63 ELF_PROGRAM_HEADER_STATE, 64 ELF_OFFSET_STATE, 65 ELF_SEGMENT_STATE, 66 ELF_END_STATE 67 } elf_loader_t; 68 69 elf_loader_t init_state; 70 init_state = ELF_HEADER_STATE; 71 72 #if (RESET_DEBUG == 1) 73 elf_loader_t init_state_debug; 74 init_state_debug = ELF_END_STATE; 75 #endif 22 size_t file_offset = lba * BLOCK_SIZE; 76 23 77 24 reset_puts("\n[RESET] Start reset_elf_loader at cycle "); … … 79 26 reset_puts("\n"); 80 27 81 nb_block = lba; 82 nb_available = 0; 83 nb_rest = sizeof(Elf32_Ehdr); 84 pseg = 0; 85 offset = 0; 86 elf_ehdr_ptr = (Elf32_Ehdr *) &elf_header; 87 elf_phdr_ptr = (Elf32_Phdr *) &elf_pht[0]; 28 /* 29 * Load ELF HEADER 30 */ 31 Elf32_Ehdr elf_header; 32 if (pread(file_offset, (void*)&elf_header, sizeof(Elf32_Ehdr), 0) < 0) { 33 goto error; 34 } 35 check_elf_header(&elf_header); 88 36 89 while(init_state != ELF_END_STATE) 37 /* 38 * Load ELF PROGRAM HEADER TABLE 39 */ 40 Elf32_Phdr elf_pht[PHDR_ARRAY_SIZE]; 41 size_t phdr_nbyte = sizeof(Elf32_Phdr) * elf_header.e_phnum; 42 size_t phdr_off = elf_header.e_phoff; 43 if (pread(file_offset, (void*)&elf_pht, phdr_nbyte, phdr_off) < 0) { 44 goto error; 45 } 46 47 /* 48 * Search for loadable segments in the ELF file 49 */ 50 int pseg; 51 for (pseg = 0; pseg < elf_header.e_phnum; pseg++) 90 52 { 91 if (nb_available == 0 ) 92 { 93 buffer_ptr = &reset_elf_loader_buffer[0]; 53 if(elf_pht[pseg].p_type != PT_LOAD) continue; 94 54 95 if (reset_ioc_read(nb_block , buffer_ptr, 1)) 96 { 97 reset_puts ("[RESET ERROR] reset_ioc_read() failed\n"); 98 reset_exit(); 99 } 55 #if (RESET_DEBUG == 1) 56 reset_puts("[RESET DEBUG] Loadable segment found:\n"); 57 reset_print_elf_phdr(&elf_pht[pseg]); 58 #endif 100 59 101 nb_block += 1; 102 nb_available = 512; 60 addr_t p_paddr = elf_pht[pseg].p_paddr; 61 size_t p_filesz = elf_pht[pseg].p_filesz; 62 size_t p_memsz = elf_pht[pseg].p_memsz; 63 size_t p_offset = elf_pht[pseg].p_offset; 64 65 /* 66 * Copy program segment from ELF executable into corresponding physical 67 * address 68 */ 69 if (pread(file_offset, (void*)p_paddr, p_filesz, p_offset) < 0) { 70 goto error; 103 71 } 104 72 105 nb_read = (nb_rest <= nb_available) ? nb_rest : nb_available; 106 offset += nb_read; 73 /* 74 * Fill remaining bytes with zero (filesz < memsz) 75 */ 76 char* pseg_ptr = (char*)p_paddr; 77 memset((void*)&pseg_ptr[p_filesz], 0, (p_memsz - p_filesz)); 107 78 108 #if (RESET_DEBUG == 1) 109 if (init_state != init_state_debug) 110 { 111 reset_puts("\ninit_state = "); 112 reset_puts(init_state_str[init_state]); 113 reset_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 memcpy(elf_ehdr_ptr, buffer_ptr, nb_read); 125 126 nb_rest -= nb_read; 127 128 if(nb_rest == 0) 129 { 130 nb_rest = elf_ehdr_ptr->e_phnum * elf_ehdr_ptr->e_phentsize; 131 /* 132 * Verification of ELF Magic Number 133 */ 134 if ( (elf_ehdr_ptr->e_ident[EI_MAG0] != ELFMAG0) || 135 (elf_ehdr_ptr->e_ident[EI_MAG1] != ELFMAG1) || 136 (elf_ehdr_ptr->e_ident[EI_MAG2] != ELFMAG2) || 137 (elf_ehdr_ptr->e_ident[EI_MAG3] != ELFMAG3) ) 138 { 139 reset_puts("[RESET ERROR] boot-loader file is not an ELF format\n"); 140 reset_exit(); 141 } 142 143 /* 144 * Verification of Program Headers table size. It must be 145 * smaller than the work size allocated for the 146 * elf_pht[PHDR_ARRAY_SIZE] array 147 */ 148 if (elf_ehdr_ptr->e_phnum > PHDR_ARRAY_SIZE) 149 { 150 reset_puts("[RESET ERROR] ELF PHDR table size too large\n"); 151 reset_exit(); 152 } 153 154 init_state = ELF_PROGRAM_HEADER_STATE; 155 } 156 157 break; 158 159 /* 160 * Reading ELF program headers 161 */ 162 case ELF_PROGRAM_HEADER_STATE: 163 memcpy(elf_phdr_ptr, buffer_ptr, nb_read); 164 165 elf_phdr_ptr = 166 (Elf32_Phdr *)((unsigned char *) elf_phdr_ptr + nb_read); 167 168 nb_rest -= nb_read; 169 170 if(nb_rest == 0) 171 { 172 elf_phdr_ptr = (Elf32_Phdr *) &elf_pht[0]; 173 174 /* 175 * Search the first not NULL segment in the ELF file 176 */ 177 for (pseg = 0; pseg < elf_ehdr_ptr->e_phnum; pseg++) 178 { 179 if(elf_phdr_ptr[pseg].p_type == PT_LOAD) 180 { 181 #if (RESET_DEBUG == 1) 182 reset_puts("loadable segment found:\n"); 183 reset_print_elf_phdr(&elf_phdr_ptr[pseg]); 184 #endif 185 if (elf_phdr_ptr[pseg].p_offset < offset) 186 { 187 /* 188 * Case where the segment to load includes the 189 * elf and program headers 190 */ 191 nb_rest = elf_phdr_ptr[pseg].p_filesz - offset; 192 init_state = ELF_SEGMENT_STATE; 193 } 194 else 195 { 196 /* 197 * Segment to load is further away in ELF file 198 */ 199 nb_rest = elf_phdr_ptr[pseg].p_offset - offset; 200 init_state = ELF_OFFSET_STATE; 201 } 202 break; 203 } 204 } 205 206 if (pseg == elf_ehdr_ptr->e_phnum) 207 { 208 reset_puts("[RESET ERROR] No PT_LOAD found\n"); 209 reset_exit(); 210 } 211 212 } 213 214 break; 215 216 /* 217 * Go to the offset of the first not null program segment in the 218 * ELF file 219 * 220 * TODO: 221 * No need to read from the disk the useless bytes. Try to compute 222 * the next usefull lba 223 */ 224 case ELF_OFFSET_STATE: 225 nb_rest -= nb_read; 226 227 if (nb_rest == 0) 228 { 229 nb_rest = elf_phdr_ptr[pseg].p_filesz; 230 init_state = ELF_SEGMENT_STATE; 231 } 232 233 break; 234 235 /* 236 * Reading ELF segments 237 * 238 * TODO: 239 * Do not pass by block buffer but write directly in target memory 240 * address 241 */ 242 case ELF_SEGMENT_STATE: 243 /* 244 * Verify that loadable segment does not conflict with 245 * pre-loader memory space 246 */ 247 pseg_start = elf_phdr_ptr[pseg].p_paddr; 248 249 pseg_end = elf_phdr_ptr[pseg].p_paddr + 250 elf_phdr_ptr[pseg].p_memsz; 251 252 if ((pseg_start >= 0xBFC00000 && pseg_start <= 0xBFC10000) || 253 (pseg_end >= 0xBFC00000 && pseg_end <= 0xBFC10000) || 254 (pseg_start < 0xBFC00000 && pseg_end > 0xBFC10000)) 255 { 256 reset_puts("[RESET ERROR] conflict with pre-loader memory space\n"); 257 reset_exit(); 258 } 259 260 /* 261 * Copy the ELF segment data in memory using the 262 * virtual address obtained from the ELF file 263 */ 264 pseg_ptr = (unsigned char *) 265 elf_phdr_ptr[pseg].p_paddr + 266 elf_phdr_ptr[pseg].p_filesz - 267 nb_rest; 268 269 memcpy(pseg_ptr, buffer_ptr, nb_read); 270 271 nb_rest -= nb_read; 272 273 if (nb_rest == 0) 274 { 275 /* 276 * Fill remaining bytes with zeros (filesz < memsz) 277 */ 278 pseg_remainder = 279 elf_phdr_ptr[pseg].p_memsz - 280 elf_phdr_ptr[pseg].p_filesz ; 281 282 pseg_ptr = (unsigned char *) 283 elf_phdr_ptr[pseg].p_paddr + 284 elf_phdr_ptr[pseg].p_filesz ; 285 286 memset(pseg_ptr, 0, pseg_remainder); 287 288 reset_puts("\n[RESET] Segment loaded : address = "); 289 reset_putx(elf_phdr_ptr[pseg].p_paddr); 290 reset_puts(" / size = "); 291 reset_putx(elf_phdr_ptr[pseg].p_filesz); 292 reset_puts("\n"); 293 294 /* 295 * Search the next first not NULL segment in the ELF file 296 */ 297 for (pseg += 1; pseg < elf_ehdr_ptr->e_phnum; pseg++) 298 { 299 if(elf_phdr_ptr[pseg].p_type == PT_LOAD) 300 { 301 #if (RESET_DEBUG == 1) 302 reset_puts("loadable segment found:\n"); 303 reset_print_elf_phdr(&elf_phdr_ptr[pseg]); 304 #endif 305 nb_rest = elf_phdr_ptr[pseg].p_offset - offset; 306 break; 307 } 308 } 309 310 /* 311 * Program loading finished 312 */ 313 if(pseg == elf_ehdr_ptr->e_phnum) 314 { 315 init_state = ELF_END_STATE; 316 break; 317 } 318 319 init_state = ELF_OFFSET_STATE; 320 } 321 break; 322 323 default: 324 break; 325 } 326 327 buffer_ptr += nb_read; 328 nb_available -= nb_read; 79 reset_puts("\n[RESET] Segment loaded : address = "); 80 reset_putx(p_paddr); 81 reset_puts(" / size = "); 82 reset_putx(p_filesz); 83 reset_puts("\n"); 329 84 } 330 85 … … 332 87 reset_putd( proctime() ); 333 88 reset_puts(" / boot entry = "); 334 reset_putx( ( unsigned int)(elf_ehdr_ptr->e_entry) );89 reset_putx( (addr_t)(elf_header.e_entry) ); 335 90 reset_puts("\n"); 336 91 337 return ((void *) elf_ehdr_ptr->e_entry); 92 return ((void *) elf_header.e_entry); 93 94 error: 95 reset_puts("\n[RESET ERROR] Error while loading ELF file"); 96 reset_exit(); 97 return 0; 338 98 } 339 99
Note: See TracChangeset
for help on using the changeset viewer.