Index: trunk/kernel/syscalls/sys_exec.c
===================================================================
--- trunk/kernel/syscalls/sys_exec.c	(revision 637)
+++ trunk/kernel/syscalls/sys_exec.c	(revision 670)
@@ -2,5 +2,5 @@
  * sys_exec.c - Kernel function implementing the "exec" system call.
  *
- * Authors   Alain Greiner (2016,2017,2017,2019)
+ * Authors   Alain Greiner (2016,2017,2017,2019,2020)
  *
  * Copyright (c) UPMC Sorbonne Universites
@@ -38,128 +38,11 @@
 #include <syscalls.h>
 
-////////////////////////////////////////////////i//////////////////////////////////////
-// This static function is called twice by the sys_exec() function :
-// - to register the main() arguments (args) in the exec_info structure.
-// - to register the environment variables (envs) in the exec_info structure.
-// In both cases the input is an array of string pointers in user space,
-// and a set of strings in user space.
-// We allocate one physical page to store a kernel copy of the array of pointers,
-// we allocate one or several physical pages to store the strings themselve,
-// and register these buffers and the number of strings in the exec_info structure.
-// The max number of strings is 1024 (for both args and envs). The numbers of pages
-// to store the (args) and (envs) strings are configuration parameters.
-///////////////////////////////////////////////////////////////////////////////////////
-// @ exec_info   : pointer on the exec_info structure.
-// @ is_args     : true if called for (args) / false if called for (envs).
-// @ u_pointers  : array of pointers on the strings (in user space).
-// @ return 0 if success / non-zero if too many strings or no more memory.
-///////////////////////////////////////////////////////////////////////////////////////
-static error_t process_exec_get_strings( exec_info_t  * exec_info,
-                                         bool_t         is_args,
-                                         char        ** u_pointers )
+///////////////////////////////
+int sys_exec( char  * pathname,       // .elf file pathname in user space
+              char ** user_args,      // pointer on process arguments in user space
+              char ** user_envs )     // pointer on env variables in user space
 {
-    uint32_t     index;       // string index
-    uint32_t     found_null;  // NULL pointer found in array of pointers
-    uint32_t     length;      // string length
-    kmem_req_t   req;         // kmem request
-    uint32_t     order;       // ln2( number of pages to store strings )
-    char      ** k_pointers;  // base of kernel array of pointers
-    char       * k_buf_base;  // base address of the kernel strings buffer
-    char       * k_buf_ptr;   // pointer on first empty slot in kernel strings buffer
-
-    // compute ln2( number of pages for kernel strings buffer )
-    if( is_args ) order = bits_log2( CONFIG_VMM_ARGS_SIZE );
-    else          order = bits_log2( CONFIG_VMM_ENVS_SIZE );
-
-    // allocate one physical page for kernel array of pointers
-    req.type   = KMEM_PPM;
-    req.order  = 0;
-    req.flags  = AF_KERNEL | AF_ZERO;
-    k_pointers = kmem_alloc( &req );
-
-    if( k_pointers == NULL ) return ENOMEM;
-
-    // allocate several physical pages to store the strings themselve
-    req.type   = KMEM_PPM;
-    req.order  = order;
-    req.flags  = AF_KERNEL | AF_ZERO;
-    k_buf_base = kmem_alloc( &req );
-
-    if( k_buf_base == NULL ) return ENOMEM;
-
-    // copy the array of pointers to kernel buffer
-    hal_copy_from_uspace( XPTR( local_cxy , k_pointers ),
-                          u_pointers,
-                          CONFIG_PPM_PAGE_SIZE );
-
-    // scan kernel array of pointers to copy the strings
-    found_null = 0;
-    k_buf_ptr  = k_buf_base;
-    for( index = 0 ; index < 1024 ; index++ )
-    {
-        if( k_pointers[index] == NULL )
-        {
-            found_null = 1;
-            break;
-        }
-
-        // compute string length
-        length = hal_strlen_from_uspace( k_pointers[index] );
-
-        // copy the user string to kernel buffer
-        hal_copy_from_uspace( XPTR( local_cxy , k_buf_ptr ),
-                              k_pointers[index],
-                              length );
-
-        // update k_pointer[index] entry
-        k_pointers[index] = k_buf_ptr;
-
-        // increment pointer on kernel strings buffer
-        k_buf_ptr += (length + 1);
-    }
-
-    // update into exec_info structure
-    if( found_null && is_args )
-    {
-        exec_info->args_pointers  =  k_pointers;
-        exec_info->args_buf_base  =  k_buf_base;
-        exec_info->args_nr        =  index;
-    }
-    else if( found_null && !is_args )
-    {
-        exec_info->envs_pointers  =  k_pointers;
-        exec_info->envs_buf_base  =  k_buf_base;
-        exec_info->envs_buf_free  =  k_buf_ptr;
-        exec_info->envs_nr        =  index;
-    }
-    else
-    {
-        return EINVAL;
-    }
-
-    return 0;
-} // end process_exec_get_strings()
-
-/////////////////////////////////////////////////////////////////////////////////////////
-// Implementation note:
-// This function must be called by the main thread (thread 0 in owner cluster).
-// It build an exec_info_t structure containing all informations
-// required to initialize the new process descriptor and the associated thread.
-// It includes the new process main() arguments, the environment variables, 
-// and the pathname to the new process .elf file. 
-// It calls the process_exec_get_strings() functions to copy the main() arguments and 
-// the environment variables from user buffers to the exec_info_t structure, allocate
-// and call the process_make_exec() function.
-// As it must destroy all process copies, and all other threads in all clusters,
-// the process_make_exec() function must be executed in the owner cluster. 
-// 
-// TODO : the args & envs arguments are not supported yet : both must be NULL  [AG]
-/////////////////////////////////////////////////////////////////////////////////////////
-int sys_exec( char  * pathname,       // .elf file pathname
-              char ** args,           // process arguments
-              char ** envs )          // environment variables
-{
-    exec_info_t   exec_info;          // structure to pass to process_make_exec()
     error_t       error;
+    vseg_t      * vseg;
 
     // get calling thread, process, & pid
@@ -167,28 +50,40 @@
     process_t   * process = this->process;
     pid_t         pid     = process->pid;
+    trdid_t       trdid   = this->trdid;
 
-#if DEBUG_SYS_EXEC
+assert( __FUNCTION__, (CXY_FROM_PID( pid ) == local_cxy) ,
+"must be called in the owner cluster\n");
+
+assert( __FUNCTION__, (LTID_FROM_TRDID( trdid ) == 0) ,
+"must be called by the main thread\n");
+
+assert( __FUNCTION__, (user_envs == NULL) ,
+"environment variables not supported yet\n" );
+
+#if DEBUG_SYS_EXEC || DEBUG_SYSCALLS_ERROR 
 uint64_t     tm_start = hal_get_cycles();
 #endif
 
-    assert( (CXY_FROM_PID( pid ) == local_cxy) ,
-    "must be called in the owner cluster\n");
+    // check "pathname" mapped in user space
+    if( vmm_get_vseg( process , (intptr_t)pathname , &vseg ) )
+	{
 
-    assert( (LTID_FROM_TRDID( this->trdid ) == 0) ,
-    "must be called by the main thread\n");
+#if DEBUG_SYSCALLS_ERROR
+if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
+printk("\n[ERROR] in %s : thread[%x,%] / pathname pointer %x unmapped\n",
+__FUNCTION__, pid, trdid, pathname );
+#endif
+        this->errno = EINVAL;
+		return -1;
+	}
 
-    assert( (args == NULL) ,
-    "args not supported yet\n" );
-
-    assert( (envs == NULL) ,
-    "args not supported yet\n" );
-
-    // check pathname length
+    // check "pathname" length
     if( hal_strlen_from_uspace( pathname ) >= CONFIG_VFS_MAX_PATH_LENGTH )
     {
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : thread[%x,%x] pathname too long\n",
-__FUNCTION__, pid, this->trdid );
+if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
+printk("\n[ERROR] in %s : thread[%x,%x] / pathname too long\n",
+__FUNCTION__, pid, trdid );
 #endif
         this->errno = ENFILE;
@@ -196,47 +91,88 @@
     }
 
