source: mainline/kernel/generic/src/proc/program.c@ 2902e1bb

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 2902e1bb was 2902e1bb, checked in by Martin Decky <martin@…>, 13 years ago

add support for variable uspace stack size
create individual address space areas for stacks of additional threads (instead of allocating the stack from heap)
avoid memory leaks in program_create()

  • Property mode set to 100644
File size: 6.8 KB
RevLine 
[c98e6ee]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
[91001e2]36 * @brief Running userspace programs.
[c98e6ee]37 */
38
39#include <main/uinit.h>
40#include <proc/thread.h>
41#include <proc/task.h>
42#include <mm/as.h>
43#include <mm/slab.h>
44#include <arch.h>
45#include <adt/list.h>
46#include <ipc/ipc.h>
47#include <ipc/ipcrsc.h>
48#include <security/cap.h>
[e16e2ba4]49#include <lib/elf_load.h>
[c98e6ee]50#include <errno.h>
51#include <print.h>
52#include <syscall/copy.h>
53#include <proc/program.h>
54
55/**
56 * Points to the binary image used as the program loader. All non-initial
57 * tasks are created from this executable image.
58 */
59void *program_loader = NULL;
60
61/** Create a program using an existing address space.
62 *
[91001e2]63 * @param as Address space containing a binary program image.
64 * @param entry_addr Program entry-point address in program address space.
65 * @param name Name to set for the program's task.
66 * @param prg Buffer for storing program information.
67 *
68 * @return EOK on success or negative error code.
69 *
[c98e6ee]70 */
[91001e2]71int program_create(as_t *as, uintptr_t entry_addr, char *name, program_t *prg)
[c98e6ee]72{
[db675dd]73 prg->loader_status = EE_OK;
[91001e2]74 prg->task = task_create(as, name);
75 if (!prg->task)
76 return ELIMIT;
77
[c98e6ee]78 /*
[26aafe8]79 * Create the stack address space area.
[c98e6ee]80 */
[fbcdeb8]81 uintptr_t virt = USTACK_ADDRESS;
[91001e2]82 as_area_t *area = as_area_create(as,
83 AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
[fbcdeb8]84 STACK_SIZE, AS_AREA_ATTR_NONE, &anon_backend, NULL, &virt, 0);
[2902e1bb]85 if (!area) {
86 task_destroy(prg->task);
[91001e2]87 return ENOMEM;
[2902e1bb]88 }
89
90 uspace_arg_t *kernel_uarg = (uspace_arg_t *)
91 malloc(sizeof(uspace_arg_t), 0);
92
93 kernel_uarg->uspace_entry = (void *) entry_addr;
94 kernel_uarg->uspace_stack = (void *) virt;
95 kernel_uarg->uspace_stack_size = STACK_SIZE;
96 kernel_uarg->uspace_thread_function = NULL;
97 kernel_uarg->uspace_thread_arg = NULL;
98 kernel_uarg->uspace_uarg = NULL;
[91001e2]99
[c98e6ee]100 /*
101 * Create the main thread.
102 */
[91001e2]103 prg->main_thread = thread_create(uinit, kernel_uarg, prg->task,
[c98e6ee]104 THREAD_FLAG_USPACE, "uinit", false);
[2902e1bb]105 if (!prg->main_thread) {
106 free(kernel_uarg);
107 as_area_destroy(as, virt);
108 task_destroy(prg->task);
[91001e2]109 return ELIMIT;
[2902e1bb]110 }
[91001e2]111
112 return EOK;
[c98e6ee]113}
114
115/** Parse an executable image in the kernel memory.
116 *
117 * If the image belongs to a program loader, it is registered as such,
118 * (and *task is set to NULL). Otherwise a task is created from the
119 * executable image. The task is returned in *task.
120 *
[db675dd]121 * @param[in] image_addr Address of an executable program image.
122 * @param[in] name Name to set for the program's task.
123 * @param[out] prg Buffer for storing program info.
124 * If image_addr points to a loader image,
125 * prg->task will be set to NULL and EOK
126 * will be returned.
[c98e6ee]127 *
128 * @return EOK on success or negative error code.
[91001e2]129 *
[c98e6ee]130 */
[91001e2]131int program_create_from_image(void *image_addr, char *name, program_t *prg)
[c98e6ee]132{
[91001e2]133 as_t *as = as_create(0);
134 if (!as)
135 return ENOMEM;
136
[db675dd]137 prg->loader_status = elf_load((elf_header_t *) image_addr, as, 0);
138 if (prg->loader_status != EE_OK) {
[c98e6ee]139 as_destroy(as);
[91001e2]140 prg->task = NULL;
141 prg->main_thread = NULL;
142
[db675dd]143 if (prg->loader_status != EE_LOADER)
[c98e6ee]144 return ENOTSUP;
145
146 /* Register image as the program loader */
[91001e2]147 if (program_loader != NULL)
148 return ELIMIT;
149
[c98e6ee]150 program_loader = image_addr;
[db675dd]151 printf("Program loader at %p\n", (void *) image_addr);
[91001e2]152
[c98e6ee]153 return EOK;
154 }
[91001e2]155
156 return program_create(as, ((elf_header_t *) image_addr)->e_entry,
157 name, prg);
[c98e6ee]158}
159
160/** Create a task from the program loader image.
161 *
[91001e2]162 * @param prg Buffer for storing program info.
163 * @param name Name to set for the program's task.
[24345a5]164 *
[c98e6ee]165 * @return EOK on success or negative error code.
[91001e2]166 *
[c98e6ee]167 */
[91001e2]168int program_create_loader(program_t *prg, char *name)
[c98e6ee]169{
[91001e2]170 as_t *as = as_create(0);
171 if (!as)
172 return ENOMEM;
173
174 void *loader = program_loader;
[c98e6ee]175 if (!loader) {
[bfe43d5a]176 as_destroy(as);
[c98e6ee]177 printf("Cannot spawn loader as none was registered\n");
178 return ENOENT;
179 }
[91001e2]180
[db675dd]181 prg->loader_status = elf_load((elf_header_t *) program_loader, as,
[91001e2]182 ELD_F_LOADER);
[db675dd]183 if (prg->loader_status != EE_OK) {
[c98e6ee]184 as_destroy(as);
[db675dd]185 printf("Cannot spawn loader (%s)\n",
186 elf_error(prg->loader_status));
[c98e6ee]187 return ENOENT;
188 }
[91001e2]189
190 return program_create(as, ((elf_header_t *) program_loader)->e_entry,
191 name, prg);
[c98e6ee]192}
193
194/** Make program ready.
195 *
196 * Switch program's main thread to the ready state.
197 *
[91001e2]198 * @param prg Program to make ready.
199 *
[c98e6ee]200 */
[91001e2]201void program_ready(program_t *prg)
[c98e6ee]202{
[91001e2]203 thread_ready(prg->main_thread);
[c98e6ee]204}
205
206/** Syscall for creating a new loader instance from userspace.
207 *
[bfd1546]208 * Creates a new task from the program loader image and sets
209 * the task name.
[c98e6ee]210 *
[91001e2]211 * @param uspace_name Name to set on the new task (typically the same
212 * as the command used to execute it).
213 * @param name_len Length of the name.
214 *
215 * @return EOK on success or an error code from @ref errno.h.
[c98e6ee]216 *
217 */
[96b02eb9]218sysarg_t sys_program_spawn_loader(char *uspace_name, size_t name_len)
[c98e6ee]219{
[24345a5]220 /* Cap length of name and copy it from userspace. */
[bc18d63]221 if (name_len > TASK_NAME_BUFLEN - 1)
222 name_len = TASK_NAME_BUFLEN - 1;
[91001e2]223
224 char namebuf[TASK_NAME_BUFLEN];
225 int rc = copy_from_uspace(namebuf, uspace_name, name_len);
[24345a5]226 if (rc != 0)
[96b02eb9]227 return (sysarg_t) rc;
[91001e2]228
[b60c582]229 namebuf[name_len] = 0;
[91001e2]230
[24345a5]231 /* Spawn the new task. */
[91001e2]232 program_t prg;
233 rc = program_create_loader(&prg, namebuf);
[c98e6ee]234 if (rc != 0)
235 return rc;
[91001e2]236
[c98e6ee]237 // FIXME: control the capabilities
[91001e2]238 cap_set(prg.task, cap_get(TASK));
239 program_ready(&prg);
240
[c98e6ee]241 return EOK;
242}
243
244/** @}
245 */
Note: See TracBrowser for help on using the repository browser.