bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH hurd] rumpusbdisk: Add USB mass storage translator


From: Samuel Thibault
Subject: Re: [PATCH hurd] rumpusbdisk: Add USB mass storage translator
Date: Tue, 27 Jun 2023 23:48:41 +0200
User-agent: NeoMutt/20170609 (1.8.3)

Hello,

Damien Zammit, le mar. 27 juin 2023 11:11:09 +0000, a ecrit:
> This is mostly a copy of rumpdisk,

It should be possible to share the code, by setting makemode to servers,
and using -D / #ifdef?

> 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
> 
> 
> 

-- 
Samuel
---
Pour une évaluation indépendante, transparente et rigoureuse !
Je soutiens la Commission d'Évaluation de l'Inria.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]