/*- * Copyright (c) 2005-2007, Kohsuke Ohtani * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of any co-contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ /* * Exec server - Execute various types of image files. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "exec.h" /* * Object for system server */ object_t proc_obj; /* Process server */ object_t fs_obj; /* File system server */ /* * File header */ static char header[HEADER_SIZE]; /* * Wait until specified server starts. */ static void wait_server(const char *name, object_t *obj) { int i, err = 0; /* * Wait 1sec for loading server. */ for (i = 0; i < 100; i++) { err = object_lookup((char *)name, obj); if (err == 0) break; /* Wait 10msec */ timer_sleep(10, 0); thread_yield(); } if (err) sys_panic("exec: server not found"); } static void process_init(void) { struct msg m; m.hdr.code = PS_REGISTER; msg_send(proc_obj, &m, sizeof(m)); } /* * Notify exec() to servers. */ static void notify_server(task_t org_task, task_t new_task, void *stack) { struct msg m; int err; /* Notify to file system server */ do { m.hdr.code = FS_EXEC; m.data[0] = org_task; m.data[1] = new_task; err = msg_send(fs_obj, &m, sizeof(m)); } while (err == EINTR); /* Notify to process server */ do { m.hdr.code = PS_EXEC; m.data[0] = org_task; m.data[1] = new_task; m.data[2] = (int)stack; err = msg_send(proc_obj, &m, sizeof(m)); } while (err == EINTR); } /* * Execute program */ static int do_exec(struct exec_msg *msg) { struct exec_loader *ldr; char *name; int err, fd, count; struct stat st; task_t old_task, new_task; thread_t th; void *stack, *sp; void (*entry)(void); cap_t cap; dprintf("do_exec: path=%s task=%x\n", msg->path, msg->hdr.task); old_task = msg->hdr.task; /* * Check capability of caller task. */ if (task_getcap(old_task, &cap)) { err = EINVAL; goto err1; } if ((cap & CAP_EXEC) == 0) { err = EPERM; goto err1; } /* * Check target file */ if ((fd = open(msg->path, O_RDONLY)) == -1) { err = ENOENT; goto err1; } if (fstat(fd, &st) == -1) { err = EIO; goto err2; } if (!S_ISREG(st.st_mode)) { err = EACCES; /* must be regular file */ goto err2; } /* * Find file loader from the file header. */ if ((count = read(fd, header, HEADER_SIZE)) == -1) { err = EIO; goto err2; } for (ldr = loader_table; ldr->name != NULL; ldr++) { if (ldr->probe(header) == 0) break; /* Check next format */ } if (ldr->name == NULL) { dprintf("Unsupported file format\n"); err = ENOEXEC; goto err2; } dprintf("exec loader=%s\n", ldr->name); /* * Suspend old task */ if ((err = task_suspend(old_task)) != 0) goto err2; /* * Create new task */ if ((err = task_create(old_task, VM_NEW, &new_task)) != 0) goto err2; if (msg->path[0] != '\0') { name = strrchr(msg->path, '/'); if (name) name++; else name = msg->path; task_name(new_task, name); } /* * Copy capabilities */ task_getcap(old_task, &cap); /* cap &= CONFIG_CAP_MASK; */ task_setcap(new_task, &cap); if ((err = thread_create(new_task, &th)) != 0) goto err3; /* * Allocate stack and build arguments on it. */ err = vm_allocate(new_task, &stack, USTACK_SIZE, 1); if (err) goto err4; if ((err = build_args(new_task, stack, msg, &sp)) != 0) goto err5; /* * Load file image. */ if ((err = ldr->load(header, new_task, fd, (void **)&entry)) != 0) goto err5; if ((err = thread_load(th, entry, sp)) != 0) goto err5; /* * Notify to servers. */ notify_server(old_task, new_task, stack); /* * Terminate old task. */ task_terminate(old_task); /* * Set him running. */ thread_resume(th); close(fd); dprintf("exec complete successfully\n"); return 0; err5: vm_free(new_task, stack); err4: thread_terminate(th); err3: task_terminate(new_task); err2: close(fd); err1: dprintf("exec failed err=%d\n", err); return err; } /* * Debug */ static void exec_debug(void) { #ifdef DEBUG /* mstat(); */ #endif } /* * Initialize all exec loaders */ static void exec_init(void) { struct exec_loader *ldr; for (ldr = loader_table; ldr->name; ldr++) { dprintf("Initialize \'%s\' loader\n", ldr->name); ldr->init(); } } /* * Main routine for exec service. */ int main(int argc, char *argv[]) { struct exec_msg msg; object_t obj; int err; sys_log("Starting Exec Server\n"); /* * Boost current priority */ thread_setprio(thread_self(), PRIO_EXEC); /* * Wait until system server becomes available. */ wait_server(OBJNAME_PROC, &proc_obj); wait_server(OBJNAME_FS, &fs_obj); /* * Register to process server */ process_init(); /* * Register to file server */ fslib_init(); /* * Initialize everything */ exec_init(); /* * Create an object to expose our service. */ err = object_create(OBJNAME_EXEC, &obj); if (err) sys_panic("fail to create object"); /* * Message loop */ for (;;) { /* * Wait for an incoming request. */ err = msg_receive(obj, &msg, sizeof(struct exec_msg)); if (err) continue; /* * Process request. */ err = EINVAL; switch (msg.hdr.code) { case STD_DEBUG: exec_debug(); err = 0; break; case EX_EXEC: err = do_exec(&msg); break; } #ifdef DEBUG_EXEC if (err) dprintf("msg error=%d\n", err); #endif /* * Reply to the client. */ msg.hdr.status = err; err = msg_reply(obj, &msg, sizeof(struct exec_msg)); } return 0; }