source: trunk/kernel/libk/elf.c @ 406

Last change on this file since 406 was 406, checked in by alain, 4 years ago

This version executed successfully the user "init" process on a mono-processor TSAR architecture.

File size: 11.1 KB
RevLine 
[1]1/*
2 * elf.c - elf parser: find and map process CODE and DATA segments
3 *
4 * Authors   Alain Greiner    (2016)
5 *
6 * Copyright (c) UPMC Sorbonne Universites
7 *
8 * This file is part of ALMOS-MKH.
9 *
10 * ALMOS-MKH is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; version 2.0 of the License.
13 *
14 * ALMOS-MKH is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
[14]24#include <kernel_config.h>
[1]25#include <hal_types.h>
[406]26#include <hal_special.h>
[1]27#include <hal_uspace.h>
28#include <printk.h>
29#include <process.h>
[406]30#include <thread.h>
31#include <mapper.h>
[1]32#include <vseg.h>
33#include <kmem.h>
34#include <vfs.h>
35#include <elf.h>
[23]36#include <syscalls.h>
[1]37
38///////////////////////////////////////////////////////////////////
39// This static function checks the .elf header.
40// - return true if legal header.
41// - return false with an error message if illegal header.
42///////////////////////////////////////////////////////////////////
[227]43static bool_t elf_isValidHeader(Elf_Ehdr *header)
[1]44{
[270]45        if((header->e_ident[EI_CLASS] == ELFCLASS)
[156]46           && (header->e_ident[EI_DATA] == ELFDATA2LSB)
[1]47           && (header->e_ident[EI_VERSION] == EV_CURRENT)
[270]48/*
[1]49           && (header->e_ident[EI_OSABI] == ELFOSABI_NONE)
[270]50*/
[156]51           && ((header->e_machine == EM_MIPS) ||
[1]52               (header->e_machine == EM_MIPS_RS3_LE) ||
[157]53               (header->e_machine == EM_X86_64))
[156]54           && (header->e_type == ET_EXEC))
55                return true;
56
[270]57        if( header->e_ident[EI_CLASS] != ELFCLASS )
58                printk("\n[ERROR] in %s : Elf is not 32/64-Binary\n", __FUNCTION__ );
[1]59
60        if( header->e_ident[EI_DATA] != ELFDATA2LSB )
[156]61                printk("\n[ERROR] in %s : Elf is not 2's complement, little endian\n", __FUNCTION__ );
[1]62
[156]63        if( header->e_ident[EI_VERSION] != EV_CURRENT )
64                printk("\n[ERROR] in %s : Elf is not in Current Version\n", __FUNCTION__);
[270]65/*
[1]66        if( header->e_ident[EI_OSABI] != ELFOSABI_NONE )
[156]67                printk("\n[ERROR] in %s : Unexpected Elf ABI, need UNIX System V ABI\n", __FUNCTION__ );
[270]68*/
69        if( (header->e_machine != EM_MIPS) &&
70            (header->e_machine != EM_MIPS_RS3_LE) &&
71            (header->e_machine != EM_X86_64) )
[157]72                printk("\n[ERROR] in %s : unexpected core / accept only MIPS or x86_64\n", __FUNCTION__ );
[1]73
[270]74        if( header->e_type != ET_EXEC )
[156]75                printk("\n[ERROR] in %s : Elf is not executable binary\n", __FUNCTION__ );
[1]76
77        return false;
78}
79
80///////////////////////////////////////////////////////////////////////////////////////
[156]81// This function loads the .elf header in the buffer allocated by the caller.
[204]82///////////////////////////////////////////////////////////////////////////////////////
[1]83// @ file   : extended pointer on the remote file descriptor.
84// @ buffer : pointer on buffer allocated by the caller.
85// @ size   : number of bytes to read.
86///////////////////////////////////////////////////////////////////////////////////////
[204]87static error_t elf_header_load( xptr_t   file_xp,
[1]88                                void   * buffer,
89                                uint32_t size )
[156]90{
[332]91        error_t   error;
[328]92        xptr_t    buf_xp;
[1]93
[337]94        buf_xp = XPTR( local_cxy , buffer );
[328]95
[156]96        // load .elf header
[332]97        error = vfs_kernel_move( true,     // to_buffer
[328]98                                 file_xp,
99                                 buf_xp,
100                                 size );
[1]101
[332]102        if( error )
[1]103        {
[332]104                printk("\n[ERROR] in %s : cannot read ELF header size : %d\n",
105               __FUNCTION__ , size );
[1]106                return -1;
107        }
108
[227]109        Elf_Ehdr * header = (Elf_Ehdr *)buffer;
[156]110
[1]111        if( (header->e_ident[EI_MAG0] != ELFMAG0) ||
112            (header->e_ident[EI_MAG1] != ELFMAG1) ||
113            (header->e_ident[EI_MAG2] != ELFMAG2) ||
114            (header->e_ident[EI_MAG3] != ELFMAG3) )
115        {
[332]116                printk("\n[ERROR] in %s : file not in ELF format\n", __FUNCTION__ );
[1]117                return -1;
118        }
119
120        if( !(elf_isValidHeader( header ) ) )
121        {
122                printk("\n[ERROR] in %s : not supported Elf\n", __FUNCTION__ );
123                return -1;
124        }
125        return 0;
126
[204]127} // end elf_header_load()
128
[1]129///////////////////////////////////////////////////////////////////////////////////////
130// This function registers in the process VMM the CODE and DATA segments.
[204]131///////////////////////////////////////////////////////////////////////////////////////
[1]132// @ file      : extended pointer on the remote file descriptor.
133// @ segs_base : local pointer on buffer containing the segments descriptors array
134// @ segs_nr   : number of segments in segment descriptors array.
135// @ process   : local pointer on process descriptor.
136///////////////////////////////////////////////////////////////////////////////////////
[313]137static error_t elf_segments_register( xptr_t       file_xp,
138                                      void       * segs_base,
139                                      uint32_t     nb_segs,
140                                      process_t  * process )
[1]141{
142        uint32_t     index;
[313]143        intptr_t     file_size;
144        intptr_t     mem_size;
145        intptr_t     file_offset;
146        intptr_t     vbase;
[1]147        uint32_t     type;
148        uint32_t     flags;
[156]149        vseg_t     * vseg;
[1]150
[227]151        Elf_Phdr * seg_ptr = (Elf_Phdr *)segs_base;
[1]152
[156]153        // loop on segments
154        for( index = 0 ; index < nb_segs ; index++ , seg_ptr++ )
155        {
156                if( seg_ptr->p_type != PT_LOAD)
157                        continue;
158
159                // get segment attributes
[313]160                vbase       = seg_ptr->p_vaddr;     // vseg base vaddr
161                mem_size    = seg_ptr->p_memsz;     // actual vseg size
162                file_offset = seg_ptr->p_offset;    // vseg offset in .elf file
163                file_size   = seg_ptr->p_filesz;    // vseg size in .elf file
164                flags       = seg_ptr->p_flags;
[1]165
166                if( flags & PF_X ) // found CODE segment
167                {
[156]168                        type                       = VSEG_TYPE_CODE;
[315]169                        process->vmm.code_vpn_base = vbase >> CONFIG_PPM_PAGE_SHIFT;
[1]170                }
[156]171                else               // found DATA segment
[1]172                {
[156]173                        type                       = VSEG_TYPE_DATA;
[315]174                        process->vmm.data_vpn_base = vbase >> CONFIG_PPM_PAGE_SHIFT;
[1]175                }
176
[156]177                // register vseg in VMM
178                vseg = (vseg_t *)vmm_create_vseg( process,
[313]179                                                  vbase,
[156]180                                                  mem_size,
181                                                  type );
[1]182                if( vseg == NULL )
183                {
184                        printk("\n[ERROR] in %s : cannot map segment / base = %x / size = %x\n",
[313]185                               __FUNCTION__ , vbase , mem_size );
[1]186                        return -1;
187                }
188
[313]189        // get .elf file descriptor cluster and local pointer
190        cxy_t        file_cxy = GET_CXY( file_xp );
191        vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp );
192
[406]193        // get local pointer on .elf file mapper
194        mapper_t * mapper_ptr = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , 
195                                                                  &file_ptr->mapper ) );
196
[313]197        // initialize "file_mapper", "file_offset", "file_size" fields in vseg
[406]198        vseg->mapper_xp   = XPTR( file_cxy , mapper_ptr );
[313]199        vseg->file_offset = file_offset;
200        vseg->file_size   = file_size;
201
202        // update reference counter in file descriptor
[1]203                vfs_file_count_up( file_xp );
[406]204
205                elf_dmsg("\n[DMSG] %s : found %s vseg / base = %x / size = %x\n"
206                 "       file_size = %x / file_offset = %x / mapper_xp = %l\n",
207            __FUNCTION__ , vseg_type_str(vseg->type) , vseg->min , vseg->max - vseg->min ,
208        vseg->file_size , vseg->file_offset , vseg->mapper_xp );
[1]209        }
210
211        return 0;
212
[313]213} // end elf_segments_register()
[204]214
[1]215///////////////////////////////////////////////
216error_t elf_load_process( char      * pathname,
217                          process_t * process)
218{
219        kmem_req_t   req;              // kmem request for program header
[227]220        Elf_Ehdr     header;           // local buffer for .elf header
[1]221        void       * segs_base;        // pointer on buffer for segment descriptors array
[156]222        uint32_t     segs_size;        // size of buffer for segment descriptors array
[1]223        xptr_t       file_xp;          // extended pointer on created file descriptor
[156]224        uint32_t     file_id;          // file descriptor index (unused)
[1]225        error_t      error;
226
[406]227    elf_dmsg("\n[DMSG] %s : core[%x,%d] enter for <%s>\n",
[401]228    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , pathname );
[1]229
[204]230    // avoid GCC warning
231        file_xp = XPTR_NULL; 
232        file_id = -1;
[1]233
[156]234        // open file
235        error = vfs_open( process->vfs_cwd_xp,
[204]236                          pathname,
[156]237                          O_RDONLY,
238                          0,
239                          &file_xp,
240                          &file_id );
[1]241        if( error )
242        {
[204]243                printk("\n[ERROR] in %s : failed to open file %s\n", __FUNCTION__ , pathname );
[1]244                return -1;
245        }
246
[406]247    elf_dmsg("\n[DMSG] %s : open file <%s>\n", __FUNCTION__ , pathname );
[204]248
[156]249        // load header in local buffer
[204]250        error = elf_header_load( file_xp ,
[156]251                                 &header,
[227]252                                 sizeof(Elf_Ehdr) );
[156]253        if( error )
254        {
[204]255                printk("\n[ERROR] in %s : cannot get header file %s\n", __FUNCTION__ , pathname );
[156]256                vfs_close( file_xp , file_id );
257                return -1;
258        }
[1]259
[406]260        elf_dmsg("\n[DMSG] %s : loaded elf header for %s\n", __FUNCTION__ , pathname );
[1]261
262        if( header.e_phnum == 0 )
263        {
264                printk("\n[ERROR] in %s : no segments found\n", __FUNCTION__ );
[156]265                vfs_close( file_xp , file_id );
[1]266                return -1;
267        }
268
[156]269        // compute buffer size for segment descriptors array
[227]270        segs_size = sizeof(Elf_Phdr) * header.e_phnum;
[156]271
272        // allocate memory for segment descriptors array
[1]273        req.type  = KMEM_GENERIC;
274        req.size  = segs_size;
275        req.flags = AF_KERNEL;
276        segs_base = kmem_alloc( &req );
277
278        if( segs_base == NULL )
[156]279        {
[1]280                printk("\n[ERROR] in %s : no memory for segment descriptors\n", __FUNCTION__ );
[156]281                vfs_close( file_xp , file_id );
282                return -1;
283        }
[1]284
[156]285        // set seek pointer in file descriptor to access segment descriptors array
[23]286        error = vfs_lseek( file_xp , header.e_phoff, SEEK_SET , NULL );
[1]287
288        if( error )
289        {
290                printk("\n[ERROR] in %s : cannot seek for descriptors array\n", __FUNCTION__ );
[156]291                vfs_close( file_xp , file_id );
292                req.ptr = segs_base;
293                kmem_free( &req );
[1]294                return -1;
295        }
296
[406]297        elf_dmsg("\n[DMSG] %s : segments array allocated for %s\n", __FUNCTION__ , pathname );
[367]298
[156]299        // load seg descriptors array to local buffer
[367]300        error = vfs_kernel_move( true,                  // to_buffer
301                                 file_xp,
302                                 XPTR( local_cxy , segs_base ),
303                                 segs_size );
[1]304
[333]305        if( error )
[1]306        {
307                printk("\n[ERROR] in %s : cannot read segments descriptors\n", __FUNCTION__ );
[156]308                vfs_close( file_xp , file_id );
309                req.ptr = segs_base;
310                kmem_free( &req );
[1]311                return -1;
312        }
313
[406]314        elf_dmsg("\n[DMSG] %s loaded segments descriptors for %s \n", __FUNCTION__ , pathname );
[1]315
[156]316        // register loadable segments in process VMM
[313]317        error = elf_segments_register( file_xp,
318                                       segs_base,
319                                       header.e_phnum,
320                                       process );
[1]321        if( error )
[156]322        {
323                vfs_close( file_xp , file_id );
324                req.ptr = segs_base;
325                kmem_free( &req );
[1]326                return -1;
[156]327        }
[1]328
[156]329        // register process entry point in VMM
[1]330        process->vmm.entry_point = (intptr_t)header.e_entry;
331
[156]332        // register extended pointer on .elf file descriptor
333        process->vfs_bin_xp = file_xp;
[1]334
[156]335        // release allocated memory for program header
[1]336        req.ptr = segs_base;
337        kmem_free(&req);
338
[406]339    elf_dmsg("\n[DMSG] %s : core[%x,%d] exit for <%s> / entry_point = %x\n",
[401]340    __FUNCTION__ , local_cxy , CURRENT_THREAD->core->lid , pathname , header.e_entry );
[1]341
342        return 0;
343
[204]344}  // end elf_load_process()
345
Note: See TracBrowser for help on using the repository browser.