Ignore:
Timestamp:
May 25, 2014, 5:35:37 PM (10 years ago)
Author:
cfuguet
Message:

tsar_boot:

  • Important optimization in the reset_elf_loader function.
  • Implementation of pread function which uses bytes addressing to read disk.
  • pread function alternates between direct tranfer from disk to memory and from disk to a memory cache block based on alignment of byte address, i.e., when file offset is aligned to disk block (512 bytes), pread uses DMA capacity of disk to transfer directly to memory, otherwise it passes before by a memory cache block and then performs a memcpy to transfer data to final destination.
  • the cache block used by pread function, allows to treat succeeding reads on the same block without accessing the disk.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/softs/tsar_boot/src/reset_elf_loader.c

    r694 r701  
    1616#include <defs.h>
    1717
    18 #if (RESET_DEBUG == 1)
    19 static char const * const init_state_str[] =
     18///////////////////////////////////////////////////////////////////////////////
     19void * reset_elf_loader(size_t lba)
     20///////////////////////////////////////////////////////////////////////////////
    2021{
    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;
    7623
    7724    reset_puts("\n[RESET] Start reset_elf_loader at cycle ");
     
    7926    reset_puts("\n");
    8027
    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);
    8836
    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++)
    9052    {
    91         if (nb_available == 0 )
    92         {
    93             buffer_ptr = &reset_elf_loader_buffer[0];
     53        if(elf_pht[pseg].p_type != PT_LOAD) continue;
    9454
    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
    10059
    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;
    10371        }
    10472
    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));
    10778
    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");
    32984    }
    33085
     
    33287    reset_putd( proctime() );
    33388    reset_puts(" / boot entry = ");
    334     reset_putx( (unsigned int)(elf_ehdr_ptr->e_entry) );
     89    reset_putx( (addr_t)(elf_header.e_entry) );
    33590    reset_puts("\n");
    33691
    337     return ((void *) elf_ehdr_ptr->e_entry);
     92    return ((void *) elf_header.e_entry);
     93
     94error:
     95    reset_puts("\n[RESET ERROR] Error while loading ELF file");
     96    reset_exit();
     97    return 0;
    33898}
    33999
Note: See TracChangeset for help on using the changeset viewer.