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

Last change on this file since 448 was 441, checked in by alain, 6 years ago

Fix a bug in rpc_vmm_get_pte_client() function (bad RPC index).

File size: 11.4 KB
Line 
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
24#include <kernel_config.h>
25#include <hal_types.h>
26#include <hal_special.h>
27#include <hal_uspace.h>
28#include <printk.h>
29#include <process.h>
30#include <thread.h>
31#include <mapper.h>
32#include <vseg.h>
33#include <kmem.h>
34#include <vfs.h>
35#include <elf.h>
36#include <syscalls.h>
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///////////////////////////////////////////////////////////////////
43static bool_t elf_isValidHeader(Elf_Ehdr *header)
44{
45        if((header->e_ident[EI_CLASS] == ELFCLASS)
46           && (header->e_ident[EI_DATA] == ELFDATA2LSB)
47           && (header->e_ident[EI_VERSION] == EV_CURRENT)
48           && ((header->e_machine == EM_MIPS) ||
49               (header->e_machine == EM_MIPS_RS3_LE) ||
50               (header->e_machine == EM_X86_64))
51           && (header->e_type == ET_EXEC))
52                return true;
53
54        if( header->e_ident[EI_CLASS] != ELFCLASS )
55                printk("\n[ERROR] in %s : Elf is not 32/64-Binary\n", __FUNCTION__ );
56
57        if( header->e_ident[EI_DATA] != ELFDATA2LSB )
58                printk("\n[ERROR] in %s : Elf is not 2's complement, little endian\n", __FUNCTION__ );
59
60        if( header->e_ident[EI_VERSION] != EV_CURRENT )
61                printk("\n[ERROR] in %s : Elf is not in Current Version\n", __FUNCTION__);
62
63        if( (header->e_machine != EM_MIPS) &&
64            (header->e_machine != EM_MIPS_RS3_LE) &&
65            (header->e_machine != EM_X86_64) )
66                printk("\n[ERROR] in %s : unexpected core / accept only MIPS or x86_64\n", __FUNCTION__ );
67
68        if( header->e_type != ET_EXEC )
69                printk("\n[ERROR] in %s : Elf is not executable binary\n", __FUNCTION__ );
70
71        return false;
72}
73
74///////////////////////////////////////////////////////////////////////////////////////
75// This function loads the .elf header in the buffer allocated by the caller.
76///////////////////////////////////////////////////////////////////////////////////////
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///////////////////////////////////////////////////////////////////////////////////////
81static error_t elf_header_load( xptr_t   file_xp,
82                                void   * buffer,
83                                uint32_t size )
84{
85        error_t   error;
86        xptr_t    buf_xp;
87
88        buf_xp = XPTR( local_cxy , buffer );
89
90        // load .elf header
91        error = vfs_kernel_move( true,     // to_buffer
92                                 file_xp,
93                                 buf_xp,
94                                 size );
95
96        if( error )
97        {
98                printk("\n[ERROR] in %s : cannot read ELF header size : %d\n",
99               __FUNCTION__ , size );
100                return -1;
101        }
102
103        Elf_Ehdr * header = (Elf_Ehdr *)buffer;
104
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        {
110                printk("\n[ERROR] in %s : file not in ELF format\n", __FUNCTION__ );
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
121} // end elf_header_load()
122
123///////////////////////////////////////////////////////////////////////////////////////
124// This function registers in the process VMM the CODE and DATA segments.
125///////////////////////////////////////////////////////////////////////////////////////
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///////////////////////////////////////////////////////////////////////////////////////
131static error_t elf_segments_register( xptr_t       file_xp,
132                                      void       * segs_base,
133                                      uint32_t     nb_segs,
134                                      process_t  * process )
135{
136        uint32_t     index;
137        intptr_t     file_size;
138        intptr_t     mem_size;
139        intptr_t     file_offset;
140        intptr_t     vbase;
141        uint32_t     type;
142        uint32_t     flags;
143        vseg_t     * vseg;
144
145        Elf_Phdr * seg_ptr = (Elf_Phdr *)segs_base;
146
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
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;
159
160                if( flags & PF_X ) // found CODE segment
161                {
162                        type                       = VSEG_TYPE_CODE;
163                        process->vmm.code_vpn_base = vbase >> CONFIG_PPM_PAGE_SHIFT;
164                }
165                else               // found DATA segment
166                {
167                        type                       = VSEG_TYPE_DATA;
168                        process->vmm.data_vpn_base = vbase >> CONFIG_PPM_PAGE_SHIFT;
169                }
170
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 ) );
178                // register vseg in VMM
179                vseg = (vseg_t *)vmm_create_vseg( process,
180                                          type,
181                                                  vbase,
182                                                  mem_size,
183                                          file_offset,
184                                          file_size,
185                                          XPTR( file_cxy , mapper_ptr ),
186                                                  local_cxy ); 
187                if( vseg == NULL )
188                {
189                        printk("\n[ERROR] in %s : cannot map segment / base = %x / size = %x\n",
190                               __FUNCTION__ , vbase , mem_size );
191                        return -1;
192                }
193
194        // update reference counter in file descriptor
195                vfs_file_count_up( file_xp );
196
197#if DEBUG_ELF_LOAD
198uint32_t cycle = (uint32_t)hal_get_cycles();
199if( DEBUG_ELF_LOAD < cycle )
200printk("\n[DBG] %s : found %s vseg / base %x / size %x\n"
201"  file_size %x / file_offset %x / mapper_xp %l / cycle %d\n",
202__FUNCTION__ , vseg_type_str(vseg->type) , vseg->min , vseg->max - vseg->min ,
203vseg->file_size , vseg->file_offset , vseg->mapper_xp );
204#endif
205
206        }
207
208        return 0;
209
210} // end elf_segments_register()
211
212///////////////////////////////////////////////
213error_t elf_load_process( char      * pathname,
214                          process_t * process)
215{
216        kmem_req_t   req;              // kmem request for program header
217        Elf_Ehdr     header;           // local buffer for .elf header
218        void       * segs_base;        // pointer on buffer for segment descriptors array
219        uint32_t     segs_size;        // size of buffer for segment descriptors array
220        xptr_t       file_xp;          // extended pointer on created file descriptor
221        uint32_t     file_id;          // file descriptor index (unused)
222        error_t      error;
223
224#if DEBUG_ELF_LOAD
225uint32_t cycle = (uint32_t)hal_get_cycles();
226if( DEBUG_ELF_LOAD < cycle )
227printk("\n[DBG] %s : thread %d enter for <%s> / cycle %d\n",
228__FUNCTION__, CURRENT_THREAD, pathname, cycle );
229#endif
230
231    // avoid GCC warning
232        file_xp = XPTR_NULL; 
233        file_id = -1;
234
235        // open file
236        error = vfs_open( process,
237                          pathname,
238                          O_RDONLY,
239                          0,
240                          &file_xp,
241                          &file_id );
242        if( error )
243        {
244                printk("\n[ERROR] in %s : failed to open file <%s>\n", __FUNCTION__ , pathname );
245                return -1;
246        }
247
248#if (DEBUG_ELF_LOAD & 1)
249if( DEBUG_ELF_LOAD < cycle )
250printk("\n[DBG] %s : open file <%s>\n", __FUNCTION__, pathname );
251#endif
252
253        // load header in local buffer
254        error = elf_header_load( file_xp ,
255                                 &header,
256                                 sizeof(Elf_Ehdr) );
257        if( error )
258        {
259                printk("\n[ERROR] in %s : cannot get header for <%s>\n", __FUNCTION__ , pathname );
260                vfs_close( file_xp , file_id );
261                return -1;
262        }
263
264#if (DEBUG_ELF_LOAD & 1)
265if( DEBUG_ELF_LOAD < cycle )
266printk("\n[DBG] %s : loaded elf header for <%s>\n", __FUNCTION__ , pathname );
267#endif
268
269        if( header.e_phnum == 0 )
270        {
271                printk("\n[ERROR] in %s : no segments found\n", __FUNCTION__ );
272                vfs_close( file_xp , file_id );
273                return -1;
274        }
275
276        // compute buffer size for segment descriptors array
277        segs_size = sizeof(Elf_Phdr) * header.e_phnum;
278
279        // allocate memory for segment descriptors array
280        req.type  = KMEM_GENERIC;
281        req.size  = segs_size;
282        req.flags = AF_KERNEL;
283        segs_base = kmem_alloc( &req );
284
285        if( segs_base == NULL )
286        {
287                printk("\n[ERROR] in %s : no memory for segment descriptors\n", __FUNCTION__ );
288                vfs_close( file_xp , file_id );
289                return -1;
290        }
291
292        // set seek pointer in file descriptor to access segment descriptors array
293        error = vfs_lseek( file_xp , header.e_phoff, SEEK_SET , NULL );
294
295        if( error )
296        {
297                printk("\n[ERROR] in %s : cannot seek for descriptors array\n", __FUNCTION__ );
298                vfs_close( file_xp , file_id );
299                req.ptr = segs_base;
300                kmem_free( &req );
301                return -1;
302        }
303
304#if (DEBUG_ELF_LOAD & 1)
305if( DEBUG_ELF_LOAD < cycle )
306printk("\n[DBG] %s : segments array allocated for <%s>\n", __FUNCTION__ , pathname );
307#endif
308
309        // load seg descriptors array to local buffer
310        error = vfs_kernel_move( true,                  // to_buffer
311                                 file_xp,
312                                 XPTR( local_cxy , segs_base ),
313                                 segs_size );
314
315        if( error )
316        {
317                printk("\n[ERROR] in %s : cannot read segments descriptors\n", __FUNCTION__ );
318                vfs_close( file_xp , file_id );
319                req.ptr = segs_base;
320                kmem_free( &req );
321                return -1;
322        }
323
324#if (DEBUG_ELF_LOAD & 1)
325if( DEBUG_ELF_LOAD < cycle )
326printk("\n[DBG] %s loaded segments descriptors for <%s>\n", __FUNCTION__ , pathname );
327#endif
328
329        // register loadable segments in process VMM
330        error = elf_segments_register( file_xp,
331                                       segs_base,
332                                       header.e_phnum,
333                                       process );
334        if( error )
335        {
336                vfs_close( file_xp , file_id );
337                req.ptr = segs_base;
338                kmem_free( &req );
339                return -1;
340        }
341
342        // register process entry point in VMM
343        process->vmm.entry_point = (intptr_t)header.e_entry;
344
345        // register extended pointer on .elf file descriptor
346        process->vfs_bin_xp = file_xp;
347
348        // release allocated memory for program header
349        req.ptr = segs_base;
350        kmem_free(&req);
351
352#if DEBUG_ELF_LOAD
353cycle = (uint32_t)hal_get_cycles();
354if( DEBUG_ELF_LOAD < cycle )
355printk("\n[DBG] %s : thread %d exit for <%s> / entry_point %x / cycle %d\n",
356__FUNCTION__, CURRENT_THREAD, pathname, header.e_entry, cycle );
357#endif
358
359        return 0;
360
361}  // end elf_load_process()
362
Note: See TracBrowser for help on using the repository browser.