| [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 by the sys_exec() function to register the .elf | 
|---|
 | 41 | // pathname in the exec_info  structure, from a string stored in user space. | 
|---|
| [302] | 42 | ////////////////////////////////////////////////i////////////////////////////////////// | 
|---|
| [1] | 43 | // @ exec_info : pointer on the exec_info structure. | 
|---|
 | 44 | // @ pathname  : string containing the path to the .elf file (user space). | 
|---|
| [302] | 45 | // return 0 if success / non-zero if one string too long, or too many strings. | 
|---|
| [1] | 46 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 47 | static error_t process_exec_get_path( exec_info_t  * exec_info, | 
|---|
 | 48 |                                       char         * pathname ) | 
|---|
 | 49 | { | 
|---|
| [302] | 50 |     error_t error; | 
|---|
| [1] | 51 |  | 
|---|
 | 52 |     // copy string to exec_info | 
|---|
| [302] | 53 |     error = hal_strcpy_from_uspace( &exec_info->path[0] , pathname , | 
|---|
 | 54 |                                     CONFIG_VFS_MAX_PATH_LENGTH ); | 
|---|
 | 55 |     if( error ) | 
|---|
 | 56 |         return EINVAL; | 
|---|
| [1] | 57 |  | 
|---|
 | 58 |     return 0; | 
|---|
 | 59 | } | 
|---|
 | 60 |  | 
|---|
| [302] | 61 | ////////////////////////////////////////////////i////////////////////////////////////// | 
|---|
| [1] | 62 | // This static function is called twice by the sys_exec() function : | 
|---|
 | 63 | // - to register the main() arguments (args) in the exec_info structure. | 
|---|
 | 64 | // - to register the environment variables (envs) in the exec_info structure. | 
|---|
 | 65 | // In both cases the input is an array of string pointers in user space, | 
|---|
| [302] | 66 | // and a set of strings in user space. | 
|---|
| [1] | 67 | // We allocate one physical page to store a kernel copy of the array of pointers, | 
|---|
 | 68 | // we allocate one or several physical pages to store the strings themselve, | 
|---|
 | 69 | // and register these buffers and the number of strings in the exec_info structure. | 
|---|
| [302] | 70 | // The max number of strings is 1024 (for both args and envs). The numbers of pages | 
|---|
| [1] | 71 | // to store the (args) and (envs) strings are configuration parameters. | 
|---|
| [302] | 72 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [1] | 73 | // @ exec_info : pointer on the exec_info structure. | 
|---|
 | 74 | // @ is_args   : true if called for (args) / false if called for (envs). | 
|---|
 | 75 | // @ pointers  : array of pointers on the strings (in user space). | 
|---|
| [302] | 76 | // @ return 0 if success / non-zero if too many strings or no more memory. | 
|---|
| [1] | 77 | /////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 78 | static error_t process_exec_get_strings( exec_info_t  * exec_info, | 
|---|
 | 79 |                                          bool_t         is_args, | 
|---|
| [302] | 80 |                                          char        ** u_pointers ) | 
|---|
| [1] | 81 | { | 
|---|
 | 82 |     uint32_t     index;       // string index | 
|---|
 | 83 |     uint32_t     found_null;  // NULL pointer found in array of pointers | 
|---|
 | 84 |     uint32_t     length;      // string length | 
|---|
 | 85 |     kmem_req_t   req;         // kmem request | 
|---|
 | 86 |     page_t     * page;        // page descriptor | 
|---|
| [315] | 87 |     xptr_t       base_xp;     // extended pointer on page base | 
|---|
| [1] | 88 |     uint32_t     order;       // ln2( number of pages to store strings ) | 
|---|
| [23] | 89 |     char      ** k_pointers;  // base of kernel array of pointers | 
|---|
 | 90 |     char       * k_buf_ptr;   // pointer on first empty slot in kernel strings buffer | 
|---|
 | 91 |     char       * k_buf_base;  // base address of the kernel strings buffer | 
|---|
| [1] | 92 |  | 
|---|
 | 93 |     // compute ln2( number of pages for kernel strings buffer ) | 
|---|
| [23] | 94 |     if( is_args ) order = bits_log2( CONFIG_VMM_ARGS_SIZE ); | 
|---|
 | 95 |     else          order = bits_log2( CONFIG_VMM_ENVS_SIZE ); | 
|---|
| [1] | 96 |  | 
|---|
| [302] | 97 |     req.type   = KMEM_PAGE; | 
|---|
 | 98 |     req.flags  = AF_KERNEL | AF_ZERO; | 
|---|
| [1] | 99 |  | 
|---|
 | 100 |     // allocate one physical page for kernel array of pointers | 
|---|
 | 101 |     req.type   = 0; | 
|---|
 | 102 |     page       = kmem_alloc( &req ); | 
|---|
| [23] | 103 |  | 
|---|
 | 104 |     if( page == NULL ) return ENOMEM; | 
|---|
 | 105 |  | 
|---|
| [315] | 106 |     base_xp = ppm_page2base( XPTR( local_cxy , page ) ); | 
|---|
 | 107 |     k_pointers = (char **)GET_PTR( base_xp ); | 
|---|
| [302] | 108 |  | 
|---|
| [1] | 109 |     // allocate several physical pages to store the strings themselve | 
|---|
 | 110 |     req.type   = order; | 
|---|
 | 111 |     page       = kmem_alloc( &req ); | 
|---|
| [23] | 112 |  | 
|---|
 | 113 |     if( page == NULL ) return ENOMEM; | 
|---|
 | 114 |  | 
|---|
| [315] | 115 |     base_xp = ppm_page2base( XPTR( local_cxy , page ) ); | 
|---|
 | 116 |     k_buf_base = (char *)GET_PTR( base_xp ); | 
|---|
| [302] | 117 |  | 
|---|
 | 118 |     // copy the array of pointers to kernel buffer | 
|---|
 | 119 |     hal_copy_from_uspace( k_pointers, | 
|---|
| [1] | 120 |                           u_pointers, | 
|---|
 | 121 |                           CONFIG_PPM_PAGE_SIZE ); | 
|---|
 | 122 |  | 
|---|
| [23] | 123 |     // scan kernel array of pointers to copy the strings | 
|---|
| [1] | 124 |     found_null = 0; | 
|---|
| [23] | 125 |     k_buf_ptr  = k_buf_base; | 
|---|
| [1] | 126 |     for( index = 0 ; index < 1024 ; index++ ) | 
|---|
 | 127 |     { | 
|---|
| [302] | 128 |         if( k_pointers[index] == NULL ) | 
|---|
| [1] | 129 |         { | 
|---|
 | 130 |             found_null = 1; | 
|---|
 | 131 |             break; | 
|---|
 | 132 |         } | 
|---|
 | 133 |  | 
|---|
 | 134 |         // compute string length | 
|---|
| [302] | 135 |         length = hal_strlen_from_uspace( k_pointers[index] ); | 
|---|
 | 136 |  | 
|---|
| [1] | 137 |         // copy the user string to kernel buffer | 
|---|
| [23] | 138 |         hal_copy_from_uspace( k_buf_ptr, | 
|---|
 | 139 |                               k_pointers[index], | 
|---|
| [1] | 140 |                               length ); | 
|---|
 | 141 |  | 
|---|
 | 142 |         // update k_pointer[index] entry | 
|---|
| [23] | 143 |         k_pointers[index] = k_buf_ptr; | 
|---|
| [1] | 144 |  | 
|---|
 | 145 |         // increment pointer on kernel strings buffer | 
|---|
| [23] | 146 |         k_buf_ptr += (length + 1); | 
|---|
| [1] | 147 |     } | 
|---|
 | 148 |  | 
|---|
| [302] | 149 |     // update into exec_info structure | 
|---|
| [1] | 150 |     if( found_null && is_args ) | 
|---|
 | 151 |     { | 
|---|
 | 152 |         exec_info->args_pointers  =  k_pointers; | 
|---|
| [23] | 153 |         exec_info->args_buf_base  =  k_buf_base; | 
|---|
| [1] | 154 |         exec_info->args_nr        =  index; | 
|---|
 | 155 |     } | 
|---|
 | 156 |     else if( found_null && !is_args ) | 
|---|
 | 157 |     { | 
|---|
 | 158 |         exec_info->envs_pointers  =  k_pointers; | 
|---|
| [23] | 159 |         exec_info->envs_buf_base  =  k_buf_base; | 
|---|
 | 160 |         exec_info->envs_buf_free  =  k_buf_ptr; | 
|---|
| [1] | 161 |         exec_info->envs_nr        =  index; | 
|---|
 | 162 |     } | 
|---|
| [302] | 163 |     else | 
|---|
| [1] | 164 |     { | 
|---|
 | 165 |         return EINVAL; | 
|---|
 | 166 |     } | 
|---|
 | 167 |  | 
|---|
 | 168 |     return 0; | 
|---|
 | 169 | } // end process_exec_get_strings() | 
