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

Last change on this file since 640 was 637, checked in by alain, 5 years ago

Introduce the non-standard pthread_parallel_create() system call
and re-write the <fft> and <sort> applications to improve the
intrinsic paralelism in applications.

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