summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libdiskfs/boot-start.c444
1 files changed, 444 insertions, 0 deletions
diff --git a/libdiskfs/boot-start.c b/libdiskfs/boot-start.c
new file mode 100644
index 00000000..c252be2b
--- /dev/null
+++ b/libdiskfs/boot-start.c
@@ -0,0 +1,444 @@
+/*
+ Copyright (C) 1993, 1994 Free Software Foundation
+
+This file is part of the GNU Hurd.
+
+The GNU Hurd is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+The GNU Hurd is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with the GNU Hurd; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by Michael I. Bushnell. */
+
+#include "priv.h"
+#include <hurd/fsys.h>
+#include <stdio.h>
+#include <hurd/exec.h>
+#include <fcntl.h>
+#include <device/device.h>
+#include <sys/reboot.h>
+#include <string.h>
+#include <hurd.h>
+#include "fsys_S.h"
+#include "fsys_reply.h"
+
+mach_port_t diskfs_exec_ctl;
+mach_port_t diskfs_exec;
+
+
+static struct mutex execstartlock;
+static struct condition execstarted;
+
+static task_t exectask;
+static vm_address_t exec_stack_base;
+static vm_size_t exec_stack_size;
+
+static char *default_init = "hurd/init";
+
+static void start_execserver ();
+
+/* Once diskfs_root_node is set, call this if we are a bootstrap
+ filesystem. */
+void
+diskfs_start_bootstrap (void)
+{
+ mach_port_t root_pt, startup_pt, bootpt;
+ retry_type retry;
+ char pathbuf[1024];
+ uid_t idlist[] = {0, 0, 0};
+ mach_port_t portarray[INIT_PORT_MAX];
+ mach_port_t fdarray[3]; /* XXX */
+ mach_port_t con; /* XXX */
+ task_t newt;
+ error_t err;
+ char *initname;
+ char *argv;
+ int argvlen;
+
+ /* Get the execserver going and wait for its fsys_startup */
+ mutex_init (&execstartlock);
+ condition_init (&execstarted);
+ mutex_lock (&execstartlock);
+ start_execserver ();
+ condition_wait (&execstarted, &execstartlock);
+ mutex_unlock (&execstartlock);
+ assert (diskfs_exec_ctl);
+
+ /* Create the port for current and root directory */
+ err = fsys_getroot (diskfs_exec_ctl, 0, idlist, 3, idlist, 3, &diskfs_exec);
+ assert (!err);
+ assert (diskfs_exec);
+
+ root_pt = (ports_get_right
+ (diskfs_make_protid
+ (diskfs_make_peropen (diskfs_root_node, O_READ | O_EXEC),
+ 0,0,0,0)));
+ mach_port_insert_right (mach_task_self (), root_pt, root_pt,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+ /* Execute the startup server. */
+
+ if (diskfs_bootflags & RB_INITNAME)
+ {
+ printf ("Init name [%s]: ", default_init);
+ fflush (stdout);
+ scanf ("%as\n", &initname);
+ if (*initname)
+ while (*initname == '/')
+ initname++;
+ else
+ initname = default_init;
+ }
+ else
+ initname = default_init;
+
+ err = dir_pathtrans (root_pt, initname, O_READ, 0,
+ &retry, pathbuf, &startup_pt);
+
+ assert (!err);
+ assert (retry == FS_RETRY_NONE);
+
+ bootpt = ports_get_right (ports_allocate_port (sizeof (struct port_info),
+ PT_INITBOOT));
+ mach_port_insert_right (mach_task_self (), bootpt, bootpt,
+ MACH_MSG_TYPE_MAKE_SEND);
+
+
+ portarray[INIT_PORT_CRDIR] = root_pt;
+ portarray[INIT_PORT_CWDIR] = root_pt;
+ portarray[INIT_PORT_AUTH] = MACH_PORT_NULL;
+ portarray[INIT_PORT_PROC] = MACH_PORT_NULL;
+ portarray[INIT_PORT_LOGINCOLL] = MACH_PORT_NULL;
+ portarray[INIT_PORT_CTTYID] = MACH_PORT_NULL;
+ portarray[INIT_PORT_BOOTSTRAP] = bootpt;
+
+/* XXX */
+ device_open (diskfs_master_device, D_WRITE | D_READ, "console", &con);
+
+ fdarray[0] = con;
+ fdarray[1] = con;
+ fdarray[2] = con;
+/* XXX */
+ argvlen = asprintf (&argv, "%s%c%s%c", initname, '\0', diskfs_bootflagarg,
+ '\0');
+
+ task_create (mach_task_self (), 0, &newt);
+ printf ("pausing for init...\n");
+ getc (stdin);
+ err = exec_exec (diskfs_exec, startup_pt, MACH_MSG_TYPE_COPY_SEND,
+ newt, 0, argv, argvlen, 0, 0,
+ fdarray, MACH_MSG_TYPE_COPY_SEND, 3,
+ portarray, MACH_MSG_TYPE_COPY_SEND, INIT_PORT_MAX,
+ /* Supply no intarray, since we have no info for it.
+ With none supplied, it will use the defaults. */
+ NULL, 0, 0, 0, 0, 0);
+ free (argv);
+ mach_port_deallocate (mach_task_self (), root_pt);
+ mach_port_deallocate (mach_task_self (), startup_pt);
+ mach_port_deallocate (mach_task_self (), bootpt);
+ if (initname != default_init)
+ free (initname); /* XXX BUG -- might have been incremented */
+ assert (!err);
+}
+
+/* We look like an execserver to the execserver itself; it makes this
+ call (as does any task) to get its state. We can't give it all of
+ its ports (we'll provide those with a later call to exec_init). */
+kern_return_t
+diskfs_S_exec_startup (mach_port_t port,
+ vm_address_t *base_addr,
+ vm_size_t *stack_size,
+ int *flags,
+ char **argvP,
+ u_int *argvlen,
+ char **envpP,
+ u_int *envplen,
+ mach_port_t **dtableP,
+ mach_msg_type_name_t *dtablepoly,
+ u_int *dtablelen,
+ mach_port_t **portarrayP,
+ mach_msg_type_name_t *portarraypoly,
+ u_int *portarraylen,
+ int **intarrayP,
+ u_int *intarraylen)
+{
+ mach_port_t *portarray, *dtable;
+/* char *argv, *envp; */
+ mach_port_t rootport;
+ device_t con;
+ struct ufsport *upt;
+ char exec_argv[] = "[BOOT EXECSERVER]\0";
+
+ if (!(upt = ports_check_port_type (port, PT_EXECBOOT)))
+ return EOPNOTSUPP;
+
+ *base_addr = exec_stack_base;
+ *stack_size = exec_stack_size;
+
+ *flags = 0;
+
+ *argvP = exec_argv;
+ *argvlen = sizeof (exec_argv) + 1;
+
+ *envplen = 0;
+
+ if (*portarraylen < INIT_PORT_MAX)
+ vm_allocate (mach_task_self (), (u_int *)portarrayP,
+ (INIT_PORT_MAX * sizeof (mach_port_t)), 1);
+ portarray = *portarrayP;
+ *portarraylen = INIT_PORT_MAX;
+
+ if (*dtablelen < 3)
+ vm_allocate (mach_task_self (), (u_int *)dtableP,
+ (3 * sizeof (mach_port_t)), 1);
+ dtable = *dtableP;
+ *dtablelen = 3;
+
+ *intarrayP = NULL;
+ *intarraylen = 0;
+
+ rootport = (ports_get_right
+ (diskfs_make_protid
+ (diskfs_make_peropen (diskfs_root_node, O_READ | O_EXEC),
+ 0,0,0,0)));
+
+ portarray[INIT_PORT_CWDIR] = rootport;
+ portarray[INIT_PORT_CRDIR] = rootport;
+ portarray[INIT_PORT_AUTH] = MACH_PORT_NULL;
+ portarray[INIT_PORT_PROC] = MACH_PORT_NULL;
+ portarray[INIT_PORT_LOGINCOLL] = MACH_PORT_NULL;
+ portarray[INIT_PORT_CTTYID] = MACH_PORT_NULL;
+ portarray[INIT_PORT_BOOTSTRAP] = port; /* use the same port */
+
+ *portarraypoly = MACH_MSG_TYPE_MAKE_SEND;
+
+/* XXX */
+ device_open (diskfs_master_device, D_WRITE | D_READ, "console", &con);
+
+ dtable[0] = con;
+ dtable[1] = con;
+ dtable[2] = con;
+/* XXX */
+
+ *dtablepoly = MACH_MSG_TYPE_COPY_SEND;
+
+ ports_done_with_port (upt);
+ return 0;
+}
+
+/* Called by S_fsys_startup for execserver bootstrap. The execserver
+ is able to function without a real node, hence this fraud. */
+error_t
+diskfs_execboot_fsys_startup (mach_port_t port,
+ mach_port_t ctl,
+ mach_port_t *real,
+ mach_msg_type_name_t *realpoly,
+ mach_port_t *dotdot_node,
+ mach_msg_type_name_t *dotdot_node_poly)
+{
+ struct port_info *pt;
+
+ if (!(pt = ports_check_port_type (port, PT_EXECBOOT)))
+ return EOPNOTSUPP;
+
+ *real = MACH_PORT_NULL;
+ *realpoly = MACH_MSG_TYPE_COPY_SEND;
+ *dotdot_node = MACH_PORT_NULL;
+ *dotdot_node_poly = MACH_MSG_TYPE_COPY_SEND;
+
+ diskfs_exec_ctl = ctl;
+
+ mutex_lock (&execstartlock);
+ condition_signal (&execstarted);
+ mutex_unlock (&execstartlock);
+ ports_done_with_port (pt);
+ return 0;
+}
+
+/* Called by init to get the privileged ports as described
+ in <hurd/fsys.defs>. */
+kern_return_t
+diskfs_S_fsys_getpriv (mach_port_t port,
+ mach_port_t *hostpriv,
+ mach_port_t *device_master,
+ mach_port_t *fstask)
+{
+ struct port_info *pt;
+ if (!(pt = ports_check_port_type (port, PT_INITBOOT)))
+ return EOPNOTSUPP;
+
+ *hostpriv = diskfs_host_priv;
+ *device_master = diskfs_master_device;
+ *fstask = mach_task_self ();
+ ports_done_with_port (pt);
+ return 0;
+}
+
+/* Called by init to give us ports to the procserver and authserver as
+ described in <hurd/fsys.defs>. */
+kern_return_t
+diskfs_S_fsys_init (mach_port_t port,
+ mach_port_t reply, mach_msg_type_name_t replytype,
+ mach_port_t procserver,
+ mach_port_t authhandle)
+{
+ struct port_infe *pt;
+ static int initdone = 0;
+ process_t execprocess;
+ error_t err;
+
+ pt = ports_check_port_type (port, PT_INITBOOT);
+ if (!pt)
+ return EOPNOTSUPP;
+ ports_done_with_port (pt);
+ if (initdone)
+ return EOPNOTSUPP;
+ initdone = 1;
+
+ /* init is single-threaded, so we must reply to its RPC before doing
+ anything which might attempt to send an RPC to init. */
+ fsys_init_reply (reply, replytype, 0);
+
+ _hurd_port_set (&_hurd_ports[INIT_PORT_PROC], procserver);
+ _hurd_port_set (&_hurd_ports[INIT_PORT_AUTH], authhandle);
+
+ if (diskfs_auth_server_port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self (), diskfs_auth_server_port);
+ diskfs_auth_server_port = authhandle;
+
+ assert (exectask);
+ err = proc_task2proc (procserver, exectask, &execprocess);
+ assert (!err);
+ exec_init (diskfs_exec, authhandle, execprocess, MACH_MSG_TYPE_MOVE_SEND);
+
+ /* Declare that the exec server is our child. */
+ proc_child (procserver, exectask);
+
+ /* We don't need this anymore. */
+ mach_port_deallocate (mach_task_self (), exectask);
+ exectask = MACH_PORT_NULL;
+
+ diskfs_init_completed ();
+
+ return MIG_NO_REPLY; /* Already replied above. */
+}
+
+/* Unused */
+error_t
+diskfs_S_exec_init (mach_port_t a,
+ auth_t b,
+ process_t c)
+{
+ return EOPNOTSUPP;
+}
+
+/* Unused */
+error_t
+diskfs_S_exec_setexecdata (mach_port_t a,
+ mach_port_t *b,
+ u_int c,
+ int *d,
+ u_int e)
+{
+ return EOPNOTSUPP;
+}
+
+/* Unused. */
+error_t
+diskfs_S_exec_exec ( mach_port_t execserver,
+ mach_port_t file,
+ mach_port_t oldtask,
+ int flags,
+ data_t argv,
+ mach_msg_type_number_t argvCnt,
+ boolean_t argvSCopy,
+ data_t envp,
+ mach_msg_type_number_t envpCnt,
+ boolean_t envpSCopy,
+ portarray_t dtable,
+ mach_msg_type_number_t dtableCnt,
+ portarray_t portarray,
+ mach_msg_type_number_t portarrayCnt,
+ intarray_t intarray,
+ mach_msg_type_number_t intarrayCnt,
+ mach_port_t *deallocnames,
+ u_int deallocnamescnt,
+ mach_port_t *destroynames,
+ u_int destroynamescnt
+)
+{
+ return EOPNOTSUPP;
+}
+
+/* Unused. */
+error_t
+diskfs_S_exec_boot_init ( mach_port_t execserver,
+ startup_t init
+)
+{
+ return EOPNOTSUPP;
+}
+
+/* Start the execserver running (when we are a bootstrap filesystem).
+ CON will eventually go away; right now it's the console device. */
+static void
+start_execserver (void)
+{
+ task_t newt;
+ thread_t newthd;
+ vm_address_t buf;
+ vm_size_t bufsiz;
+ vm_address_t bssloc, textloc;
+ volatile error_t err;
+ mach_port_t right;
+
+ extern int execserver_text_size, execserver_data_size, execserver_bss_size;
+ extern int execserver_start;
+ extern int execserver_text, execserver_data;
+
+ /* This just sets up and runs the execserver task. It will do an
+ exec_startup (as every new task does) to get other stuff. */
+
+ err = task_create (mach_task_self (), 0, &newt);
+ exectask = newt;
+
+ right = ports_get_right (ports_allocate_port (sizeof (struct port_info),
+ PT_EXECBOOT));
+ mach_port_insert_right (mach_task_self (), right,
+ right, MACH_MSG_TYPE_MAKE_SEND);
+ task_set_special_port (newt, TASK_BOOTSTRAP_PORT, right);
+ mach_port_deallocate (mach_task_self (), right);
+
+ bufsiz = round_page (execserver_text_size + execserver_data_size);
+
+ err = vm_allocate (mach_task_self (), &buf, bufsiz, 1);
+ bcopy (&execserver_text, (char *)buf, execserver_text_size);
+ bcopy (&execserver_data, (char *)(buf + execserver_text_size),
+ execserver_data_size);
+ textloc = 0x10000;
+ err = vm_allocate (newt, &textloc, bufsiz, 0);
+ err = vm_write (newt, 0x10000, buf, bufsiz);
+ err = vm_deallocate (mach_task_self (), buf, bufsiz);
+ err = vm_protect (newt, 0, trunc_page (execserver_text_size) + 0x10000, 0,
+ VM_PROT_READ | VM_PROT_EXECUTE);
+
+ bssloc = 0x10000 + bufsiz;
+ err = vm_allocate (newt, &bssloc, round_page (execserver_bss_size), 0);
+
+ err = thread_create (newt, &newthd);
+ err = mach_setup_thread (newt, newthd, (void *) execserver_start,
+ &exec_stack_base, &exec_stack_size);
+ printf ("pausing for exec\n");
+ getc (stdin);
+ thread_resume (newthd);
+}
+