summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2020-03-29 22:37:23 +1100
committerDamien Zammit <damien@zamaudio.com>2020-03-29 23:06:15 +1100
commit90636893c91c2aa5a01de7eb7e10bd7df3b1e93f (patch)
tree29abc77acd15db61d063d9eb4e21d6c51200b8d8
parent65acd70fcc369ab075594796330f00d4e0439a04 (diff)
libmachdevrump,rumpdisk: Add rumpdisk support
-rw-r--r--Makefile2
-rw-r--r--libmachdevrump/Makefile38
-rw-r--r--libmachdevrump/block.c355
-rw-r--r--libmachdevrump/mach_glue.h7
-rw-r--r--rumpdisk/Makefile35
-rw-r--r--rumpdisk/main.c18
6 files changed, 455 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index 6b1e8066..9629cbfb 100644
--- a/Makefile
+++ b/Makefile
@@ -32,6 +32,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
libhurd-slab \
libbpf \
libmachdev \
+ libmachdevrump \
# Hurd programs
prog-subdirs = auth proc exec term \
@@ -47,6 +48,7 @@ prog-subdirs = auth proc exec term \
devnode \
eth-multiplexer \
acpi \
+ rumpdisk \
shutdown
ifeq ($(HAVE_SUN_RPC),yes)
diff --git a/libmachdevrump/Makefile b/libmachdevrump/Makefile
new file mode 100644
index 00000000..8e786277
--- /dev/null
+++ b/libmachdevrump/Makefile
@@ -0,0 +1,38 @@
+# Copyright (C) 2009 Free Software Foundation, Inc.
+# This file is part of the GNU Hurd.
+#
+# The GNU Hurd 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.
+#
+# The GNU Hurd 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 the GNU Hurd; see the file COPYING. If not, write to
+# the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+RUMPLIB=-lrump
+RUMPLIBS=$(RUMPLIB) \
+ $(RUMPLIB)user \
+ $(RUMPLIB)dev \
+ $(RUMPLIB)dev_disk \
+ $(RUMPLIB)dev_pci \
+ $(RUMPLIB)vfs \
+ $(RUMPLIB)dev_ahcisata
+
+dir := libmachdevrump
+makemode := library
+libname = libmachdevrump
+
+SRCS = block.c
+
+HURDLIBS = machdev
+LDLIBS += -lpthread -ldl -lpciaccess
+LDLIBS += $(RUMPLIBS) $(RUMPLIB)dev_scsipi
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+
+include ../Makeconf
diff --git a/libmachdevrump/block.c b/libmachdevrump/block.c
new file mode 100644
index 00000000..0f90bd9f
--- /dev/null
+++ b/libmachdevrump/block.c
@@ -0,0 +1,355 @@
+/*
+ * Rump block driver support
+ *
+ * Copyright (C) 2019 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_U.h"
+
+#include <mach.h>
+#include <hurd.h>
+
+#define MACH_INCLUDE
+
+#include "libmachdev/machdev.h"
+#include "libmachdev/ds_routines.h"
+#include "libmachdev/vm_param.h"
+#include "libmachdev/dev_hdr.h"
+#include "device_reply_U.h"
+#include "mach_glue.h"
+
+#include <rump/rump.h>
+#include <rump/rump_syscalls.h>
+#include <rump/rumperrno2host.h>
+
+/* rump ioctl stuff */
+#define IOCPARM_MASK 0x1fff
+#define IOCPARM_SHIFT 16
+#define IOCGROUP_SHIFT 8
+#define _IOC(inout, group, num, len) \
+ ((inout) | (((len) & IOCPARM_MASK) << IOCPARM_SHIFT) | \
+ ((group) << IOCGROUP_SHIFT) | (num))
+#define IOC_OUT (unsigned long)0x40000000
+#define _IOR(g,n,t) _IOC(IOC_OUT, (g), (n), sizeof(t))
+#define DIOCGMEDIASIZE _IOR('d', 132, off_t)
+#define DIOCGSECTORSIZE _IOR('d', 133, unsigned int)
+
+#define DISK_NAME_LEN 32
+
+/* One of these is associated with each open instance of a device. */
+struct block_data
+{
+ struct port_info port; /* device port */
+ struct 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/wd0 */
+ off_t media_size; /* total block device size */
+ uint32_t block_size; /* size in bytes of 1 sector */
+ bool taken; /* simple refcount */
+ struct block_data *next;
+};
+
+/* Return a send right associated with network device ND. */
+static mach_port_t
+dev_to_port (void *nd)
+{
+ return (nd
+ ? ports_get_send_right (nd)
+ : MACH_PORT_NULL);
+}
+
+static struct block_data *block_head;
+static struct device_emulation_ops rump_block_emulation_ops;
+
+static struct block_data *
+search_bd (char *name)
+{
+ struct block_data *bd = block_head;
+
+ while (bd)
+ {
+ if (!strcmp(bd->name, name))
+ return bd;
+ bd = bd->next;
+ }
+ return NULL;
+}
+
+/* BSD name of whole disk device is /dev/wdXd
+ * but we will receive /dev/wdX as the name */
+static char *
+translate_name (char *name)
+{
+ char *ret;
+ ret = malloc (DISK_NAME_LEN);
+ snprintf (ret, DISK_NAME_LEN, "%sd", name);
+ return ret;
+}
+
+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
+device_init (void)
+{
+ rump_init();
+}
+
+static io_return_t
+device_close (void *d)
+{
+ io_return_t err;
+ struct block_data *bd = d;
+
+ err = rump_errno2host (rump_sys_close (bd->rump_fd));
+
+ return err;
+}
+
+static void
+device_dealloc (void *d)
+{
+ rump_sys_reboot(0, NULL);
+}
+
+static io_return_t
+device_open (mach_port_t reply_port, mach_msg_type_name_t reply_port_type,
+ dev_mode_t mode, char *name, device_t *devp,
+ mach_msg_type_name_t *devicePoly)
+{
+ io_return_t err = D_SUCCESS;
+ struct block_data *bd = NULL;
+ char *dev_name;
+ off_t media_size;
+ uint32_t block_size;
+
+ dev_name = translate_name (name);
+
+ /* Find previous device or open if new */
+ bd = search_bd (name);
+ if (!bd)
+ {
+ err = create_device_port (sizeof (*bd), &bd);
+
+ snprintf(bd->name, DISK_NAME_LEN, "%s", name);
+ bd->mode = mode;
+ bd->device.emul_data = bd;
+ bd->device.emul_ops = &rump_block_emulation_ops;
+ bd->next = block_head;
+ block_head = bd;
+
+ err = rump_sys_open (dev_name, dev_mode_to_rump_mode (bd->mode));
+ if (err < 0)
+ {
+ mach_print ("rump_sys_open fails: ");
+ mach_print (dev_name);
+ mach_print ("\n");
+ err = rump_errno2host (errno);
+ goto out;
+ }
+ bd->rump_fd = err;
+
+ err = rump_sys_ioctl (bd->rump_fd, DIOCGMEDIASIZE, &media_size);
+ if (err < 0)
+ {
+ mach_print ("DIOCGMEDIASIZE ioctl fails\n");
+ err = D_NO_SUCH_DEVICE;
+ goto out;
+ }
+
+ err = rump_sys_ioctl (bd->rump_fd, DIOCGSECTORSIZE, &block_size);
+ if (err < 0)
+ {
+ mach_print ("DIOCGSECTORSIZE ioctl fails\n");
+ err = D_NO_SUCH_DEVICE;
+ goto out;
+ }
+ bd->media_size = media_size;
+ bd->block_size = block_size;
+
+ err = D_SUCCESS;
+ }
+
+out:
+ free (dev_name);
+ if (err)
+ {
+ if (bd)
+ {
+ ports_port_deref (bd);
+ ports_destroy_right (bd);
+ bd = NULL;
+ }
+ }
+
+ if (bd)
+ {
+ *devp = ports_get_right (bd);
+ *devicePoly = MACH_MSG_TYPE_MAKE_SEND;
+ }
+ return err;
+}
+
+static io_return_t
+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;
+ io_return_t err = D_SUCCESS;
+
+ if ((bd->mode & D_WRITE) == 0)
+ return D_INVALID_OPERATION;
+
+ if (rump_sys_lseek (bd->rump_fd, (off_t)bn * bd->block_size, SEEK_SET) < 0)
+ {
+ *bytes_written = 0;
+ return EIO;
+ }
+
+ err = rump_sys_write (bd->rump_fd, data, count);
+ if (err < 0)
+ {
+ *bytes_written = 0;
+ return EIO;
+ }
+ else
+ {
+ *bytes_written = err;
+ return D_SUCCESS;
+ }
+}
+
+static io_return_t
+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;
+ io_return_t err = D_SUCCESS;
+ char *buf;
+ int pagesize = sysconf(_SC_PAGE_SIZE);
+ int npages = (count + pagesize - 1) / pagesize;
+
+ if ((bd->mode & D_READ) == 0)
+ return D_INVALID_OPERATION;
+
+ if (count == 0)
+ return D_SUCCESS;
+
+ *data = 0;
+ buf = mmap (NULL, npages * pagesize, PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+ if (buf == MAP_FAILED)
+ return errno;
+
+ if (rump_sys_lseek(bd->rump_fd, (off_t)bn * bd->block_size, SEEK_SET) < 0)
+ {
+ *bytes_read = 0;
+ return EIO;
+ }
+
+ err = rump_sys_read(bd->rump_fd, buf, count);
+ if (err < 0)
+ {
+ *bytes_read = 0;
+ return EIO;
+ }
+ else
+ {
+ *bytes_read = err;
+ *data = buf;
+ return D_SUCCESS;
+ }
+}
+
+static io_return_t
+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;
+ break;
+ }
+ return D_SUCCESS;
+}
+
+static struct device_emulation_ops rump_block_emulation_ops =
+{
+ device_init,
+ NULL,
+ device_dealloc,
+ dev_to_port,
+ device_open,
+ device_close,
+ device_write,
+ NULL,
+ device_read,
+ NULL,
+ NULL,
+ device_get_status,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+void register_block()
+{
+ extern void reg_dev_emul (struct device_emulation_ops *ops);
+ reg_dev_emul (&rump_block_emulation_ops);
+}
diff --git a/libmachdevrump/mach_glue.h b/libmachdevrump/mach_glue.h
new file mode 100644
index 00000000..dc19ea14
--- /dev/null
+++ b/libmachdevrump/mach_glue.h
@@ -0,0 +1,7 @@
+#ifndef __MACH_GLUE_H__
+#define __MACH_GLUE_H__
+
+/* block device */
+struct block_data;
+
+#endif
diff --git a/rumpdisk/Makefile b/rumpdisk/Makefile
new file mode 100644
index 00000000..9cfd34cd
--- /dev/null
+++ b/rumpdisk/Makefile
@@ -0,0 +1,35 @@
+#
+# Copyright (C) 2019 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.
+
+RUMPPATH=/usr/lib
+RUMPLIBS=rump rumpuser rumpdev rumpdev_disk rumpdev_pci rumpvfs rumpdev_ahcisata
+RUMPEXTRA=rumpdev_scsipi
+
+dir := rumpdisk
+makemode := server
+
+SRCS = main.c
+target = rumpdisk
+OBJS = $(SRCS:.c=.o)
+HURDLIBS = machdev machdevrump
+LDLIBS += -lpthread
+LDLIBS += $(RUMPLIBS:%=-l%) $(RUMPEXTRA:%=-l%)
+
+include ../Makeconf
+
+rumpdisk.static: main.o
+ $(CC) -static main.o -Wl,--whole-archive $(RUMPLIBS:%=$(RUMPPATH)/lib%_pic.a) ../libmachdevrump/libmachdevrump_pic.a ../libmachdev/libmachdev_pic.a -Wl,--no-whole-archive $(RUMPEXTRA:%=$(RUMPPATH)/lib%_pic.a) ../libtrivfs/libtrivfs_pic.a ../libshouldbeinlibc/libshouldbeinlibc_pic.a ../libports/libports_pic.a ../libiohelp/libiohelp_pic.a ../libihash/libihash_pic.a ../libfshelp/libfshelp_pic.a /usr/lib/i386-gnu/libpthread.a /usr/lib/i386-gnu/libpciaccess.a /usr/lib/i386-gnu/libdl.a -o $@
diff --git a/rumpdisk/main.c b/rumpdisk/main.c
new file mode 100644
index 00000000..b563f4cd
--- /dev/null
+++ b/rumpdisk/main.c
@@ -0,0 +1,18 @@
+#include "libmachdev/machdev.h"
+#include <cthreads.h>
+#include <mach.h>
+
+void ds_pre_server(void)
+{
+ /* empty */
+}
+
+int main()
+{
+ register_block ();
+ mach_device_init ();
+ trivfs_init ();
+ cthread_detach (cthread_fork (ds_server, NULL));
+ trivfs_server ();
+ return 0;
+}