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

Last change on this file since 401 was 401, checked in by alain, 7 years ago

Few bugs in VMM

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