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

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

1) Introduce independant command fields for the various devices in the thread descriptor.
2) Introduce a new dev_pic_enable_ipi() function in the generic PIC device
3) Fix two bugs identified by Maxime in the scheduler initialisation, and in the sched_select().
4) fix several bugs in the TSAR hal_kentry.S.
5) Introduce a third kgiet segment (besides kdata and kcode) in the TSAR bootloader.

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