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

Last change on this file since 351 was 315, checked in by alain, 9 years ago

Redefine the fuctions ppm_base2page() / ppm_page2base() / ppm_page2ppn() / ppm_ppn2page() / ppm_base2ppn() / ppm_ppn2base(),
to use explicitely extended pointers.

File size: 10.1 KB
RevLine 
[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///////////////////////////////////////////////////////////////////////////////////////
47static 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///////////////////////////////////////////////////////////////////////////////////////
78static 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/////////////////////////////////////////////////////////////////////////////////////////
179int 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
Note: See TracBrowser for help on using the repository browser.