Rev 4344 | Rev 4347 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 4344 | Rev 4345 | ||
---|---|---|---|
Line 25... | Line 25... | ||
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
25 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
27 | */ |
27 | */ |
28 | 28 | ||
29 | /** @addtogroup loader |
29 | /** @addtogroup loader |
30 | * @brief Loads and runs programs from VFS. |
30 | * @brief Loads and runs programs from VFS. |
31 | * @{ |
31 | * @{ |
32 | */ |
32 | */ |
33 | /** |
33 | /** |
34 | * @file |
34 | * @file |
35 | * @brief Loads and runs programs from VFS. |
35 | * @brief Loads and runs programs from VFS. |
36 | * |
36 | * |
37 | * The program loader is a special init binary. Its image is used |
37 | * The program loader is a special init binary. Its image is used |
38 | * to create a new task upon a @c task_spawn syscall. The syscall |
38 | * to create a new task upon a @c task_spawn syscall. The syscall |
39 | * returns the id of a phone connected to the newly created task. |
39 | * returns the id of a phone connected to the newly created task. |
40 | * |
40 | * |
Line 88... | Line 88... | ||
88 | static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request) |
88 | static void loader_get_taskid(ipc_callid_t rid, ipc_call_t *request) |
89 | { |
89 | { |
90 | ipc_callid_t callid; |
90 | ipc_callid_t callid; |
91 | task_id_t task_id; |
91 | task_id_t task_id; |
92 | size_t len; |
92 | size_t len; |
93 | 93 | ||
94 | task_id = task_get_id(); |
94 | task_id = task_get_id(); |
95 | 95 | ||
96 | if (!ipc_data_read_receive(&callid, &len)) { |
96 | if (!ipc_data_read_receive(&callid, &len)) { |
97 | ipc_answer_0(callid, EINVAL); |
97 | ipc_answer_0(callid, EINVAL); |
98 | ipc_answer_0(rid, EINVAL); |
98 | ipc_answer_0(rid, EINVAL); |
99 | return; |
99 | return; |
100 | } |
100 | } |
101 | 101 | ||
102 | if (len > sizeof(task_id)) len = sizeof(task_id); |
102 | if (len > sizeof(task_id)) |
- | 103 | len = sizeof(task_id); |
|
103 | 104 | ||
104 | ipc_data_read_finalize(callid, &task_id, len); |
105 | ipc_data_read_finalize(callid, &task_id, len); |
105 | ipc_answer_0(rid, EOK); |
106 | ipc_answer_0(rid, EOK); |
106 | } |
107 | } |
107 | 108 | ||
108 | 109 | ||
Line 114... | Line 115... | ||
114 | static void loader_set_pathname(ipc_callid_t rid, ipc_call_t *request) |
115 | static void loader_set_pathname(ipc_callid_t rid, ipc_call_t *request) |
115 | { |
116 | { |
116 | ipc_callid_t callid; |
117 | ipc_callid_t callid; |
117 | size_t len; |
118 | size_t len; |
118 | char *name_buf; |
119 | char *name_buf; |
119 | 120 | ||
120 | if (!ipc_data_write_receive(&callid, &len)) { |
121 | if (!ipc_data_write_receive(&callid, &len)) { |
121 | ipc_answer_0(callid, EINVAL); |
122 | ipc_answer_0(callid, EINVAL); |
122 | ipc_answer_0(rid, EINVAL); |
123 | ipc_answer_0(rid, EINVAL); |
123 | return; |
124 | return; |
124 | } |
125 | } |
125 | 126 | ||
126 | name_buf = malloc(len + 1); |
127 | name_buf = malloc(len + 1); |
127 | if (!name_buf) { |
128 | if (!name_buf) { |
128 | ipc_answer_0(callid, ENOMEM); |
129 | ipc_answer_0(callid, ENOMEM); |
129 | ipc_answer_0(rid, ENOMEM); |
130 | ipc_answer_0(rid, ENOMEM); |
130 | return; |
131 | return; |
131 | } |
132 | } |
132 | 133 | ||
133 | ipc_data_write_finalize(callid, name_buf, len); |
134 | ipc_data_write_finalize(callid, name_buf, len); |
134 | ipc_answer_0(rid, EOK); |
135 | ipc_answer_0(rid, EOK); |
135 | 136 | ||
136 | if (pathname != NULL) { |
137 | if (pathname != NULL) { |
137 | free(pathname); |
138 | free(pathname); |
138 | pathname = NULL; |
139 | pathname = NULL; |
139 | } |
140 | } |
140 | 141 | ||
141 | name_buf[len] = '\0'; |
142 | name_buf[len] = '\0'; |
142 | pathname = name_buf; |
143 | pathname = name_buf; |
143 | } |
144 | } |
144 | 145 | ||
145 | /** Receive a call setting arguments of the program to execute. |
146 | /** Receive a call setting arguments of the program to execute. |
Line 151... | Line 152... | ||
151 | { |
152 | { |
152 | ipc_callid_t callid; |
153 | ipc_callid_t callid; |
153 | size_t buf_len, arg_len; |
154 | size_t buf_len, arg_len; |
154 | char *p; |
155 | char *p; |
155 | int n; |
156 | int n; |
156 | 157 | ||
157 | if (!ipc_data_write_receive(&callid, &buf_len)) { |
158 | if (!ipc_data_write_receive(&callid, &buf_len)) { |
158 | ipc_answer_0(callid, EINVAL); |
159 | ipc_answer_0(callid, EINVAL); |
159 | ipc_answer_0(rid, EINVAL); |
160 | ipc_answer_0(rid, EINVAL); |
160 | return; |
161 | return; |
161 | } |
162 | } |
162 | 163 | ||
163 | if (arg_buf != NULL) { |
164 | if (arg_buf != NULL) { |
164 | free(arg_buf); |
165 | free(arg_buf); |
165 | arg_buf = NULL; |
166 | arg_buf = NULL; |
166 | } |
167 | } |
167 | 168 | ||
168 | if (argv != NULL) { |
169 | if (argv != NULL) { |
169 | free(argv); |
170 | free(argv); |
170 | argv = NULL; |
171 | argv = NULL; |
171 | } |
172 | } |
172 | 173 | ||
173 | arg_buf = malloc(buf_len + 1); |
174 | arg_buf = malloc(buf_len + 1); |
174 | if (!arg_buf) { |
175 | if (!arg_buf) { |
175 | ipc_answer_0(callid, ENOMEM); |
176 | ipc_answer_0(callid, ENOMEM); |
176 | ipc_answer_0(rid, ENOMEM); |
177 | ipc_answer_0(rid, ENOMEM); |
177 | return; |
178 | return; |
178 | } |
179 | } |
179 | 180 | ||
180 | ipc_data_write_finalize(callid, arg_buf, buf_len); |
181 | ipc_data_write_finalize(callid, arg_buf, buf_len); |
181 | ipc_answer_0(rid, EOK); |
182 | ipc_answer_0(rid, EOK); |
182 | 183 | ||
183 | arg_buf[buf_len] = '\0'; |
184 | arg_buf[buf_len] = '\0'; |
184 | 185 | ||
185 | /* |
186 | /* |
186 | * Count number of arguments |
187 | * Count number of arguments |
187 | */ |
188 | */ |
188 | p = arg_buf; |
189 | p = arg_buf; |
189 | n = 0; |
190 | n = 0; |
190 | while (p < arg_buf + buf_len) { |
191 | while (p < arg_buf + buf_len) { |
191 | arg_len = strlen(p); |
192 | arg_len = strlen(p); |
192 | p = p + arg_len + 1; |
193 | p = p + arg_len + 1; |
193 | ++n; |
194 | ++n; |
194 | } |
195 | } |
195 | 196 | ||
196 | /* Allocate argv */ |
197 | /* Allocate argv */ |
197 | argv = malloc((n + 1) * sizeof(char *)); |
198 | argv = malloc((n + 1) * sizeof(char *)); |
198 | 199 | ||
199 | if (argv == NULL) { |
200 | if (argv == NULL) { |
200 | free(arg_buf); |
201 | free(arg_buf); |
201 | ipc_answer_0(callid, ENOMEM); |
202 | ipc_answer_0(callid, ENOMEM); |
202 | ipc_answer_0(rid, ENOMEM); |
203 | ipc_answer_0(rid, ENOMEM); |
203 | return; |
204 | return; |
204 | } |
205 | } |
205 | 206 | ||
206 | /* |
207 | /* |
207 | * Fill argv with argument pointers |
208 | * Fill argv with argument pointers |
208 | */ |
209 | */ |
209 | p = arg_buf; |
210 | p = arg_buf; |
210 | n = 0; |
211 | n = 0; |
211 | while (p < arg_buf + buf_len) { |
212 | while (p < arg_buf + buf_len) { |
212 | argv[n] = p; |
213 | argv[n] = p; |
213 | 214 | ||
214 | arg_len = strlen(p); |
215 | arg_len = strlen(p); |
215 | p = p + arg_len + 1; |
216 | p = p + arg_len + 1; |
216 | ++n; |
217 | ++n; |
217 | } |
218 | } |
218 | 219 | ||
219 | argc = n; |
220 | argc = n; |
220 | argv[n] = NULL; |
221 | argv[n] = NULL; |
221 | } |
222 | } |
222 | 223 | ||
223 | /** Load the previously selected program. |
224 | /** Load the previously selected program. |
Line 227... | Line 228... | ||
227 | * @return 0 on success, !0 on error. |
228 | * @return 0 on success, !0 on error. |
228 | */ |
229 | */ |
229 | static int loader_load(ipc_callid_t rid, ipc_call_t *request) |
230 | static int loader_load(ipc_callid_t rid, ipc_call_t *request) |
230 | { |
231 | { |
231 | int rc; |
232 | int rc; |
232 | 233 | ||
233 | rc = elf_load_file(pathname, 0, 0, &prog_info); |
234 | rc = elf_load_file(pathname, 0, 0, &prog_info); |
234 | if (rc < 0) { |
235 | if (rc < 0) { |
235 | DPRINTF("Failed to load executable '%s'.\n", pathname); |
236 | DPRINTF("Failed to load executable '%s'.\n", pathname); |
236 | ipc_answer_0(rid, EINVAL); |
237 | ipc_answer_0(rid, EINVAL); |
237 | return 1; |
238 | return 1; |
238 | } |
239 | } |
239 | 240 | ||
240 | elf_create_pcb(&prog_info, &pcb); |
241 | elf_create_pcb(&prog_info, &pcb); |
241 | 242 | ||
242 | pcb.argc = argc; |
243 | pcb.argc = argc; |
243 | pcb.argv = argv; |
244 | pcb.argv = argv; |
244 | 245 | ||
245 | if (prog_info.interp == NULL) { |
246 | if (prog_info.interp == NULL) { |
246 | /* Statically linked program */ |
247 | /* Statically linked program */ |
247 | is_dyn_linked = false; |
248 | is_dyn_linked = false; |
248 | ipc_answer_0(rid, EOK); |
249 | ipc_answer_0(rid, EOK); |
249 | return 0; |
250 | return 0; |
250 | } |
251 | } |
251 | 252 | ||
252 | printf("Load ELF interpreter '%s'\n", prog_info.interp); |
253 | printf("Load ELF interpreter '%s'\n", prog_info.interp); |
253 | rc = elf_load_file(prog_info.interp, 0, 0, &interp_info); |
254 | rc = elf_load_file(prog_info.interp, 0, 0, &interp_info); |
254 | if (rc < 0) { |
255 | if (rc < 0) { |
255 | DPRINTF("Failed to load interpreter '%s.'\n", |
256 | DPRINTF("Failed to load interpreter '%s.'\n", |
256 | prog_info.interp); |
257 | prog_info.interp); |
257 | ipc_answer_0(rid, EINVAL); |
258 | ipc_answer_0(rid, EINVAL); |
258 | return 1; |
259 | return 1; |
259 | } |
260 | } |
260 | 261 | ||
261 | printf("Run interpreter.\n"); |
262 | printf("Run interpreter.\n"); |
262 | printf("entry point: 0x%lx\n", interp_info.entry); |
263 | printf("entry point: 0x%lx\n", interp_info.entry); |
263 | printf("pcb address: 0x%lx\n", &pcb); |
264 | printf("pcb address: 0x%lx\n", &pcb); |
264 | printf("prog dynamic: 0x%lx\n", prog_info.dynamic); |
265 | printf("prog dynamic: 0x%lx\n", prog_info.dynamic); |
265 | 266 | ||
266 | is_dyn_linked = true; |
267 | is_dyn_linked = true; |
267 | ipc_answer_0(rid, EOK); |
268 | ipc_answer_0(rid, EOK); |
268 | 269 | ||
269 | return 0; |
270 | return 0; |
270 | } |
271 | } |
271 | 272 | ||
272 | 273 | ||
273 | /** Run the previously loaded program. |
274 | /** Run the previously loaded program. |
Line 276... | Line 277... | ||
276 | * @param request |
277 | * @param request |
277 | * @return 0 on success, !0 on error. |
278 | * @return 0 on success, !0 on error. |
278 | */ |
279 | */ |
279 | static void loader_run(ipc_callid_t rid, ipc_call_t *request) |
280 | static void loader_run(ipc_callid_t rid, ipc_call_t *request) |
280 | { |
281 | { |
- | 282 | const char *cp; |
|
- | 283 | ||
281 | /* Set the task name. */ |
284 | /* Set the task name. */ |
- | 285 | cp = strrchr(pathname, '/'); |
|
- | 286 | cp = (cp == NULL) ? pathname : (cp + 1); |
|
282 | task_set_name(pathname); |
287 | task_set_name(cp); |
283 | 288 | ||
284 | if (is_dyn_linked == true) { |
289 | if (is_dyn_linked == true) { |
285 | /* Dynamically linked program */ |
290 | /* Dynamically linked program */ |
286 | DPRINTF("Run ELF interpreter.\n"); |
291 | DPRINTF("Run ELF interpreter.\n"); |
287 | DPRINTF("Entry point: 0x%lx\n", interp_info.entry); |
292 | DPRINTF("Entry point: 0x%lx\n", interp_info.entry); |
288 | close_console(); |
293 | close_console(); |
289 | 294 | ||
290 | ipc_answer_0(rid, EOK); |
295 | ipc_answer_0(rid, EOK); |
291 | program_run(interp_info.entry, &pcb); |
296 | program_run(interp_info.entry, &pcb); |
292 | - | ||
293 | } else { |
297 | } else { |
294 | /* Statically linked program */ |
298 | /* Statically linked program */ |
295 | close_console(); |
299 | close_console(); |
296 | ipc_answer_0(rid, EOK); |
300 | ipc_answer_0(rid, EOK); |
297 | program_run(prog_info.entry, &pcb); |
301 | program_run(prog_info.entry, &pcb); |
Line 308... | Line 312... | ||
308 | static void loader_connection(ipc_callid_t iid, ipc_call_t *icall) |
312 | static void loader_connection(ipc_callid_t iid, ipc_call_t *icall) |
309 | { |
313 | { |
310 | ipc_callid_t callid; |
314 | ipc_callid_t callid; |
311 | ipc_call_t call; |
315 | ipc_call_t call; |
312 | int retval; |
316 | int retval; |
313 | 317 | ||
314 | /* Already have a connection? */ |
318 | /* Already have a connection? */ |
315 | if (connected) { |
319 | if (connected) { |
316 | ipc_answer_0(iid, ELIMIT); |
320 | ipc_answer_0(iid, ELIMIT); |
317 | return; |
321 | return; |
318 | } |
322 | } |
319 | 323 | ||
320 | connected = true; |
324 | connected = true; |
321 | 325 | ||
322 | /* Accept the connection */ |
326 | /* Accept the connection */ |
323 | ipc_answer_0(iid, EOK); |
327 | ipc_answer_0(iid, EOK); |
324 | 328 | ||
325 | /* Ignore parameters, the connection is already open */ |
329 | /* Ignore parameters, the connection is already open */ |
- | 330 | (void) iid; |
|
326 | (void)iid; (void)icall; |
331 | (void) icall; |
327 | 332 | ||
328 | while (1) { |
333 | while (1) { |
329 | callid = async_get_call(&call); |
334 | callid = async_get_call(&call); |
330 | 335 | ||
331 | switch (IPC_GET_METHOD(call)) { |
336 | switch (IPC_GET_METHOD(call)) { |
332 | case IPC_M_PHONE_HUNGUP: |
337 | case IPC_M_PHONE_HUNGUP: |
333 | exit(0); |
338 | exit(0); |
334 | case LOADER_GET_TASKID: |
339 | case LOADER_GET_TASKID: |
335 | loader_get_taskid(callid, &call); |
340 | loader_get_taskid(callid, &call); |
Line 362... | Line 367... | ||
362 | /** Program loader main function. |
367 | /** Program loader main function. |
363 | */ |
368 | */ |
364 | int main(int argc, char *argv[]) |
369 | int main(int argc, char *argv[]) |
365 | { |
370 | { |
366 | ipcarg_t phonead; |
371 | ipcarg_t phonead; |
367 | 372 | ||
368 | connected = false; |
373 | connected = false; |
369 | 374 | ||
370 | /* Set a handler of incomming connections. */ |
375 | /* Set a handler of incomming connections. */ |
371 | async_set_client_connection(loader_connection); |
376 | async_set_client_connection(loader_connection); |
372 | 377 | ||
373 | /* Register at naming service. */ |
378 | /* Register at naming service. */ |
374 | if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) |
379 | if (ipc_connect_to_me(PHONE_NS, SERVICE_LOAD, 0, 0, &phonead) != 0) |
375 | return -1; |
380 | return -1; |
376 | 381 | ||
377 | async_manager(); |
382 | async_manager(); |
378 | 383 | ||
379 | /* Never reached */ |
384 | /* Never reached */ |
380 | return 0; |
385 | return 0; |
381 | } |
386 | } |
382 | 387 | ||
383 | /** @} |
388 | /** @} |