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

Last change on this file since 423 was 421, checked in by alain, 9 years ago

Introduce sys_fg() , sys_display() , sys_wait() syscalls.

File size: 9.2 KB
Line 
1/*
2 * sys_exec.c - Kernel function implementing the "exec" system call.
3 *
4 * Authors Alain Greiner (2016,2017)
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
24#include <kernel_config.h>
25#include <hal_types.h>
26#include <hal_uspace.h>
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
39////////////////////////////////////////////////i//////////////////////////////////////
40// This static function is called twice by the sys_exec() function :
41// - to register the main() arguments (args) in the exec_info structure.
42// - to register the environment variables (envs) in the exec_info structure.
43// In both cases the input is an array of string pointers in user space,
44// and a set of strings in user space.
45// We allocate one physical page to store a kernel copy of the array of pointers,
46// we allocate one or several physical pages to store the strings themselve,
47// and register these buffers and the number of strings in the exec_info structure.
48// The max number of strings is 1024 (for both args and envs). The numbers of pages
49// to store the (args) and (envs) strings are configuration parameters.
50///////////////////////////////////////////////////////////////////////////////////////
51// @ exec_info : pointer on the exec_info structure.
52// @ is_args : true if called for (args) / false if called for (envs).
53// @ u_pointers : array of pointers on the strings (in user space).
54// @ return 0 if success / non-zero if too many strings or no more memory.
55///////////////////////////////////////////////////////////////////////////////////////
56static error_t process_exec_get_strings( exec_info_t * exec_info,
57 bool_t is_args,
58 char ** u_pointers )
59{
60 uint32_t index; // string index
61 uint32_t found_null; // NULL pointer found in array of pointers
62 uint32_t length; // string length
63 kmem_req_t req; // kmem request
64 page_t * page; // page descriptor
65 xptr_t base_xp; // extended pointer on page base
66 uint32_t order; // ln2( number of pages to store strings )
67 char ** k_pointers; // base of kernel array of pointers
68 char * k_buf_ptr; // pointer on first empty slot in kernel strings buffer
69 char * k_buf_base; // base address of the kernel strings buffer
70
71 // compute ln2( number of pages for kernel strings buffer )
72 if( is_args ) order = bits_log2( CONFIG_VMM_ARGS_SIZE );
73 else order = bits_log2( CONFIG_VMM_ENVS_SIZE );
74
75 req.type = KMEM_PAGE;
76 req.flags = AF_KERNEL | AF_ZERO;
77
78 // allocate one physical page for kernel array of pointers
79 req.type = 0;
80 page = kmem_alloc( &req );
81
82 if( page == NULL ) return ENOMEM;
83
84 base_xp = ppm_page2base( XPTR( local_cxy , page ) );
85 k_pointers = (char **)GET_PTR( base_xp );
86
87 // allocate several physical pages to store the strings themselve
88 req.type = order;
89 page = kmem_alloc( &req );
90
91 if( page == NULL ) return ENOMEM;
92
93 base_xp = ppm_page2base( XPTR( local_cxy , page ) );
94 k_buf_base = (char *)GET_PTR( base_xp );
95
96 // copy the array of pointers to kernel buffer
97 hal_copy_from_uspace( k_pointers,
98 u_pointers,
99 CONFIG_PPM_PAGE_SIZE );
100
101 // scan kernel array of pointers to copy the strings
102 found_null = 0;
103 k_buf_ptr = k_buf_base;
104 for( index = 0 ; index < 1024 ; index++ )
105 {
106 if( k_pointers[index] == NULL )
107 {
108 found_null = 1;
109 break;
110 }
111
112 // compute string length
113 length = hal_strlen_from_uspace( k_pointers[index] );
114
115 // copy the user string to kernel buffer
116 hal_copy_from_uspace( k_buf_ptr,
117 k_pointers[index],
118 length );
119
120 // update k_pointer[index] entry
121 k_pointers[index] = k_buf_ptr;
122
123 // increment pointer on kernel strings buffer
124 k_buf_ptr += (length + 1);
125 }
126
127 // update into exec_info structure
128 if( found_null && is_args )
129 {
130 exec_info->args_pointers = k_pointers;
131 exec_info->args_buf_base = k_buf_base;
132 exec_info->args_nr = index;
133 }
134 else if( found_null && !is_args )
135 {
136 exec_info->envs_pointers = k_pointers;
137 exec_info->envs_buf_base = k_buf_base;
138 exec_info->envs_buf_free = k_buf_ptr;
139 exec_info->envs_nr = index;
140 }
141 else
142 {
143 return EINVAL;
144 }
145
146 return 0;
147} // end process_exec_get_strings()
148
149/////////////////////////////////////////////////////////////////////////////////////////
150// Implementation note:
151// This function build an exec_info_t structure containing all informations
152// required to initialize the new process descriptor and the associated thread.
153// It includes the process PID (unchanged), main() arguments, environment variables,
154// and the pathname to the new process .elf file.
155// It calls the process_exec_get_strings() functions to copy the main() arguments and
156// the environment variables from user buffers to the exec_info_t structure, allocate
157// and call the process_make_exec() function.
158// As it must destroy all parent process copies, and all parent threads in all clusters,
159// the process_make_exec() function must be executed in the parent owner cluster,
160// and this sys_exec() function uses a RPC to access the owner cluster if required.
161//
162// TODO : the args & envs arguments are not supported yet : both must be NULL [AG]
163/////////////////////////////////////////////////////////////////////////////////////////
164int sys_exec( char * pathname, // .elf file pathname
165 char ** args, // process arguments
166 char ** envs ) // environment variables
167{
168 exec_info_t exec_info; // structure to pass to process_make_exec()
169 error_t error;
170
171 // get parent process pid
172 thread_t * this = CURRENT_THREAD;
173 process_t * process = this->process;
174 pid_t pid = process->pid;
175
176#if CONFIG_SYSCALL_DEBUG
177uint64_t tm_start;
178uint64_t tm_end;
179tm_start = hal_get_cycles();
180printk("\n[DBG] %s : core[%x,%d] enter / process %x / cycle = %d\n",
181__FUNCTION__, local_cxy, this->core->lid, pid, (uint32_t)tm_start );
182#endif
183
184 // get owner cluster
185 cxy_t owner_cxy = CXY_FROM_PID( pid );
186
187 // check pathname length
188 if( hal_strlen_from_uspace( pathname ) >= CONFIG_VFS_MAX_PATH_LENGTH )
189 {
190 printk("\n[ERROR] in %s : pathname too long\n", __FUNCTION__ );
191 this->errno = ENFILE;
192 return -1;
193 }
194
195 // copy pathname in exec_info structure (kernel space)
196 hal_strcpy_from_uspace( exec_info.path , pathname , CONFIG_VFS_MAX_PATH_LENGTH );
197
198 // check args argument
199 assert( (args == NULL) , __FUNCTION__ ,
200 "args not supported yet\n" );
201
202 // check envs argument
203 assert( (envs == NULL) , __FUNCTION__ ,
204 "args not supported yet\n" );
205
206 // check and store args in exec_info structure if required
207 if( args != NULL )
208 {
209 if( process_exec_get_strings( &exec_info , true , args ) )
210 {
211 printk("\n[ERROR] in %s : cannot access args\n", __FUNCTION__ );
212 this->errno = error;
213 return -1;
214 }
215 }
216
217 // check and store envs in exec_info structure if required
218 if( envs != NULL )
219 {
220 if( process_exec_get_strings( &exec_info , false , envs ) )
221 {
222 printk("\n[ERROR] in %s : cannot access envs\n", __FUNCTION__ );
223 this->errno = error;
224 return -1;
225 }
226 }
227
228 // register PID in exec_info
229 exec_info.pid = pid;
230
231 // call process_make_exec (local or remote)
232 if( owner_cxy == local_cxy )
233 {
234 error = process_make_exec( &exec_info );
235 }
236 else
237 {
238 rpc_process_make_exec_client( owner_cxy,
239 &exec_info,
240 &error );
241 }
242
243 if( error )
244 {
245 printk("\n[ERROR] in %s : cannot create new process %x in cluster %x\n",
246 __FUNCTION__, pid, owner_cxy );
247 this->errno = error;
248 return -1;
249 }
250
251#if CONFIG_SYSCALL_DEBUG
252tm_end = hal_get_cycles();
253printk("\n[DBG] %s : core[%x,%d] exit / process %x / path = %s / cost = %d / cycle %d\n",
254__FUNCTION__, local_cxy, this->core->lid, pid, exec_info.path,
255(uint32_t)(tm_end - tm_start) , (uint32_t)tm_end );
256#endif
257
258 return 0;
259
260} // end sys_exec()
261
Note: See TracBrowser for help on using the repository browser.