|---|
 | 170 |  | 
|---|
 | 171 | ///////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 172 | // Implementation note: | 
|---|
 | 173 | // This function build an exec_info_t structure containing all informations | 
|---|
 | 174 | // required to create the new process descriptor and the associated thread. | 
|---|
 | 175 | // It calls the static process_exec_get_path() and process_exec_get_strings() functions | 
|---|
 | 176 | // to copy the .elf pathname, the main() arguments and the environment variables from | 
|---|
| [23] | 177 | // user buffers to the exec_info_t structure, and call the process_make_exec() function. | 
|---|
| [1] | 178 | ///////////////////////////////////////////////////////////////////////////////////////// | 
|---|
 | 179 | int sys_exec( char  * filename,     // .elf file pathname | 
|---|
| [23] | 180 |               char ** args,         // process arguments | 
|---|
 | 181 |               char ** envs )        // environment variables | 
|---|
| [1] | 182 | { | 
|---|
 | 183 |     exec_info_t  exec_info;         // structure to pass to process_make_exec() | 
|---|
| [302] | 184 |     error_t      error; | 
|---|
| [23] | 185 |     paddr_t      paddr; | 
|---|
| [1] | 186 |  | 
|---|
| [23] | 187 |     thread_t   * this    = CURRENT_THREAD; | 
|---|
| [302] | 188 |     process_t  * process = this->process; | 
|---|
| [23] | 189 |  | 
|---|
 | 190 |     // check argument fileme | 
|---|
 | 191 |     error = vmm_v2p_translate( false , filename , &paddr ); | 
|---|
 | 192 |  | 
|---|
| [302] | 193 |     if( error ) | 
|---|
| [1] | 194 |     { | 
|---|
| [23] | 195 |         printk("\n[ERROR] in %s : filename unmapped\n", __FUNCTION__ ); | 
|---|
 | 196 |         this->errno = EINVAL; | 
|---|
 | 197 |         return -1; | 
|---|
| [1] | 198 |     } | 
|---|
 | 199 |  | 
|---|
| [23] | 200 |     // check argument fileme | 
|---|
 | 201 |     error = vmm_v2p_translate( false , args , &paddr ); | 
|---|
 | 202 |  | 
|---|
| [302] | 203 |     if( error ) | 
|---|
| [23] | 204 |     { | 
|---|
 | 205 |         printk("\n[ERROR] in %s : args unmapped\n", __FUNCTION__ ); | 
|---|
 | 206 |         this->errno = EINVAL; | 
|---|
 | 207 |         return -1; | 
|---|
 | 208 |     } | 
|---|
 | 209 |  | 
|---|
 | 210 |     // check argument fileme | 
|---|
 | 211 |     error = vmm_v2p_translate( false , envs , &paddr ); | 
|---|
 | 212 |  | 
|---|
| [302] | 213 |     if( error ) | 
|---|
| [23] | 214 |     { | 
|---|
 | 215 |         printk("\n[ERROR] in %s : envs unmapped\n", __FUNCTION__ ); | 
|---|
 | 216 |         this->errno = EINVAL; | 
|---|
 | 217 |         return -1; | 
|---|
 | 218 |     } | 
|---|
 | 219 |  | 
|---|
| [1] | 220 |     // compute client_cxy (local cluster) and server_cxy (target cluster) | 
|---|
 | 221 |     cxy_t     cxy_server = CXY_FROM_PID( process->pid ); | 
|---|
 | 222 |     cxy_t     cxy_client = local_cxy; | 
|---|
 | 223 |     bool_t    is_local   = (cxy_server == cxy_client); | 
|---|
 | 224 |  | 
|---|
 | 225 |     exec_dmsg("\n[INFO] %s starts for process %x on core %d in cluster %x" | 
|---|
 | 226 |                  " / target_cluster = %x / cycle %d\n", | 
|---|
| [302] | 227 |                  __FUNCTION__, process->pid , CURRENT_CORE->lid, | 
|---|
| [101] | 228 |                  cxy_client, cxy_server, hal_get_cycles()); | 
|---|
| [1] | 229 |  | 
|---|
| [302] | 230 |     // register reference parent process in exec_info | 
|---|
| [101] | 231 |     exec_info.parent_xp   = process->ref_xp; | 
|---|
| [1] | 232 |  | 
|---|
| [302] | 233 |     // check pathname and store it in exec_info structure | 
|---|
 | 234 |     error = process_exec_get_path( &exec_info , filename ); | 
|---|
| [1] | 235 |  | 
|---|
| [302] | 236 |     if ( error ) | 
|---|
| [1] | 237 |     { | 
|---|
| [23] | 238 |         printk("\n[ERROR] in %s : elf pathname too long\n", __FUNCTION__ ); | 
|---|
 | 239 |         this->errno = error; | 
|---|
 | 240 |         return -1; | 
|---|
 | 241 |     } | 
|---|
| [1] | 242 |  | 
|---|
| [302] | 243 |     // check and store args in exec_info structure | 
|---|
 | 244 |     error = process_exec_get_strings( &exec_info , true , args ); | 
|---|
| [1] | 245 |  | 
|---|
| [302] | 246 |     if( error ) | 
|---|
| [23] | 247 |     { | 
|---|
 | 248 |         printk("\n[ERROR] in %s : cannot access args\n", __FUNCTION__ ); | 
|---|
 | 249 |         this->errno = error; | 
|---|
 | 250 |         return -1; | 
|---|
| [1] | 251 |     } | 
|---|
| [23] | 252 |  | 
|---|
| [302] | 253 |     // check and store envs in exec_info structure | 
|---|
 | 254 |     error = process_exec_get_strings( &exec_info , false , envs ); | 
|---|
 | 255 |  | 
|---|
 | 256 |     if( error ) | 
|---|
| [1] | 257 |     { | 
|---|
| [23] | 258 |         printk("\n[ERROR] in %s : cannot access envs\n", __FUNCTION__ ); | 
|---|
 | 259 |         this->errno = error; | 
|---|
 | 260 |         return -1; | 
|---|
 | 261 |     } | 
|---|
| [302] | 262 |  | 
|---|
| [23] | 263 |     exec_dmsg("\n[INFO] %s starts exec for process %x at cycle %d\n", | 
|---|
| [101] | 264 |               __FUNCTION__, process->pid, hal_get_cycles() ); | 
|---|
| [1] | 265 |  | 
|---|
| [23] | 266 |     if( is_local )  error = process_make_exec( &exec_info ); | 
|---|
 | 267 |     else            rpc_process_exec_client( cxy_server , &exec_info , &error ); | 
|---|
| [1] | 268 |  | 
|---|
| [23] | 269 |     if( error ) | 
|---|
 | 270 |     { | 
|---|
 | 271 |         printk("\n[ERROR] in %s : cannot create new process %x\n", | 
|---|
 | 272 |                __FUNCTION__ , process->pid ); | 
|---|
 | 273 |         this->errno = error; | 
|---|
 | 274 |         return -1; | 
|---|
| [1] | 275 |     } | 
|---|
 | 276 |  | 
|---|
| [23] | 277 |     exec_dmsg("\n[INFO] %s completes exec for process %x at cycle %d\n", | 
|---|
| [101] | 278 |               __FUNCTION__, process->pid , hal_get_cycles() ); | 
|---|
| [23] | 279 |  | 
|---|
 | 280 |     // delete the calling thread an process | 
|---|
| [1] | 281 |     thread_kill( CURRENT_THREAD ); | 
|---|
| [23] | 282 |     process_kill( CURRENT_THREAD->process ); | 
|---|
| [1] | 283 |  | 
|---|
 | 284 |     return 0; | 
|---|
| [23] | 285 |  | 
|---|
| [1] | 286 | } // end sys_exec() | 
|---|
 | 287 |  | 
|---|