diff options
-rw-r--r-- | libdiskfs/boot-parse.c | 98 |
1 files changed, 88 insertions, 10 deletions
diff --git a/libdiskfs/boot-parse.c b/libdiskfs/boot-parse.c index 4403fcfe..58685464 100644 --- a/libdiskfs/boot-parse.c +++ b/libdiskfs/boot-parse.c @@ -24,6 +24,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #include <device/device.h> #include <string.h> #include <sys/reboot.h> +#include <mach/mig_support.h> int diskfs_bootflags; char *diskfs_bootflagarg; @@ -40,19 +41,96 @@ diskfs_parse_bootargs (int argc, char **argv) { char *devname; device_t con; - - /* The arguments, as passed by the kernel, are as follows: - -<flags> hostport deviceport rootname */ + mach_port_t bootstrap; + + task_get_bootstrap_port (mach_task_self (), &bootstrap); + if (bootstrap != MACH_PORT_NULL) + { + /* We were started not by the kernel, but by the CMU default_pager. + It passes us args: -<flags> root_name server_dir_name. We ignore + the last one. An RPC on our bootstrap port fetches the privileged + ports. */ + + struct + { + mach_msg_header_t Head; + mach_msg_type_t priv_hostType; + mach_port_t priv_host; + mach_msg_type_t priv_deviceType; + mach_port_t priv_device; + } msg; + mach_msg_return_t msg_result; + + static const mach_msg_type_t portCheck = { + /* msgt_name = */ MACH_MSG_TYPE_MOVE_SEND, + /* msgt_size = */ 32, + /* msgt_number = */ 1, + /* msgt_inline = */ TRUE, + /* msgt_longform = */ FALSE, + /* msgt_deallocate = */ FALSE, + /* msgt_unused = */ 0 + }; + + msg.Head.msgh_bits = + MACH_MSGH_BITS(19, MACH_MSG_TYPE_MAKE_SEND_ONCE); + /* msgh_size passed as argument */ + msg.Head.msgh_remote_port = bootstrap; + msg.Head.msgh_local_port = mig_get_reply_port (); + msg.Head.msgh_seqno = 0; + msg.Head.msgh_id = 999999; - if (argc != 5 || argv[1][0] != '-') + msg_result = mach_msg(&msg.Head, MACH_SEND_MSG|MACH_RCV_MSG, + sizeof msg.Head, sizeof msg, + msg.Head.msgh_local_port, + MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL); + if (msg_result != MACH_MSG_SUCCESS) + { + if ((msg_result == MACH_SEND_INVALID_REPLY) || + (msg_result == MACH_SEND_INVALID_MEMORY) || + (msg_result == MACH_SEND_INVALID_RIGHT) || + (msg_result == MACH_SEND_INVALID_TYPE) || + (msg_result == MACH_SEND_MSG_TOO_SMALL) || + (msg_result == MACH_RCV_INVALID_NAME)) + mig_dealloc_reply_port (msg.Head.msgh_local_port); + else + mig_put_reply_port (msg.Head.msgh_local_port); + assert (msg_result == MACH_MSG_SUCCESS); + } + mig_put_reply_port (msg.Head.msgh_local_port); + + assert (msg.Head.msgh_id == 999999 + 100); + assert (msg.Head.msgh_size == sizeof msg); + assert (msg.Head.msgh_bits & MACH_MSGH_BITS_COMPLEX); + assert (*(int *) &msg.priv_hostType == *(int *) &portCheck); + assert (*(int *) &msg.priv_deviceType == *(int *) &portCheck); + diskfs_host_priv = msg.priv_host; + diskfs_master_device = msg.priv_device; + + /* bootstrap_privileged_ports (bootstrap, + &diskfs_host_priv, + &diskfs_master_device); */ + + /* Clear our bootstrap port, to appear as if run by the kernel. */ + task_set_bootstrap_port (mach_task_self (), MACH_PORT_NULL); + + devname = argv[2]; + } + else { - fprintf (stderr, "Usage: %s: -[qsdnx] hostport deviceport rootname\n", - program_invocation_name); - exit (1); + /* The arguments, as passed by the kernel, are as follows: + -<flags> hostport deviceport rootname */ + + if (argc != 5 || argv[1][0] != '-') + { + fprintf (stderr, + "Usage: %s: -[qsdnx] hostport deviceport rootname\n", + program_invocation_name); + exit (1); + } + diskfs_host_priv = atoi (argv[2]); + diskfs_master_device = atoi (argv[3]); + devname = argv[4]; } - diskfs_host_priv = atoi (argv[2]); - diskfs_master_device = atoi (argv[3]); - devname = argv[4]; (void) device_open (diskfs_master_device, D_WRITE, "console", &con); stderr = stdout = mach_open_devstream (con, "w"); |