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

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

First import

File size: 11.2 KB
Line 
1/*
2 * sys_exec.c - Kernel function implementing the "exec" syscall
3 *
4 * Authors    Mohamed Lamine Karaoui (2015)
5 *            Alain Greiner          (2016)
6 *
7 * Copyright (c) UPMC Sorbonne Universites
8 *
9 * This file is part of ALMOS-MKH.
10 *
11 * ALMOS-MKH is free software; you can redistribute it and/or modify it
12 * under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; version 2.0 of the License.
14 *
15 * ALMOS-MKH is distributed in the hope that it will be useful, but
16 * WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with ALMOS-MKH; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24
25#include <almos_config.h>
26#include <hal_types.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        hal_strlen_from_uspace( pathname , &length );
54        if( length > 255 ) 
55    {
56        printk(ERROR, "%s: elf file pathname larger than 255 bytes\n", __FUNCTION__ );
57        return EINVAL;
58    }
59
60    // copy string to exec_info
61    hal_copy_from_uspace( &exec_info->path[0] , pathname , length );
62
63    return 0;
64}
65
66////////////////////////////////////////////////i//////////////////////////////////////
67// This static function is called twice by the sys_exec() function :
68// - to register the main() arguments (args) in the exec_info structure.
69// - to register the environment variables (envs) in the exec_info structure.
70// In both cases the input is an array of string pointers in user space,
71// and a set of strings in user space.
72// We allocate one physical page to store a kernel copy of the array of pointers,
73// we allocate one or several physical pages to store the strings themselve,
74// and register these buffers and the number of strings in the exec_info structure.
75// The max number of strings is 1024 (for both args and envs). The numbers of pages
76// to store the (args) and (envs) strings are configuration parameters.
77////////////////////////////////////////////////i//////////////////////////////////////
78// @ exec_info : pointer on the exec_info structure.
79// @ is_args   : true if called for (args) / false if called for (envs).
80// @ pointers  : array of pointers on the strings (in user space).
81// @ return 0 if success / non-zero if too many strings or no more memory.
82///////////////////////////////////////////////////////////////////////////////////////
83static error_t process_exec_get_strings( exec_info_t  * exec_info,
84                                         bool_t         is_args,
85                                                     char        ** u_pointers )
86{
87    uint32_t     index;       // string index
88    uint32_t     found_null;  // NULL pointer found in array of pointers
89    uint32_t     length;      // string length
90    uint32_t     strings;     // actual number of strings
91    kmem_req_t   req;         // kmem request
92    page_t     * page;        // page descriptor
93    uint32_t     order;       // ln2( number of pages to store strings )
94    char      ** k_pointers;  // base of kernel buffer containing array of pointers
95    char       * buf_ptr;     // pointer on first empty slot in kernel strings buffer
96    char       * buf_base;    // base address of the kernel strings buffer
97
98    // compute ln2( number of pages for kernel strings buffer )
99    if( is_args ) order = CONFIG_PROCESS_ARGS_ORDER;
100    else          order = CONFIG_PROCESS_ENVS_ORDER;
101
102        req.type   = KMEM_PAGE;
103        req.flags  = AF_KERNEL | AF_ZERO;
104
105    // allocate one physical page for kernel array of pointers
106    req.type   = 0;
107    page       = kmem_alloc( &req );
108    if( page == NULL )
109    {
110        printk("ERROR in %s : cannot allocate memory for pointers\n", __FUNCTION__ );
111        return ENOMEM;
112    }
113    k_pointers = ppm_page2base( page );
114   
115    // allocate several physical pages to store the strings themselve
116    req.type   = order;
117    page       = kmem_alloc( &req );
118    if( page == NULL )
119    {
120        printk("ERROR in %s : cannot allocate memory for strings\n", __FUNCTION__ );
121        return ENOMEM;
122    }
123    buf_base    = ppm_page2base( page );
124   
125    // copy the array of pointers to kernel buffer
126    hal_copy_from_uspace( k_pointers, 
127                          u_pointers,
128                          CONFIG_PPM_PAGE_SIZE );
129
130    // scan local copy of array of pointers to copy the strings
131    found_null = 0;
132    buf_ptr    = buf_base;
133    for( index = 0 ; index < 1024 ; index++ )
134    {
135        if( k_pointers[index] == NULL ) 
136        {
137            found_null = 1;
138            break;
139        }
140
141        // compute string length
142            hal_strlen_from_uspace( k_pointers[index] , &length );
143 
144        // copy the user string to kernel buffer
145        hal_copy_from_uspace( k_strings,
146                              k_pointers[index];
147                              length );
148
149        // update k_pointer[index] entry
150        k_pointers[index] = buf_ptr;
151
152        // increment pointer on kernel strings buffer
153        buf_ptr += (length + 1);
154    }
155
156    // update into exec_info structure
157    if( found_null && is_args )
158    {
159        exec_info->args_pointers  =  k_pointers;
160        exec_info->args_buf_base  =  buf_base;
161        exec_info->args_nr        =  index;
162    }
163    else if( found_null && !is_args )
164    {
165        exec_info->envs_pointers  =  k_pointers;
166        exec_info->envs_buf_base  =  buf_base;
167        exec_info->envs_buf_free  =  buf_ptr;
168        exec_info->envs_nr        =  index;
169    }
170    else 
171    {
172        printk("ERROR in %s : number of strings larger than 1024\n", __FUNCTION__ );
173        return EINVAL;
174    }
175
176    return 0;
177} // end process_exec_get_strings()
178
179/////////////////////////////////////////////////////////////////////////////////////////
180// This function is executed in a "client" cluster by a process whose PID can belong
181// to another "server" cluster (defined by the MSB bits of the calling process PID).
182// A new process descriptor, and the associated main thread descriptor must be created
183// in the "server" cluster, using directly the process_make_exec() function if local,
184// or the rpc_process_exec_client() function if server is remote.
185/////////////////////////////////////////////////////////////////////////////////////////
186// Implementation note:
187// This function build an exec_info_t structure containing all informations
188// required to create the new process descriptor and the associated thread.
189// It calls the static process_exec_get_path() and process_exec_get_strings() functions
190// to copy the .elf pathname, the main() arguments and the environment variables from
191// user buffers to the exec_info_t, and calls the static process_make_exec() function.
192/////////////////////////////////////////////////////////////////////////////////////////
193int sys_exec( char  * filename,     // .elf file pathname
194              char ** argv,         // process arguments
195              char ** envp )        // environment variables
196{
197    exec_info_t  exec_info;         // structure to pass to process_make_exec()
198    thread_t   * thread;            // pointer on thread created in server cluster
199        error_t      error   = 0;
200        process_t  * process = CURRENT_PROCESS;
201
202    // check arguments
203        if((filename == NULL) || (argv == NULL) || (envp == NULL)) 
204    {
205        printk("\n[ERROR] in %s : missing arguments / file = %x / argv = %x / envp = %x\n",
206               __FUNCTION__ , filename , argv , envp );
207        return EINVAL;
208    }
209
210    // compute client_cxy (local cluster) and server_cxy (target cluster)
211    cxy_t     cxy_server = CXY_FROM_PID( process->pid );
212    cxy_t     cxy_client = local_cxy;
213    bool_t    is_local   = (cxy_server == cxy_client);
214
215    exec_dmsg("\n[INFO] %s starts for process %x on core %d in cluster %x"
216                 " / target_cluster = %x / cycle %d\n",
217                 __FUNCTION__, process->pid , CURRENT_CORE->lid, 
218                 cxy_client, cxy_server, hal_time_stamp());
219
220    // Change process's state to prevent any concurent access TODO ??? [AG]
221
222    // initialize exec_info structure
223    exec_info->pid      = process->pid;
224    exec_info->ppid     = process->ppid;
225    exec_info->fd_array = &process->fd_array;
226    exec_info->vfs_root = &process->vfs_root;
227    exec_info->vfs_cwd  = &process->vfs_cwd;
228    exec_info->vfs_bin  = &process->vfs_bin;
229
230        // check pathname and store it in exec_info structure
231        error = process_exec_get_path( &exec_info , filename );
232        if ( error ) return EINVAL;
233
234        // check and store argv in exec_info structure
235        error = process_exec_get_strings( &exec_info , true , argv );
236        if( error )  return EINVAL;
237       
238        // check and store envp in exec_info structure
239        error = process_exec_get_strings( &exec_info , false , envp );
240        if( error )  return EINVAL;
241       
242    if( is_local )  ////////////// local exec //////////////////////////
243    {
244        exec_dmsg("\n[INFO] %s starts local exec for process %x at cycle %d\n",
245                  __FUNCTION__, process->pid, hal_time_stamp());
246
247        // call directly the local process_make_exec() function
248        error = process_make_exec( &exec_info , &thread );
249        if error
250        {
251            printk("\n[ERROR] in %s : failed in local exec for process %x\n",
252                   __FUNCTION__ , process->pid );
253            return EINVAL;
254        }
255
256        exec_dmsg("\n[INFO] %s completes local exec for process %x at cycle %d\n",
257                  __FUNCTION__, process->pid , hal_time_stamp() );
258    }
259    else             ///////////// remote exec /////////////////////////
260    {
261        exec_dmsg("\n[INFO] %s starts remote exec for process %x at cycle %d\n",
262                  __FUNCTION__, process->pid, hal_time_stamp() );
263
264        // call the rpc_process_exec_client() function   
265        rpc_process_exec_client( cxy_server , &exec_info , &thread , &error );
266
267        if( error )
268        {
269            printk("\n[ERROR] in %s : failed in remote exec for process %x\n",
270                   __FUNCTION__ , process->pid );
271            return EINVAL;
272        }
273
274        exec_dmsg("\n[INFO] %s completes remote exec for process %x at cycle %d\n",
275                  __FUNCTION__, process->pid , hal_time_stamp() );
276    }
277
278    // If no error, delete the current thread an process descriptors.
279    thread_kill( CURRENT_THREAD );
280    process_kill( CURRENT_PROCESS );
281
282    return 0;
283} // end sys_exec()
284
Note: See TracBrowser for help on using the repository browser.