--- libmachdev/ds_routines.c | 19 ++++-- libmachdev/machdev.h | 5 +- libmachdev/trivfs_server.c | 135 ++++++++++++++++++++++++++++++++----- 3 files changed, 131 insertions(+), 28 deletions(-)
diff --git a/libmachdev/ds_routines.c b/libmachdev/ds_routines.c index da5e47e2..d5451a92 100644 --- a/libmachdev/ds_routines.c +++ b/libmachdev/ds_routines.c @@ -65,6 +65,7 @@ #include <hurd.h> #include <mach.h> +#include <device/device.h> /* fallback to kernel device */ #include "device_S.h" #include "notify_S.h" @@ -94,11 +95,8 @@ ds_device_open (mach_port_t open_port, mach_port_t reply_port, char *name, device_t *devp, mach_msg_type_name_t *devicePoly) { int i; - io_return_t err; - - /* Open must be called on the master device port. */ - if (!machdev_is_master_device (open_port)) - return D_INVALID_OPERATION; + mach_port_t dev_master; + io_return_t err = D_NO_SUCH_DEVICE; /* There must be a reply port. */ if (! MACH_PORT_VALID (reply_port)) @@ -108,11 +106,18 @@ ds_device_open (mach_port_t open_port, mach_port_t reply_port, for (i = 0; i < num_emul; i++) { err = (*emulation_list[i]->open) (reply_port, reply_port_type, - mode, name, devp, devicePoly); + mode, name, devp, devicePoly); if (err != D_NO_SUCH_DEVICE) - break; + break; } + /* Fall back to opening kernel device master */ + if (err) + { + get_privileged_ports(NULL, &dev_master); + err = device_open (dev_master, mode, name, devp); + *devicePoly = MACH_MSG_TYPE_MOVE_SEND; + } return err; } diff --git a/libmachdev/machdev.h b/libmachdev/machdev.h index 9b2dbd31..55a56e0d 100644 --- a/libmachdev/machdev.h +++ b/libmachdev/machdev.h @@ -32,9 +32,8 @@ void machdev_register (struct machdev_device_emulation_ops *ops); void machdev_device_init(void); void * machdev_server(void *); error_t machdev_create_device_port (size_t size, void *result); - -int machdev_trivfs_init(void); -void machdev_trivfs_server(void); +int machdev_trivfs_init(mach_port_t bootstrap_resume_task, const char *name, mach_port_t *bootstrap); +void machdev_trivfs_server(mach_port_t bootstrap); boolean_t machdev_is_master_device (mach_port_t port); #endif diff --git a/libmachdev/trivfs_server.c b/libmachdev/trivfs_server.c index d6bafccb..39ef207b 100644 --- a/libmachdev/trivfs_server.c +++ b/libmachdev/trivfs_server.c @@ -27,9 +27,12 @@ #include <hurd/ports.h> #include <hurd/trivfs.h> #include <hurd.h> +#include <device/device.h> /* mach console */ +#include "libdiskfs/diskfs.h" #include "device_S.h" #include "notify_S.h" +#include "fsys_S.h" static struct port_bucket *port_bucket; @@ -90,12 +93,15 @@ do_mach_notify_dead_name (struct port_info *pi, boolean_t machdev_is_master_device (mach_port_t port) { - struct port_info *pi = ports_lookup_port (port_bucket, port, + struct port_info *pi0 = ports_lookup_port (port_bucket, port, trivfs_protid_class); - if (pi == NULL) + struct port_info *pi1 = ports_lookup_port (port_bucket, port, + trivfs_cntl_class); + if ( (pi0 == NULL) || (pi1 == NULL) ) return FALSE; - ports_port_deref (pi); + ports_port_deref (pi0); + ports_port_deref (pi1); return TRUE; } @@ -114,11 +120,106 @@ trivfs_append_args (struct trivfs_control *fsys, char **argz, size_t *argz_len) return err; } -int machdev_trivfs_init() +/* This is fraud */ +kern_return_t +trivfs_S_fsys_startup (mach_port_t bootport, + mach_port_t reply, + mach_msg_type_name_t replytype, + int flags, + mach_port_t cntl, + mach_port_t *realnode, + mach_msg_type_name_t *realnodetype) +{ + *realnode = MACH_PORT_NULL; + *realnodetype = MACH_MSG_TYPE_MOVE_SEND; + return 0; +} + +/* Override the privileged ports for booting the system */ +kern_return_t +trivfs_S_fsys_getpriv (struct diskfs_control *init_bootstrap_port, + mach_port_t reply, mach_msg_type_name_t reply_type, + mach_port_t *host_priv, mach_msg_type_name_t *hp_type, + mach_port_t *dev_master, mach_msg_type_name_t *dm_type, + mach_port_t *fstask, mach_msg_type_name_t *task_type) +{ + error_t err; + mach_port_t right; + struct port_info *server_info; + + err = ports_create_port (trivfs_protid_class, port_bucket, + sizeof (struct port_info), &server_info); + assert_perror_backtrace (err); + right = ports_get_send_right (server_info); + ports_port_deref (server_info); + + err = get_privileged_ports (host_priv, NULL); + if (!err) + { + *dev_master = right; + *fstask = mach_task_self (); + *hp_type = *dm_type = MACH_MSG_TYPE_COPY_SEND; + *task_type = MACH_MSG_TYPE_COPY_SEND; + } + return err; +} + +static void +resume_bootstrap_server(mach_port_t server_task, const char *server_name) +{ + error_t err; + mach_port_t right; + mach_port_t dev, cons; + struct port_info *server_info; + + assert_backtrace (server_task != MACH_PORT_NULL); + + err = ports_create_port (trivfs_cntl_class, port_bucket, + sizeof (struct port_info), &server_info); + assert_perror_backtrace (err); + right = ports_get_send_right (server_info); + ports_port_deref (server_info); + err = task_set_special_port (server_task, TASK_BOOTSTRAP_PORT, right); + assert_perror_backtrace (err); + err = mach_port_deallocate (mach_task_self (), right); + assert_perror_backtrace (err); + + err = task_resume (server_task); + assert_perror_backtrace (err); + + /* Make sure we have a console */ + err = get_privileged_ports (NULL, &dev); + assert_perror_backtrace (err); + err = device_open (dev, D_READ|D_WRITE, "console", &cons); + mach_port_deallocate (mach_task_self (), dev); + assert_perror_backtrace (err); + stdin = mach_open_devstream (cons, "r"); + stdout = stderr = mach_open_devstream (cons, "w"); + mach_port_deallocate (mach_task_self (), cons); + + printf (" %s", server_name); + fflush (stdout); +} + +int +machdev_trivfs_init(mach_port_t bootstrap_resume_task, const char *name, mach_port_t *bootstrap) { port_bucket = ports_create_bucket (); trivfs_cntl_class = ports_create_class (trivfs_clean_cntl, 0); trivfs_protid_class = ports_create_class (trivfs_clean_protid, 0); + + if (bootstrap_resume_task != MACH_PORT_NULL) + { + resume_bootstrap_server(bootstrap_resume_task, name); + *bootstrap = MACH_PORT_NULL; + } + else + { + task_get_bootstrap_port (mach_task_self (), bootstrap); + if (*bootstrap == MACH_PORT_NULL) + error (1, 0, "must be started as a translator"); + } + return 0; } @@ -166,23 +267,21 @@ trivfs_modify_stat (struct trivfs_protid *cred, io_statbuf_t *stat) { } -void machdev_trivfs_server() +void +machdev_trivfs_server(mach_port_t bootstrap) { - mach_port_t bootstrap; - struct trivfs_control *fsys; + struct trivfs_control *fsys = NULL; int err; - task_get_bootstrap_port (mach_task_self (), &bootstrap); - if (bootstrap == MACH_PORT_NULL) - error (1, 0, "must be started as a translator"); - - /* Reply to our parent. */ - err = trivfs_startup (bootstrap, 0, - trivfs_cntl_class, port_bucket, - trivfs_protid_class, port_bucket, &fsys); - mach_port_deallocate (mach_task_self (), bootstrap); - if (err) - error (1, err, "Contacting parent"); + if (bootstrap != MACH_PORT_NULL) + { + err = trivfs_startup (bootstrap, 0, + trivfs_cntl_class, port_bucket, + trivfs_protid_class, port_bucket, &fsys); + mach_port_deallocate (mach_task_self (), bootstrap); + if (err) + error (1, err, "Contacting parent"); + } /* Launch. */ do -- 2.25.1