[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH hurd] rumpusbdisk: Add USB mass storage translator
From: |
Damien Zammit |
Subject: |
[PATCH hurd] rumpusbdisk: Add USB mass storage translator |
Date: |
Tue, 27 Jun 2023 11:11:09 +0000 |
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
- [PATCH hurd] rumpusbdisk: Add USB mass storage translator,
Damien Zammit <=