aboutsummaryrefslogtreecommitdiff
path: root/kern/bootstrap.c
diff options
context:
space:
mode:
Diffstat (limited to 'kern/bootstrap.c')
-rw-r--r--kern/bootstrap.c918
1 files changed, 918 insertions, 0 deletions
diff --git a/kern/bootstrap.c b/kern/bootstrap.c
new file mode 100644
index 0000000..49358ac
--- /dev/null
+++ b/kern/bootstrap.c
@@ -0,0 +1,918 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1992-1989 Carnegie Mellon University.
+ * Copyright (c) 1995-1993 The University of Utah and
+ * the Computer Systems Laboratory (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
+ * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
+ * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
+ * THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ * Bootstrap the various built-in servers.
+ */
+
+#include <alloca.h>
+#include <string.h>
+
+#include <mach/port.h>
+#include <mach/message.h>
+#include <machine/locore.h>
+#include <machine/vm_param.h>
+#include <machine/pcb.h>
+#include <ipc/ipc_port.h>
+#include <ipc/mach_port.server.h>
+#include <kern/bootstrap.h>
+#include <kern/debug.h>
+#include <kern/host.h>
+#include <kern/printf.h>
+#include <kern/kalloc.h>
+#include <kern/task.h>
+#include <kern/thread.h>
+#include <kern/lock.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_user.h>
+#include <vm/pmap.h>
+#include <device/device_port.h>
+
+#if MACH_KDB
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h>
+#endif
+
+#if OSKIT_MACH
+#include <stddef.h>
+#include <oskit/machine/base_multiboot.h>
+#include <oskit/exec/exec.h>
+#include <oskit/c/stdio.h>
+#define safe_gets(s, n) fgets((s),(n),stdin)
+#else
+#include <mach/machine/multiboot.h>
+#include <mach/exec/exec.h>
+#ifdef MACH_XEN
+#include <mach/xen.h>
+extern struct start_info boot_info; /* XXX put this in a header! */
+#else /* MACH_XEN */
+extern struct multiboot_raw_info boot_info; /* XXX put this in a header! */
+#endif /* MACH_XEN */
+#endif
+
+#include "boot_script.h"
+
+
+static mach_port_name_t boot_device_port; /* local name */
+static mach_port_name_t boot_host_port; /* local name */
+
+extern char *kernel_cmdline;
+
+static void user_bootstrap(void); /* forward */
+static void user_bootstrap_compat(void); /* forward */
+static void bootstrap_exec_compat(void *exec_data); /* forward */
+static void get_compat_strings(char *flags_str, char *root_str); /* forward */
+
+static mach_port_name_t
+task_insert_send_right(
+ task_t task,
+ ipc_port_t port)
+{
+ mach_port_name_t name;
+
+ for (name = 1;; name++) {
+ kern_return_t kr;
+
+ kr = mach_port_insert_right(task->itk_space, name,
+ port, MACH_MSG_TYPE_PORT_SEND);
+ if (kr == KERN_SUCCESS)
+ break;
+ assert(kr == KERN_NAME_EXISTS);
+ }
+
+ return name;
+}
+
+static void
+free_bootstrap_pages(phys_addr_t start, phys_addr_t end)
+{
+ struct vm_page *page;
+
+ while (start < end)
+ {
+ page = vm_page_lookup_pa(start);
+ assert(page != NULL);
+ vm_page_manage(page);
+ start += PAGE_SIZE;
+ }
+}
+
+void bootstrap_create(void)
+{
+ int compat;
+ unsigned n = 0;
+#ifdef MACH_XEN
+#ifdef __x86_64__ // 32_ON_64 actually
+ struct multiboot32_module *bmods32 = (struct multiboot32_module *)
+ boot_info.mod_start;
+ struct multiboot_module *bmods;
+ if (bmods32) {
+ int i;
+ for (n = 0; bmods32[n].mod_start; n++)
+ ;
+ bmods = alloca(n * sizeof(*bmods));
+ for (i = 0; i < n ; i++)
+ {
+ bmods[i].mod_start = kvtophys(bmods32[i].mod_start + (vm_offset_t) bmods32);
+ bmods[i].mod_end = kvtophys(bmods32[i].mod_end + (vm_offset_t) bmods32);
+ bmods[i].string = kvtophys(bmods32[i].string + (vm_offset_t) bmods32);
+ }
+ }
+#else
+ struct multiboot_module *bmods = (struct multiboot_module *)
+ boot_info.mod_start;
+ if (bmods)
+ for (n = 0; bmods[n].mod_start; n++) {
+ bmods[n].mod_start = kvtophys(bmods[n].mod_start + (vm_offset_t) bmods);
+ bmods[n].mod_end = kvtophys(bmods[n].mod_end + (vm_offset_t) bmods);
+ bmods[n].string = kvtophys(bmods[n].string + (vm_offset_t) bmods);
+ }
+#endif
+ boot_info.mods_count = n;
+ boot_info.flags |= MULTIBOOT_MODS;
+#else /* MACH_XEN */
+#ifdef __x86_64__
+ struct multiboot_raw_module *bmods32 = ((struct multiboot_raw_module *)
+ phystokv(boot_info.mods_addr));
+ struct multiboot_module *bmods=NULL;
+ if (bmods32)
+ {
+ int i;
+ bmods = alloca(boot_info.mods_count * sizeof(*bmods));
+ for (i=0; i<boot_info.mods_count; i++)
+ {
+ bmods[i].mod_start = bmods32[i].mod_start;
+ bmods[i].mod_end = bmods32[i].mod_end;
+ bmods[i].string = bmods32[i].string;
+ }
+ }
+#else
+ struct multiboot_module *bmods = ((struct multiboot_module *)
+ phystokv(boot_info.mods_addr));
+#endif
+#endif /* MACH_XEN */
+ if (!(boot_info.flags & MULTIBOOT_MODS)
+ || (boot_info.mods_count == 0))
+ panic ("No bootstrap code loaded with the kernel!");
+
+ compat = boot_info.mods_count == 1;
+ if (compat)
+ {
+ char *p = strchr((char*)phystokv(bmods[0].string), ' ');
+ if (p != 0)
+ do
+ ++p;
+ while (*p == ' ' || *p == '\n');
+ compat = p == 0 || *p == '\0';
+ }
+
+ if (compat)
+ {
+ printf("Loading single multiboot module in compat mode: %s\n",
+ (char*)phystokv(bmods[0].string));
+ bootstrap_exec_compat(&bmods[0]);
+ }
+ else
+ {
+ unsigned i;
+ int losers;
+
+ /* Initialize boot script variables. We leak these send rights. */
+ losers = boot_script_set_variable
+ ("host-port", VAL_PORT,
+ (long) realhost.host_priv_self);
+ if (losers)
+ panic ("cannot set boot-script variable host-port: %s",
+ boot_script_error_string (losers));
+ losers = boot_script_set_variable
+ ("device-port", VAL_PORT,
+ (long) master_device_port);
+ if (losers)
+ panic ("cannot set boot-script variable device-port: %s",
+ boot_script_error_string (losers));
+ losers = boot_script_set_variable
+ ("kernel-task", VAL_PORT,
+ (long) kernel_task->itk_self);
+ if (losers)
+ panic ("cannot set boot-script variable kernel-task: %s",
+ boot_script_error_string (losers));
+
+ losers = boot_script_set_variable ("kernel-command-line", VAL_STR,
+ (long) kernel_cmdline);
+ if (losers)
+ panic ("cannot set boot-script variable %s: %s",
+ "kernel-command-line", boot_script_error_string (losers));
+
+ {
+ /* Set the same boot script variables that the old Hurd's
+ serverboot did, so an old Hurd and boot script previously
+ used with serverboot can be used directly with this kernel. */
+
+ char *flag_string = alloca(1024);
+ char *root_string = alloca(1024);
+
+ /*
+ * Get the (compatibility) boot flags and root name strings.
+ */
+ get_compat_strings(flag_string, root_string);
+
+ losers = boot_script_set_variable ("boot-args", VAL_STR,
+ (long) flag_string);
+ if (losers)
+ panic ("cannot set boot-script variable %s: %s",
+ "boot-args", boot_script_error_string (losers));
+ losers = boot_script_set_variable ("root-device", VAL_STR,
+ (long) root_string);
+ if (losers)
+ panic ("cannot set boot-script variable %s: %s",
+ "root-device", boot_script_error_string (losers));
+ }
+
+#if OSKIT_MACH
+ {
+ /* The oskit's "environ" array contains all the words from
+ the multiboot command line that looked like VAR=VAL.
+ We set each of these as boot-script variables, which
+ can be used for things like ${root}. */
+
+ extern char **environ;
+ char **ep;
+ for (ep = environ; *ep != 0; ++ep)
+ {
+ size_t len = strlen (*ep) + 1;
+ char *var = memcpy (alloca (len), *ep, len);
+ char *val = strchr (var, '=');
+ *val++ = '\0';
+ losers = boot_script_set_variable (var, VAL_STR, (long) val);
+ if (losers)
+ panic ("cannot set boot-script variable %s: %s",
+ var, boot_script_error_string (losers));
+ }
+ }
+#else /* GNUmach, not oskit-mach */
+ {
+ /* Turn each `FOO=BAR' word in the command line into a boot script
+ variable ${FOO} with value BAR. This matches what we get from
+ oskit's environ in the oskit-mach case (above). */
+
+ int len = strlen (kernel_cmdline) + 1;
+ char *s = memcpy (alloca (len), kernel_cmdline, len);
+ char *word;
+ while ((word = strsep (&s, " \t")) != 0)
+ {
+ char *eq = strchr (word, '=');
+ if (eq == 0)
+ continue;
+ *eq++ = '\0';
+ losers = boot_script_set_variable (word, VAL_STR, (long) eq);
+ if (losers)
+ panic ("cannot set boot-script variable %s: %s",
+ word, boot_script_error_string (losers));
+ }
+ }
+#endif
+
+ for (i = 0; i < boot_info.mods_count; ++i)
+ {
+ int err;
+ char *line = (char*)phystokv(bmods[i].string);
+ printf ("module %d: %s\n", i, line);
+ err = boot_script_parse_line (&bmods[i], line);
+ if (err)
+ {
+ printf ("\n\tERROR: %s", boot_script_error_string (err));
+ ++losers;
+ }
+ }
+ printf ("%d multiboot modules\n", i);
+ if (losers)
+ panic ("%d of %d boot script commands could not be parsed",
+ losers, boot_info.mods_count);
+ losers = boot_script_exec ();
+ if (losers)
+ panic ("ERROR in executing boot script: %s",
+ boot_script_error_string (losers));
+ }
+ /* XXX we could free the memory used
+ by the boot loader's descriptors and such. */
+ for (n = 0; n < boot_info.mods_count; n++)
+ free_bootstrap_pages(bmods[n].mod_start, bmods[n].mod_end);
+}
+
+static void
+bootstrap_exec_compat(void *e)
+{
+ task_t bootstrap_task;
+ thread_t bootstrap_thread;
+
+ /*
+ * Create the bootstrap task.
+ */
+
+ (void) task_create(TASK_NULL, FALSE, &bootstrap_task);
+ (void) thread_create(bootstrap_task, &bootstrap_thread);
+
+ /*
+ * Insert send rights to the master host and device ports.
+ */
+
+ boot_host_port =
+ task_insert_send_right(bootstrap_task,
+ ipc_port_make_send(realhost.host_priv_self));
+
+ boot_device_port =
+ task_insert_send_right(bootstrap_task,
+ ipc_port_make_send(master_device_port));
+
+ /*
+ * Start the bootstrap thread.
+ */
+ bootstrap_thread->saved.other = e;
+ thread_start(bootstrap_thread, user_bootstrap_compat);
+ (void) thread_resume(bootstrap_thread);
+}
+
+/*
+ * The following code runs as the kernel mode portion of the
+ * first user thread.
+ */
+
+/*
+ * Convert an unsigned integer to its decimal representation.
+ */
+static void
+itoa(
+ char *str,
+ vm_size_t num)
+{
+ char buf[sizeof(vm_size_t)*2+3];
+ char *np;
+
+ np = buf + sizeof(buf);
+ *--np = 0;
+
+ do {
+ *--np = '0' + num % 10;
+ num /= 10;
+ } while (num != 0);
+
+ strcpy(str, np);
+}
+
+/*
+ * Collect the boot flags into a single argument string,
+ * for compatibility with existing bootstrap and startup code.
+ * Format as a standard flag argument: '-qsdn...'
+ */
+static void get_compat_strings(char *flags_str, char *root_str)
+{
+ char *ip, *cp;
+
+ strcpy (root_str, "UNKNOWN");
+
+ cp = flags_str;
+ *cp++ = '-';
+
+ for (ip = kernel_cmdline; *ip; )
+ {
+ if (*ip == ' ')
+ {
+ ip++;
+ }
+ else if (*ip == '-')
+ {
+ ip++;
+ while (*ip > ' ')
+ *cp++ = *ip++;
+ }
+ else if (strncmp(ip, "root=", 5) == 0)
+ {
+ char *rp = root_str;
+
+ ip += 5;
+ if (strncmp(ip, "/dev/", 5) == 0)
+ ip += 5;
+ while (*ip > ' ')
+ *rp++ = *ip++;
+ *rp = '\0';
+ }
+ else
+ {
+ while (*ip > ' ')
+ ip++;
+ }
+ }
+
+ if (cp == &flags_str[1]) /* no flags */
+ *cp++ = 'x';
+ *cp = '\0';
+}
+
+#if 0
+/*
+ * Copy boot_data (executable) to the user portion of this task.
+ */
+static boolean_t load_protect_text = TRUE;
+#if MACH_KDB
+ /* if set, fault in the text segment */
+static boolean_t load_fault_in_text = TRUE;
+#endif
+
+static vm_offset_t
+boot_map(
+ void * data, /* private data */
+ vm_offset_t offset) /* offset to map */
+{
+ vm_offset_t start_offset = (vm_offset_t) data;
+
+ return pmap_extract(kernel_pmap, start_offset + offset);
+}
+
+
+#if BOOTSTRAP_SYMBOLS
+static boolean_t load_bootstrap_symbols = TRUE;
+#else
+static boolean_t load_bootstrap_symbols = FALSE;
+#endif
+#endif
+
+
+
+static int
+boot_read(void *handle, vm_offset_t file_ofs, void *buf, vm_size_t size,
+ vm_size_t *out_actual)
+{
+ struct multiboot_module *mod = handle;
+
+ if (mod->mod_start + file_ofs + size > mod->mod_end)
+ return -1;
+
+ memcpy(buf, (const char*) phystokv (mod->mod_start) + file_ofs, size);
+ *out_actual = size;
+ return 0;
+}
+
+static int
+read_exec(void *handle, vm_offset_t file_ofs, vm_size_t file_size,
+ vm_offset_t mem_addr, vm_size_t mem_size,
+ exec_sectype_t sec_type)
+{
+ struct multiboot_module *mod = handle;
+
+ vm_map_t user_map = current_task()->map;
+ vm_offset_t start_page, end_page;
+ vm_prot_t mem_prot = sec_type & EXEC_SECTYPE_PROT_MASK;
+ int err;
+
+ if (mod->mod_start + file_ofs + file_size > mod->mod_end)
+ return -1;
+
+ if (!(sec_type & EXEC_SECTYPE_ALLOC))
+ return 0;
+
+ assert(mem_size > 0);
+ assert(mem_size >= file_size);
+
+ start_page = trunc_page(mem_addr);
+ end_page = round_page(mem_addr + mem_size);
+
+#if 0
+ printf("reading bootstrap section %08x-%08x-%08x prot %d pages %08x-%08x\n",
+ mem_addr, mem_addr+file_size, mem_addr+mem_size, mem_prot, start_page, end_page);
+#endif
+
+ err = vm_allocate(user_map, &start_page, end_page - start_page, FALSE);
+ assert(err == 0);
+ assert(start_page == trunc_page(mem_addr));
+
+ if (file_size > 0)
+ {
+ err = copyout((char *)phystokv (mod->mod_start) + file_ofs,
+ (void *)mem_addr, file_size);
+ assert(err == 0);
+ }
+
+ if (mem_prot != VM_PROT_ALL)
+ {
+ err = vm_protect(user_map, start_page, end_page - start_page, FALSE, mem_prot);
+ assert(err == 0);
+ }
+
+ return 0;
+}
+
+static void copy_bootstrap(void *e, exec_info_t *boot_exec_info)
+{
+ /* vm_map_t user_map = current_task()->map; */
+ int err;
+
+ if ((err = exec_load(boot_read, read_exec, e, boot_exec_info)))
+ panic("Cannot load user-bootstrap image: error code %d", err);
+
+#if MACH_KDB
+ /*
+ * Enter the bootstrap symbol table.
+ */
+
+#if 0 /*XXX*/
+ if (load_bootstrap_symbols)
+ (void) X_db_sym_init(
+ (char*) boot_start+lp->sym_offset,
+ (char*) boot_start+lp->sym_offset+lp->sym_size,
+ "bootstrap",
+ (char *) user_map);
+#endif
+
+#if 0 /*XXX*/
+ if (load_fault_in_text)
+ {
+ vm_offset_t lenp = round_page(lp->text_start+lp->text_size) -
+ trunc_page(lp->text_start);
+ vm_offset_t i = 0;
+
+ while (i < lenp)
+ {
+ vm_fault(user_map, text_page_start +i,
+ load_protect_text ?
+ VM_PROT_READ|VM_PROT_EXECUTE :
+ VM_PROT_READ|VM_PROT_EXECUTE | VM_PROT_WRITE,
+ 0,0,0);
+ i = round_page (i+1);
+ }
+ }
+#endif
+#endif /* MACH_KDB */
+}
+
+/*
+ * Allocate the stack, and build the argument list.
+ */
+static void
+build_args_and_stack(struct exec_info *boot_exec_info,
+ char **argv, char **envp)
+{
+ vm_offset_t stack_base;
+ vm_size_t stack_size;
+ char * arg_ptr;
+ long arg_count, envc;
+ int arg_len;
+ char * arg_pos;
+ int arg_item_len;
+ char * string_pos;
+ rpc_vm_offset_t zero = 0;
+ int i;
+
+#define STACK_SIZE (2*64*1024)
+
+ /*
+ * Calculate the size of the argument list.
+ */
+ arg_len = 0;
+ arg_count = 0;
+ while (argv[arg_count] != 0) {
+ arg_ptr = argv[arg_count++];
+ arg_len += strlen(arg_ptr) + 1;
+ }
+ envc = 0;
+ if (envp != 0)
+ while (envp[envc] != 0)
+ arg_len += strlen (envp[envc++]) + 1;
+
+ /*
+ * Add space for:
+ * arg count
+ * pointers to arguments
+ * trailing 0 pointer
+ * pointers to environment variables
+ * trailing 0 pointer
+ */
+ arg_len += (sizeof(rpc_vm_offset_t)
+ + (arg_count + 1 + envc + 1) * sizeof(rpc_vm_offset_t));
+
+ /*
+ * Allocate the stack.
+ */
+ stack_size = round_page(STACK_SIZE);
+ stack_base = user_stack_low(stack_size);
+
+ (void) vm_allocate(current_task()->map,
+ &stack_base,
+ stack_size,
+ FALSE);
+
+ arg_pos = (char *)
+ set_user_regs(stack_base, stack_size, boot_exec_info, arg_len);
+
+ /*
+ * Start the strings after the arg-count and pointers
+ */
+ string_pos = (arg_pos
+ + sizeof(rpc_vm_offset_t)
+ + (arg_count + 1 + envc + 1) * sizeof(rpc_vm_offset_t));
+
+ /*
+ * first the argument count
+ */
+ (void) copyout(&arg_count,
+ arg_pos,
+ sizeof(rpc_vm_offset_t));
+ arg_pos += sizeof(rpc_vm_offset_t);
+
+ /*
+ * Then the strings and string pointers for each argument
+ */
+ for (i = 0; i < arg_count; ++i) {
+ rpc_vm_offset_t pos = convert_vm_to_user((vm_offset_t) string_pos);
+ arg_ptr = argv[i];
+ arg_item_len = strlen(arg_ptr) + 1; /* include trailing 0 */
+
+ /* set string pointer */
+ (void) copyout(&pos, arg_pos, sizeof (rpc_vm_offset_t));
+ arg_pos += sizeof(rpc_vm_offset_t);
+
+ /* copy string */
+ (void) copyout(arg_ptr, string_pos, arg_item_len);
+ string_pos += arg_item_len;
+ }
+
+ /*
+ * Null terminator for argv.
+ */
+ (void) copyout(&zero, arg_pos, sizeof(rpc_vm_offset_t));
+ arg_pos += sizeof(rpc_vm_offset_t);
+
+ /*
+ * Then the strings and string pointers for each environment variable
+ */
+ for (i = 0; i < envc; ++i) {
+ rpc_vm_offset_t pos = convert_vm_to_user((vm_offset_t) string_pos);
+ arg_ptr = envp[i];
+ arg_item_len = strlen(arg_ptr) + 1; /* include trailing 0 */
+
+ /* set string pointer */
+ (void) copyout(&pos, arg_pos, sizeof (rpc_vm_offset_t));
+ arg_pos += sizeof(rpc_vm_offset_t);
+
+ /* copy string */
+ (void) copyout(arg_ptr, string_pos, arg_item_len);
+ string_pos += arg_item_len;
+ }
+
+ /*
+ * Null terminator for envp.
+ */
+ (void) copyout(&zero, arg_pos, sizeof(rpc_vm_offset_t));
+}
+
+
+static void
+user_bootstrap_compat(void)
+{
+ exec_info_t boot_exec_info;
+
+ char host_string[12];
+ char device_string[12];
+ char flag_string[1024];
+ char root_string[1024];
+
+ /*
+ * Copy the bootstrap code from boot_exec into the user task.
+ */
+ copy_bootstrap(current_thread()->saved.other, &boot_exec_info);
+
+ /*
+ * Convert the host and device ports to strings,
+ * to put in the argument list.
+ */
+ itoa(host_string, boot_host_port);
+ itoa(device_string, boot_device_port);
+
+ /*
+ * Get the (compatibility) boot flags and root name strings.
+ */
+ get_compat_strings(flag_string, root_string);
+
+ /*
+ * Build the argument list and insert in the user task.
+ * Argument list is
+ * "bootstrap -<boothowto> <host_port> <device_port> <root_name>"
+
+$0 ${boot-args} ${host-port} ${device-port} ${root-device} $(task-create) $(task-resume)
+
+ */
+ {
+ char *argv[] = { "bootstrap",
+ flag_string,
+ host_string,
+ device_string,
+ root_string,
+ 0 };
+ char *envp[] = { 0, 0 };
+ if (kernel_cmdline[0] != '\0')
+ {
+ static const char cmdline_var[] = "MULTIBOOT_CMDLINE=";
+ envp[0] = alloca (sizeof cmdline_var + strlen (kernel_cmdline));
+ memcpy (envp[0], cmdline_var, sizeof cmdline_var - 1);
+ strcpy (envp[0] + sizeof cmdline_var - 1, kernel_cmdline);
+ }
+ build_args_and_stack(&boot_exec_info, argv, envp);
+ }
+
+ /*
+ * Exit to user thread.
+ */
+ thread_bootstrap_return();
+ /*NOTREACHED*/
+}
+
+
+struct user_bootstrap_info
+{
+ struct multiboot_module *mod;
+ char **argv;
+ int done;
+ decl_simple_lock_data(,lock)
+};
+
+int
+boot_script_exec_cmd (void *hook, task_t task, char *path, int argc,
+ char **argv, char *strings, int stringlen)
+{
+ struct multiboot_module *mod = hook;
+
+ int err;
+
+ if (task != MACH_PORT_NULL)
+ {
+ thread_t thread;
+ struct user_bootstrap_info info = { mod, argv, 0, };
+ simple_lock_init (&info.lock);
+
+ err = thread_create ((task_t)task, &thread);
+ assert(err == 0);
+ simple_lock (&info.lock);
+ thread->saved.other = &info;
+ thread_start (thread, user_bootstrap);
+ err = thread_resume (thread);
+ assert(err == 0);
+
+ /* We need to synchronize with the new thread and block this
+ main thread until it has finished referring to our local state. */
+ while (! info.done)
+ {
+ thread_sleep ((event_t) &info, simple_lock_addr(info.lock), FALSE);
+ simple_lock (&info.lock);
+ }
+ simple_unlock (&info.lock);
+ thread_deallocate (thread);
+ printf ("\n");
+ }
+
+ return 0;
+}
+
+static void user_bootstrap(void)
+{
+ struct user_bootstrap_info *info = current_thread()->saved.other;
+ exec_info_t boot_exec_info;
+ int err;
+ char **av;
+
+ /* Load this task up from the executable file in the module. */
+ err = exec_load(boot_read, read_exec, info->mod, &boot_exec_info);
+ if (err)
+ panic ("Cannot load user executable module (error code %d): %s",
+ err, info->argv[0]);
+
+ printf ("task loaded:");
+
+ /* Set up the stack with arguments. */
+ build_args_and_stack(&boot_exec_info, info->argv, 0);
+
+ for (av = info->argv; *av != 0; ++av)
+ printf (" %s", *av);
+
+ task_suspend (current_task());
+
+ /* Tell the bootstrap thread running boot_script_exec_cmd
+ that we are done looking at INFO. */
+ simple_lock (&info->lock);
+ assert (!info->done);
+ info->done = 1;
+ simple_unlock (&info->lock);
+ thread_wakeup ((event_t) info);
+
+ /*
+ * Exit to user thread.
+ */
+ thread_bootstrap_return();
+ /*NOTREACHED*/
+}
+
+
+
+void *
+boot_script_malloc (unsigned int size)
+{
+ return (void *) kalloc (size);
+}
+
+void
+boot_script_free (void *ptr, unsigned int size)
+{
+ kfree ((vm_offset_t)ptr, size);
+}
+
+int
+boot_script_task_create (struct cmd *cmd)
+{
+ kern_return_t rc = task_create_kernel(TASK_NULL, FALSE, &cmd->task);
+ if (rc)
+ {
+ printf("boot_script_task_create failed with %x\n", rc);
+ return BOOT_SCRIPT_MACH_ERROR;
+ }
+ task_set_name(cmd->task, cmd->path);
+ return 0;
+}
+
+int
+boot_script_task_resume (struct cmd *cmd)
+{
+ kern_return_t rc = task_resume (cmd->task);
+ if (rc)
+ {
+ printf("boot_script_task_resume failed with %x\n", rc);
+ return BOOT_SCRIPT_MACH_ERROR;
+ }
+ printf ("\nstart %s: ", cmd->path);
+ return 0;
+}
+
+int
+boot_script_prompt_task_resume (struct cmd *cmd)
+{
+#if ! MACH_KDB
+ char xx[5];
+#endif
+
+ printf ("Pausing for %s...\n", cmd->path);
+
+#if ! MACH_KDB
+ printf ("Hit <return> to resume bootstrap.");
+ safe_gets (xx, sizeof xx);
+#else
+ SoftDebugger("Hit `c<return>' to resume bootstrap.");
+#endif
+
+ return boot_script_task_resume (cmd);
+}
+
+void
+boot_script_free_task (task_t task, int aborting)
+{
+ if (aborting)
+ task_terminate (task);
+ task_deallocate (task);
+}
+
+int
+boot_script_insert_right (struct cmd *cmd, mach_port_t port, mach_port_name_t *name)
+{
+ *name = task_insert_send_right (cmd->task,
+ ipc_port_make_send((ipc_port_t) port));
+ return 0;
+}
+
+int
+boot_script_insert_task_port (struct cmd *cmd, task_t task, mach_port_name_t *name)
+{
+ *name = task_insert_send_right (cmd->task,
+ ipc_port_make_send(task->itk_sself));
+ return 0;
+}