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

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

Introduce sys_fg() , sys_display() , sys_wait() syscalls.

File size: 9.2 KB
RevLine 
[1]1/*
[23]2 * sys_exec.c - Kernel function implementing the "exec" system call.
[302]3 *
[23]4 * Authors   Alain Greiner (2016,2017)
[1]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
[14]24#include <kernel_config.h>
[1]25#include <hal_types.h>
[23]26#include <hal_uspace.h>
[1]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
[302]39////////////////////////////////////////////////i//////////////////////////////////////
[1]40// This static function is called twice by the sys_exec() function :
41// - to register the main() arguments (args) in the exec_info structure.
42// - to register the environment variables (envs) in the exec_info structure.
43// In both cases the input is an array of string pointers in user space,
[302]44// and a set of strings in user space.
[1]45// We allocate one physical page to store a kernel copy of the array of pointers,
46// we allocate one or several physical pages to store the strings themselve,
47// and register these buffers and the number of strings in the exec_info structure.
[302]48// The max number of strings is 1024 (for both args and envs). The numbers of pages
[1]49// to store the (args) and (envs) strings are configuration parameters.
[302]50///////////////////////////////////////////////////////////////////////////////////////
[407]51// @ exec_info   : pointer on the exec_info structure.
52// @ is_args     : true if called for (args) / false if called for (envs).
53// @ u_pointers  : array of pointers on the strings (in user space).
[302]54// @ return 0 if success / non-zero if too many strings or no more memory.
[1]55///////////////////////////////////////////////////////////////////////////////////////
56static error_t process_exec_get_strings( exec_info_t  * exec_info,
57                                         bool_t         is_args,
[302]58                                         char        ** u_pointers )
[1]59{
60    uint32_t     index;       // string index
61    uint32_t     found_null;  // NULL pointer found in array of pointers
62    uint32_t     length;      // string length
63    kmem_req_t   req;         // kmem request
64    page_t     * page;        // page descriptor
[315]65    xptr_t       base_xp;     // extended pointer on page base
[1]66    uint32_t     order;       // ln2( number of pages to store strings )
[23]67    char      ** k_pointers;  // base of kernel array of pointers
68    char       * k_buf_ptr;   // pointer on first empty slot in kernel strings buffer
69    char       * k_buf_base;  // base address of the kernel strings buffer
[1]70
71    // compute ln2( number of pages for kernel strings buffer )
[23]72    if( is_args ) order = bits_log2( CONFIG_VMM_ARGS_SIZE );
73    else          order = bits_log2( CONFIG_VMM_ENVS_SIZE );
[1]74
[302]75    req.type   = KMEM_PAGE;
76    req.flags  = AF_KERNEL | AF_ZERO;
[1]77
78    // allocate one physical page for kernel array of pointers
79    req.type   = 0;
80    page       = kmem_alloc( &req );
[23]81
82    if( page == NULL ) return ENOMEM;
83
[315]84    base_xp = ppm_page2base( XPTR( local_cxy , page ) );
85    k_pointers = (char **)GET_PTR( base_xp );
[302]86
[1]87    // allocate several physical pages to store the strings themselve
88    req.type   = order;
89    page       = kmem_alloc( &req );
[23]90
91    if( page == NULL ) return ENOMEM;
92
[315]93    base_xp = ppm_page2base( XPTR( local_cxy , page ) );
94    k_buf_base = (char *)GET_PTR( base_xp );
[302]95
96    // copy the array of pointers to kernel buffer
97    hal_copy_from_uspace( k_pointers,
[1]98                          u_pointers,
99                          CONFIG_PPM_PAGE_SIZE );
100
[23]101    // scan kernel array of pointers to copy the strings
[1]102    found_null = 0;
[23]103    k_buf_ptr  = k_buf_base;
[1]104    for( index = 0 ; index < 1024 ; index++ )
105    {
[302]106        if( k_pointers[index] == NULL )
[1]107        {
108            found_null = 1;
109            break;
110        }
111
112        // compute string length
[302]113        length = hal_strlen_from_uspace( k_pointers[index] );
114
[1]115        // copy the user string to kernel buffer
[23]116        hal_copy_from_uspace( k_buf_ptr,
117                              k_pointers[index],
[1]118                              length );
119
120        // update k_pointer[index] entry
[23]121        k_pointers[index] = k_buf_ptr;
[1]122
123        // increment pointer on kernel strings buffer
[23]124        k_buf_ptr += (length + 1);
[1]125    }
126
[302]127    // update into exec_info structure
[1]128    if( found_null && is_args )
129    {
130        exec_info->args_pointers  =  k_pointers;
[23]131        exec_info->args_buf_base  =  k_buf_base;
[1]132        exec_info->args_nr        =  index;
133    }
134    else if( found_null && !is_args )
135    {
136        exec_info->envs_pointers  =  k_pointers;
[23]137        exec_info->envs_buf_base  =  k_buf_base;
138        exec_info->envs_buf_free  =  k_buf_ptr;
[1]139        exec_info->envs_nr        =  index;
140    }
[302]141    else
[1]142    {
143        return EINVAL;
144    }
145
146    return 0;
147} // end process_exec_get_strings()
148
149/////////////////////////////////////////////////////////////////////////////////////////
150// Implementation note:
151// This function build an exec_info_t structure containing all informations
[408]152// required to initialize the new process descriptor and the associated thread.
153// It includes the process PID (unchanged), main() arguments, environment variables,
154// and the pathname to the new process .elf file.
[407]155// It calls the process_exec_get_strings() functions to copy the main() arguments and
156// the environment variables from user buffers to the exec_info_t structure, allocate
157// and call the process_make_exec() function.
[408]158// As it must destroy all parent process copies, and all parent threads in all clusters,
159// the process_make_exec() function must be executed in the parent owner cluster,
160// and this sys_exec() function uses a RPC to access the owner cluster if required.
161//
[416]162// TODO : the args & envs arguments are not supported yet : both must be NULL  [AG]
[1]163/////////////////////////////////////////////////////////////////////////////////////////
[407]164int sys_exec( char  * pathname,     // .elf file pathname
[23]165              char ** args,         // process arguments
166              char ** envs )        // environment variables
[1]167{
[407]168    exec_info_t   exec_info;        // structure to pass to process_make_exec()
169    error_t       error;
[1]170
[408]171    // get parent process pid
[421]172    thread_t    * this    = CURRENT_THREAD;
173    process_t   * process = this->process;
174    pid_t         pid     = process->pid;
[23]175
[416]176#if CONFIG_SYSCALL_DEBUG
177uint64_t      tm_start;
178uint64_t      tm_end;
179tm_start = hal_get_cycles();
[421]180printk("\n[DBG] %s : core[%x,%d] enter / process %x / cycle = %d\n",
181__FUNCTION__, local_cxy, this->core->lid, pid, (uint32_t)tm_start );
[416]182#endif
[23]183
[408]184    // get owner cluster
185    cxy_t  owner_cxy = CXY_FROM_PID( pid );
[1]186
[407]187    // check pathname length
188    if( hal_strlen_from_uspace( pathname ) >= CONFIG_VFS_MAX_PATH_LENGTH )
[23]189    {
[407]190        printk("\n[ERROR] in %s : pathname too long\n", __FUNCTION__ );
191        this->errno = ENFILE;
[23]192        return -1;
193    }
194
[407]195    // copy pathname in exec_info structure (kernel space)
196    hal_strcpy_from_uspace( exec_info.path , pathname , CONFIG_VFS_MAX_PATH_LENGTH );
[408]197
[407]198    // check args argument
199    assert( (args == NULL) , __FUNCTION__ , 
200    "args not supported yet\n" );
[23]201
[407]202    // check envs argument
203    assert( (envs == NULL) , __FUNCTION__ , 
204    "args not supported yet\n" );
[23]205
[407]206    // check and store args in exec_info structure if required
207    if( args != NULL )
[1]208    {
[407]209        if( process_exec_get_strings( &exec_info , true , args ) )
210        {
211            printk("\n[ERROR] in %s : cannot access args\n", __FUNCTION__ );
212            this->errno = error;
213            return -1;
214        }
[23]215    }
[1]216
[407]217    // check and store envs in exec_info structure if required
218    if( envs != NULL )
[23]219    {
[407]220        if( process_exec_get_strings( &exec_info , false , envs ) )
221        {
222            printk("\n[ERROR] in %s : cannot access envs\n", __FUNCTION__ );
223            this->errno = error;
224            return -1;
225        }
[1]226    }
[23]227
[408]228    // register PID in exec_info
229    exec_info.pid = pid;
230
[407]231    // call process_make_exec (local or remote)
[408]232    if( owner_cxy == local_cxy )
[1]233    {
[407]234        error = process_make_exec( &exec_info );
[23]235    }
[407]236    else
237    {
[408]238        rpc_process_make_exec_client( owner_cxy,
239                                      &exec_info,
240                                      &error );
[407]241    }
[302]242
[23]243    if( error )
244    {
[407]245        printk("\n[ERROR] in %s : cannot create new process %x in cluster %x\n",
[408]246        __FUNCTION__, pid, owner_cxy );
[23]247        this->errno = error;
248        return -1;
[1]249    }
250
[416]251#if CONFIG_SYSCALL_DEBUG
252tm_end = hal_get_cycles();
[421]253printk("\n[DBG] %s : core[%x,%d] exit / process %x / path = %s / cost = %d / cycle %d\n",
254__FUNCTION__, local_cxy, this->core->lid, pid, exec_info.path, 
255(uint32_t)(tm_end - tm_start) , (uint32_t)tm_end );
[416]256#endif
[1]257
258    return 0;
[23]259
[1]260} // end sys_exec()
261
Note: See TracBrowser for help on using the repository browser.