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

Last change on this file since 315 was 315, checked in by alain, 9 years ago

Redefine the fuctions ppm_base2page() / ppm_page2base() / ppm_page2ppn() / ppm_ppn2page() / ppm_base2ppn() / ppm_ppn2base(),
to use explicitely extended pointers.

File size: 10.6 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_user_move( true, // to_buffer
92 file_xp,
93 buffer,
94 size );
95
96 if( count != size )
97 {
98 printk("\n[ERROR] in %s : cannot read ELF header size : %d / done = %d\n",
99 __FUNCTION__ , size , count );
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 %s 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 elf_dmsg("\n[INFO] %s : found CODE vseg / base = %x / size = %x\n",
166 __FUNCTION__ , vbase , mem_size );
167 }
168 else // found DATA segment
169 {
170 type = VSEG_TYPE_DATA;
171 process->vmm.data_vpn_base = vbase >> CONFIG_PPM_PAGE_SHIFT;
172
173 elf_dmsg("\n[INFO] %s : found DATA vseg / base = %x / size = %x\n",
174 __FUNCTION__, vbase , mem_size );
175 }
176
177 // register vseg in VMM
178 vseg = (vseg_t *)vmm_create_vseg( process,
179 vbase,
180 mem_size,
181 type );
182 if( vseg == NULL )
183 {
184 printk("\n[ERROR] in %s : cannot map segment / base = %x / size = %x\n",
185 __FUNCTION__ , vbase , mem_size );
186 return -1;
187 }
188
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
193 // initialize "file_mapper", "file_offset", "file_size" fields in vseg
194 vseg->mapper_xp = (xptr_t)hal_remote_lwd( XPTR( file_cxy , &file_ptr->mapper ) );
195 vseg->file_offset = file_offset;
196 vseg->file_size = file_size;
197
198 // update reference counter in file descriptor
199 vfs_file_count_up( file_xp );
200 }
201
202 return 0;
203
204} // end elf_segments_register()
205
206///////////////////////////////////////////////
207error_t elf_load_process( char * pathname,
208 process_t * process)
209{
210 kmem_req_t req; // kmem request for program header
211 Elf_Ehdr header; // local buffer for .elf header
212 void * segs_base; // pointer on buffer for segment descriptors array
213 uint32_t segs_size; // size of buffer for segment descriptors array
214 xptr_t file_xp; // extended pointer on created file descriptor
215 uint32_t file_id; // file descriptor index (unused)
216 uint32_t count; // bytes counter
217 error_t error;
218
219 elf_dmsg("\n[INFO] %s : enters for <%s>\n", __FUNCTION__ , pathname );
220
221 // avoid GCC warning
222 file_xp = XPTR_NULL;
223 file_id = -1;
224
225 // open file
226 error = vfs_open( process->vfs_cwd_xp,
227 pathname,
228 O_RDONLY,
229 0,
230 &file_xp,
231 &file_id );
232 if( error )
233 {
234 printk("\n[ERROR] in %s : failed to open file %s\n", __FUNCTION__ , pathname );
235 return -1;
236 }
237
238 elf_dmsg("\n[INFO] %s : file <%s> open\n", __FUNCTION__ , pathname );
239
240 // load header in local buffer
241 error = elf_header_load( file_xp ,
242 &header,
243 sizeof(Elf_Ehdr) );
244 if( error )
245 {
246 printk("\n[ERROR] in %s : cannot get header file %s\n", __FUNCTION__ , pathname );
247 vfs_close( file_xp , file_id );
248 return -1;
249 }
250
251 elf_dmsg("\n[INFO] %s : loaded elf header for %s\n", __FUNCTION__ , pathname );
252
253 if( header.e_phnum == 0 )
254 {
255 printk("\n[ERROR] in %s : no segments found\n", __FUNCTION__ );
256 vfs_close( file_xp , file_id );
257 return -1;
258 }
259
260 // compute buffer size for segment descriptors array
261 segs_size = sizeof(Elf_Phdr) * header.e_phnum;
262
263 // allocate memory for segment descriptors array
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 )
270 {
271 printk("\n[ERROR] in %s : no memory for segment descriptors\n", __FUNCTION__ );
272 vfs_close( file_xp , file_id );
273 return -1;
274 }
275
276 // set seek pointer in file descriptor to access segment descriptors array
277 error = vfs_lseek( file_xp , header.e_phoff, SEEK_SET , NULL );
278
279 if( error )
280 {
281 printk("\n[ERROR] in %s : cannot seek for descriptors array\n", __FUNCTION__ );
282 vfs_close( file_xp , file_id );
283 req.ptr = segs_base;
284 kmem_free( &req );
285 return -1;
286 }
287
288 // load seg descriptors array to local buffer
289 count = vfs_user_move( true, // to_buffer
290 file_xp,
291 segs_base,
292 segs_size );
293
294 if( count != segs_size )
295 {
296 printk("\n[ERROR] in %s : cannot read segments descriptors\n", __FUNCTION__ );
297 vfs_close( file_xp , file_id );
298 req.ptr = segs_base;
299 kmem_free( &req );
300 return -1;
301 }
302
303 elf_dmsg("\n[INFO] %s loaded segments descriptors for %s \n", __FUNCTION__ , pathname );
304
305 // register loadable segments in process VMM
306 error = elf_segments_register( file_xp,
307 segs_base,
308 header.e_phnum,
309 process );
310 if( error )
311 {
312 vfs_close( file_xp , file_id );
313 req.ptr = segs_base;
314 kmem_free( &req );
315 return -1;
316 }
317
318 // register process entry point in VMM
319 process->vmm.entry_point = (intptr_t)header.e_entry;
320
321 // register extended pointer on .elf file descriptor
322 process->vfs_bin_xp = file_xp;
323
324 // release allocated memory for program header
325 req.ptr = segs_base;
326 kmem_free(&req);
327
328 elf_dmsg("\n[INFO] %s successfully completed / entry point = %x for %s]\n",
329 __FUNCTION__, (uint32_t) header.e_entry , pathname );
330
331 return 0;
332
333} // end elf_load_process()
334
Note: See TracBrowser for help on using the repository browser.