~vojtech-horky/helenos/numa

« back to all changes in this revision

Viewing changes to kernel/generic/src/proc/program.c

  • Committer: Martin Decky
  • Date: 2009-08-04 11:19:19 UTC
  • Revision ID: martin@uranus.dsrg.hide.ms.mff.cuni.cz-20090804111919-evyclddlr3v5lhmp
Initial import

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
 
56
#ifndef LOADED_PROG_STACK_PAGES_NO
 
57
#define LOADED_PROG_STACK_PAGES_NO 1
 
58
#endif
 
59
 
 
60
/**
 
61
 * Points to the binary image used as the program loader. All non-initial
 
62
 * tasks are created from this executable image.
 
63
 */
 
64
void *program_loader = NULL;
 
65
 
 
66
/** Create a program using an existing address space.
 
67
 *
 
68
 * @param as            Address space containing a binary program image.
 
69
 * @param entry_addr    Program entry-point address in program address space.
 
70
 * @param name          Name to set for the program's task.
 
71
 * @param p             Buffer for storing program information.
 
72
 */
 
73
void program_create(as_t *as, uintptr_t entry_addr, char *name, program_t *p)
 
74
{
 
75
        as_area_t *a;
 
76
        uspace_arg_t *kernel_uarg;
 
77
 
 
78
        kernel_uarg = (uspace_arg_t *) malloc(sizeof(uspace_arg_t), 0);
 
79
        kernel_uarg->uspace_entry = (void *) entry_addr;
 
80
        kernel_uarg->uspace_stack = (void *) USTACK_ADDRESS;
 
81
        kernel_uarg->uspace_thread_function = NULL;
 
82
        kernel_uarg->uspace_thread_arg = NULL;
 
83
        kernel_uarg->uspace_uarg = NULL;
 
84
        
 
85
        p->task = task_create(as, name);
 
86
        ASSERT(p->task);
 
87
 
 
88
        /*
 
89
         * Create the data as_area.
 
90
         */
 
91
        a = as_area_create(as, AS_AREA_READ | AS_AREA_WRITE | AS_AREA_CACHEABLE,
 
92
            LOADED_PROG_STACK_PAGES_NO * PAGE_SIZE, USTACK_ADDRESS,
 
93
            AS_AREA_ATTR_NONE, &anon_backend, NULL);
 
94
 
 
95
        /*
 
96
         * Create the main thread.
 
97
         */
 
98
        p->main_thread = thread_create(uinit, kernel_uarg, p->task,
 
99
            THREAD_FLAG_USPACE, "uinit", false);
 
100
        ASSERT(p->main_thread);
 
101
}
 
102
 
 
103
/** Parse an executable image in the kernel memory.
 
104
 *
 
105
 * If the image belongs to a program loader, it is registered as such,
 
106
 * (and *task is set to NULL). Otherwise a task is created from the
 
107
 * executable image. The task is returned in *task.
 
108
 *
 
109
 * @param image_addr    Address of an executable program image.
 
110
 * @param name          Name to set for the program's task.
 
111
 * @param p             Buffer for storing program info. If image_addr
 
112
 *                      points to a loader image, p->task will be set to
 
113
 *                      NULL and EOK will be returned.
 
114
 *
 
115
 * @return EOK on success or negative error code.
 
116
 */
 
117
int program_create_from_image(void *image_addr, char *name, program_t *p)
 
118
{
 
119
        as_t *as;
 
120
        unsigned int rc;
 
121
 
 
122
        as = as_create(0);
 
123
        ASSERT(as);
 
124
 
 
125
        rc = elf_load((elf_header_t *) image_addr, as, 0);
 
126
        if (rc != EE_OK) {
 
127
                as_destroy(as);
 
128
                p->task = NULL;
 
129
                p->main_thread = NULL;
 
130
                if (rc != EE_LOADER)
 
131
                        return ENOTSUP;
 
132
                
 
133
                /* Register image as the program loader */
 
134
                ASSERT(program_loader == NULL);
 
135
                program_loader = image_addr;
 
136
                LOG("Registered program loader at 0x%" PRIp "\n",
 
137
                    image_addr);
 
138
                return EOK;
 
139
        }
 
140
 
 
141
        program_create(as, ((elf_header_t *) image_addr)->e_entry, name, p);
 
142
 
 
143
        return EOK;
 
144
}
 
145
 
 
146
/** Create a task from the program loader image.
 
147
 *
 
148
 * @param p     Buffer for storing program info.
 
149
 * @param name  Name to set for the program's task.
 
150
 *
 
151
 * @return EOK on success or negative error code.
 
152
 */
 
153
int program_create_loader(program_t *p, char *name)
 
154
{
 
155
        as_t *as;
 
156
        unsigned int rc;
 
157
        void *loader;
 
158
 
 
159
        as = as_create(0);
 
160
        ASSERT(as);
 
161
 
 
162
        loader = program_loader;
 
163
        if (!loader) {
 
164
                printf("Cannot spawn loader as none was registered\n");
 
165
                return ENOENT;
 
166
        }
 
167
 
 
168
        rc = elf_load((elf_header_t *) program_loader, as, ELD_F_LOADER);
 
169
        if (rc != EE_OK) {
 
170
                as_destroy(as);
 
171
                return ENOENT;
 
172
        }
 
173
 
 
174
        program_create(as, ((elf_header_t *) program_loader)->e_entry,
 
175
            name, p);
 
176
 
 
177
        return EOK;
 
178
}
 
179
 
 
180
/** Make program ready.
 
181
 *
 
182
 * Switch program's main thread to the ready state.
 
183
 *
 
184
 * @param p Program to make ready.
 
185
 */
 
186
void program_ready(program_t *p)
 
187
{
 
188
        thread_ready(p->main_thread);
 
189
}
 
190
 
 
191
/** Syscall for creating a new loader instance from userspace.
 
192
 *
 
193
 * Creates a new task from the program loader image and sets
 
194
 * the task name.
 
195
 *
 
196
 * @param name                  Name to set on the new task (typically the same
 
197
 *                              as the command used to execute it).
 
198
 *
 
199
 * @return 0 on success or an error code from @ref errno.h.
 
200
 */
 
201
unative_t sys_program_spawn_loader(char *uspace_name, size_t name_len)
 
202
{
 
203
        program_t p;
 
204
        int rc;
 
205
        char namebuf[TASK_NAME_BUFLEN];
 
206
 
 
207
        /* Cap length of name and copy it from userspace. */
 
208
 
 
209
        if (name_len > TASK_NAME_BUFLEN - 1)
 
210
                name_len = TASK_NAME_BUFLEN - 1;
 
211
 
 
212
        rc = copy_from_uspace(namebuf, uspace_name, name_len);
 
213
        if (rc != 0)
 
214
                return (unative_t) rc;
 
215
 
 
216
        namebuf[name_len] = 0;
 
217
 
 
218
        /* Spawn the new task. */
 
219
 
 
220
        rc = program_create_loader(&p, namebuf);
 
221
        if (rc != 0)
 
222
                return rc;
 
223
 
 
224
        // FIXME: control the capabilities
 
225
        cap_set(p.task, cap_get(TASK));
 
226
 
 
227
        program_ready(&p);
 
228
 
 
229
        return EOK;
 
230
}
 
231
 
 
232
/** @}
 
233
 */