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

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

Don't include sys-vfs.h.

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