-    // copy pathname in exec_info structure (kernel space)
-    hal_strcpy_from_uspace( XPTR( local_cxy , exec_info.path ),
+    // check "args" mapped in user space if non NULL
+    if( (user_args != NULL) && (vmm_get_vseg( process , (intptr_t)user_args , &vseg )) )
+	{
+
+#if DEBUG_SYSCALLS_ERROR
+printk("\n[ERROR] in %s for thread[%x,%] : user_args pointer %x unmapped\n",
+__FUNCTION__, pid, trdid, user_args );
+#endif
+        this->errno = EINVAL;
+		return -1;
+	}
+
+    // check "envs" mapped in user space if not NULL
+    if( (user_envs != NULL) && (vmm_get_vseg( process , (intptr_t)user_envs , &vseg )) )
+	{
+
+#if DEBUG_SYSCALLS_ERROR
+if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
+printk("\n[ERROR] in %s : thread[%x,%] / user_envs pointer %x unmapped\n",
+__FUNCTION__, pid, trdid, user_envs );
+#endif
+        this->errno = EINVAL;
+		return -1;
+	}
+
+#if DEBUG_SYS_EXEC
+if( DEBUG_SYS_EXEC < (uint32_t)tm_start )
+printk("\n[%s] thread[%x,%x] enter / path <%s> / args %x / envs %x / cycle %d\n",
+__FUNCTION__, pid, trdid, &process->exec_info.path[0], user_args, user_envs, cycle );
+#endif
+
+    // 1. copy "pathname" in kernel exec_info structure 
+    hal_strcpy_from_uspace( XPTR( local_cxy , &process->exec_info.path[0] ),
                             pathname,
                             CONFIG_VFS_MAX_PATH_LENGTH );
 
-#if DEBUG_SYS_EXEC
-if( DEBUG_SYS_EXEC < tm_start )
-printk("\n[%s] thread[%x,%x] enter for path <%s> / cycle = %d\n",
-__FUNCTION__, pid, this->trdid, exec_info.path, (uint32_t)tm_start );
-#endif
-
-    // check and store args in exec_info structure if required
-    if( args != NULL )
+    // 2. copy "arguments" pointers & strings in process exec_info if required
+    if( user_args != NULL )
     {
-        if( process_exec_get_strings( &exec_info , true , args ) )
+        if( process_exec_get_strings( true , user_args , &process->exec_info ) )
         {
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : thread[%x,%x] cannot access args for <%s>\n",
-__FUNCTION__, pid, this->trdid, exec_info.path );
+if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
+printk("\n[ERROR] in %s : thread[%x,%] get arguments for <%s>\n",
+__FUNCTION__, pid, trdid, pathname );
 #endif
             this->errno = EINVAL;
             return -1;
         }
+
+#if DEBUG_SYS_EXEC
+if( DEBUG_SYS_EXEC < (uint32_t)tm_start )
+printk("\n[%s] thread[%x,%x] got arguments / arg[0] = <%s>\n",
+__FUNCTION__, pid, trdid, process->exec_info.args_pointers[0] );
+#endif
+
     }
 
