source: trunk/kernel/syscalls/sys_exec.c@ 23

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

Introduce syscalls.

File size: 10.1 KB
Line 
1/*
2 * sys_exec.c - Kernel function implementing the "exec" system call.
3 *
4 * Authors Alain Greiner (2016,2017)
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 <errno.h>
28#include <printk.h>
29#include <core.h>
30#include <vfs.h>
31#include <cluster.h>
32#include <process.h>
33#include <thread.h>
34#include <vmm.h>
35#include <ppm.h>
36#include <rpc.h>
37
38
39////////////////////////////////////////////////i//////////////////////////////////////
40// This static function is called by the sys_exec() function to register the .elf
41// pathname in the exec_info structure, from a string stored in user space.
42////////////////////////////////////////////////i//////////////////////////////////////
43// @ exec_info : pointer on the exec_info structure.
44// @ pathname : string containing the path to the .elf file (user space).
45// return 0 if success / non-zero if one string too long, or too many strings.
46///////////////////////////////////////////////////////////////////////////////////////
47static error_t process_exec_get_path( exec_info_t * exec_info,
48 char * pathname )
49{
50 uint32_t length;
51
52 // get string length
53 length = hal_strlen_from_uspace( pathname );
54
55 if( length >= CONFIG_VFS_MAX_PATH_LENGTH ) return EINVAL;
56
57 // copy string to exec_info
58 hal_copy_from_uspace( &exec_info->path[0] , pathname , length );
59
60 return 0;
61}
62
63////////////////////////////////////////////////i//////////////////////////////////////
64// This static function is called twice by the sys_exec() function :
65// - to register the main() arguments (args) in the exec_info structure.
66// - to register the environment variables (envs) in the exec_info structure.
67// In both cases the input is an array of string pointers in user space,
68// and a set of strings in user space.
69// We allocate one physical page to store a kernel copy of the array of pointers,
70// we allocate one or several physical pages to store the strings themselve,
71// and register these buffers and the number of strings in the exec_info structure.
72// The max number of strings is 1024 (for both args and envs). The numbers of pages
73// to store the (args) and (envs) strings are configuration parameters.
74///////////////////////////////////////////////////////////////////////////////////////
75// @ exec_info : pointer on the exec_info structure.
76// @ is_args : true if called for (args) / false if called for (envs).
77// @ pointers : array of pointers on the strings (in user space).
78// @ return 0 if success / non-zero if too many strings or no more memory.
79///////////////////////////////////////////////////////////////////////////////////////
80static error_t process_exec_get_strings( exec_info_t * exec_info,
81 bool_t is_args,
82 char ** u_pointers )
83{
84 uint32_t index; // string index
85 uint32_t found_null; // NULL pointer found in array of pointers
86 uint32_t length; // string length
87 kmem_req_t req; // kmem request
88 page_t * page; // page descriptor
89 uint32_t order; // ln2( number of pages to store strings )
90 char ** k_pointers; // base of kernel array of pointers
91 char * k_buf_ptr; // pointer on first empty slot in kernel strings buffer
92 char * k_buf_base; // base address of the kernel strings buffer
93
94 // compute ln2( number of pages for kernel strings buffer )
95 if( is_args ) order = bits_log2( CONFIG_VMM_ARGS_SIZE );
96 else order = bits_log2( CONFIG_VMM_ENVS_SIZE );
97
98 req.type = KMEM_PAGE;
99 req.flags = AF_KERNEL | AF_ZERO;
100
101 // allocate one physical page for kernel array of pointers
102 req.type = 0;
103 page = kmem_alloc( &req );
104
105 if( page == NULL ) return ENOMEM;
106
107 k_pointers = ppm_page2base( page );
108
109 // allocate several physical pages to store the strings themselve
110 req.type = order;
111 page = kmem_alloc( &req );
112
113 if( page == NULL ) return ENOMEM;
114
115 k_buf_base = ppm_page2base( page );
116
117 // copy the array of pointers to kernel buffer
118 hal_copy_from_uspace( k_pointers,
119 u_pointers,
120 CONFIG_PPM_PAGE_SIZE );
121
122 // scan kernel array of pointers to copy the strings
123 found_null = 0;
124 k_buf_ptr = k_buf_base;
125 for( index = 0 ; index < 1024 ; index++ )
126 {
127 if( k_pointers[index] == NULL )
128 {
129 found_null = 1;
130 break;
131 }
132
133 // compute string length
134 length = hal_strlen_from_uspace( k_pointers[index] );
135
136 // copy the user string to kernel buffer
137 hal_copy_from_uspace( k_buf_ptr,
138 k_pointers[index],
139 length );
140
141 // update k_pointer[index] entry
142 k_pointers[index] = k_buf_ptr;
143
144 // increment pointer on kernel strings buffer
145 k_buf_ptr += (length + 1);
146 }
147
148 // update into exec_info structure
149 if( found_null && is_args )
150 {
151 exec_info->args_pointers = k_pointers;
152 exec_info->args_buf_base = k_buf_base;
153 exec_info->args_nr = index;
154 }
155 else if( found_null && !is_args )
156 {
157 exec_info->envs_pointers = k_pointers;
158 exec_info->envs_buf_base = k_buf_base;
159 exec_info->envs_buf_free = k_buf_ptr;
160 exec_info->envs_nr = index;
161 }
162 else
163 {
164 return EINVAL;
165 }
166
167 return 0;
168} // end process_exec_get_strings()
169
170/////////////////////////////////////////////////////////////////////////////////////////
171// Implementation note:
172// This function build an exec_info_t structure containing all informations
173// required to create the new process descriptor and the associated thread.
174// It calls the static process_exec_get_path() and process_exec_get_strings() functions
175// to copy the .elf pathname, the main() arguments and the environment variables from
176// user buffers to the exec_info_t structure, and call the process_make_exec() function.
177/////////////////////////////////////////////////////////////////////////////////////////
178int sys_exec( char * filename, // .elf file pathname
179 char ** args, // process arguments
180 char ** envs ) // environment variables
181{
182 exec_info_t exec_info; // structure to pass to process_make_exec()
183 error_t error;
184 paddr_t paddr;
185
186 thread_t * this = CURRENT_THREAD;
187 process_t * process = this->process;
188
189 // check argument fileme
190 error = vmm_v2p_translate( false , filename , &paddr );
191
192 if( error )
193 {
194 printk("\n[ERROR] in %s : filename unmapped\n", __FUNCTION__ );
195 this->errno = EINVAL;
196 return -1;
197 }
198
199 // check argument fileme
200 error = vmm_v2p_translate( false , args , &paddr );
201
202 if( error )
203 {
204 printk("\n[ERROR] in %s : args unmapped\n", __FUNCTION__ );
205 this->errno = EINVAL;
206 return -1;
207 }
208
209 // check argument fileme
210 error = vmm_v2p_translate( false , envs , &paddr );
211
212 if( error )
213 {
214 printk("\n[ERROR] in %s : envs unmapped\n", __FUNCTION__ );
215 this->errno = EINVAL;
216 return -1;
217 }
218
219 // compute client_cxy (local cluster) and server_cxy (target cluster)
220 cxy_t cxy_server = CXY_FROM_PID( process->pid );
221 cxy_t cxy_client = local_cxy;
222 bool_t is_local = (cxy_server == cxy_client);
223
224 exec_dmsg("\n[INFO] %s starts for process %x on core %d in cluster %x"
225 " / target_cluster = %x / cycle %d\n",
226 __FUNCTION__, process->pid , CURRENT_CORE->lid,
227 cxy_client, cxy_server, hal_time_stamp());
228
229 // initialize exec_info structure
230 exec_info.pid = process->pid;
231 exec_info.ppid = process->ppid;
232 exec_info.fd_array_xp = XPTR( local_cxy , &process->fd_array );
233 exec_info.vfs_root_xp = process->vfs_root_xp;
234 exec_info.vfs_cwd_xp = process->vfs_cwd_xp;
235 exec_info.vfs_bin_xp = process->vfs_bin_xp;
236
237 // check pathname and store it in exec_info structure
238 error = process_exec_get_path( &exec_info , filename );
239
240 if ( error )
241 {
242 printk("\n[ERROR] in %s : elf pathname too long\n", __FUNCTION__ );
243 this->errno = error;
244 return -1;
245 }
246
247 // check and store args in exec_info structure
248 error = process_exec_get_strings( &exec_info , true , args );
249
250 if( error )
251 {
252 printk("\n[ERROR] in %s : cannot access args\n", __FUNCTION__ );
253 this->errno = error;
254 return -1;
255 }
256
257 // check and store envs in exec_info structure
258 error = process_exec_get_strings( &exec_info , false , envs );
259
260 if( error )
261 {
262 printk("\n[ERROR] in %s : cannot access envs\n", __FUNCTION__ );
263 this->errno = error;
264 return -1;
265 }
266
267 exec_dmsg("\n[INFO] %s starts exec for process %x at cycle %d\n",
268 __FUNCTION__, process->pid, hal_time_stamp() );
269
270 if( is_local ) error = process_make_exec( &exec_info );
271 else rpc_process_exec_client( cxy_server , &exec_info , &error );
272
273 if( error )
274 {
275 printk("\n[ERROR] in %s : cannot create new process %x\n",
276 __FUNCTION__ , process->pid );
277 this->errno = error;
278 return -1;
279 }
280
281 exec_dmsg("\n[INFO] %s completes exec for process %x at cycle %d\n",
282 __FUNCTION__, process->pid , hal_time_stamp() );
283
284 // delete the calling thread an process
285 thread_kill( CURRENT_THREAD );
286 process_kill( CURRENT_THREAD->process );
287
288 return 0;
289
290} // end sys_exec()
291
Note: See TracBrowser for help on using the repository browser.