This is mostly a copy of rumpdisk, with small tweaks to compile in the rump USB stack instead of SATA/IDE.
This can be tested by running qemu with a USB3 controller as follows: -drive if=none,id=usbstick,format=raw,file=/path/to/disk.img \ -device qemu-xhci \ -device usb-storage,drive=usbstick \ NB: /path/to/disk.img can be a block device on the host. Then call grub module rumpusbdisk.static instead of rumpdisk.static and pass ' root=part:X:device:sd0 noide' as gnumach parameters, where X is the partition number of / within the disk/image. (IRQ sharing still seems broken). --- Makefile | 2 +- rumpusbdisk/Makefile | 42 +++ rumpusbdisk/block-rumpusb.c | 530 ++++++++++++++++++++++++++++++++++++ rumpusbdisk/block-rumpusb.h | 23 ++ rumpusbdisk/ioccom-rump.h | 82 ++++++ rumpusbdisk/main.c | 148 ++++++++++ 6 files changed, 826 insertions(+), 1 deletion(-) create mode 100644 rumpusbdisk/Makefile create mode 100644 rumpusbdisk/block-rumpusb.c create mode 100644 rumpusbdisk/block-rumpusb.h create mode 100644 rumpusbdisk/ioccom-rump.h create mode 100644 rumpusbdisk/main.c diff --git a/Makefile b/Makefile index 874349c0..154386ba 100644 --- a/Makefile +++ b/Makefile @@ -49,7 +49,7 @@ prog-subdirs = auth proc exec term \ shutdown ifeq ($(HAVE_LIBRUMP),yes) -prog-subdirs += rumpdisk +prog-subdirs += rumpdisk rumpusbdisk endif ifeq ($(HAVE_SUN_RPC),yes) diff --git a/rumpusbdisk/Makefile b/rumpusbdisk/Makefile new file mode 100644 index 00000000..de6374b9 --- /dev/null +++ b/rumpusbdisk/Makefile @@ -0,0 +1,42 @@ +# +# Copyright (C) 2023 Free Software Foundation, Inc. +# +# This program 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. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +RUMPLIBS=rump rumpuser rumpdev rumpdev_disk rumpdev_pci rumpvfs rumpdev_usb rumpdev_pci_usbhc rumpdev_umass +RUMPEXTRA=rumpdev_scsipi + +# If we have a configured tree, include the configuration so that we +# can conditionally build translators. +ifneq (,$(wildcard ../config.make)) + include ../config.make +endif + +ifeq ($(HAVE_LIBRUMP_VFSNOFIFO),yes) +RUMPLIBS += rumpvfs_nofifofs +endif + +dir := rumpusbdisk +makemode := server + +SRCS = main.c block-rumpusb.c +LCLHDRS = block-rumpusb.h ioccom-rump.h +target = rumpusbdisk +OBJS = $(SRCS:.c=.o) +HURDLIBS = machdev ports trivfs shouldbeinlibc iohelp ihash fshelp +LDLIBS += -lpthread -lpciaccess -ldl +LDLIBS += -Wl,--whole-archive $(RUMPLIBS:%=-l%_pic) -Wl,--no-whole-archive $(RUMPEXTRA:%=-l%_pic) + +include ../Makeconf diff --git a/rumpusbdisk/block-rumpusb.c b/rumpusbdisk/block-rumpusb.c new file mode 100644 index 00000000..1b249baa --- /dev/null +++ b/rumpusbdisk/block-rumpusb.c @@ -0,0 +1,530 @@ +/* + * Rump usb block driver support + * + * Copyright (C) 2023 Free Software Foundation + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdbool.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> + +#include <mach.h> +#include <mach/gnumach.h> +#include <hurd.h> +#include <hurd/ports.h> +#include <device/device.h> + +#define MACH_INCLUDE +#define _STANDALONE + +#include "libmachdev/machdev.h" +#include <rump/rump.h> +#include <rump/rump_syscalls.h> +#include <rump/rumperrno2host.h> + +#include "ioccom-rump.h" +#define DIOCGMEDIASIZE _IOR('d', 132, off_t) +#define DIOCGSECTORSIZE _IOR('d', 133, unsigned int) + +#define BLKRRPART 0x125F /* re-read partition table */ + +#define DISK_NAME_LEN 32 +#define MAX_DISK_DEV 2 + +static bool disabled; + +static mach_port_t master_host; + +/* rwlock to protect concurrent close while reading/writing */ +pthread_rwlock_t rumpusbdisk_rwlock = PTHREAD_RWLOCK_INITIALIZER; + +/* One of these is associated with each open instance of a device. */ +struct block_data +{ + struct port_info port; /* device port */ + struct machdev_emul_device device; /* generic device structure */ + dev_mode_t mode; /* r/w etc */ + int rump_fd; /* block device fd handle */ + char name[DISK_NAME_LEN]; /* eg /dev/sd0 */ + off_t media_size; /* total block device size */ + uint32_t block_size; /* size in bytes of 1 sector */ + int taken; /* refcount */ + struct block_data *next; +}; + +/* Return a send right associated with network device ND. */ +static mach_port_t +rumpusbdisk_dev_to_port (void *nd) +{ + return (nd ? ports_get_send_right (nd) : MACH_PORT_NULL); +} + +static struct block_data *block_head; +static struct machdev_device_emulation_ops rumpusb_block_emulation_ops; + +static struct block_data * +search_bd (const char *name) +{ + struct block_data *bd = block_head; + + while (bd) + { + /* Check name and refcount > 0 */ + if (!strcmp (bd->name, name) && bd->taken) + return bd; + bd = bd->next; + } + return NULL; +} + +/* BSD name of whole disk device is /dev/rwdXd + * but we will receive wdX as the name */ +static void +translate_name (char *output, int len, const char *name) +{ + snprintf (output, len - 1, "/dev/r%sd", name); +} + +static boolean_t +is_disk_device (const char *name) +{ + const char *dev; + const char *allowed_devs[MAX_DISK_DEV] = { + "sd", + "cd" + }; + uint8_t i; + + for (i = 0; i < MAX_DISK_DEV; i++) + { + dev = allowed_devs[i]; + /* /dev/XXN but we only care about /dev/XX prefix */ + if (! strncmp (dev, name, strlen(dev))) + return TRUE; + } + return FALSE; +} + +static int +dev_mode_to_rump_mode (const dev_mode_t mode) +{ + int ret = 0; + if (mode & D_READ) + { + if (mode & D_WRITE) + ret = RUMP_O_RDWR; + else + ret = RUMP_O_RDONLY; + } + else + { + if (mode & D_WRITE) + ret = RUMP_O_WRONLY; + } + return ret; +} + +static void +rumpusbdisk_device_init (void) +{ + mach_port_t device_master; + + if (! get_privileged_ports (&master_host, &device_master)) + { + device_t device; + + if (! device_open (device_master, D_READ, "sd0", &device) + || ! device_open (device_master, D_READ, "sd1", &device) + || ! device_open (device_master, D_READ, "sd2", &device) + || ! device_open (device_master, D_READ, "sd3", &device)) + { + device_close (device); + mach_port_deallocate (mach_task_self (), device); + fprintf(stderr, "Kernel is already driving a SATA device, skipping probing usb disks\n"); + fflush(stderr); + disabled = 1; + return; + } + } + rump_init (); +} + +static io_return_t +rumpusbdisk_device_close (void *d) +{ + struct block_data *bd = d; + io_return_t err; + + pthread_rwlock_wrlock (&rumpusbdisk_rwlock); + + bd->taken--; + if (bd->taken) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return D_SUCCESS; + } + + err = rump_errno2host (rump_sys_close (bd->rump_fd)); + if (err != D_SUCCESS) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return err; + } + + ports_port_deref (bd); + ports_destroy_right (bd); + + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return D_SUCCESS; +} + +static void +rumpusbdisk_device_dealloc (void *d) +{ + rump_sys_reboot (0, NULL); +} + +static void +rumpusbdisk_device_sync (void) +{ + if (disabled) + return; + + rump_sys_sync (); +} + +static io_return_t +rumpusbdisk_device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type, + dev_mode_t mode, const char *name, device_t * devp, + mach_msg_type_name_t * devicePoly) +{ + io_return_t err; + int ret, fd; + struct block_data *bd; + char dev_name[DISK_NAME_LEN]; + off_t media_size; + uint32_t block_size; + + if (disabled) + return D_NO_SUCH_DEVICE; + + if (! is_disk_device (name)) + return D_NO_SUCH_DEVICE; + + /* Protect against concurrent open/close */ + pthread_rwlock_wrlock (&rumpusbdisk_rwlock); + + /* Find previous device or open if new */ + bd = search_bd (name); + if (bd) + { + bd->taken++; + *devp = ports_get_right (bd); + *devicePoly = MACH_MSG_TYPE_MAKE_SEND; + + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return D_SUCCESS; + } + + translate_name (dev_name, DISK_NAME_LEN, name); + + fd = rump_sys_open (dev_name, dev_mode_to_rump_mode (mode)); + if (fd < 0) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return rump_errno2host (errno); + } + + ret = rump_sys_ioctl (fd, DIOCGMEDIASIZE, &media_size); + if (ret < 0) + { + mach_print ("DIOCGMEDIASIZE ioctl fails\n"); + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return rump_errno2host (errno); + } + + ret = rump_sys_ioctl (fd, DIOCGSECTORSIZE, &block_size); + if (ret < 0) + { + mach_print ("DIOCGSECTORSIZE ioctl fails\n"); + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return rump_errno2host (errno); + } + + err = machdev_create_device_port (sizeof (*bd), &bd); + if (err != 0) + { + rump_sys_close (fd); + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return err; + } + + bd->taken = 1; + snprintf (bd->name, DISK_NAME_LEN, "%s", name); + bd->rump_fd = fd; + bd->mode = mode; + bd->device.emul_data = bd; + bd->device.emul_ops = &rumpusb_block_emulation_ops; + bd->media_size = media_size; + bd->block_size = block_size; + + bd->next = block_head; + block_head = bd; + + *devp = ports_get_right (bd); + *devicePoly = MACH_MSG_TYPE_MAKE_SEND; + + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return D_SUCCESS; +} + +static io_return_t +rumpusbdisk_device_write (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, io_buf_ptr_t data, unsigned int count, + int *bytes_written) +{ + struct block_data *bd = d; + ssize_t written; + int pagesize = sysconf (_SC_PAGE_SIZE); + + if ((bd->mode & D_WRITE) == 0) + return D_INVALID_OPERATION; + + pthread_rwlock_rdlock (&rumpusbdisk_rwlock); + /* Ensure device is still open */ + if (! bd->taken) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return D_INVALID_OPERATION; + } + + if ((vm_offset_t) data % pagesize) + { + /* Not aligned, have to copy to aligned buffer. */ + vm_address_t buf; + rpc_phys_addr_t pap; + kern_return_t ret; + int err; + + /* While at it, make it contiguous */ + ret = vm_allocate_contiguous (master_host, mach_task_self (), &buf, &pap, count, 0, 0x100000000ULL, 0); + if (ret != KERN_SUCCESS) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return ENOMEM; + } + + memcpy ((void*) buf, data, count); + + written = rump_sys_pwrite (bd->rump_fd, (const void *)buf, (size_t)count, (off_t)bn * bd->block_size); + err = errno; + + vm_deallocate (mach_task_self (), (vm_address_t) buf, count); + + if (written < 0) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return rump_errno2host (err); + } + } + else + { + volatile uint8_t dummy_read __attribute__ ((unused)); + int npages = (count + pagesize - 1) / pagesize; + int i; + + /* Fault-in the memory pages by reading a single byte of each */ + for (i = 0; i < npages; i++) + dummy_read = ((volatile uint8_t *)data)[i * pagesize]; + + /* XXX: _bus_dmamap_load_buffer seems not to call rumpcomp_pci_virt_to_mach + * for each page, so separate out pages ourselves :/ */ + written = 0; + while (written < count) + { + size_t todo = count - written; + ssize_t done; + + if (todo > pagesize) + todo = pagesize; + + done = rump_sys_pwrite (bd->rump_fd, (const void *)data + written, todo, (off_t)bn * bd->block_size + written); + + if (done < 0) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return rump_errno2host (errno); + } + + written += done; + } + } + + vm_deallocate (mach_task_self (), (vm_address_t) data, count); + + *bytes_written = (int)written; + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return D_SUCCESS; +} + +static io_return_t +rumpusbdisk_device_read (void *d, mach_port_t reply_port, + mach_msg_type_name_t reply_port_type, dev_mode_t mode, + recnum_t bn, int count, io_buf_ptr_t * data, + unsigned *bytes_read) +{ + struct block_data *bd = d; + vm_address_t buf; + int pagesize = sysconf (_SC_PAGE_SIZE); + int npages = (count + pagesize - 1) / pagesize; + int i; + ssize_t done, err; + kern_return_t ret; + + if ((bd->mode & D_READ) == 0) + return D_INVALID_OPERATION; + + if (count == 0) + return D_SUCCESS; + + pthread_rwlock_rdlock (&rumpusbdisk_rwlock); + /* Ensure device is still open */ + if (! bd->taken) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return D_INVALID_OPERATION; + } + + /* TODO: directly write at *data when it is aligned */ + *data = 0; + ret = vm_allocate (mach_task_self (), &buf, npages * pagesize, TRUE); + if (ret != KERN_SUCCESS) + { + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return ENOMEM; + } + + /* Ensure physical allocation by writing a single byte of each */ + for (i = 0; i < npages; i++) + ((uint8_t *)buf)[i * pagesize] = 0; + + /* XXX: _bus_dmamap_load_buffer seems not to call rumpcomp_pci_virt_to_mach + * for each page, so separate out pages ourselves :/ */ + done = 0; + while (done < count) + { + size_t todo = count - done; + + if (todo > pagesize) + todo = pagesize; + + err = rump_sys_pread (bd->rump_fd, (void *)buf + done, todo, (off_t)bn * bd->block_size + done); + if (err < 0) + { + err = errno; + vm_deallocate (mach_task_self (), buf, npages * pagesize); + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return rump_errno2host (err); + } + + done += err; + } + + *bytes_read = done; + *data = (void*) buf; + pthread_rwlock_unlock (&rumpusbdisk_rwlock); + return D_SUCCESS; +} + +static io_return_t +rumpusbdisk_device_set_status (void *d, dev_flavor_t flavor, dev_status_t status, + mach_msg_type_number_t status_count) +{ + switch (flavor) + { + case BLKRRPART: + /* Partitions are not implemented here, but in the parted-based + * translators. */ + return D_SUCCESS; + default: + return D_INVALID_OPERATION; + } +} + +static io_return_t +rumpusbdisk_device_get_status (void *d, dev_flavor_t flavor, dev_status_t status, + mach_msg_type_number_t * count) +{ + struct block_data *bd = d; + + switch (flavor) + { + case DEV_GET_SIZE: + status[DEV_GET_SIZE_RECORD_SIZE] = bd->block_size; + status[DEV_GET_SIZE_DEVICE_SIZE] = bd->media_size; + *count = 2; + break; + case DEV_GET_RECORDS: + status[DEV_GET_RECORDS_RECORD_SIZE] = bd->block_size; + status[DEV_GET_RECORDS_DEVICE_RECORDS] = + bd->media_size / (unsigned long long) bd->block_size; + *count = 2; + break; + default: + return D_INVALID_OPERATION; + } + return D_SUCCESS; +} + +/* FIXME: + * Long term strategy: + * + * Call rump_sys_aio_read/write and return MIG_NO_REPLY from + * device_read/write, and send the mig reply once the aio request has + * completed. That way, only the aio request will be kept in rumpusbdisk + * memory instead of a whole thread structure. + */ +static struct machdev_device_emulation_ops rumpusb_block_emulation_ops = { + rumpusbdisk_device_init, + NULL, + rumpusbdisk_device_dealloc, + rumpusbdisk_dev_to_port, + rumpusbdisk_device_open, + rumpusbdisk_device_close, + rumpusbdisk_device_write, + NULL, + rumpusbdisk_device_read, + NULL, + rumpusbdisk_device_set_status, + rumpusbdisk_device_get_status, + NULL, + NULL, + NULL, + NULL, + NULL, + rumpusbdisk_device_sync +}; + +void +rump_register_block (void) +{ + machdev_register (&rumpusb_block_emulation_ops); +} diff --git a/rumpusbdisk/block-rumpusb.h b/rumpusbdisk/block-rumpusb.h new file mode 100644 index 00000000..693f35a6 --- /dev/null +++ b/rumpusbdisk/block-rumpusb.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2023 Free Software Foundation + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ +#ifndef _BLOCK_RUMPUSB_H_ +#define _BLOCK_RUMPUSB_H_ + +void rump_register_block (void); + +#endif diff --git a/rumpusbdisk/ioccom-rump.h b/rumpusbdisk/ioccom-rump.h new file mode 100644 index 00000000..6f41b05b --- /dev/null +++ b/rumpusbdisk/ioccom-rump.h @@ -0,0 +1,82 @@ +/* $NetBSD: ioccom.h,v 1.12 2014/12/10 00:16:05 christos Exp $ */ + +/*- + * Copyright (c) 1982, 1986, 1990, 1993, 1994 + * The Regents of the University of California. 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 University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + * + * @(#)ioccom.h 8.3 (Berkeley) 1/9/95 + */ + +#ifndef _SYS_IOCCOM_H_ +#define _SYS_IOCCOM_H_ + +/* + * Ioctl's have the command encoded in the lower word, and the size of + * any in or out parameters in the upper word. The high 3 bits of the + * upper word are used to encode the in/out status of the parameter. + * + * 31 29 28 16 15 8 7 0 + * +---------------------------------------------------------------+ + * | I/O | Parameter Length | Command Group | Command | + * +---------------------------------------------------------------+ + */ +#define IOCPARM_MASK 0x1fff /* parameter length, at most 13 bits */ +#define IOCPARM_SHIFT 16 +#define IOCGROUP_SHIFT 8 +#define IOCPARM_LEN(x) (((x) >> IOCPARM_SHIFT) & IOCPARM_MASK) +#define IOCBASECMD(x) ((x) & ~(IOCPARM_MASK << IOCPARM_SHIFT)) +#define IOCGROUP(x) (((x) >> IOCGROUP_SHIFT) & 0xff) + +#define IOCPARM_MAX NBPG /* max size of ioctl args, mult. of NBPG */ + /* no parameters */ +#define IOC_VOID (unsigned long)0x20000000 + /* copy parameters out */ +#define IOC_OUT (unsigned long)0x40000000 + /* copy parameters in */ +#define IOC_IN (unsigned long)0x80000000 + /* copy parameters in and out */ +#define IOC_INOUT (IOC_IN|IOC_OUT) + /* mask for IN/OUT/VOID */ +#define IOC_DIRMASK (unsigned long)0xe0000000 + +#define _IOC(inout, group, num, len) \ + ((inout) | (((len) & IOCPARM_MASK) << IOCPARM_SHIFT) | \ + ((group) << IOCGROUP_SHIFT) | (num)) +#define _IO(g,n) _IOC(IOC_VOID, (g), (n), 0) +#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t)) +#define _IOW(g,n,t) _IOC(IOC_IN, (g), (n), sizeof(t)) +/* this should be _IORW, but stdio got there first */ +#define _IOWR(g,n,t) _IOC(IOC_INOUT, (g), (n), sizeof(t)) + +#define IOCSNPRINTF(buf, len, cmd) \ + snprintf((buf), (len), "_IO%s%s('%c', %hhu)", \ + (((cmd) >> 30) & 1) ? "W" : "", \ + (((cmd) >> 30) & 2) ? "R" : "", \ + (char)IOCGROUP(cmd), (unsigned char)(cmd)) + + +#endif /* !_SYS_IOCCOM_H_ */ diff --git a/rumpusbdisk/main.c b/rumpusbdisk/main.c new file mode 100644 index 00000000..d5257683 --- /dev/null +++ b/rumpusbdisk/main.c @@ -0,0 +1,148 @@ +/* + * Copyright (C) 2023 Free Software Foundation + * + * This program 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include <stdarg.h> +#include <stdio.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <error.h> +#include <argp.h> +#include <version.h> + +#include "libmachdev/machdev.h" +#include "libshouldbeinlibc/wire.h" +#include "block-rumpusb.h" +#include <pthread.h> +#include <mach.h> + +mach_port_t bootstrap_resume_task = MACH_PORT_NULL; + +static const struct argp_option options[] = { + {"host-priv-port", 'h', "PORT", 0, "Host private port PORT"}, + {"device-master-port",'d', "PORT", 0, "Device master port PORT"}, + {"next-task", 'N', "TASK", 0, "Next bootstrap task TASK"}, + {0} +}; + + +/* Parse a command line option. */ +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + /* We save our parsed values in this structure, hung off STATE->hook. + Only after parsing all options successfully will we use these values. */ + struct + { + int host_priv; + int dev_master; + int next_task; + } *values = state->hook; + + switch (key) + { + case 'h': + values->host_priv = atoi(arg); + break; + case 'd': + values->dev_master = atoi(arg); + break; + case 'N': + values->next_task = atoi(arg); + break; + + case ARGP_KEY_INIT: + state->child_inputs[0] = state->input; + values = malloc (sizeof *values); + if (values == 0) + return ENOMEM; + state->hook = values; + memset (values, 0, sizeof *values); + break; + + case ARGP_KEY_SUCCESS: + /* All options parsed successfully */ + _hurd_host_priv = values->host_priv; + _hurd_device_master = values->dev_master; + bootstrap_resume_task = values->next_task; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +static struct argp_child empty_argp_children[] = {{0}}; +static struct argp rumpusbdisk_argp = {options, parse_opt, 0, 0, empty_argp_children}; +static const struct argp *rumpusbdisk_argp_bootup = &rumpusbdisk_argp; + +static void * +rumpusbdisk_multithread_server(void *arg) +{ + do + { + ports_manage_port_operations_multithread (machdev_device_bucket, + machdev_demuxer, + 1000 * 60 * 2, /* 2 minute thread */ + 1000 * 60 * 10, /* 10 minute server */ + 0); + } while (1); + + return NULL; +} + +int +main (int argc, char **argv) +{ + mach_port_t bootstrap = MACH_PORT_NULL; + int err; + pthread_t t; + + setenv ("RUMP_NCPU", "1", 1); + setenv ("RUMP_VERBOSE", "1", 1); + setenv ("RUMP_HOSTNAME", "HURD0", 1); + setenv ("HOSTNAME", "HURD0", 1); + setenv ("RUMP_PANIC", "1", 1); + + err = argp_parse (rumpusbdisk_argp_bootup, argc, argv, 0, 0, NULL); + if (err) + { + error(1, err, "Missing parameters for bootstrap"); + } + + rump_register_block (); + machdev_trivfs_init (argc, argv, bootstrap_resume_task, "rumpusbdisk", "/dev/rumpusbdisk", &bootstrap); + + /* Make sure we will not swap out, in case we drive the disk used for + swapping. */ + err = wire_task_self (); + if (err) + error (1, errno, "cannot lock all memory"); + + machdev_device_init (); + err = pthread_create (&t, NULL, rumpusbdisk_multithread_server, NULL); + if (err) + return err; + pthread_detach (t); + machdev_trivfs_server_startup (bootstrap); + machdev_trivfs_server_loop (NULL); + /* Never reached */ + return 0; +} -- 2.40.1