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

Last change on this file since 634 was 626, checked in by alain, 7 years ago

This version has been tested on the sort multithreaded application
for TSAR_IOB architectures ranging from 1 to 8 clusters.
It fixes three bigs bugs:
1) the dev_ioc device API has been modified: the dev_ioc_sync_read()
and dev_ioc_sync_write() function use now extended pointers on the
kernel buffer to access a mapper stored in any cluster.
2) the hal_uspace API has been modified: the hal_copy_to_uspace()
and hal_copy_from_uspace() functions use now a (cxy,ptr) couple
to identify the target buffer (equivalent to an extended pointer.
3) an implementation bug has been fixed in the assembly code contained
in the hal_copy_to_uspace() and hal_copy_from_uspace() functions.

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