source: trunk/kernel/kern/do_exec.c @ 173

Last change on this file since 173 was 1, checked in by alain, 8 years ago

First import

File size: 17.6 KB
RevLine 
[1]1/*
2 * kern/do_exec.c - excecutes a new user process, load init.
3 *
4 * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless
5 * Copyright (c) 2011,2012,2013,2014,2015 UPMC Sorbonne Universites
6 *
7 * This file is part of ALMOS-kernel.
8 *
9 * ALMOS-kernel is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2.0 of the License.
12 *
13 * ALMOS-kernel is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ALMOS-kernel; if not, write to the Free Software Foundation,
20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#include <stdarg.h>
24#include <config.h>
25#include <errno.h>
26#include <types.h>
27#include <libk.h>
28#include <bits.h>
29#include <kmem.h>
30#include <process.h>
31#include <cpu.h>
32#include <pmm.h>
33#include <page.h>
34#include <process.h>
35#include <thread.h>
36#include <pid.h>
37#include <list.h>
38#include <vfs.h>
39#include <sys-vfs.h>
40#include <scheduler.h>
41#include <spinlock.h>
42#include <cluster.h>
43#include <ku_transfert.h>
44#include <dqdt.h>
45
46#define USR_LIMIT  (CONFIG_USR_LIMIT)
47
48#define DEV_STDIN   CONFIG_DEV_STDIN
49#define DEV_STDOUT  CONFIG_DEV_STDOUT
50#define DEV_STDERR  CONFIG_DEV_STDERR
51
52#define TASK_DEFAULT_HEAP_SIZE  CONFIG_TASK_HEAP_MIN_SIZE
53
54#define INIT_PATH   "/bin/init"
55
56/* FIXME : ecopy et estrlen attendent une adresse de vecteur dans l'espace utilisateur. Or pour
57 * l'instant l'environnement des processus est "forgé" dans do_exec(), c'est donc des buffers
58 * noyaux. Solution temporaire : on utilise kexec_copy et kexec_strlen.
59 */
60//////////////////////////////////////
61error_t args_len( char        ** vect, 
62                  uint32_t       pages_max, 
63                          uint32_t     * pages_nr,
64                  uint32_t     * entries_nr,
65                          exec_copy_t    ecopy, 
66                  exec_strlen_t  estrlen)
67{
68        uint32_t     cntr;
69        uint32_t     pgnr;
70        error_t      error;
71        uint32_t     count;
72        uint32_t     len;
73    char       * ptr;
74 
75        cntr  = 0;
76        count = 0;
77        pgnr  = 0;
78
79        while(1)
80        {
81                if((error = ecopy(&ptr, &vect[cntr], sizeof(ptr))))
82                {
83                        printk(INFO, "INFO: %s:%s: EFAULT Has been Catched on vect, cntr %d, strlen &vect[%x] = %x\n",  \
84                                        __FUNCTION__, __LINE__, cntr, &vect[cntr], vect[cntr]);
85                        return err;
86                }
87
88                if(ptr == NULL)
89                        break;
90
91                if((err=estrlen(ptr, &len)))
92                {
93                        printk(INFO, "INFO: %s:%s: EFAULT Has been Catched, cntr %d, strlen &vect[%x] = %x\n",          \
94                                        __FUNCTION__, __LINE__, cntr, &vect[cntr], vect[cntr]);
95                        return err;
96                }
97                cntr  ++;
98                len   ++;
99                count += (ARROUND_UP(len, 8));
100                pgnr   = ARROUND_UP(count, PMM_PAGE_SIZE);
101   
102                if((pgnr >> PMM_PAGE_SHIFT) >= pages_max)
103                        return E2BIG;
104        }
105
106        count       = (cntr + 1) * sizeof(char*);
107        *pages_nr   = (ARROUND_UP(count, PMM_PAGE_SIZE)) / PMM_PAGE_SIZE;
108        *entries_nr = cntr;
109        return 0;
110}
111
112//for now the pointers can be either be from uspace
113//or kernel space. Solutions :
114//first keep this binaroty and add a flag to
115//choose how to copy the arguments
116//second make them all user space ptr
117//third make them kernel space ptr
118//the first solution (although ugly), is the most
119//perfroming(compared to u->k) and simple
120//(compared to k->u)
121
122//////////////////////////////////////////////
123//////////////////////////////////////////////
124error_t compute_args( process_t     * process, 
125                              char         ** vect,
126                              page_t       ** pgtbl,
127                              uint32_t        pages_max, 
128                              uint32_t        start,
129                              uint32_t      * current, 
130                              uint32_t      * pgnr,
131                              uint32_t      * pgindex,
132                              exec_copy_t     ecopy, 
133                              exec_strlen_t   estrlen)
134{
135        kmem_req_t req;
136        uint32_t   count;
137        uint32_t   cntr;
138        uint32_t   pages_nr;
139        char    ** args;
140        char     * ptr;
141        uint32_t   i;
142        uint32_t   len;
143        uint32_t   index;
144        uint32_t   paddr;
145        error_t    error;
146
147        req.type  = KMEM_PAGE;
148        req.size  = 0;
149        req.flags = AF_USER | AF_ZERO | AF_REMOTE;
150        req.ptr   = process->cluster;
151
152        pages_nr  = 0;
153        count     = 0;
154        cntr      = 0;
155        index     = *pgindex;
156
157        error = args_len(vect, pages_max, &pages_nr, &cntr, ecopy, estrlen);
158 
159        if( error ) return error;
160
161        *pgnr += pages_nr;
162
163        for(i = index; i < (pages_nr + index); i++)
164        {
165                pgtbl[i] = kmem_alloc(&req);
166   
167                if(pgtbl[i] == NULL) return ENOMEM;
168        }
169 
170        *current = start - (pages_nr * PMM_PAGE_SIZE);
171 
172        paddr = (uint32_t) ppm_page2addr(pgtbl[index]);
173        count = (cntr + 1) * sizeof(char*);
174        args = (char **) paddr;
175        pages_nr = 0;
176
177        /* Copy the table of pointer */
178        while(count > PMM_PAGE_SIZE)
179        {
180                error = ecopy((void*)paddr, vect + (pages_nr << PMM_PAGE_SHIFT), PMM_PAGE_SIZE);
181
182                if( error ) return error;
183   
184                index ++;
185                paddr  = (uint32_t) ppm_page2addr(pgtbl[index]);
186                count -= PMM_PAGE_SIZE;
187                pages_nr ++;
188        }
189
190        if(count > 0)
191        {
192                error = ecopy((void*)paddr, vect + (pages_nr << PMM_PAGE_SHIFT), count);
193                if( error ) return error;
194        }
195
196        paddr += count;
197 
198        /* Copy the the table of pointer content */
199        for(i=0; i < cntr; i++)
200        {
201                if((error = ecopy(&ptr, &vect[i], sizeof(ptr))))
202                {
203                        printk(INFO, "INFO: %s: EFAULT Has been Catched on vect\n", __FUNCTION__);
204                        return err;
205                }
206
207                error = estrlen(ptr, &len);
208                if(err) return err;
209                len++;
210
211
212                /* Update pointer */
213                args[i] = (char*)(*current + (pages_nr << PMM_PAGE_SHIFT) + count);
214   
215                /* The content could span multiple pages */
216                while(len)
217                {
218                        if((PMM_PAGE_SIZE - count) > (ARROUND_UP(len, 8)))
219                        {
220                                error = ecopy((void*)paddr, ptr, len);
221                                if(err) return err;
222                                paddr += (ARROUND_UP(len, 8));
223                                count += (ARROUND_UP(len, 8));
224                                len = 0;
225                        }
226                        else
227                        {
228                                error = ecopy((void*)paddr, ptr, PMM_PAGE_SIZE - count);
229                                if(err) return err;
230                                ptr += (PMM_PAGE_SIZE - count);
231                                len -= (PMM_PAGE_SIZE - count);
232                                index ++;
233                                paddr = (uint32_t) ppm_page2addr(pgtbl[index]);
234                                pages_nr ++;
235                                count = 0;
236                        }
237                }
238        }
239
240        *pgindex = index + 1; 
241        return 0;
242}
243
244///////////////////////////////////////
245error_t map_args( process_s  * process,
246                          page_t    ** pgtbl, 
247                          uint32_t     start_index, 
248                          uint32_t     end_index,
249                          uint32_t     start_addr )
250{
251        struct pmm_s *pmm;
252        pmm_page_info_t info;
253        uint32_t current_vma;
254        error_t err;
255        uint32_t i;
256
257        pmm = &process->vmm.pmm;
258        info.attr = PMM_PRESENT | PMM_READ | PMM_WRITE | PMM_CACHED | PMM_USER; 
259        info.cluster = process->cluster;
260        current_vma = start_addr;
261
262        for(i = start_index; i < end_index; i++)
263        {   
264                info.ppn = ppm_page2ppn(pgtbl[i]);
265   
266                if((error = pmm_set_page(pmm, current_vma, &info)))
267                        return err;
268
269                pgtbl[i] = NULL;
270                current_vma += PMM_PAGE_SIZE;
271        }
272 
273        return 0;
274}
275
276//////////////////////////////////////
277error_t do_exec( process_t  * process,
278                     char       * pathname,
279                         page_t     * pgtbl[],
280                         uint32_t     env_end,
281                         uint32_t     env_index,
282                         uint32_t     argv_end,    // user_stack_top
283                         uint32_t     argv_index,
284                 thread_t  ** new )
285{
286        error_t        error;
287        pthread_attr_t attr;
288        uint32_t       usr_stack_top;
289        int32_t        order;
290        thread_t     * main_thread;
291 
292        attr.arg2     = (void*)env_end; /* environ */
293        attr.arg1     = (void*)argv_end;        /* argv */
294        usr_stack_top = argv_end;
295 
296    /* FIXME:
297     * zero should not be hard-coded. Use something like MAIN_KERNEL which represents the
298     * kernel with the init and sh processes (assuming that both of them are on the same kernel).
299     */
300
301        if( ((process->pid != PID_MIN_GLOBAL+1) && (current_cid == 0)) ||
302                ( (process->pid != PID_MIN_GLOBAL) && (current_cid != 0) ) )
303        {
304                vmm_destroy(&process->vmm);
305                pmm_release(&process->vmm.pmm);   
306                error = vmm_init(&process->vmm);
307                if(err) goto DO_EXEC_ERR;
308        }
309 
310        attr.stack_addr = (void*)(usr_stack_top - CONFIG_PTHREAD_STACK_SIZE);
311        attr.stack_size = CONFIG_PTHREAD_STACK_SIZE;
312
313    // create stack vseg
314        error = (error_t) vmm_mmap( process,
315                                                attr.stack_addr,                            // base
316                                                USR_LIMIT - (uint32_t)attr.stack_addr,      // size
317                                VSEG_TYPE_STACK,                            // type
318                                                VSEG_RD | VSEG_WR,                          // flags
319//                                              PRIVATE | ANON | STACK | FIXED, 
320                                NULL,                                       // file
321                                0 );                                        // offset
322 
323        if( error == VM_FAILURE )
324        {
325                error = CURRENT_THREAD->info.errno;
326                printk(INFO, "%s: failed to mmap main's stack for process %x / error = %d\n", 
327                       __FUNCTION__, process->pid , error );
328        return error;
329        }
330
331    // TODO ??? AG       
332        error = map_args(process, pgtbl, 0, env_index, (uint32_t)attr.arg2);
333        if( error )
334    {
335        return error;
336    }
337 
338    // TODO ??? AG       
339        error = map_args(process, pgtbl, env_index, argv_index, (uint32_t)attr.arg1);
340        if(err)
341    {
342        return error;
343    }
344
345    // register "entry_point" in VMM, register "code" and "data" vsegs in VMM,
346    // using informations contained in the elf file identified by the pathname.
347        error = elf_load_process( path_name , process );
348        if( error )
349        {
350                printk(INFO, "%s: failed to access elf for process %x\n", 
351                       __FUNCTION__, process->pid );
352        return error;
353        }
354
355    // create "heap" vseg
356        error = (error_t) vmm_mmap( process,
357                                                (void *)process->vmm.heap_start,            // base
358                                                PROCESS_DEFAULT_HEAP_SIZE,                  // size
359                                VSEG_TYPE_HEAP,                             // type
360                                VSEG_RD | VSEG_WR,                          // flags
361//                                              PRIVATE | ANON | HEAP | FIXED,
362                                NULL,                                       // file
363                                0 );                                        // offset
364
365        if( error == VM_FAILURE )
366        {
367                error = CURRENT_THREAD->info.errno;
368                printk(INFO, "%s: failed to mmap heap for process %x\n", 
369                       __FUNCTION__, process->pid );
370                return error;
371        }
372
373        process->vmm.heap_current += TASK_DEFAULT_HEAP_SIZE;
374
375    // initialize pthread attributes
376    attr.pid          = exec_info->pid;
377    attr.entry_func   = (void*)process->vmm.entry_point;
378    attr.entry_args   = bloup;               // TODO [AG]
379    attr.flags        = PT_FLAG_DETACH; 
380    attr.stack_size   = CONFIG_PTHREAD_STACK_SIZE;
381        attr.sched_policy = SCHED_RR;
382    attr.cxy          = LOCAL_CLUSTER;
383    attr.lid          = bloup;               // TODO [AG] 
384
385//      attr.flags = (CURRENT_THREAD->info.attr.flags | PT_ATTR_DETACH);
386//      attr.sched_policy = SCHED_RR;
387//      attr.cid = process->cluster->id;
388//      attr.cpu_lid = process->cpu->lid;
389//      attr.cpu_gid = process->cpu->gid;
390//      attr.entry_func = (void*)process->vmm.entry_point;
391//      attr.exit_func = NULL;
392//      attr.stack_size = attr.stack_size - SIG_DEFAULT_STACK_SIZE;
393//      attr.sigstack_addr = (void*)((uint32_t)attr.stack_addr + attr.stack_size);
394//      attr.sigstack_size = SIG_DEFAULT_STACK_SIZE;
395//      attr.sigreturn_func = 0;
396
397    // create and initialise thread descriptor,
398    // register the thread in local process descriptor
399        error = thread_user_create( &attr , &main_thread );
400        if( error )
401        {
402                printk(INFO, "%s: failed to create main thread for process %x\n"
403                       __FUNCTION__, process->pid );
404        return error;
405        }
406 
407        return 0;
408}  // end do_exec()
409
410//////////////////////////////////////////////////////////////////////
411//
412//////////////////////////////////////////////////////////////////////
413error_t prepare_args( process_t   * process,
414                                  char       ** argv,
415                      char       ** envp,
416                      page_t      * pgtbl[],
417                      uint32_t    * argv_index,
418                      uint32_t    * env_index,
419                      uint32_t    * argv_end,
420                      uint32_t    * env_end,
421                      exec_copy_t   ecopy,
422                      exec_strlen_t estrlen )
423{
424        uint32_t usr_stack_top = USR_LIMIT;
425        uint32_t pages_nr      = 0;
426        uint32_t pages_max     = CONFIG_TASK_ARGS_PAGES_MAX_NR;
427        uint32_t index         = 0;
428        error_t  error         = 0;
429
430        memset( &pgtbl[0] , 0 , pages_max*sizeof(page_t *) );
431
432    // env_index & env_end
433        error = compute_args( process,
434                                      envp,
435                                      &pgtbl[0],
436                                      pages_max,
437                                      USR_LIMIT,
438                                      &usr_stack_top,
439                                      &pages_nr,
440                                      &index,
441                                      ecopy,
442                                      estrlen );
443
444        *env_index = index;
445        *env_end   = usr_stack_top;     /* environ */
446
447        if( error ) return error;
448
449    // argv_index & argv_end
450        error = compute_args( process,
451                                      argv,
452                                      &pgtbl[0],
453                                      pages_max - pages_nr,
454                                      usr_stack_top,
455                                      &usr_stack_top,
456                                      &pages_nr,
457                                      &index,
458                                      ecopy,
459                                      estrlen );
460
461        *argv_index = index;
462        *argv_end   = usr_stack_top;    /* argv */
463
464        return error;
465}
466
467//////////////////////////////////
468void free_args( page_t * pgtbl[] )
469{
470        uint32_t index;
471
472        for(index = 0; index < CONFIG_TASK_ARGS_PAGES_MAX_NR; index ++)
473        {
474                if(pgtbl[index] != NULL)
475                        ppm_free_pages(pgtbl[index]);
476        }
477}
478
479/////////////////////////////////////////////
480error_t full_do_exec( process_t    * process,
481                              char         * path_name,
482                              char        ** argv,
483                              char        ** envp,
484                              uint32_t     * isFatal,
485                              thread_t    ** new,
486                              exec_copy_t    ecopy,
487                              exec_strlen_t  estrlen )
488{
489        error_t    err;
490        uint32_t   argv_index;
491        uint32_t   env_index;
492        uint32_t   argv_end;
493        uint32_t   env_end;
494    page_t   * pgtbl[CONFIG_TASK_ARGS_PAGES_MAX_NR];
495
496        *isFatal = 0;
497        error = prepare_args( process, 
498                        argv, 
499                        envp,
500                                    pgtbl, 
501                        &argv_index,
502                                    &env_index,
503                                    &argv_end,
504                                    &env_end,
505                                    ecopy,
506                                    estrlen );
507
508        if(err)
509                goto EXEC_EXIT;
510
511        error = do_exec( process, 
512                   path_name, 
513                   &pgtbl[0], 
514                   env_end, 
515                               env_index,
516                   argv_end, 
517                   argv_index,
518                   new );
519
520        if(err)
521        {
522                printk(INFO, "%s: do_exec failed",  __FUNCTION__);
523                *isFatal = 1;
524        }
525
526EXEC_EXIT:
527        if(err)
528        {
529                free_args(pgtbl);
530        }
531 
532        return err;
533}
534
535
536///////////////////////////////////
537error_t kexec_copy( void     * dst,
538                    void     * src,
539                    uint32_t   count )
540{
541        memcpy( dst , src , count );
542        return 0;
543}
544
545/////////////////////////////////////
546error_t kexec_strlen( char     * dst,
547                      uint32_t * count)
548{
549        *count = strlen( dst );
550        return 0;
551}
552
553////////////////////////////////////////////////
554error_t process_load_init( process_t * process )
555{
556        process_t   * init;
557        dqdt_attr_t   attr;
558        thread_t    * main_thread;
559
560        struct vfs_file_s stdin;
561        struct vfs_file_s stdout;
562        struct vfs_file_s stderr;
563        struct ku_obj ku_path;
564
565        error_t err;
566        error_t err1;
567        error_t err2;
568        uint32_t isFatal;
569        char *environ[] = {"ALMOS_VERSION="CONFIG_ALMOS_VERSION, NULL};
570        char *argv[]    = {INIT_PATH, "init", NULL};
571
572        printk(INFO, "INFO: Loading Init Process [ %s ]\n", INIT_PATH);
573
574        error = dqdt_process_placement(dqdt_root, &attr);
575        /* Force init to be on current cluster */
576        attr.cid_exec = current_cid;
577
578        assert(error == 0);
579
580        if((error = process_create(&init, &attr, CPU_USR_MODE)))
581                return err;
582
583        error = vmm_init(&init->vmm);
584
585        if(err) goto INIT_ERR;
586
587        error = pmm_init(&init->vmm.pmm, current_cluster);
588
589        if(err) goto INIT_ERR;
590 
591        error = pmm_dup(&init->vmm.pmm, &process->vmm.pmm);
592 
593        if(err) goto INIT_ERR;
594 
595        vfs_file_up(&process->vfs_root);
596        init->vfs_root = process->vfs_root;
597
598        vfs_file_up(&process->vfs_root);
599        init->vfs_cwd  = process->vfs_root;
600
601        init->vmm.limit_addr = CONFIG_USR_LIMIT;
602        init->uid = 0;
603        init->parent = process->pid;
604        atomic_init(&init->childs_nr, 0);
605        atomic_init(&process->childs_nr, 1);
606 
607        list_add_last(&process->children, &init->list);
608
609        KK_BUFF(ku_path, ((void*) DEV_STDIN));
610        error  = vfs_open(&init->vfs_cwd, &ku_path,  VFS_O_RDONLY, 0, &stdin);
611        KK_BUFF(ku_path, ((void*) DEV_STDOUT));
612        err1 = vfs_open(&init->vfs_cwd, &ku_path, VFS_O_WRONLY, 0, &stdout);
613        KK_BUFF(ku_path, ((void*) DEV_STDERR));
614        err2 = vfs_open(&init->vfs_cwd, &ku_path, VFS_O_WRONLY, 0, &stderr);
615
616        if(error || err1 || err2)
617        {
618                if(!err)  vfs_close(&stdin,  NULL);
619                if(!err1) vfs_close(&stdout, NULL);
620                if(!err2) vfs_close(&stderr, NULL);
621   
622                printk(ERROR,"ERROR: do_exec: cannot open fds [%d, %d, %d]\n", err, err1, err2);
623                error = ENOMEM;
624   
625                goto INIT_ERR;
626        }
627
628        process_fd_set(init, 0, &stdin);
629        process_fd_set(init, 1, &stdout);
630        process_fd_set(init, 2, &stderr);
631
632        CURRENT_THREAD->info.attr.flags = PT_ATTR_AUTO_NXTT | PT_ATTR_MEM_PRIO | PT_ATTR_AUTO_MGRT;
633
634        error = full_do_exec(init, INIT_PATH, &argv[0], &environ[0], &isFatal, 
635                                &main_thread, kexec_copy, kexec_strlen);
636 
637        if(error == 0)
638        {
639                assert(main_thread != NULL && (main_thread->signature == THREAD_ID));
640                init->state = TASK_READY;
641                error = sched_register(main_thread);
642                assert(error == 0);             /* FIXME: ask DQDT for another core */
643
644#if CONFIG_ENABLE_TASK_TRACE
645                main_thread->info.isTraced = true;
646#endif
647                sched_add_created(main_thread);
648
649                printk(INFO, "INFO: Init Process Loaded [ %s ]\n", INIT_PATH);
650
651                return 0;
652        }
653
654INIT_ERR:
655        process_destroy(init);
656        return err;
657}
Note: See TracBrowser for help on using the repository browser.