Changeset 670 for trunk/kernel/syscalls/sys_exec.c
- Timestamp:
- Nov 19, 2020, 11:45:52 PM (4 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/kernel/syscalls/sys_exec.c
r637 r670 2 2 * sys_exec.c - Kernel function implementing the "exec" system call. 3 3 * 4 * Authors Alain Greiner (2016,2017,2017,2019 )4 * Authors Alain Greiner (2016,2017,2017,2019,2020) 5 5 * 6 6 * Copyright (c) UPMC Sorbonne Universites … … 38 38 #include <syscalls.h> 39 39 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 /////////////////////////////// 41 int 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 60 44 { 61 uint32_t index; // string index62 uint32_t found_null; // NULL pointer found in array of pointers63 uint32_t length; // string length64 kmem_req_t req; // kmem request65 uint32_t order; // ln2( number of pages to store strings )66 char ** k_pointers; // base of kernel array of pointers67 char * k_buf_base; // base address of the kernel strings buffer68 char * k_buf_ptr; // pointer on first empty slot in kernel strings buffer69 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 pointers75 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 themselve83 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 buffer91 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 strings96 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 length107 length = hal_strlen_from_uspace( k_pointers[index] );108 109 // copy the user string to kernel buffer110 hal_copy_from_uspace( XPTR( local_cxy , k_buf_ptr ),111 k_pointers[index],112 length );113 114 // update k_pointer[index] entry115 k_pointers[index] = k_buf_ptr;116 117 // increment pointer on kernel strings buffer118 k_buf_ptr += (length + 1);119 }120 121 // update into exec_info structure122 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 else136 {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 informations147 // 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 and151 // the environment variables from user buffers to the exec_info_t structure, allocate152 // 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 pathname159 char ** args, // process arguments160 char ** envs ) // environment variables161 {162 exec_info_t exec_info; // structure to pass to process_make_exec()163 45 error_t error; 46 vseg_t * vseg; 164 47 165 48 // get calling thread, process, & pid … … 167 50 process_t * process = this->process; 168 51 pid_t pid = process->pid; 52 trdid_t trdid = this->trdid; 169 53 170 #if DEBUG_SYS_EXEC 54 assert( __FUNCTION__, (CXY_FROM_PID( pid ) == local_cxy) , 55 "must be called in the owner cluster\n"); 56 57 assert( __FUNCTION__, (LTID_FROM_TRDID( trdid ) == 0) , 58 "must be called by the main thread\n"); 59 60 assert( __FUNCTION__, (user_envs == NULL) , 61 "environment variables not supported yet\n" ); 62 63 #if DEBUG_SYS_EXEC || DEBUG_SYSCALLS_ERROR 171 64 uint64_t tm_start = hal_get_cycles(); 172 65 #endif 173 66 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 { 176 70 177 assert( (LTID_FROM_TRDID( this->trdid ) == 0) , 178 "must be called by the main thread\n"); 71 #if DEBUG_SYSCALLS_ERROR 72 if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) 73 printk("\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 } 179 79 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 187 81 if( hal_strlen_from_uspace( pathname ) >= CONFIG_VFS_MAX_PATH_LENGTH ) 188 82 { 189 83 190 84 #if DEBUG_SYSCALLS_ERROR 191 printk("\n[ERROR] in %s : thread[%x,%x] pathname too long\n", 192 __FUNCTION__, pid, this->trdid ); 85 if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) 86 printk("\n[ERROR] in %s : thread[%x,%x] / pathname too long\n", 87 __FUNCTION__, pid, trdid ); 193 88 #endif 194 89 this->errno = ENFILE; … … 196 91 } 197 92 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 98 printk("\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 110 if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) 111 printk("\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 119 if( DEBUG_SYS_EXEC < (uint32_t)tm_start ) 120 printk("\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] ), 200 126 pathname, 201 127 CONFIG_VFS_MAX_PATH_LENGTH ); 202 128 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 ) 211 131 { 212 if( process_exec_get_strings( &exec_info , true , args) )132 if( process_exec_get_strings( true , user_args , &process->exec_info ) ) 213 133 { 214 134 215 135 #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 ); 136 if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) 137 printk("\n[ERROR] in %s : thread[%x,%] get arguments for <%s>\n", 138 __FUNCTION__, pid, trdid, pathname ); 218 139 #endif 219 140 this->errno = EINVAL; 220 141 return -1; 221 142 } 143 144 #if DEBUG_SYS_EXEC 145 if( DEBUG_SYS_EXEC < (uint32_t)tm_start ) 146 printk("\n[%s] thread[%x,%x] got arguments / arg[0] = <%s>\n", 147 __FUNCTION__, pid, trdid, process->exec_info.args_pointers[0] ); 148 #endif 149 222 150 } 223 151 224 // check and store envs in exec_info structureif required225 if( envs != NULL )152 // 3. copy "environment" pointers & strings in process exec_info if required 153 if( user_envs != NULL ) 226 154 { 227 if( process_exec_get_strings( &exec_info , false , envs) )155 if( process_exec_get_strings( false , user_envs , &process->exec_info ) ) 228 156 { 229 157 230 158 #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 ); 159 if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) 160 printk("\n[ERROR] in %s : thread[%x,%] get env variables for <%s>\n", 161 __FUNCTION__, pid, trdid, pathname ); 233 162 #endif 234 163 this->errno = EINVAL; 235 164 return -1; 236 165 } 166 167 #if DEBUG_SYS_EXEC 168 if( DEBUG_SYS_EXEC < (uint32_t)tm_start ) 169 printk("\n[%s] thread[%x,%x] got envs / env[0] = <%s>\n", 170 __FUNCTION__, pid, trdid, process->exec_info.envs_pointers[0] ); 171 #endif 172 237 173 } 238 174 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(); 241 177 242 178 if( error ) … … 244 180 245 181 #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 ); 182 if( DEBUG_SYSCALLS_ERROR < (uint32_t)tm_start ) 183 printk("\n[ERROR] in %s : thread[%x,%x] cannot create process <%s>\n", 184 __FUNCTION__, pid, trdid, process->exec_info.path ); 248 185 #endif 249 186 this->errno = error; … … 251 188 } 252 189 253 assert( false , "we should never execute this code" );254 255 190 return 0; 256 191
Note: See TracChangeset
for help on using the changeset viewer.