Ignore:
Timestamp:
Nov 19, 2020, 11:45:52 PM (4 years ago)
Author:
alain
Message:

1) Introduce up to 4 command lines arguments in the KSH "load" command.
These arguments are transfered to the user process through the
argc/argv mechanism, using the user space "args" vseg.

2) Introduce the named and anonymous "pipes", for inter-process communication
through the pipe() and mkfifo() syscalls.

3) Introduce the "chat" application to validate the two above mechanisms.

4) Improve printk() and assert() fonctions in printk.c.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/kernel/syscalls/sys_exec.c

    r637 r670  
    22 * sys_exec.c - Kernel function implementing the "exec" system call.
    33 *
    4  * Authors   Alain Greiner (2016,2017,2017,2019)
     4 * Authors   Alain Greiner (2016,2017,2017,2019,2020)
    55 *
    66 * Copyright (c) UPMC Sorbonne Universites
     
    3838#include <syscalls.h>
    3939
    40 ////////////////////////////////////////////////i//////////////////////////////////////
    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,
    45 // and a set of strings in user space.
    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.
    49 // The max number of strings is 1024 (for both args and envs). The numbers of pages
    50 // to store the (args) and (envs) strings are configuration parameters.
    51 ///////////////////////////////////////////////////////////////////////////////////////
    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).
    55 // @ return 0 if success / non-zero if too many strings or no more memory.
    56 ///////////////////////////////////////////////////////////////////////////////////////
    57 static error_t process_exec_get_strings( exec_info_t  * exec_info,
    58                                          bool_t         is_args,
    59                                          char        ** u_pointers )
     40///////////////////////////////
     41int sys_exec( char  * pathname,       // .elf file pathname in user space
     42              char ** user_args,      // pointer on process arguments in user space
     43              char ** user_envs )     // pointer on env variables in user space
    6044{
    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 )
    66     char      ** k_pointers;  // base of kernel array of pointers
    67     char       * k_buf_base;  // base address of the kernel strings buffer
    68     char       * k_buf_ptr;   // pointer on first empty slot in kernel strings buffer
    69 
    70     // compute ln2( number of pages for kernel strings buffer )
    71     if( is_args ) order = bits_log2( CONFIG_VMM_ARGS_SIZE );
    72     else          order = bits_log2( CONFIG_VMM_ENVS_SIZE );
    73 
    74     // allocate one physical page for kernel array of pointers
    75     req.type   = KMEM_PPM;
    76     req.order  = 0;
    77     req.flags  = AF_KERNEL | AF_ZERO;
    78     k_pointers = kmem_alloc( &req );
    79 
    80     if( k_pointers == NULL ) return ENOMEM;
    81 
    82     // allocate several physical pages to store the strings themselve
    83     req.type   = KMEM_PPM;
    84     req.order  = order;
    85     req.flags  = AF_KERNEL | AF_ZERO;
    86     k_buf_base = kmem_alloc( &req );
    87 
    88     if( k_buf_base == NULL ) return ENOMEM;
    89 
    90     // copy the array of pointers to kernel buffer
    91     hal_copy_from_uspace( XPTR( local_cxy , k_pointers ),
    92                           u_pointers,
    93                           CONFIG_PPM_PAGE_SIZE );
    94 
    95     // scan kernel array of pointers to copy the strings
    96     found_null = 0;
    97     k_buf_ptr  = k_buf_base;
    98     for( index = 0 ; index < 1024 ; index++ )
    99     {
    100         if( k_pointers[index] == NULL )
    101         {
    102             found_null = 1;
    103             break;
    104         }
    105 
    106         // compute string length
    107         length = hal_strlen_from_uspace( k_pointers[index] );
    108 
    109         // copy the user string to kernel buffer
    110         hal_copy_from_uspace( XPTR( local_cxy , k_buf_ptr ),
    111                               k_pointers[index],
    112                               length );
    113 
    114         // update k_pointer[index] entry
    115         k_pointers[index] = k_buf_ptr;
    116 
    117         // increment pointer on kernel strings buffer
    118         k_buf_ptr += (length + 1);
    119     }
    120 
    121     // update into exec_info structure
    122     if( found_null && is_args )
    123     {
    124         exec_info->args_pointers  =  k_pointers;
    125         exec_info->args_buf_base  =  k_buf_base;
    126         exec_info->args_nr        =  index;
    127     }
    128     else if( found_null && !is_args )
    129     {
    130         exec_info->envs_pointers  =  k_pointers;
    131         exec_info->envs_buf_base  =  k_buf_base;
    132         exec_info->envs_buf_free  =  k_buf_ptr;
    133         exec_info->envs_nr        =  index;
    134     }
    135     else
    136     {
    137         return EINVAL;
    138     }
    139 
    140     return 0;
    141 } // end process_exec_get_strings()
    142 
    143 /////////////////////////////////////////////////////////////////////////////////////////
    144 // Implementation note:
    145 // This function must be called by the main thread (thread 0 in owner cluster).
    146 // It build an exec_info_t structure containing all informations
    147 // required to initialize the new process descriptor and the associated thread.
    148 // It includes the new process main() arguments, the environment variables,
    149 // and the pathname to the new process .elf file.
    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.
    153 // As it must destroy all process copies, and all other threads in all clusters,
    154 // the process_make_exec() function must be executed in the owner cluster.
    155 //
    156 // TODO : the args & envs arguments are not supported yet : both must be NULL  [AG]
    157 /////////////////////////////////////////////////////////////////////////////////////////
    158 int sys_exec( char  * pathname,       // .elf file pathname
    159               char ** args,           // process arguments
    160               char ** envs )          // environment variables
    161 {
    162     exec_info_t   exec_info;          // structure to pass to process_make_exec()
    16345    error_t       error;
     46    vseg_t      * vseg;
    16447
    16548    // get calling thread, process, & pid
     
    16750    process_t   * process = this->process;
    16851    pid_t         pid     = process->pid;
     52    trdid_t       trdid   = this->trdid;
    16953
    170 #if DEBUG_SYS_EXEC
     54assert( __FUNCTION__, (CXY_FROM_PID( pid ) == local_cxy) ,
     55"must be called in the owner cluster\n");
     56
     57assert( __FUNCTION__, (LTID_FROM_TRDID( trdid ) == 0) ,
     58"must be called by the main thread\n");
     59
     60assert( __FUNCTION__, (user_envs == NULL) ,
     61"environment variables not supported yet\n" );
     62
     63#if DEBUG_SYS_EXEC || DEBUG_SYSCALLS_ERROR
    17164uint64_t     tm_start = hal_get_cycles();
    17265#endif
    17366
    174     assert( (CXY_FROM_PID( pid ) == local_cxy) ,
    175     "must be called in the owner cluster\n");
     67    // check "pathname" mapped in user space
     68    if( vmm_get_vseg( process , (intptr_t)pathname , &vseg ) )
     69        {
    17670
    177     assert( (LTID_FROM_TRDID( this->trdid ) == 0) ,
    178     "must be called by the main thread\n");
     71#if DEBUG_SYSCALLS_ERROR
     72if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
     73printk("\n[ERROR] in %s : thread[%x,%] / pathname pointer %x unmapped\n",
     74__FUNCTION__, pid, trdid, pathname );
     75#endif
     76        this->errno = EINVAL;
     77                return -1;
     78        }
    17979
    180     assert( (args == NULL) ,
    181     "args not supported yet\n" );
    182 
    183     assert( (envs == NULL) ,
    184     "args not supported yet\n" );
    185 
    186     // check pathname length
     80    // check "pathname" length
    18781    if( hal_strlen_from_uspace( pathname ) >= CONFIG_VFS_MAX_PATH_LENGTH )
    18882    {
    18983
    19084#if DEBUG_SYSCALLS_ERROR
    191 printk("\n[ERROR] in %s : thread[%x,%x] pathname too long\n",
    192 __FUNCTION__, pid, this->trdid );
     85if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
     86printk("\n[ERROR] in %s : thread[%x,%x] / pathname too long\n",
     87__FUNCTION__, pid, trdid );
    19388#endif
    19489        this->errno = ENFILE;
     
    19691    }
    19792
    198     // copy pathname in exec_info structure (kernel space)
    199     hal_strcpy_from_uspace( XPTR( local_cxy , exec_info.path ),
     93    // check "args" mapped in user space if non NULL
     94    if( (user_args != NULL) && (vmm_get_vseg( process , (intptr_t)user_args , &vseg )) )
     95        {
     96
     97#if DEBUG_SYSCALLS_ERROR
     98printk("\n[ERROR] in %s for thread[%x,%] : user_args pointer %x unmapped\n",
     99__FUNCTION__, pid, trdid, user_args );
     100#endif
     101        this->errno = EINVAL;
     102                return -1;
     103        }
     104
     105    // check "envs" mapped in user space if not NULL
     106    if( (user_envs != NULL) && (vmm_get_vseg( process , (intptr_t)user_envs , &vseg )) )
     107        {
     108
     109#if DEBUG_SYSCALLS_ERROR
     110if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
     111printk("\n[ERROR] in %s : thread[%x,%] / user_envs pointer %x unmapped\n",
     112__FUNCTION__, pid, trdid, user_envs );
     113#endif
     114        this->errno = EINVAL;
     115                return -1;
     116        }
     117
     118#if DEBUG_SYS_EXEC
     119if( DEBUG_SYS_EXEC < (uint32_t)tm_start )
     120printk("\n[%s] thread[%x,%x] enter / path <%s> / args %x / envs %x / cycle %d\n",
     121__FUNCTION__, pid, trdid, &process->exec_info.path[0], user_args, user_envs, cycle );
     122#endif
     123
     124    // 1. copy "pathname" in kernel exec_info structure
     125    hal_strcpy_from_uspace( XPTR( local_cxy , &process->exec_info.path[0] ),
    200126                            pathname,
    201127                            CONFIG_VFS_MAX_PATH_LENGTH );
    202128
    203 #if DEBUG_SYS_EXEC
    204 if( DEBUG_SYS_EXEC < tm_start )
    205 printk("\n[%s] thread[%x,%x] enter for path <%s> / cycle = %d\n",
    206 __FUNCTION__, pid, this->trdid, exec_info.path, (uint32_t)tm_start );
    207 #endif
    208 
    209     // check and store args in exec_info structure if required
    210     if( args != NULL )
     129    // 2. copy "arguments" pointers & strings in process exec_info if required
     130    if( user_args != NULL )
    211131    {
    212         if( process_exec_get_strings( &exec_info , true , args ) )
     132        if( process_exec_get_strings( true , user_args , &process->exec_info ) )
    213133        {
    214134
    215135#if DEBUG_SYSCALLS_ERROR
    216 printk("\n[ERROR] in %s : thread[%x,%x] cannot access args for <%s>\n",
    217 __FUNCTION__, pid, this->trdid, exec_info.path );
     136if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
     137printk("\n[ERROR] in %s : thread[%x,%] get arguments for <%s>\n",
     138__FUNCTION__, pid, trdid, pathname );
    218139#endif
    219140            this->errno = EINVAL;
    220141            return -1;
    221142        }
     143
     144#if DEBUG_SYS_EXEC
     145if( DEBUG_SYS_EXEC < (uint32_t)tm_start )
     146printk("\n[%s] thread[%x,%x] got arguments / arg[0] = <%s>\n",
     147__FUNCTION__, pid, trdid, process->exec_info.args_pointers[0] );
     148#endif
     149
    222150    }
    223151
    224     // check and store envs in exec_info structure if required
    225     if( envs != NULL )
     152    // 3. copy "environment" pointers & strings in process exec_info if required
     153    if( user_envs != NULL )
    226154    {
    227         if( process_exec_get_strings( &exec_info , false , envs ) )
     155        if( process_exec_get_strings( false , user_envs , &process->exec_info ) )
    228156        {
    229157
    230158#if DEBUG_SYSCALLS_ERROR
    231 printk("\n[ERROR] in %s : thread[%x,%x] cannot access envs for <%s>\n",
    232 __FUNCTION__ , pid, this->trdid, exec_info.path );
     159if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
     160printk("\n[ERROR] in %s : thread[%x,%] get env variables for <%s>\n",
     161__FUNCTION__, pid, trdid, pathname );
    233162#endif
    234163            this->errno = EINVAL;
    235164            return -1;
    236165        }
     166
     167#if DEBUG_SYS_EXEC
     168if( DEBUG_SYS_EXEC < (uint32_t)tm_start )
     169printk("\n[%s] thread[%x,%x] got envs / env[0] = <%s>\n",
     170__FUNCTION__, pid, trdid, process->exec_info.envs_pointers[0] );
     171#endif
     172
    237173    }
    238174
    239     // call relevant kernel function
    240     error = process_make_exec( &exec_info );
     175    // call relevant kernel function (no return if success)
     176    error = process_make_exec();
    241177
    242178    if( error )
     
    244180
    245181#if DEBUG_SYSCALLS_ERROR
    246 printk("\n[ERROR] in %s : thread[%x,%x] cannot create process for <%s>\n",
    247 __FUNCTION__, pid, this->trdid, exec_info.path );
     182if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
     183printk("\n[ERROR] in %s : thread[%x,%x] cannot create process <%s>\n",
     184__FUNCTION__, pid, trdid, process->exec_info.path );
    248185#endif
    249186        this->errno = error;
     
    251188    }
    252189
    253     assert( false , "we should never execute this code" );
    254 
    255190    return 0; 
    256191
Note: See TracChangeset for help on using the changeset viewer.