Subversion Repositories HelenOS

Rev

Rev 3593 | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2001-2004 Jakub Jermar
  3.  * Copyright (c) 2008 Jiri Svoboda
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms, with or without
  7.  * modification, are permitted provided that the following conditions
  8.  * are met:
  9.  *
  10.  * - Redistributions of source code must retain the above copyright
  11.  *   notice, this list of conditions and the following disclaimer.
  12.  * - Redistributions in binary form must reproduce the above copyright
  13.  *   notice, this list of conditions and the following disclaimer in the
  14.  *   documentation and/or other materials provided with the distribution.
  15.  * - The name of the author may not be used to endorse or promote products
  16.  *   derived from this software without specific prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  19.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  20.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  22.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  24.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  25.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28.  */
  29.  
  30. /** @addtogroup genericproc
  31.  * @{
  32.  */
  33.  
  34. /**
  35.  * @file
  36.  * @brief   Running userspace programs.
  37.  */
  38.  
  39. #include <main/uinit.h>
  40. #include <proc/thread.h>
  41. #include <proc/task.h>
  42. #include <proc/uarg.h>
  43. #include <mm/as.h>
  44. #include <mm/slab.h>
  45. #include <arch.h>
  46. #include <adt/list.h>
  47. #include <ipc/ipc.h>
  48. #include <ipc/ipcrsc.h>
  49. #include <security/cap.h>
  50. #include <lib/elf.h>
  51. #include <errno.h>
  52. #include <print.h>
  53. #include <syscall/copy.h>
  54. #include <proc/program.h>
  55. #include <arch/asm.h>
  56.  
  57. #ifndef LOADED_PROG_STACK_PAGES_NO
  58. #define LOADED_PROG_STACK_PAGES_NO 1
  59. #endif
  60.  
  61. /**
  62.  * Points to the binary image used as the program loader. All non-initial
  63.  * tasks are created from this executable image.
  64.  */
  65. void *program_loader = NULL;
  66.  
  67. /** Create a program using an existing address space.
  68.  *
  69.  * @param as        Address space containing a binary program image.
  70.  * @param entry_addr    Program entry-point address in program address space.
  71.  * @param name      Name to set for the program's task.
  72.  * @param p     Buffer for storing program information.
  73.  */
  74. void program_create(as_t *as, uintptr_t entry_addr, char *name, program_t *p)
  75. {
  76.     as_area_t *a;
  77.     uspace_arg_t *kernel_uarg;
  78.  
  79.     kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
  80.     kernel_uarg->uspace_entry = (void *) entry_addr;
  81.     kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS;
  82.     kernel_uarg->uspace_thread_function = NULL;
  83.     kernel_uarg->uspace_thread_arg = NULL;
  84.     kernel_uarg->uspace_uarg = NULL;
  85.    
  86.     p->task = task_create(as, name);
  87.     ASSERT(p->task);
  88.  
  89.     /*
  90.      * Create the data as_area.
  91.      */
  92.     a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
  93.         LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS,
  94.         AS_AREA_ATTR_NONE, &anon_backend, NULL);
  95.  
  96.     /*
  97.      * Create the main thread.
  98.      */
  99.     p->main_thread = thread_create(uinit, kernel_uarg, p->task,
  100.         THREAD_FLAG_USPACE, "uinit", false);
  101.     ASSERT(p->main_thread);
  102. }
  103.  
  104. /** Parse an executable image in the kernel memory.
  105.  *
  106.  * If the image belongs to a program loader, it is registered as such,
  107.  * (and *task is set to NULL). Otherwise a task is created from the
  108.  * executable image. The task is returned in *task.
  109.  *
  110.  * @param image_addr    Address of an executable program image.
  111.  * @param name      Name to set for the program's task.
  112.  * @param p     Buffer for storing program info. If image_addr
  113.  *          points to a loader image, p->task will be set to
  114.  *          NULL and EOK will be returned.
  115.  *
  116.  * @return EOK on success or negative error code.
  117.  */
  118. int program_create_from_image(void *image_addr, char *name, program_t *p)
  119. {
  120.     as_t *as;
  121.     unsigned int rc;
  122.  
  123.     as = as_create(0);
  124.     ASSERT(as);
  125.  
  126.     rc = elf_load((elf_header_t *) image_addr, as, 0);
  127.     if (rc != EE_OK) {
  128.         as_destroy(as);
  129.         p->task = NULL;
  130.         p->main_thread = NULL;
  131.         if (rc != EE_LOADER)
  132.             return ENOTSUP;
  133.        
  134.         /* Register image as the program loader */
  135.         ASSERT(program_loader == NULL);
  136.         program_loader = image_addr;
  137.         printf("Registered program loader at 0x%" PRIp "\n",
  138.             image_addr);
  139.         return EOK;
  140.     }
  141.  
  142.     program_create(as, ((elf_header_t *) image_addr)->e_entry, name, p);
  143.  
  144.     return EOK;
  145. }
  146.  
  147. /** Create a task from the program loader image.
  148.  *
  149.  * @param p Buffer for storing program info.
  150.  * @param name  Name to set for the program's task.
  151.  *
  152.  * @return EOK on success or negative error code.
  153.  */
  154. int program_create_loader(program_t *p, char *name)
  155. {
  156.     as_t *as;
  157.     unsigned int rc;
  158.     void *loader;
  159.  
  160.     as = as_create(0);
  161.     ASSERT(as);
  162.  
  163.     loader = program_loader;
  164.     if (!loader) {
  165.         printf("Cannot spawn loader as none was registered\n");
  166.         return ENOENT;
  167.     }
  168.  
  169.     rc = elf_load((elf_header_t *) program_loader, as, ELD_F_LOADER);
  170.     if (rc != EE_OK) {
  171.         as_destroy(as);
  172.         return ENOENT;
  173.     }
  174.  
  175.     program_create(as, ((elf_header_t *) program_loader)->e_entry,
  176.         name, p);
  177.  
  178.     return EOK;
  179. }
  180.  
  181. /** Make program ready.
  182.  *
  183.  * Switch program's main thread to the ready state.
  184.  *
  185.  * @param p Program to make ready.
  186.  */
  187. void program_ready(program_t *p)
  188. {
  189.     thread_ready(p->main_thread);
  190. }
  191.  
  192. /** Syscall for creating a new loader instance from userspace.
  193.  *
  194.  * Creates a new task from the program loader image, connects a phone
  195.  * to it and stores the phone id into the provided buffer.
  196.  *
  197.  * @param uspace_phone_id   Userspace address where to store the phone id.
  198.  * @param name          Name to set on the new task (typically the same
  199.  *              as the command used to execute it).
  200.  *
  201.  * @return 0 on success or an error code from @ref errno.h.
  202.  */
  203. unative_t sys_program_spawn_loader(int *uspace_phone_id, char *uspace_name,
  204.     size_t name_len)
  205. {
  206.     program_t p;
  207.     int fake_id;
  208.     int rc;
  209.     int phone_id;
  210.     char namebuf[TASK_NAME_BUFLEN];
  211.  
  212.     fake_id = 0;
  213.  
  214.     /* Before we even try creating the task, see if we can write the id */
  215.     rc = (unative_t) copy_to_uspace(uspace_phone_id, &fake_id,
  216.         sizeof(fake_id));
  217.     if (rc != 0)
  218.         return rc;
  219.  
  220.     /* Cap length of name and copy it from userspace. */
  221.  
  222.     if (name_len > THREAD_NAME_BUFLEN - 1)
  223.         name_len = THREAD_NAME_BUFLEN - 1;
  224.  
  225.     rc = copy_from_uspace(namebuf, uspace_name, name_len);
  226.     if (rc != 0)
  227.         return (unative_t) rc;
  228.  
  229.     namebuf[name_len] = '\0';
  230.  
  231.     /* Allocate the phone for communicating with the new task. */
  232.  
  233.     phone_id = phone_alloc();
  234.     if (phone_id < 0)
  235.         return ELIMIT;
  236.  
  237.     /* Spawn the new task. */
  238.  
  239.     rc = program_create_loader(&p, namebuf);
  240.     if (rc != 0)
  241.         return rc;
  242.  
  243.     phone_connect(phone_id, &p.task->answerbox);
  244.  
  245.     /* No need to aquire lock before task_ready() */
  246.     rc = (unative_t) copy_to_uspace(uspace_phone_id, &phone_id,
  247.         sizeof(phone_id));
  248.     if (rc != 0) {
  249.         /* Ooops */
  250.         ipc_phone_hangup(&TASK->phones[phone_id]);
  251.         task_kill(p.task->taskid);
  252.         return rc;
  253.     }
  254.  
  255.     // FIXME: control the capabilities
  256.     cap_set(p.task, cap_get(TASK));
  257.  
  258.     program_ready(&p);
  259.  
  260.     return EOK;
  261. }
  262.  
  263. /** @}
  264.  */
  265.