-    // check and store envs in exec_info structure if required
-    if( envs != NULL )
+    // 3. copy "environment" pointers & strings in process exec_info if required
+    if( user_envs != NULL )
     {
-        if( process_exec_get_strings( &exec_info , false , envs ) )
+        if( process_exec_get_strings( false , user_envs , &process->exec_info ) )
         {
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : thread[%x,%x] cannot access envs for <%s>\n",
-__FUNCTION__ , pid, this->trdid, exec_info.path );
+if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
+printk("\n[ERROR] in %s : thread[%x,%] get env variables for <%s>\n",
+__FUNCTION__, pid, trdid, pathname );
 #endif
             this->errno = EINVAL;
             return -1;
         }
+
+#if DEBUG_SYS_EXEC 
+if( DEBUG_SYS_EXEC < (uint32_t)tm_start )
+printk("\n[%s] thread[%x,%x] got envs / env[0] = <%s>\n",
+__FUNCTION__, pid, trdid, process->exec_info.envs_pointers[0] );
+#endif
+
     }
 
-    // call relevant kernel function
-    error = process_make_exec( &exec_info );
+    // call relevant kernel function (no return if success)
+    error = process_make_exec();
 
     if( error )
@@ -244,6 +180,7 @@
 
 #if DEBUG_SYSCALLS_ERROR
-printk("\n[ERROR] in %s : thread[%x,%x] cannot create process for <%s>\n",
-__FUNCTION__, pid, this->trdid, exec_info.path );
+if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start )
+printk("\n[ERROR] in %s : thread[%x,%x] cannot create process <%s>\n",
+__FUNCTION__, pid, trdid, process->exec_info.path );
 #endif
         this->errno = error;
@@ -251,6 +188,4 @@
     }
 
-    assert( false , "we should never execute this code" );
-
     return 0;  
 
