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

Last change on this file since 625 was 625, checked in by alain, 5 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

File size: 11.0 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>
[457]25#include <hal_kernel_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)
[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__);
[441]62
[270]63        if( (header->e_machine != EM_MIPS) &&
64            (header->e_machine != EM_MIPS_RS3_LE) &&
65            (header->e_machine != EM_X86_64) )
[157]66                printk("\n[ERROR] in %s : unexpected core / accept only MIPS or x86_64\n", __FUNCTION__ );
[1]67
[270]68        if( header->e_type != ET_EXEC )
[156]69                printk("\n[ERROR] in %s : Elf is not executable binary\n", __FUNCTION__ );
[1]70
71        return false;
72}
73
74///////////////////////////////////////////////////////////////////////////////////////
[156]75// This function loads the .elf header in the buffer allocated by the caller.
[204]76///////////////////////////////////////////////////////////////////////////////////////
[1]77// @ file   : extended pointer on the remote file descriptor.
78// @ buffer : pointer on buffer allocated by the caller.
79// @ size   : number of bytes to read.
80///////////////////////////////////////////////////////////////////////////////////////
[204]81static error_t elf_header_load( xptr_t   file_xp,
[1]82                                void   * buffer,
83                                uint32_t size )
[156]84{
[332]85        error_t   error;
[328]86        xptr_t    buf_xp;
[1]87
[337]88        buf_xp = XPTR( local_cxy , buffer );
[328]89
[156]90        // load .elf header
[332]91        error = vfs_kernel_move( true,     // to_buffer
[328]92                                 file_xp,
93                                 buf_xp,
94                                 size );
[1]95
[332]96        if( error )
[1]97        {
[332]98                printk("\n[ERROR] in %s : cannot read ELF header size : %d\n",
99               __FUNCTION__ , size );
[1]100                return -1;
101        }
102
[227]103        Elf_Ehdr * header = (Elf_Ehdr *)buffer;
[156]104
[1]105        if( (header->e_ident[EI_MAG0] != ELFMAG0) ||
106            (header->e_ident[EI_MAG1] != ELFMAG1) ||
107            (header->e_ident[EI_MAG2] != ELFMAG2) ||
108            (header->e_ident[EI_MAG3] != ELFMAG3) )
109        {
[332]110                printk("\n[ERROR] in %s : file not in ELF format\n", __FUNCTION__ );
[1]111                return -1;
112        }
113
114        if( !(elf_isValidHeader( header ) ) )
115        {
116                printk("\n[ERROR] in %s : not supported Elf\n", __FUNCTION__ );
117                return -1;
118        }
119        return 0;
120
[204]121} // end elf_header_load()
122
[1]123///////////////////////////////////////////////////////////////////////////////////////
124// This function registers in the process VMM the CODE and DATA segments.
[204]125///////////////////////////////////////////////////////////////////////////////////////
[1]126// @ file      : extended pointer on the remote file descriptor.
127// @ segs_base : local pointer on buffer containing the segments descriptors array
128// @ segs_nr   : number of segments in segment descriptors array.
129// @ process   : local pointer on process descriptor.
130///////////////////////////////////////////////////////////////////////////////////////
[313]131static error_t elf_segments_register( xptr_t       file_xp,
132                                      void       * segs_base,
133                                      uint32_t     nb_segs,
134                                      process_t  * process )
[1]135{
136        uint32_t     index;
[313]137        intptr_t     file_size;
138        intptr_t     mem_size;
139        intptr_t     file_offset;
140        intptr_t     vbase;
[1]141        uint32_t     type;
142        uint32_t     flags;
[156]143        vseg_t     * vseg;
[1]144
[227]145        Elf_Phdr * seg_ptr = (Elf_Phdr *)segs_base;
[1]146
[156]147        // loop on segments
148        for( index = 0 ; index < nb_segs ; index++ , seg_ptr++ )
149        {
150                if( seg_ptr->p_type != PT_LOAD)
151                        continue;
152
153                // get segment attributes
[313]154                vbase       = seg_ptr->p_vaddr;     // vseg base vaddr
155                mem_size    = seg_ptr->p_memsz;     // actual vseg size
156                file_offset = seg_ptr->p_offset;    // vseg offset in .elf file
157                file_size   = seg_ptr->p_filesz;    // vseg size in .elf file
158                flags       = seg_ptr->p_flags;
[1]159
160                if( flags & PF_X ) // found CODE segment
161                {
[156]162                        type                       = VSEG_TYPE_CODE;
[315]163                        process->vmm.code_vpn_base = vbase >> CONFIG_PPM_PAGE_SHIFT;
[1]164                }
[156]165                else               // found DATA segment
[1]166                {
[156]167                        type                       = VSEG_TYPE_DATA;
[315]168                        process->vmm.data_vpn_base = vbase >> CONFIG_PPM_PAGE_SHIFT;
[1]169                }
170
[407]171        // get .elf file descriptor cluster and local pointer
172        cxy_t        file_cxy = GET_CXY( file_xp );
173        vfs_file_t * file_ptr = (vfs_file_t *)GET_PTR( file_xp );
174
175        // get local pointer on .elf file mapper
176        mapper_t * mapper_ptr = (mapper_t *)hal_remote_lpt( XPTR( file_cxy , 
177                                                                  &file_ptr->mapper ) );
[156]178                // register vseg in VMM
179                vseg = (vseg_t *)vmm_create_vseg( process,
[407]180                                          type,
[313]181                                                  vbase,
[156]182                                                  mem_size,
[407]183                                          file_offset,
184                                          file_size,
185                                          XPTR( file_cxy , mapper_ptr ),
186                                                  local_cxy ); 
[1]187                if( vseg == NULL )
188                {
189                        printk("\n[ERROR] in %s : cannot map segment / base = %x / size = %x\n",
[313]190                               __FUNCTION__ , vbase , mem_size );
[1]191                        return -1;
192                }
193
[313]194        // update reference counter in file descriptor
[1]195                vfs_file_count_up( file_xp );
[406]196
[438]197#if DEBUG_ELF_LOAD
[625]198uint32_t   cycle = (uint32_t)hal_get_cycles();
199thread_t * this  = CURRENT_THREAD;
[438]200if( DEBUG_ELF_LOAD < cycle )
[625]201printk("\n[%s] thread[%x,%x] found %s vseg / base %x / size %x\n"
[433]202"  file_size %x / file_offset %x / mapper_xp %l / cycle %d\n",
[625]203__FUNCTION__ , this->process_pid, this->trdid, 
204vseg_type_str(vseg->type) , vseg->min , vseg->max - vseg->min ,
[433]205vseg->file_size , vseg->file_offset , vseg->mapper_xp );
206#endif
207
[1]208        }
209
210        return 0;
211
[313]212} // end elf_segments_register()
[204]213
[457]214//////////////////////////////////////////////
215error_t elf_load_process( xptr_t      file_xp,
216                          process_t * process )
[1]217{
218        kmem_req_t   req;              // kmem request for program header
[227]219        Elf_Ehdr     header;           // local buffer for .elf header
[1]220        void       * segs_base;        // pointer on buffer for segment descriptors array
[156]221        uint32_t     segs_size;        // size of buffer for segment descriptors array
[457]222    char         name[CONFIG_VFS_MAX_NAME_LENGTH];
[1]223        error_t      error;
224
[457]225    // get file name for error reporting and debug
226    cxy_t         file_cxy = GET_CXY( file_xp );
227    vfs_file_t  * file_ptr = GET_PTR( file_xp );
228    vfs_inode_t * inode    = hal_remote_lpt( XPTR( file_cxy , &file_ptr->inode ) );
229    vfs_inode_get_name( XPTR( file_cxy , inode ) , name );
230   
[438]231#if DEBUG_ELF_LOAD
[603]232uint32_t   cycle = (uint32_t)hal_get_cycles();
233thread_t * this  = CURRENT_THREAD;
[438]234if( DEBUG_ELF_LOAD < cycle )
[603]235printk("\n[%s] thread[%x,%x] enter for <%s> / cycle %d\n",
236__FUNCTION__, this->process->pid, this->trdid, name, cycle );
[433]237#endif
[1]238
[156]239        // load header in local buffer
[204]240        error = elf_header_load( file_xp ,
[156]241                                 &header,
[227]242                                 sizeof(Elf_Ehdr) );
[156]243        if( error )
244        {
[457]245                printk("\n[ERROR] in %s : cannot get header for <%s>\n", __FUNCTION__ , name );
[156]246                return -1;
247        }
[1]248
[438]249#if (DEBUG_ELF_LOAD & 1)
250if( DEBUG_ELF_LOAD < cycle )
[603]251printk("\n[%s] loaded elf header for <%s>\n", __FUNCTION__ , name );
[433]252#endif
[1]253
254        if( header.e_phnum == 0 )
255        {
256                printk("\n[ERROR] in %s : no segments found\n", __FUNCTION__ );
257                return -1;
258        }
259
[156]260        // compute buffer size for segment descriptors array
[227]261        segs_size = sizeof(Elf_Phdr) * header.e_phnum;
[156]262
263        // allocate memory for segment descriptors array
[1]264        req.type  = KMEM_GENERIC;
265        req.size  = segs_size;
266        req.flags = AF_KERNEL;
267        segs_base = kmem_alloc( &req );
268
269        if( segs_base == NULL )
[156]270        {
[1]271                printk("\n[ERROR] in %s : no memory for segment descriptors\n", __FUNCTION__ );
[156]272                return -1;
273        }
[1]274
[156]275        // set seek pointer in file descriptor to access segment descriptors array
[23]276        error = vfs_lseek( file_xp , header.e_phoff, SEEK_SET , NULL );
[1]277
278        if( error )
279        {
280                printk("\n[ERROR] in %s : cannot seek for descriptors array\n", __FUNCTION__ );
[156]281                req.ptr = segs_base;
282                kmem_free( &req );
[1]283                return -1;
284        }
285
[438]286#if (DEBUG_ELF_LOAD & 1)
287if( DEBUG_ELF_LOAD < cycle )
[603]288printk("\n[%s] segments array allocated for <%s>\n", __FUNCTION__ , name );
[433]289#endif
[367]290
[156]291        // load seg descriptors array to local buffer
[367]292        error = vfs_kernel_move( true,                  // to_buffer
293                                 file_xp,
294                                 XPTR( local_cxy , segs_base ),
295                                 segs_size );
[1]296
[333]297        if( error )
[1]298        {
299                printk("\n[ERROR] in %s : cannot read segments descriptors\n", __FUNCTION__ );
[156]300                req.ptr = segs_base;
301                kmem_free( &req );
[1]302                return -1;
303        }
304
[438]305#if (DEBUG_ELF_LOAD & 1)
306if( DEBUG_ELF_LOAD < cycle )
[603]307printk("\n[%s] loaded segments descriptors for <%s>\n", __FUNCTION__ , name );
[433]308#endif
[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                req.ptr = segs_base;
318                kmem_free( &req );
[1]319                return -1;
[156]320        }
[1]321
[156]322        // register process entry point in VMM
[1]323        process->vmm.entry_point = (intptr_t)header.e_entry;
324
[156]325        // register extended pointer on .elf file descriptor
326        process->vfs_bin_xp = file_xp;
[1]327
[156]328        // release allocated memory for program header
[1]329        req.ptr = segs_base;
330        kmem_free(&req);
331
[438]332#if DEBUG_ELF_LOAD
[433]333cycle = (uint32_t)hal_get_cycles();
[438]334if( DEBUG_ELF_LOAD < cycle )
[603]335printk("\n[%s] thread[%x,%x] exit for <%s> / entry_point %x / cycle %d\n",
336__FUNCTION__, this->process->pid, this->trdid, name, header.e_entry, cycle );
[433]337#endif
[1]338
339        return 0;
340
[204]341}  // end elf_load_process()
342
Note: See TracBrowser for help on using the repository browser.