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

Last change on this file since 302 was 302, checked in by max@…, 7 years ago

Style, and use hal_strcpy_from_uspace.

File size: 9.9 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
87    uint32_t     order;       // ln2( number of pages to store strings )
[23]88    char      ** k_pointers;  // base of kernel array of pointers
89    char       * k_buf_ptr;   // pointer on first empty slot in kernel strings buffer
90    char       * k_buf_base;  // base address of the kernel strings buffer
[1]91
92    // compute ln2( number of pages for kernel strings buffer )
[23]93    if( is_args ) order = bits_log2( CONFIG_VMM_ARGS_SIZE );
94    else          order = bits_log2( CONFIG_VMM_ENVS_SIZE );
[1]95
[302]96    req.type   = KMEM_PAGE;
97    req.flags  = AF_KERNEL | AF_ZERO;
[1]98
99    // allocate one physical page for kernel array of pointers
100    req.type   = 0;
101    page       = kmem_alloc( &req );
[23]102
103    if( page == NULL ) return ENOMEM;
104
[53]105    k_pointers = ppm_page2vaddr( page );
[302]106
[1]107    // allocate several physical pages to store the strings themselve
108    req.type   = order;
109    page       = kmem_alloc( &req );
[23]110
111    if( page == NULL ) return ENOMEM;
112
[53]113    k_buf_base = ppm_page2vaddr( page );
[302]114
115    // copy the array of pointers to kernel buffer
116    hal_copy_from_uspace( k_pointers,
[1]117                          u_pointers,
118                          CONFIG_PPM_PAGE_SIZE );
119
[23]120    // scan kernel array of pointers to copy the strings
[1]121    found_null = 0;
[23]122    k_buf_ptr  = k_buf_base;
[1]123    for( index = 0 ; index < 1024 ; index++ )
124    {
[302]125        if( k_pointers[index] == NULL )
[1]126        {
127            found_null = 1;
128            break;
129        }
130
131        // compute string length
[302]132        length = hal_strlen_from_uspace( k_pointers[index] );
133
[1]134        // copy the user string to kernel buffer
[23]135        hal_copy_from_uspace( k_buf_ptr,
136                              k_pointers[index],
[1]137                              length );
138
139        // update k_pointer[index] entry
[23]140        k_pointers[index] = k_buf_ptr;
[1]141
142        // increment pointer on kernel strings buffer
[23]143        k_buf_ptr += (length + 1);
[1]144    }
145
[302]146    // update into exec_info structure
[1]147    if( found_null && is_args )
148    {
149        exec_info->args_pointers  =  k_pointers;
[23]150        exec_info->args_buf_base  =  k_buf_base;
[1]151        exec_info->args_nr        =  index;
152    }
153    else if( found_null && !is_args )
154    {
155        exec_info->envs_pointers  =  k_pointers;
[23]156        exec_info->envs_buf_base  =  k_buf_base;
157        exec_info->envs_buf_free  =  k_buf_ptr;
[1]158        exec_info->envs_nr        =  index;
159    }
[302]160    else
[1]161    {
162        return EINVAL;
163    }
164
165    return 0;
166} // end process_exec_get_strings()
167
168/////////////////////////////////////////////////////////////////////////////////////////
169// Implementation note:
170// This function build an exec_info_t structure containing all informations
171// required to create the new process descriptor and the associated thread.
172// It calls the static process_exec_get_path() and process_exec_get_strings() functions
173// to copy the .elf pathname, the main() arguments and the environment variables from
[23]174// user buffers to the exec_info_t structure, and call the process_make_exec() function.
[1]175/////////////////////////////////////////////////////////////////////////////////////////
176int sys_exec( char  * filename,     // .elf file pathname
[23]177              char ** args,         // process arguments
178              char ** envs )        // environment variables
[1]179{
180    exec_info_t  exec_info;         // structure to pass to process_make_exec()
[302]181    error_t      error;
[23]182    paddr_t      paddr;
[1]183
[23]184    thread_t   * this    = CURRENT_THREAD;
[302]185    process_t  * process = this->process;
[23]186
187    // check argument fileme
188    error = vmm_v2p_translate( false , filename , &paddr );
189
[302]190    if( error )
[1]191    {
[23]192        printk("\n[ERROR] in %s : filename unmapped\n", __FUNCTION__ );
193        this->errno = EINVAL;
194        return -1;
[1]195    }
196
[23]197    // check argument fileme
198    error = vmm_v2p_translate( false , args , &paddr );
199
[302]200    if( error )
[23]201    {
202        printk("\n[ERROR] in %s : args unmapped\n", __FUNCTION__ );
203        this->errno = EINVAL;
204        return -1;
205    }
206
207    // check argument fileme
208    error = vmm_v2p_translate( false , envs , &paddr );
209
[302]210    if( error )
[23]211    {
212        printk("\n[ERROR] in %s : envs unmapped\n", __FUNCTION__ );
213        this->errno = EINVAL;
214        return -1;
215    }
216
[1]217    // compute client_cxy (local cluster) and server_cxy (target cluster)
218    cxy_t     cxy_server = CXY_FROM_PID( process->pid );
219    cxy_t     cxy_client = local_cxy;
220    bool_t    is_local   = (cxy_server == cxy_client);
221
222    exec_dmsg("\n[INFO] %s starts for process %x on core %d in cluster %x"
223                 " / target_cluster = %x / cycle %d\n",
[302]224                 __FUNCTION__, process->pid , CURRENT_CORE->lid,
[101]225                 cxy_client, cxy_server, hal_get_cycles());
[1]226
[302]227    // register reference parent process in exec_info
[101]228    exec_info.parent_xp   = process->ref_xp;
[1]229
[302]230    // check pathname and store it in exec_info structure
231    error = process_exec_get_path( &exec_info , filename );
[1]232
[302]233    if ( error )
[1]234    {
[23]235        printk("\n[ERROR] in %s : elf pathname too long\n", __FUNCTION__ );
236        this->errno = error;
237        return -1;
238    }
[1]239
[302]240    // check and store args in exec_info structure
241    error = process_exec_get_strings( &exec_info , true , args );
[1]242
[302]243    if( error )
[23]244    {
245        printk("\n[ERROR] in %s : cannot access args\n", __FUNCTION__ );
246        this->errno = error;
247        return -1;
[1]248    }
[23]249
[302]250    // check and store envs in exec_info structure
251    error = process_exec_get_strings( &exec_info , false , envs );
252
253    if( error )
[1]254    {
[23]255        printk("\n[ERROR] in %s : cannot access envs\n", __FUNCTION__ );
256        this->errno = error;
257        return -1;
258    }
[302]259
[23]260    exec_dmsg("\n[INFO] %s starts exec for process %x at cycle %d\n",
[101]261              __FUNCTION__, process->pid, hal_get_cycles() );
[1]262
[23]263    if( is_local )  error = process_make_exec( &exec_info );
264    else            rpc_process_exec_client( cxy_server , &exec_info , &error );
[1]265
[23]266    if( error )
267    {
268        printk("\n[ERROR] in %s : cannot create new process %x\n",
269               __FUNCTION__ , process->pid );
270        this->errno = error;
271        return -1;
[1]272    }
273
[23]274    exec_dmsg("\n[INFO] %s completes exec for process %x at cycle %d\n",
[101]275              __FUNCTION__, process->pid , hal_get_cycles() );
[23]276
277    // delete the calling thread an process
[1]278    thread_kill( CURRENT_THREAD );
[23]279    process_kill( CURRENT_THREAD->process );
[1]280
281    return 0;
[23]282
[1]283} // end sys_exec()
284
Note: See TracBrowser for help on using the repository browser.