On 29/3/20 4:16 pm, Damien Zammit wrote:
> Hurd TODO for Damien:
> =====================
> 
> - Fix libstore patch
Done

> - Remove useless debugging eg:

Done

> 
> - Remove most of this header:
>>> +++ b/libmachdevrump/dev_hdr.h
>> - put the files common to dde-based and rump-based libmachdev to
>>   libmachdev/.  That includes basically all your files except disk.c,
>>   machdevrump.c and Makefile. The only real discrepancy I see is in
>>   ds_routines.c' call to l4dde26_process_from_ddekit, but we can make
>>   libmachdevdde provide a function that does that call then call
>>   ds_server(). AIUI the call to is_master_device() should indeed be made
>>   like in the incubator?  I don't think we should deallocate it at the
>>   very least, was it really needed in your tests?

I compiled rumpdisk.static with the attached patches and it probed a real disk,
but I still need to test that the disk fully mounts.

I created a ds_pre_server() hook in libmachdev and implemented it for 
libmachdevdde,
and left an empty stub for libmachdevrump. 

>> - move the dde-based files (for network) to a libmachdevdde/

Done (have not tested dde with this)

>> - put your rump-based disk.c to a libmachdevrump/

Done

>> and the rumpdisk daemon will just need to link in both libmachdev and
>> libmachdevrump.

Done
>From ef2122c9c028e0607ca54bc715d97f1ac934019a Mon Sep 17 00:00:00 2001
From: Damien Zammit <dam...@zamaudio.com>
Date: Sun, 29 Mar 2020 18:51:00 +1100
Subject: [PATCH 1/4] libstore: Add ability to pass custom master device with
 format @master:/dev/device

---
 libstore/device.c | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/libstore/device.c b/libstore/device.c
index 1d8f57fd..b8961a52 100644
--- a/libstore/device.c
+++ b/libstore/device.c
@@ -95,15 +95,22 @@ dopen (const char *name, device_t *device, int *mod_flags)
 {
   device_t dev_master;
   error_t err = ENODEV;
+  char *pos;
+  char *master;
+  char *rest;
 
-  if (name[0] == '/')
+  /* Parse @master:/dev/hello */
+  if ( (name[0] == '@') && (pos = strchr (name, ':')) )
     {
+      master = strndup (name+1, pos-(name+1));
+      rest = strdup (pos+1);
+
       if (*mod_flags & STORE_HARD_READONLY)
 	{
-	  dev_master = file_name_lookup (name, O_READ, 0);
+	  dev_master = file_name_lookup (master, O_READ, 0);
 	  if (dev_master != MACH_PORT_NULL)
 	    {
-	      err = device_open (dev_master, D_READ, "disk", device);
+	      err = device_open (dev_master, D_READ, rest, device);
 	      if (err)
 		err = ENODEV;
 
@@ -114,13 +121,13 @@ dopen (const char *name, device_t *device, int *mod_flags)
 	}
       else
 	{
-	  dev_master = file_name_lookup (name, O_READ | O_WRITE, 0);
+	  dev_master = file_name_lookup (master, O_READ | O_WRITE, 0);
 	  if (dev_master != MACH_PORT_NULL)
 	    {
-	      err = device_open (dev_master, D_READ | D_WRITE, "disk", device);
+	      err = device_open (dev_master, D_READ | D_WRITE, rest, device);
 	      if (err == ED_READ_ONLY)
 		{
-		  err = device_open (dev_master, D_READ, "disk", device);
+		  err = device_open (dev_master, D_READ, rest, device);
 		  if (! err)
 		    *mod_flags |= STORE_HARD_READONLY;
 		  else
-- 
2.25.1

>From 65acd70fcc369ab075594796330f00d4e0439a04 Mon Sep 17 00:00:00 2001
From: Damien Zammit <dam...@zamaudio.com>
Date: Sun, 29 Mar 2020 22:32:44 +1100
Subject: [PATCH 2/4] libmachdev: Add common machdev

---
 Makefile                   |   1 +
 libmachdev/Makefile        |  34 ++++
 libmachdev/dev_hdr.h       | 133 +++++++++++++++
 libmachdev/device_emul.h   |  65 +++++++
 libmachdev/ds_routines.c   | 335 +++++++++++++++++++++++++++++++++++++
 libmachdev/ds_routines.h   |  57 +++++++
 libmachdev/io_req.h        | 135 +++++++++++++++
 libmachdev/machdev.h       |  34 ++++
 libmachdev/mig-decls.h     |  50 ++++++
 libmachdev/mig-mutate.h    |  36 ++++
 libmachdev/trivfs_server.c | 169 +++++++++++++++++++
 libmachdev/vm_param.h      |   7 +
 12 files changed, 1056 insertions(+)
 create mode 100644 libmachdev/Makefile
 create mode 100644 libmachdev/dev_hdr.h
 create mode 100644 libmachdev/device_emul.h
 create mode 100644 libmachdev/ds_routines.c
 create mode 100644 libmachdev/ds_routines.h
 create mode 100644 libmachdev/io_req.h
 create mode 100644 libmachdev/machdev.h
 create mode 100644 libmachdev/mig-decls.h
 create mode 100644 libmachdev/mig-mutate.h
 create mode 100644 libmachdev/trivfs_server.c
 create mode 100644 libmachdev/vm_param.h

diff --git a/Makefile b/Makefile
index 09662f87..6b1e8066 100644
--- a/Makefile
+++ b/Makefile
@@ -31,6 +31,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
 	      libnetfs libpipe libstore libhurdbugaddr libftpconn libcons \
 	      libhurd-slab \
 	      libbpf \
+	      libmachdev \
 
 # Hurd programs
 prog-subdirs = auth proc exec term \
diff --git a/libmachdev/Makefile b/libmachdev/Makefile
new file mode 100644
index 00000000..78f0756f
--- /dev/null
+++ b/libmachdev/Makefile
@@ -0,0 +1,34 @@
+# 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.
+
+dir := libmachdev
+makemode := library
+libname = libmachdev
+
+SRCS = deviceUser.c machUser.c ds_routines.c trivfs_server.c \
+       device_replyUser.c deviceServer.c notifyServer.c
+
+LCLHDRS = dev_hdr.h device_emul.h ds_routines.h vm_param.h \
+	  io_req.h machdev.h 
+installhdrs = machdev.h
+HURDLIBS = ports trivfs
+LDLIBS += -lpthread
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+MIGSFLAGS = -imacros $(srcdir)/mig-mutate.h
+device-MIGSFLAGS="-DMACH_PAYLOAD_TO_PORT=ports_payload_get_name"
+
+include ../Makeconf
diff --git a/libmachdev/dev_hdr.h b/libmachdev/dev_hdr.h
new file mode 100644
index 00000000..79edc43a
--- /dev/null
+++ b/libmachdev/dev_hdr.h
@@ -0,0 +1,133 @@
+/* 
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ * 
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ * 
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *	Author: David B. Golub, Carnegie Mellon University
+ *	Date: 	3/89
+ */
+
+/*
+ * Mach device emulation definitions (i386at version).
+ *
+ * Copyright (c) 1996 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-d...@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ *      Author: Shantanu Goel, University of Utah CSL
+ */
+
+#ifndef	_DEVICE_DEV_HDR_H_
+#define	_DEVICE_DEV_HDR_H_
+
+#include <mach.h>
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <pthread.h>
+
+#include "device_emul.h"
+
+/*
+ * Operations list for major device types.
+ */
+struct dev_ops {
+	char *    	d_name;		/* name for major device */
+	int		(*d_open)();	/* open device */
+	int		(*d_close)();	/* close device */
+	int		(*d_read)();	/* read */
+	int		(*d_write)();	/* write */
+	int		(*d_getstat)();	/* get status/control */
+	int		(*d_setstat)();	/* set status/control */
+	vm_offset_t	(*d_mmap)();	/* map memory */
+	int		(*d_async_in)();/* asynchronous input setup */
+	int		(*d_reset)();	/* reset device */
+	int		(*d_port_death)();
+					/* clean up reply ports */
+	int		d_subdev;	/* number of sub-devices per
+					   unit */
+	int		(*d_dev_info)(); /* driver info for kernel */
+};
+typedef struct dev_ops *dev_ops_t;
+
+/* This structure is associated with each open device port.
+ * The port representing the device points to this structure.  */
+struct emul_device
+{
+    struct device_emulation_ops *emul_ops;
+    void *emul_data;
+};
+
+typedef struct emul_device *emul_device_t;
+
+#define DEVICE_NULL     ((device_t) 0)
+
+/*
+ * Generic device header.  May be allocated with the device,
+ * or built when the device is opened.
+ */
+struct mach_device {
+	struct port_info port;
+	struct emul_device	dev;		/* the real device structure */
+};
+typedef	struct mach_device *mach_device_t;
+#define	MACH_DEVICE_NULL ((mach_device_t)0)
+
+/*
+ * To find and remove device entries
+ */
+mach_device_t	device_lookup(char *);	/* by name */
+
+/*
+ * To find and remove port-to-device mappings
+ */
+void		dev_port_enter(mach_device_t);
+void		dev_port_remove(mach_device_t);
+
+/*
+ * To call a routine on each device
+ */
+boolean_t	dev_map(boolean_t (*)(), mach_port_t);
+
+/*
+ * To lock and unlock state and open-count
+ */
+#define	device_lock(device)	pthread_mutex_lock(&(device)->lock)
+#define	device_unlock(device)	pthread_mutex_unlock(&(device)->lock)
+
+#endif	/* _DEVICE_DEV_HDR_H_ */
diff --git a/libmachdev/device_emul.h b/libmachdev/device_emul.h
new file mode 100644
index 00000000..e27799cb
--- /dev/null
+++ b/libmachdev/device_emul.h
@@ -0,0 +1,65 @@
+/*
+ * Mach device emulation definitions (i386at version).
+ *
+ * Copyright (c) 1996 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-d...@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ *      Author: Shantanu Goel, University of Utah CSL
+ */
+
+#ifndef _I386AT_DEVICE_EMUL_H_
+#define _I386AT_DEVICE_EMUL_H_
+
+#include <mach.h>
+
+/* Each emulation layer provides these operations.  */
+struct device_emulation_ops
+{
+  void (*init) (void);
+  void (*reference) (void *);
+  void (*dealloc) (void *);
+  mach_port_t (*dev_to_port) (void *);
+  io_return_t (*open) (mach_port_t, mach_msg_type_name_t,
+		       dev_mode_t, char *, device_t *,
+		       mach_msg_type_name_t *type);
+  io_return_t (*close) (void *);
+  io_return_t (*write) (void *, mach_port_t, mach_msg_type_name_t,
+			dev_mode_t, recnum_t, io_buf_ptr_t, unsigned, int *);
+  io_return_t (*write_inband) (void *, mach_port_t, mach_msg_type_name_t,
+			       dev_mode_t, recnum_t, io_buf_ptr_inband_t,
+			       unsigned, int *);
+  io_return_t (*read) (void *, mach_port_t, mach_msg_type_name_t,
+		       dev_mode_t, recnum_t, int, io_buf_ptr_t *, unsigned *);
+  io_return_t (*read_inband) (void *, mach_port_t, mach_msg_type_name_t,
+			      dev_mode_t, recnum_t, int, char *, unsigned *);
+  io_return_t (*set_status) (void *, dev_flavor_t, dev_status_t,
+			     mach_msg_type_number_t);
+  io_return_t (*get_status) (void *, dev_flavor_t, dev_status_t,
+			     mach_msg_type_number_t *);
+  io_return_t (*set_filter) (void *, mach_port_t, int, filter_t [], unsigned);
+  io_return_t (*map) (void *, vm_prot_t, vm_offset_t,
+		      vm_size_t, mach_port_t *, boolean_t);
+  void (*no_senders) (mach_no_senders_notification_t *);
+  io_return_t (*write_trap) (void *, dev_mode_t,
+			     recnum_t, vm_offset_t, vm_size_t);
+  io_return_t (*writev_trap) (void *, dev_mode_t,
+			      recnum_t, io_buf_vec_t *, vm_size_t);
+};
+
+#endif /* _I386AT_DEVICE_EMUL_H_ */
diff --git a/libmachdev/ds_routines.c b/libmachdev/ds_routines.c
new file mode 100644
index 00000000..d1da8780
--- /dev/null
+++ b/libmachdev/ds_routines.c
@@ -0,0 +1,335 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *	Author: David B. Golub, Carnegie Mellon University
+ *	Date: 	3/89
+ */
+
+/*
+ * Mach device server routines (i386at version).
+ *
+ * Copyright (c) 1996 The University of Utah and
+ * the Computer Systems Laboratory at the University of Utah (CSL).
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify and distribute this software is hereby
+ * granted provided that (1) source code retains these copyright, permission,
+ * and disclaimer notices, and (2) redistributions including binaries
+ * reproduce the notices in supporting documentation, and (3) all advertising
+ * materials mentioning features or use of this software display the following
+ * acknowledgement: ``This product includes software developed by the
+ * Computer Systems Laboratory at the University of Utah.''
+ *
+ * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
+ * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
+ * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * CSL requests users of this software to return to csl-d...@cs.utah.edu any
+ * improvements that they make and grant CSL redistribution rights.
+ *
+ *      Author: Shantanu Goel, University of Utah CSL
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <error.h>
+
+#include <hurd.h>
+#include <mach.h>
+
+#include "vm_param.h"
+#include "device_S.h"
+#include "notify_S.h"
+#include "io_req.h"
+#include "dev_hdr.h"
+#include "machdev.h"
+
+struct port_bucket *device_bucket;
+struct port_class *dev_class;
+
+#define MAX_NUM_EMULATION 32
+
+/* List of emulations.  */
+static struct device_emulation_ops *emulation_list[MAX_NUM_EMULATION];
+static int num_emul = 0;
+
+boolean_t is_master_device (mach_port_t port);
+
+/*
+ * What follows is the interface for the native Mach devices.
+ */
+
+/* Implementation of device interface */
+io_return_t
+ds_device_open (mach_port_t open_port, 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)
+{
+  int i;
+  io_return_t err = D_NO_SUCH_DEVICE;
+
+  /* Open must be called on the master device port.  */
+  if (!is_master_device (open_port))
+    return D_INVALID_OPERATION;
+
+  /* There must be a reply port.  */
+  if (! MACH_PORT_VALID (reply_port))
+    {
+      mach_print ("ds_* invalid reply port\n");
+      return MIG_NO_REPLY;
+    }
+
+  /* Call each emulation's open routine to find the device.  */
+  for (i = 0; i < num_emul; i++)
+    {
+      err = (*emulation_list[i]->open) (reply_port, reply_port_type,
+					mode, name, devp, devicePoly);
+      if (err != D_NO_SUCH_DEVICE)
+	break;
+    }
+
+  return err;
+}
+
+io_return_t
+ds_device_close (struct mach_device *device)
+{
+  io_return_t ret;
+
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  ret = (device->dev.emul_ops->close
+	 ? (*device->dev.emul_ops->close) (device->dev.emul_data)
+	 : D_SUCCESS);
+  return ret;
+}
+
+io_return_t
+ds_device_write (struct mach_device *device, mach_port_t reply_port,
+		 mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+		 recnum_t recnum, io_buf_ptr_t data, unsigned int count,
+		 int *bytes_written)
+{
+  io_return_t ret;
+
+  if (data == 0)
+    return D_INVALID_SIZE;
+
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  if (! device->dev.emul_ops->write)
+    return D_INVALID_OPERATION;
+
+  ret = (*device->dev.emul_ops->write) (device->dev.emul_data, reply_port,
+					reply_port_type, mode, recnum,
+					data, count, bytes_written);
+  return ret;
+}
+
+io_return_t
+ds_device_write_inband (struct mach_device *device, mach_port_t reply_port,
+			mach_msg_type_name_t reply_port_type,
+			dev_mode_t mode, recnum_t recnum,
+			io_buf_ptr_inband_t data, unsigned count,
+			int *bytes_written)
+{
+  io_return_t ret;
+
+  if (data == 0)
+    return D_INVALID_SIZE;
+
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  if (! device->dev.emul_ops->write_inband)
+    return D_INVALID_OPERATION;
+
+  ret = (*device->dev.emul_ops->write_inband) (device->dev.emul_data,
+					       reply_port, reply_port_type,
+					       mode, recnum,
+					       data, count, bytes_written);
+  return ret;
+}
+
+io_return_t
+ds_device_read (struct mach_device *device, mach_port_t reply_port,
+		mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+		recnum_t recnum, int count, io_buf_ptr_t *data,
+		unsigned *bytes_read)
+{
+  io_return_t ret;
+
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  if (! device->dev.emul_ops->read)
+    return D_INVALID_OPERATION;
+
+  ret = (*device->dev.emul_ops->read) (device->dev.emul_data, reply_port,
+				       reply_port_type, mode, recnum,
+				       count, data, bytes_read);
+  return ret;
+}
+
+io_return_t
+ds_device_read_inband (struct mach_device *device, mach_port_t reply_port,
+		       mach_msg_type_name_t reply_port_type, dev_mode_t mode,
+		       recnum_t recnum, int count, char *data,
+		       unsigned *bytes_read)
+{
+  io_return_t ret;
+
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  if (! device->dev.emul_ops->read_inband)
+    return D_INVALID_OPERATION;
+
+  ret = (*device->dev.emul_ops->read_inband) (device->dev.emul_data,
+					      reply_port,
+					      reply_port_type, mode, recnum,
+					      count, data, bytes_read);
+  return ret;
+}
+
+io_return_t
+ds_device_set_status (struct mach_device *device, dev_flavor_t flavor,
+		      dev_status_t status, mach_msg_type_number_t status_count)
+{
+  io_return_t ret;
+
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  if (! device->dev.emul_ops->set_status)
+    return D_INVALID_OPERATION;
+
+  ret = (*device->dev.emul_ops->set_status) (device->dev.emul_data, flavor,
+					     status, status_count);
+  return ret;
+}
+
+io_return_t
+ds_device_get_status (struct mach_device *device, dev_flavor_t flavor,
+                      dev_status_t status,
+		      mach_msg_type_number_t *status_count)
+{
+  io_return_t ret;
+
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  if (! device->dev.emul_ops->get_status)
+    return D_INVALID_OPERATION;
+
+  ret = (*device->dev.emul_ops->get_status) (device->dev.emul_data, flavor,
+					     status, status_count);
+  return ret;
+}
+
+io_return_t
+ds_device_set_filter (struct mach_device *device, mach_port_t receive_port,
+                      int priority, filter_t *filter, unsigned filter_count)
+{
+  io_return_t ret;
+
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  if (! device->dev.emul_ops->set_filter)
+    return D_INVALID_OPERATION;
+
+  ret = (*device->dev.emul_ops->set_filter) (device->dev.emul_data,
+					     receive_port,
+					     priority, filter, filter_count);
+  return ret;
+}
+
+io_return_t
+ds_device_map (struct mach_device *device, vm_prot_t prot, vm_offset_t offset,
+	       vm_size_t size, mach_port_t *pager, boolean_t unmap)
+{
+  /* Refuse if device is dead or not completely open.  */
+  if (device == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  return D_INVALID_OPERATION;
+}
+
+error_t
+create_device_port (size_t size, void *result)
+{
+  return ports_create_port (dev_class, device_bucket,
+			    size, result);
+}
+
+void mach_device_init()
+{
+	int i;
+
+	device_bucket = ports_create_bucket ();
+	dev_class = ports_create_class (0, 0);
+
+	for (i = 0; i < num_emul; i++) {
+		if (emulation_list[i]->init)
+			emulation_list[i]->init();
+	}
+}
+
+static int
+demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+  mig_routine_t routine;
+  if ((routine = device_server_routine (inp)) ||
+      (routine = notify_server_routine (inp)))
+    {
+      (*routine) (inp, outp);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+void reg_dev_emul (struct device_emulation_ops *ops)
+{
+  emulation_list[num_emul++] = ops;
+}
+
+void * ds_server(void *arg)
+{
+  /* Hook for dde to identify thread */
+  ds_pre_server();
+
+  /* Launch.  */
+  do
+    {
+      ports_manage_port_operations_one_thread (device_bucket, demuxer, 0);
+    } while (1);
+
+  return NULL;
+}
diff --git a/libmachdev/ds_routines.h b/libmachdev/ds_routines.h
new file mode 100644
index 00000000..3706aa58
--- /dev/null
+++ b/libmachdev/ds_routines.h
@@ -0,0 +1,57 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *	Author: David B. Golub, Carnegie Mellon University
+ *	Date: 	8/89
+ *
+ *	Device service utility routines.
+ */
+
+#ifndef	DS_ROUTINES_H
+#define	DS_ROUTINES_H
+
+#include <mach.h>
+
+#include "io_req.h"
+
+/*
+ * Map for device IO memory.
+ */
+//vm_map_t	device_io_map;
+
+kern_return_t	device_read_alloc(io_req_t, vm_size_t);
+kern_return_t	device_write_get(io_req_t, boolean_t *);
+boolean_t	device_write_dealloc(io_req_t);
+
+boolean_t	ds_open_done(io_req_t);
+boolean_t	ds_read_done(io_req_t);
+boolean_t	ds_write_done(io_req_t);
+
+void		iowait (io_req_t ior);
+
+error_t		create_device_port (size_t size, void *result);
+
+#endif	/* DS_ROUTINES_H */
diff --git a/libmachdev/io_req.h b/libmachdev/io_req.h
new file mode 100644
index 00000000..9c810542
--- /dev/null
+++ b/libmachdev/io_req.h
@@ -0,0 +1,135 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *	Author: David B. Golub, Carnegie Mellon University
+ *	Date: 	10/88
+ */
+
+#ifndef	_IO_REQ_
+#define	_IO_REQ_
+
+#include <mach.h>
+#include <pthread.h>
+
+#include "dev_hdr.h"
+
+/*
+ * IO request element, queued on device for delayed replies.
+ */
+typedef struct io_req *io_req_t;
+struct io_req {
+	struct io_req *	io_next;	/* next, ... */
+	struct io_req *	io_prev;	/* prev pointers: link in done,
+					   defered, or in-progress list */
+	mach_device_t	io_device;	/* pointer to open-device structure */
+	char *		io_dev_ptr;	/* pointer to driver structure -
+					   filled in by driver if necessary */
+	int		io_unit;	/* unit number ('minor') of device */
+	int		io_op;		/* IO operation */
+	dev_mode_t	io_mode;	/* operation mode (wait, truncate) */
+	recnum_t	io_recnum;	/* starting record number for
+					   random-access devices */
+
+	union io_un {
+	    io_buf_ptr_t    data;	/* data, for IO requests */
+	} io_un;
+#define	io_data		io_un.data
+
+	long		io_count;	/* amount requested */
+	long		io_alloc_size;	/* amount allocated */
+	long		io_residual;	/* amount NOT done */
+	io_return_t	io_error;	/* error code */
+	/* call when done - returns TRUE if IO really finished */
+	boolean_t	(*io_done)(io_req_t);
+	mach_port_t	io_reply_port;	/* reply port, for asynchronous
+					   messages */
+	mach_msg_type_name_t io_reply_port_type;
+					/* send or send-once right? */
+	struct io_req *	io_link;	/* forward link (for driver header) */
+	struct io_req *	io_rlink;	/* reverse link (for driver header) */
+//	vm_map_copy_t	io_copy;	/* vm_map_copy obj. for this op. */
+	long		io_total;	/* total op size, for write */
+	pthread_mutex_t	io_req_lock;
+//	decl_simple_lock_data(,io_req_lock)
+					/* Lock for this structure */
+	long            io_physrec;    /* mapping to the physical block
+					   number */
+	long            io_rectotal;   /* total number of blocks to move */
+};
+
+/*
+ * LOCKING NOTE: Operations on io_req's are in general single threaded by
+ * the invoking code, obviating the need for a lock.  The usual IO_CALL
+ * path through the code is: Initiating thread hands io_req to device driver,
+ * driver passes it to io_done thread, io_done thread sends reply message.  No
+ * locking is needed in this sequence.  Unfortunately, a synchronous wait
+ * for a buffer requires a lock to avoid problems if the wait and interrupt
+ * happen simultaneously on different processors.
+ */
+
+#define ior_lock(ior)	pthread_mutex_lock(&(ior)->io_req_lock)
+#define ior_unlock(ior)	pthread_mutex_unlock(&(ior)->io_req_lock)
+
+/*
+ * Flags and operations
+ */
+
+#define	IO_WRITE	0x00000000	/* operation is write */
+#define	IO_READ		0x00000001	/* operation is read */
+#define	IO_OPEN		0x00000002	/* operation is open */
+#define	IO_DONE		0x00000100	/* operation complete */
+#define	IO_ERROR	0x00000200	/* error on operation */
+#define	IO_BUSY		0x00000400	/* operation in progress */
+#define	IO_WANTED	0x00000800	/* wakeup when no longer BUSY */
+#define	IO_BAD		0x00001000	/* bad disk block */
+#define	IO_CALL		0x00002000	/* call io_done_thread when done */
+#define IO_INBAND	0x00004000	/* mig call was inband */
+#define IO_INTERNAL	0x00008000	/* internal, device-driver specific */
+#define	IO_LOANED	0x00010000	/* ior loaned by another module */
+
+#define	IO_SPARE_START	0x00020000	/* start of spare flags */
+
+/*
+ * Standard completion routine for io_requests.
+ */
+void	iodone(io_req_t);
+
+/*
+ * Macros to allocate and free IORs - will convert to zones later.
+ */
+#define	io_req_alloc(ior,size)					\
+	MACRO_BEGIN						\
+	(ior) = (io_req_t)malloc(sizeof(struct io_req));	\
+	pthread_mutex_init(&(ior)->io_req_lock, NULL);		\
+	MACRO_END
+
+#define	io_req_free(ior)					\
+	(free(ior))
+
+
+//zone_t	io_inband_zone; /* for inband reads */
+
+#endif	/* _IO_REQ_ */
diff --git a/libmachdev/machdev.h b/libmachdev/machdev.h
new file mode 100644
index 00000000..4f272558
--- /dev/null
+++ b/libmachdev/machdev.h
@@ -0,0 +1,34 @@
+/* 
+   Copyright (C) 2010 Free Software Foundation, Inc.
+   Written by Zheng Da.
+
+   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.  */
+
+/* This file declares interfaces used by driver programs. */
+
+#ifndef __MACHDEV_H__
+#define __MACHDEV_H__
+
+void ds_pre_server(void);
+void * ds_server(void *);
+void mach_device_init(void);
+void register_net(void);
+void register_block(void);
+void trivfs_server(void);
+int trivfs_init(void);
+
+#endif
diff --git a/libmachdev/mig-decls.h b/libmachdev/mig-decls.h
new file mode 100644
index 00000000..8302029d
--- /dev/null
+++ b/libmachdev/mig-decls.h
@@ -0,0 +1,50 @@
+/*
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Written by Justus Winter.
+
+   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.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef __LIBMACHDEV_MIG_DECLS_H__
+#define __LIBMACHDEV_MIG_DECLS_H__
+
+#include <hurd/ports.h>
+#include "dev_hdr.h"
+
+extern struct port_bucket *device_bucket;
+extern struct port_class *dev_class;
+
+/* Called by server stub functions.  */
+
+static inline struct mach_device * __attribute__ ((unused))
+begin_using_device_port (mach_port_t port)
+{
+  return ports_lookup_port (device_bucket, port, dev_class);
+}
+
+static inline struct mach_device * __attribute__ ((unused))
+begin_using_device_payload (unsigned long payload)
+{
+  return ports_lookup_payload (device_bucket, payload, dev_class);
+}
+
+static inline void __attribute__ ((unused))
+end_using_device (struct mach_device *p)
+{
+  if (p)
+    ports_port_deref (p);
+}
+
+#endif /* __LIBMACHDEV_MIG_DECLS_H__ */
diff --git a/libmachdev/mig-mutate.h b/libmachdev/mig-mutate.h
new file mode 100644
index 00000000..902ff166
--- /dev/null
+++ b/libmachdev/mig-mutate.h
@@ -0,0 +1,36 @@
+/*
+   Copyright (C) 2014 Free Software Foundation, Inc.
+   Written by Justus Winter.
+
+   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.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#define NOTIFY_INTRAN						\
+  port_info_t begin_using_port_info_port (mach_port_t)
+#define NOTIFY_INTRAN_PAYLOAD					\
+  port_info_t begin_using_port_info_payload
+#define NOTIFY_DESTRUCTOR					\
+  end_using_port_info (port_info_t)
+#define NOTIFY_IMPORTS						\
+  import "libports/mig-decls.h";
+
+#define DEVICE_INTRAN						\
+  mach_device_t begin_using_device_port (mach_port_t)
+#define DEVICE_INTRAN_PAYLOAD					\
+  mach_device_t begin_using_device_payload
+#define DEVICE_DESTRUCTOR					\
+  end_using_device (mach_device_t)
+#define DEVICE_IMPORTS						\
+  import "libmachdev/mig-decls.h";
diff --git a/libmachdev/trivfs_server.c b/libmachdev/trivfs_server.c
new file mode 100644
index 00000000..bf5210df
--- /dev/null
+++ b/libmachdev/trivfs_server.c
@@ -0,0 +1,169 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <error.h>
+#include <hurd/ports.h>
+#include <hurd/trivfs.h>
+#include <hurd.h>
+
+#include "device_S.h"
+#include "notify_S.h"
+
+static struct port_bucket *port_bucket;
+
+/* Trivfs hooks.  */
+int trivfs_fstype = FSTYPE_MISC;
+int trivfs_fsid = 0;
+int trivfs_support_read = 0;
+int trivfs_support_write = 0;
+int trivfs_support_exec = 0;
+int trivfs_allow_open = O_READ | O_WRITE;
+
+/* Our port classes.  */
+struct port_class *trivfs_protid_class;
+struct port_class *trivfs_cntl_class;
+
+/* Implementation of notify interface */
+kern_return_t
+do_mach_notify_port_deleted (struct port_info *pi,
+			     mach_port_t name)
+{
+  return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_msg_accepted (struct port_info *pi,
+			     mach_port_t name)
+{
+  return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_port_destroyed (struct port_info *pi,
+			       mach_port_t port)
+{
+  return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_no_senders (struct port_info *pi,
+			   mach_port_mscount_t mscount)
+{
+  return ports_do_mach_notify_no_senders (pi, mscount);
+}
+
+kern_return_t
+do_mach_notify_send_once (struct port_info *pi)
+{
+  return EOPNOTSUPP;
+}
+
+kern_return_t
+do_mach_notify_dead_name (struct port_info *pi,
+			  mach_port_t name)
+{
+  return EOPNOTSUPP;
+}
+
+boolean_t
+is_master_device (mach_port_t port)
+{
+  struct port_info *pi = ports_lookup_port (port_bucket, port,
+					    trivfs_protid_class);
+  if (pi == NULL)
+    return FALSE;
+  
+  ports_port_deref (pi);
+  return TRUE;
+}
+
+error_t
+trivfs_append_args (struct trivfs_control *fsys, char **argz, size_t *argz_len)
+{
+  error_t err = 0;
+
+#define ADD_OPT(fmt, args...)						\
+  do { char buf[100];							\
+       if (! err) {							\
+         snprintf (buf, sizeof buf, fmt , ##args);			\
+         err = argz_add (argz, argz_len, buf); } } while (0)
+
+#undef ADD_OPT
+  return err;
+}
+
+int trivfs_init()
+{
+  port_bucket = ports_create_bucket ();
+  trivfs_cntl_class = ports_create_class (trivfs_clean_cntl, 0);
+  trivfs_protid_class = ports_create_class (trivfs_clean_protid, 0);
+  return 0;
+}
+
+error_t
+trivfs_goaway (struct trivfs_control *fsys, int flags)
+{
+  int count;
+
+  /* Stop new requests.  */
+  ports_inhibit_class_rpcs (trivfs_cntl_class);
+  ports_inhibit_class_rpcs (trivfs_protid_class);
+
+  count = ports_count_class (trivfs_protid_class);
+
+  if (count && !(flags & FSYS_GOAWAY_FORCE))
+    {
+      /* We won't go away, so start things going again...  */
+      ports_enable_class (trivfs_protid_class);
+      ports_resume_class_rpcs (trivfs_cntl_class);
+      ports_resume_class_rpcs (trivfs_protid_class);
+      return EBUSY;
+    }
+
+  exit (0);
+}
+
+static int
+demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp)
+{
+  mig_routine_t routine;
+  if ((routine = device_server_routine (inp)) ||
+      (routine = notify_server_routine (inp)) ||
+      (routine = NULL, trivfs_demuxer (inp, outp)))
+    {
+      if (routine)
+        (*routine) (inp, outp);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+void
+trivfs_modify_stat (struct trivfs_protid *cred, io_statbuf_t *stat)
+{
+}
+
+void trivfs_server()
+{
+  mach_port_t bootstrap;
+  struct trivfs_control *fsys;
+  int err;
+
+  task_get_bootstrap_port (mach_task_self (), &bootstrap);
+  if (bootstrap == MACH_PORT_NULL)
+    error (1, 0, "must be started as a translator");
+
+  /* Reply to our parent.  */
+  err = trivfs_startup (bootstrap, 0,
+			trivfs_cntl_class, port_bucket,
+			trivfs_protid_class, port_bucket, &fsys);
+  mach_port_deallocate (mach_task_self (), bootstrap);
+  if (err)
+    error (1, err, "Contacting parent");
+
+  /* Launch.  */
+  do
+    {
+      ports_manage_port_operations_one_thread (port_bucket, demuxer, 0);
+    } while (trivfs_goaway (fsys, 0));
+}
diff --git a/libmachdev/vm_param.h b/libmachdev/vm_param.h
new file mode 100644
index 00000000..7b615c8a
--- /dev/null
+++ b/libmachdev/vm_param.h
@@ -0,0 +1,7 @@
+#ifndef __VM_PARAM_H__
+#define __VM_PARAM_H__
+
+#define PAGE_SIZE __vm_page_size
+#define PAGE_MASK (PAGE_SIZE-1)
+
+#endif
-- 
2.25.1

>From 90636893c91c2aa5a01de7eb7e10bd7df3b1e93f Mon Sep 17 00:00:00 2001
From: Damien Zammit <dam...@zamaudio.com>
Date: Sun, 29 Mar 2020 22:37:23 +1100
Subject: [PATCH 3/4] libmachdevrump,rumpdisk: Add rumpdisk support

---
 Makefile                   |   2 +
 libmachdevrump/Makefile    |  38 ++++
 libmachdevrump/block.c     | 355 +++++++++++++++++++++++++++++++++++++
 libmachdevrump/mach_glue.h |   7 +
 rumpdisk/Makefile          |  35 ++++
 rumpdisk/main.c            |  18 ++
 6 files changed, 455 insertions(+)
 create mode 100644 libmachdevrump/Makefile
 create mode 100644 libmachdevrump/block.c
 create mode 100644 libmachdevrump/mach_glue.h
 create mode 100644 rumpdisk/Makefile
 create mode 100644 rumpdisk/main.c

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;
+}
-- 
2.25.1

>From 092143d506502ac81d6d9c518ac420c9bb807aa6 Mon Sep 17 00:00:00 2001
From: Damien Zammit <dam...@zamaudio.com>
Date: Sun, 29 Mar 2020 22:41:22 +1100
Subject: [PATCH 4/4] libmachdevdde: Add dde machdev lib (net)

---
 Makefile                      |   1 +
 libmachdevdde/Makefile        |  30 ++
 libmachdevdde/block.c         | 314 ++++++++++++++++
 libmachdevdde/ds_pre_server.c |   8 +
 libmachdevdde/errno-base.h    |  39 ++
 libmachdevdde/if_ether.h      |  87 +++++
 libmachdevdde/if_hdr.h        | 165 +++++++++
 libmachdevdde/linux-errno.h   | 109 ++++++
 libmachdevdde/mach_glue.h     |  41 +++
 libmachdevdde/misc.c          |  50 +++
 libmachdevdde/net.c           | 663 ++++++++++++++++++++++++++++++++++
 libmachdevdde/queue.c         | 131 +++++++
 libmachdevdde/queue.h         | 370 +++++++++++++++++++
 libmachdevdde/util.h          |  35 ++
 14 files changed, 2043 insertions(+)
 create mode 100644 libmachdevdde/Makefile
 create mode 100644 libmachdevdde/block.c
 create mode 100644 libmachdevdde/ds_pre_server.c
 create mode 100644 libmachdevdde/errno-base.h
 create mode 100644 libmachdevdde/if_ether.h
 create mode 100644 libmachdevdde/if_hdr.h
 create mode 100644 libmachdevdde/linux-errno.h
 create mode 100644 libmachdevdde/mach_glue.h
 create mode 100644 libmachdevdde/misc.c
 create mode 100644 libmachdevdde/net.c
 create mode 100644 libmachdevdde/queue.c
 create mode 100644 libmachdevdde/queue.h
 create mode 100644 libmachdevdde/util.h

diff --git a/Makefile b/Makefile
index 9629cbfb..acee222d 100644
--- a/Makefile
+++ b/Makefile
@@ -33,6 +33,7 @@ lib-subdirs = libshouldbeinlibc libihash libiohelp libports libthreads \
 	      libbpf \
 	      libmachdev \
 	      libmachdevrump \
+	      libmachdevdde \
 
 # Hurd programs
 prog-subdirs = auth proc exec term \
diff --git a/libmachdevdde/Makefile b/libmachdevdde/Makefile
new file mode 100644
index 00000000..8871e32b
--- /dev/null
+++ b/libmachdevdde/Makefile
@@ -0,0 +1,30 @@
+# 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.
+
+dir := libmachdevdde
+makemode := library
+libname = libmachdevdde
+
+SRCS = net.c queue.c misc.c ds_pre_server.c
+
+LCLHDRS = util.h queue.h if_ether.h
+
+HURDLIBS = machdev bpf ddekit
+LDLIBS += -lpthread
+OBJS = $(SRCS:.c=.o) $(MIGSTUBS)
+
+include ../Makeconf
diff --git a/libmachdevdde/block.c b/libmachdevdde/block.c
new file mode 100644
index 00000000..79962072
--- /dev/null
+++ b/libmachdevdde/block.c
@@ -0,0 +1,314 @@
+/*
+ * Linux block driver support.
+ *
+ * Copyright (C) 1996 The University of Utah and the Computer Systems
+ * Laboratory at the University of Utah (CSL)
+ *
+ * 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.
+ *
+ *	Author: Shantanu Goel, University of Utah CSL
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+
+#include "mach_U.h"
+
+#include <mach.h>
+#include <hurd.h>
+
+#define MACH_INCLUDE
+
+#include <ddekit/printf.h>
+
+#include "ds_routines.h"
+#include "vm_param.h"
+#include "device_reply_U.h"
+#include "dev_hdr.h"
+#include "util.h"
+#include "mach_glue.h"
+
+/* for submit_bio(). But it might not be very proper to keep
+ * my own definitions of these macros. */
+#define READ 0
+#define WRITE 1
+
+/* 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;
+  struct block_device *dev;
+};
+
+/* 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 device_emulation_ops linux_block_emulation_ops;
+
+#define DISK_NAME_LEN 32
+
+/* Parse the device NAME.
+   Set *SLICE to be the DOS partition and
+   *PART the BSD/Mach partition, if any.  */
+static char *
+translate_name (char *name, int *slice, int *part)
+{
+  char *p, *q, *end;
+  char *ret;
+  int disk_num;
+
+  /* Parse name into name, unit, DOS partition (slice) and partition.  */
+  for (*slice = 0, *part = -1, p = name; isalpha (*p); p++)
+    ;
+  if (p == name || ! isdigit (*p))
+    return NULL;
+  end = p;
+  disk_num = strtol (p, &p, 0);
+  if (disk_num < 0 || disk_num > 26)
+    return NULL;
+//  do
+//    p++;
+//  while (isdigit (*p));
+  if (*p)
+    {
+      q = p;
+      if (*q == 's' && isdigit (*(q + 1)))
+	{
+	  q++;
+	  do
+	    *slice = *slice * 10 + *q++ - '0';
+	  while (isdigit (*q));
+	  if (! *q)
+	    goto find_major;
+	}
+      if (! isalpha (*q) || *(q + 1))
+	return NULL;
+      *part = *q - 'a';
+    }
+
+find_major:
+  ret = malloc (DISK_NAME_LEN);
+  sprintf (ret, "hd%c", 'a' + disk_num);
+  return ret;
+}
+
+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;
+  int slice, part;
+  char *dev_name = NULL;
+  int dev_err;
+
+  // TODO I need to check whether the device has been opened before.
+  // if it has been opened with the same `flag', return the same port,
+  // otherwise, return a different port.
+  // I need to have a reference to count the number of open.
+  dev_name = translate_name (name, &slice, &part);
+  if (dev_name == NULL)
+    return D_NO_SUCH_DEVICE;
+
+  err = create_device_port (sizeof (*bd), &bd);
+  if (err)
+    {
+      ddekit_printf ("after create_device_port: cannot create a port\n");
+      goto out;
+    }
+  bd->dev = open_block_dev (dev_name, slice, mode);
+  dev_err = (int) bd->dev;
+  if (dev_err < 0)
+    {
+      ddekit_printf ("open_block_dev %s fails with %d\n", dev_name, bd->dev);
+      err = linux_to_mach_error (dev_err);
+      goto out;
+    }
+  bd->device.emul_data = bd;
+  bd->device.emul_ops = &linux_block_emulation_ops;
+  bd->mode = mode;
+
+out:
+  free (dev_name);
+  if (err)
+    {
+      if (bd)
+	{
+	  ports_destroy_right (bd);
+	  bd = NULL;
+	}
+    }
+  else
+    {
+      *devp = ports_get_send_right (bd);
+      ports_port_deref (bd);
+      *devicePoly = MACH_MSG_TYPE_MOVE_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;
+  /* the number of pages that contain DATA. */
+  int npages = (((int) data + count) - ((int) data & ~PAGE_MASK)
+		+ PAGE_MASK) / PAGE_SIZE;
+  io_return_t err = D_SUCCESS;
+  int i;
+  int writes = 0;
+
+  void write_done (int err)
+    {
+      int len = err ? 0 : count;
+      // TODO maybe I should send the reply as long as there is an error.
+      writes--;
+      if (writes == 0)
+	{
+	  err = linux_to_mach_error (err);
+	  ds_device_write_reply (reply_port, reply_port_type, err, len);
+	}
+    }
+
+  /* the data is at the beginning of a page. */
+  if ((int) data & ~PAGE_MASK)
+    return D_INVALID_OPERATION;
+  
+  if ((bd->mode & D_WRITE) == 0)
+    return D_INVALID_OPERATION;
+
+  for (i = 0; i < npages; i++)
+    {
+      int size = PAGE_SIZE - ((int) data &~PAGE_MASK) > count ?
+	count : PAGE_SIZE - ((int) data &~PAGE_MASK);
+
+      err = block_dev_rw (bd->dev, bn, data, size, WRITE, write_done);
+      if (err)
+	break;
+      bn += size >> 9;
+      data += size;
+      count -= size;
+      writes++;
+    }
+  if (writes)
+    return MIG_NO_REPLY;
+  return linux_to_mach_error (err);
+}
+
+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;
+  int i;
+  int reads = 0;
+  char *buf;
+  int npages = (count + PAGE_SIZE - 1) / PAGE_SIZE;
+  int rest = count;
+
+  void read_done (int err)
+    {
+      int len = err ? 0 : count;
+      reads--;
+      if (reads == 0)
+	{
+	  err = linux_to_mach_error (err);
+	  ds_device_read_reply (reply_port, reply_port_type, err, buf, len);
+	}
+    }
+
+  if ((bd->mode & D_READ) == 0)
+    return D_INVALID_OPERATION;
+
+  if (count == 0)
+    return 0;
+
+  *data = 0;
+  buf = mmap (NULL, npages * PAGE_SIZE, PROT_READ|PROT_WRITE,
+	      MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
+  if (buf == MAP_FAILED)
+    return errno;
+
+  ddekit_printf ("read %d pages.\n", npages);
+  for (i = 0; i < npages; i++)
+    {
+      int size = rest > PAGE_SIZE ? PAGE_SIZE : rest;
+      ddekit_printf ("read %d bytes starting from %d\n", size, bn);
+
+      err = block_dev_rw (bd->dev, bn, buf + i * PAGE_SIZE,
+			  size, READ, read_done);
+      if (err)
+	break;
+      bn += size >> 9;
+      rest -= size;
+      reads++;
+    }
+  // TODO when should I deallocate the buffer?
+  if (reads)
+    return MIG_NO_REPLY;
+  return linux_to_mach_error (err);
+}
+
+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 = (struct block_data *) d;
+  return D_SUCCESS;
+}
+
+static struct device_emulation_ops linux_block_emulation_ops =
+{
+  NULL,
+  NULL,
+  NULL,
+  dev_to_port,
+  device_open,
+  NULL,
+  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 (&linux_block_emulation_ops);
+}
diff --git a/libmachdevdde/ds_pre_server.c b/libmachdevdde/ds_pre_server.c
new file mode 100644
index 00000000..cdf190b6
--- /dev/null
+++ b/libmachdevdde/ds_pre_server.c
@@ -0,0 +1,8 @@
+#include "libmachdev/machdev.h"
+
+void ds_pre_server(void)
+{
+  /* This thread calls Linux functions,
+   * so I need to make it known to the Linux environment. */
+  l4dde26_process_from_ddekit (ddekit_thread_myself ());
+}
diff --git a/libmachdevdde/errno-base.h b/libmachdevdde/errno-base.h
new file mode 100644
index 00000000..65115978
--- /dev/null
+++ b/libmachdevdde/errno-base.h
@@ -0,0 +1,39 @@
+#ifndef _ASM_GENERIC_ERRNO_BASE_H
+#define _ASM_GENERIC_ERRNO_BASE_H
+
+#define	EPERM		 1	/* Operation not permitted */
+#define	ENOENT		 2	/* No such file or directory */
+#define	ESRCH		 3	/* No such process */
+#define	EINTR		 4	/* Interrupted system call */
+#define	EIO		 5	/* I/O error */
+#define	ENXIO		 6	/* No such device or address */
+#define	E2BIG		 7	/* Argument list too long */
+#define	ENOEXEC		 8	/* Exec format error */
+#define	EBADF		 9	/* Bad file number */
+#define	ECHILD		10	/* No child processes */
+#define	EAGAIN		11	/* Try again */
+#define	ENOMEM		12	/* Out of memory */
+#define	EACCES		13	/* Permission denied */
+#define	EFAULT		14	/* Bad address */
+#define	ENOTBLK		15	/* Block device required */
+#define	EBUSY		16	/* Device or resource busy */
+#define	EEXIST		17	/* File exists */
+#define	EXDEV		18	/* Cross-device link */
+#define	ENODEV		19	/* No such device */
+#define	ENOTDIR		20	/* Not a directory */
+#define	EISDIR		21	/* Is a directory */
+#define	EINVAL		22	/* Invalid argument */
+#define	ENFILE		23	/* File table overflow */
+#define	EMFILE		24	/* Too many open files */
+#define	ENOTTY		25	/* Not a typewriter */
+#define	ETXTBSY		26	/* Text file busy */
+#define	EFBIG		27	/* File too large */
+#define	ENOSPC		28	/* No space left on device */
+#define	ESPIPE		29	/* Illegal seek */
+#define	EROFS		30	/* Read-only file system */
+#define	EMLINK		31	/* Too many links */
+#define	EPIPE		32	/* Broken pipe */
+#define	EDOM		33	/* Math argument out of domain of func */
+#define	ERANGE		34	/* Math result not representable */
+
+#endif
diff --git a/libmachdevdde/if_ether.h b/libmachdevdde/if_ether.h
new file mode 100644
index 00000000..29974674
--- /dev/null
+++ b/libmachdevdde/if_ether.h
@@ -0,0 +1,87 @@
+/*
+ * INET		An implementation of the TCP/IP protocol suite for the LINUX
+ *		operating system.  INET is implemented using the  BSD Socket
+ *		interface as the means of communication with the user level.
+ *
+ *		Global definitions for the Ethernet IEEE 802.3 interface.
+ *
+ * Version:	@(#)if_ether.h	1.0.1a	02/08/94
+ *
+ * Author:	Fred N. van Kempen, <wal...@uwalt.nl.mugnet.org>
+ *		Donald Becker, <bec...@super.org>
+ *		Alan Cox, <a...@cymru.net>
+ *		Steve Whitehouse, <gw7...@eeshack3.swan.ac.uk>
+ *
+ *		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 of the License, or (at your option) any later version.
+ */
+ 
+#ifndef _LINUX_IF_ETHER_H
+#define _LINUX_IF_ETHER_H
+
+/*
+ *	IEEE 802.3 Ethernet magic constants.  The frame sizes omit the preamble
+ *	and FCS/CRC (frame check sequence). 
+ */
+
+#define ETH_ALEN	6		/* Octets in one ethernet addr	 */
+#define ETH_HLEN	14		/* Total octets in header.	 */
+#define ETH_ZLEN	60		/* Min. octets in frame sans FCS */
+#define ETH_DATA_LEN	1500		/* Max. octets in payload	 */
+#define ETH_FRAME_LEN	1514		/* Max. octets in frame sans FCS */
+
+/*
+ *	These are the defined Ethernet Protocol ID's.
+ */
+
+#define ETH_P_LOOP	0x0060		/* Ethernet Loopback packet	*/
+#define ETH_P_ECHO	0x0200		/* Ethernet Echo packet		*/
+#define ETH_P_PUP	0x0400		/* Xerox PUP packet		*/
+#define ETH_P_IP	0x0800		/* Internet Protocol packet	*/
+#define ETH_P_X25	0x0805		/* CCITT X.25			*/
+#define ETH_P_ARP	0x0806		/* Address Resolution packet	*/
+#define	ETH_P_BPQ	0x08FF		/* G8BPQ AX.25 Ethernet Packet	[ NOT AN OFFICIALLY REGISTERED ID ] */
+#define ETH_P_DEC       0x6000          /* DEC Assigned proto           */
+#define ETH_P_DNA_DL    0x6001          /* DEC DNA Dump/Load            */
+#define ETH_P_DNA_RC    0x6002          /* DEC DNA Remote Console       */
+#define ETH_P_DNA_RT    0x6003          /* DEC DNA Routing              */
+#define ETH_P_LAT       0x6004          /* DEC LAT                      */
+#define ETH_P_DIAG      0x6005          /* DEC Diagnostics              */
+#define ETH_P_CUST      0x6006          /* DEC Customer use             */
+#define ETH_P_SCA       0x6007          /* DEC Systems Comms Arch       */
+#define ETH_P_RARP      0x8035		/* Reverse Addr Res packet	*/
+#define ETH_P_ATALK	0x809B		/* Appletalk DDP		*/
+#define ETH_P_AARP	0x80F3		/* Appletalk AARP		*/
+#define ETH_P_IPX	0x8137		/* IPX over DIX			*/
+#define ETH_P_IPV6	0x86DD		/* IPv6 over bluebook		*/
+
+/*
+ *	Non DIX types. Won't clash for 1500 types.
+ */
+ 
+#define ETH_P_802_3	0x0001		/* Dummy type for 802.3 frames  */
+#define ETH_P_AX25	0x0002		/* Dummy protocol id for AX.25  */
+#define ETH_P_ALL	0x0003		/* Every packet (be careful!!!) */
+#define ETH_P_802_2	0x0004		/* 802.2 frames 		*/
+#define ETH_P_SNAP	0x0005		/* Internal only		*/
+#define ETH_P_DDCMP     0x0006          /* DEC DDCMP: Internal only     */
+#define ETH_P_WAN_PPP   0x0007          /* Dummy type for WAN PPP frames*/
+#define ETH_P_PPP_MP    0x0008          /* Dummy type for PPP MP frames */
+#define ETH_P_LOCALTALK 0x0009		/* Localtalk pseudo type 	*/
+#define ETH_P_PPPTALK	0x0010		/* Dummy type for Atalk over PPP*/
+#define ETH_P_TR_802_2	0x0011		/* 802.2 frames 		*/
+
+/*
+ *	This is an Ethernet frame header.
+ */
+ 
+struct ethhdr 
+{
+	unsigned char	h_dest[ETH_ALEN];	/* destination eth addr	*/
+	unsigned char	h_source[ETH_ALEN];	/* source ether addr	*/
+	unsigned short	h_proto;		/* packet type ID field	*/
+};
+
+#endif	/* _LINUX_IF_ETHER_H */
diff --git a/libmachdevdde/if_hdr.h b/libmachdevdde/if_hdr.h
new file mode 100644
index 00000000..b20f7e35
--- /dev/null
+++ b/libmachdevdde/if_hdr.h
@@ -0,0 +1,165 @@
+/* 
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ * 
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ * 
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *	Taken from (bsd)net/if.h.  Modified for MACH kernel.
+ */
+/*
+ * Copyright (c) 1982, 1986 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.
+ * 4. The name of the Laboratory may not 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.
+ *
+ *	@(#)if.h	7.3 (Berkeley) 6/27/88
+ */
+
+#ifndef	_IF_HDR_
+#define	_IF_HDR_
+
+#include <queue.h>
+#include <pthread.h>
+#include <hurd/bpf_impl.h>
+
+#if 0
+/*
+ * Queue for network output and filter input.
+ */
+struct ifqueue {
+	queue_head_t	ifq_head;	/* queue of io_req_t */
+	int		ifq_len;	/* length of queue */
+	int		ifq_maxlen;	/* maximum length of queue */
+	int		ifq_drops;	/* number of packets dropped
+					   because queue full */
+	decl_simple_lock_data(,
+			ifq_lock)	/* lock for queue and counters */
+};
+#endif
+
+/*
+ * Header for network interface drivers.
+ */
+struct ifnet {
+	short	if_unit;		/* unit number */
+	short	if_flags;		/* up/down, broadcast, etc. */
+	short	if_timer;		/* time until if_watchdog called */
+	short	if_mtu;			/* maximum transmission unit */
+	short	if_header_size;		/* length of header */
+	short	if_header_format;	/* format of hardware header */
+	short	if_address_size;	/* length of hardware address */
+	short	if_alloc_size;		/* size of read buffer to allocate */
+	char	*if_address;		/* pointer to hardware address */
+//	struct ifqueue if_snd;		/* output queue */
+	if_filter_list_t port_list;
+	pthread_mutex_t if_rcv_port_list_lock;/* lock for input filter list */
+	pthread_mutex_t if_snd_port_list_lock;/* lock for output filter list */
+/* statistics */
+	int	if_ipackets;		/* packets received */
+	int	if_ierrors;		/* input errors */
+	int	if_opackets;		/* packets sent */
+	int	if_oerrors;		/* output errors */
+	int	if_collisions;		/* collisions on csma interfaces */
+	int	if_rcvdrops;		/* packets received but dropped */
+};
+
+#define	IFF_UP		0x0001		/* interface is up */
+#define	IFF_BROADCAST	0x0002		/* interface can broadcast */
+#define	IFF_DEBUG	0x0004		/* turn on debugging */
+#define	IFF_LOOPBACK	0x0008		/* is a loopback net */
+#define	IFF_POINTOPOINT	0x0010		/* point-to-point link */
+#define	IFF_RUNNING	0x0040		/* resources allocated */
+#define	IFF_NOARP	0x0080		/* no address resolution protocol */
+#define	IFF_PROMISC	0x0100		/* receive all packets */
+#define	IFF_ALLMULTI	0x0200		/* receive all multicast packets */
+#define	IFF_BRIDGE	0x0100		/* support token ring routing field */
+#define	IFF_SNAP	0x0200		/* support extended sap header */
+
+/* internal flags only: */
+#define	IFF_CANTCHANGE	(IFF_BROADCAST | IFF_POINTOPOINT | IFF_RUNNING)
+
+/*
+ * Output queues (ifp->if_snd)
+ * have queues of messages stored on ifqueue structures.  Entries
+ * are added to and deleted from these structures by these macros, which
+ * should be called with ipl raised to splimp().
+ * XXX locking XXX
+ */
+
+#define	IF_QFULL(ifq)		((ifq)->ifq_len >= (ifq)->ifq_maxlen)
+#define	IF_DROP(ifq)		((ifq)->ifq_drops++)
+#define	IF_ENQUEUE(ifq, ior) { \
+	simple_lock(&(ifq)->ifq_lock); \
+	enqueue_tail(&(ifq)->ifq_head, (queue_entry_t)ior); \
+	(ifq)->ifq_len++; \
+	simple_unlock(&(ifq)->ifq_lock); \
+}
+#define	IF_PREPEND(ifq, ior) { \
+	simple_lock(&(ifq)->ifq_lock); \
+	enqueue_head(&(ifq)->ifq_head, (queue_entry_t)ior); \
+	(ifq)->ifq_len++; \
+	simple_unlock(&(ifq)->ifq_lock); \
+}
+
+#define	IF_DEQUEUE(ifq, ior) { \
+	simple_lock(&(ifq)->ifq_lock); \
+	if (((ior) = (io_req_t)dequeue_head(&(ifq)->ifq_head)) != 0) \
+	    (ifq)->ifq_len--; \
+	simple_unlock(&(ifq)->ifq_lock); \
+}
+
+#define	IFQ_MAXLEN	50
+
+#define	IFQ_INIT(ifq) { \
+	queue_init(&(ifq)->ifq_head); \
+	simple_lock_init(&(ifq)->ifq_lock); \
+	(ifq)->ifq_len = 0; \
+	(ifq)->ifq_maxlen = IFQ_MAXLEN; \
+	(ifq)->ifq_drops = 0; \
+}
+
+#define	IFNET_SLOWHZ	1		/* granularity is 1 second */
+
+#endif	/* _IF_HDR_ */
diff --git a/libmachdevdde/linux-errno.h b/libmachdevdde/linux-errno.h
new file mode 100644
index 00000000..be764a89
--- /dev/null
+++ b/libmachdevdde/linux-errno.h
@@ -0,0 +1,109 @@
+#ifndef _ASM_GENERIC_ERRNO_H
+#define _ASM_GENERIC_ERRNO_H
+
+#include <errno-base.h>
+
+#define	EDEADLK		35	/* Resource deadlock would occur */
+#define	ENAMETOOLONG	36	/* File name too long */
+#define	ENOLCK		37	/* No record locks available */
+#define	ENOSYS		38	/* Function not implemented */
+#define	ENOTEMPTY	39	/* Directory not empty */
+#define	ELOOP		40	/* Too many symbolic links encountered */
+#define	EWOULDBLOCK	EAGAIN	/* Operation would block */
+#define	ENOMSG		42	/* No message of desired type */
+#define	EIDRM		43	/* Identifier removed */
+#define	ECHRNG		44	/* Channel number out of range */
+#define	EL2NSYNC	45	/* Level 2 not synchronized */
+#define	EL3HLT		46	/* Level 3 halted */
+#define	EL3RST		47	/* Level 3 reset */
+#define	ELNRNG		48	/* Link number out of range */
+#define	EUNATCH		49	/* Protocol driver not attached */
+#define	ENOCSI		50	/* No CSI structure available */
+#define	EL2HLT		51	/* Level 2 halted */
+#define	EBADE		52	/* Invalid exchange */
+#define	EBADR		53	/* Invalid request descriptor */
+#define	EXFULL		54	/* Exchange full */
+#define	ENOANO		55	/* No anode */
+#define	EBADRQC		56	/* Invalid request code */
+#define	EBADSLT		57	/* Invalid slot */
+
+#define	EDEADLOCK	EDEADLK
+
+#define	EBFONT		59	/* Bad font file format */
+#define	ENOSTR		60	/* Device not a stream */
+#define	ENODATA		61	/* No data available */
+#define	ETIME		62	/* Timer expired */
+#define	ENOSR		63	/* Out of streams resources */
+#define	ENONET		64	/* Machine is not on the network */
+#define	ENOPKG		65	/* Package not installed */
+#define	EREMOTE		66	/* Object is remote */
+#define	ENOLINK		67	/* Link has been severed */
+#define	EADV		68	/* Advertise error */
+#define	ESRMNT		69	/* Srmount error */
+#define	ECOMM		70	/* Communication error on send */
+#define	EPROTO		71	/* Protocol error */
+#define	EMULTIHOP	72	/* Multihop attempted */
+#define	EDOTDOT		73	/* RFS specific error */
+#define	EBADMSG		74	/* Not a data message */
+#define	EOVERFLOW	75	/* Value too large for defined data type */
+#define	ENOTUNIQ	76	/* Name not unique on network */
+#define	EBADFD		77	/* File descriptor in bad state */
+#define	EREMCHG		78	/* Remote address changed */
+#define	ELIBACC		79	/* Can not access a needed shared library */
+#define	ELIBBAD		80	/* Accessing a corrupted shared library */
+#define	ELIBSCN		81	/* .lib section in a.out corrupted */
+#define	ELIBMAX		82	/* Attempting to link in too many shared libraries */
+#define	ELIBEXEC	83	/* Cannot exec a shared library directly */
+#define	EILSEQ		84	/* Illegal byte sequence */
+#define	ERESTART	85	/* Interrupted system call should be restarted */
+#define	ESTRPIPE	86	/* Streams pipe error */
+#define	EUSERS		87	/* Too many users */
+#define	ENOTSOCK	88	/* Socket operation on non-socket */
+#define	EDESTADDRREQ	89	/* Destination address required */
+#define	EMSGSIZE	90	/* Message too long */
+#define	EPROTOTYPE	91	/* Protocol wrong type for socket */
+#define	ENOPROTOOPT	92	/* Protocol not available */
+#define	EPROTONOSUPPORT	93	/* Protocol not supported */
+#define	ESOCKTNOSUPPORT	94	/* Socket type not supported */
+#define	EOPNOTSUPP	95	/* Operation not supported on transport endpoint */
+#define	EPFNOSUPPORT	96	/* Protocol family not supported */
+#define	EAFNOSUPPORT	97	/* Address family not supported by protocol */
+#define	EADDRINUSE	98	/* Address already in use */
+#define	EADDRNOTAVAIL	99	/* Cannot assign requested address */
+#define	ENETDOWN	100	/* Network is down */
+#define	ENETUNREACH	101	/* Network is unreachable */
+#define	ENETRESET	102	/* Network dropped connection because of reset */
+#define	ECONNABORTED	103	/* Software caused connection abort */
+#define	ECONNRESET	104	/* Connection reset by peer */
+#define	ENOBUFS		105	/* No buffer space available */
+#define	EISCONN		106	/* Transport endpoint is already connected */
+#define	ENOTCONN	107	/* Transport endpoint is not connected */
+#define	ESHUTDOWN	108	/* Cannot send after transport endpoint shutdown */
+#define	ETOOMANYREFS	109	/* Too many references: cannot splice */
+#define	ETIMEDOUT	110	/* Connection timed out */
+#define	ECONNREFUSED	111	/* Connection refused */
+#define	EHOSTDOWN	112	/* Host is down */
+#define	EHOSTUNREACH	113	/* No route to host */
+#define	EALREADY	114	/* Operation already in progress */
+#define	EINPROGRESS	115	/* Operation now in progress */
+#define	ESTALE		116	/* Stale NFS file handle */
+#define	EUCLEAN		117	/* Structure needs cleaning */
+#define	ENOTNAM		118	/* Not a XENIX named type file */
+#define	ENAVAIL		119	/* No XENIX semaphores available */
+#define	EISNAM		120	/* Is a named type file */
+#define	EREMOTEIO	121	/* Remote I/O error */
+#define	EDQUOT		122	/* Quota exceeded */
+
+#define	ENOMEDIUM	123	/* No medium found */
+#define	EMEDIUMTYPE	124	/* Wrong medium type */
+#define	ECANCELED	125	/* Operation Canceled */
+#define	ENOKEY		126	/* Required key not available */
+#define	EKEYEXPIRED	127	/* Key has expired */
+#define	EKEYREVOKED	128	/* Key has been revoked */
+#define	EKEYREJECTED	129	/* Key was rejected by service */
+
+/* for robust mutexes */
+#define	EOWNERDEAD	130	/* Owner died */
+#define	ENOTRECOVERABLE	131	/* State not recoverable */
+
+#endif
diff --git a/libmachdevdde/mach_glue.h b/libmachdevdde/mach_glue.h
new file mode 100644
index 00000000..7b122583
--- /dev/null
+++ b/libmachdevdde/mach_glue.h
@@ -0,0 +1,41 @@
+#ifndef __MACH_GLUE_H__
+#define __MACH_GLUE_H__
+
+/* network */
+#include <arpa/inet.h>
+
+#include <ddekit/thread.h>
+
+struct sk_buff;
+struct net_device;
+void skb_done_queue(struct sk_buff *skb);
+struct sk_buff *skb_done_dequeue();
+void *skb_reply(struct sk_buff *skb);
+
+int netdev_flags(struct net_device *dev);
+char *netdev_addr(struct net_device *dev);
+char *netdev_name (struct net_device *dev);
+unsigned int netdev_mtu (struct net_device *dev);
+unsigned short netdev_header_len (struct net_device *dev);
+unsigned short netdev_type (struct net_device *dev);
+unsigned char netdev_addr_len (struct net_device *dev);
+
+int dev_change_flags (struct net_device *dev, short flags);
+int linux_pkg_xmit (char *pkg_data, int len, void *del_data,
+		    int (*del_func) (struct sk_buff *, void *),
+		    struct net_device *dev);
+struct net_device *search_netdev (char *name);
+void kfree_skb (struct sk_buff *skb);
+int dev_open(struct net_device *dev);
+void *l4dde26_register_rx_callback(void *cb);
+void skb_done_head_init();
+
+/* block device */
+struct block_device;
+struct block_device *open_block_dev (char *name, int part, dev_mode_t mode);
+int block_dev_rw (struct block_device *dev, int sectornr,
+		  char *data, int count, int rw, void (*write_done) (int err));
+
+int l4dde26_process_from_ddekit(ddekit_thread_t *t);
+
+#endif
diff --git a/libmachdevdde/misc.c b/libmachdevdde/misc.c
new file mode 100644
index 00000000..977159bd
--- /dev/null
+++ b/libmachdevdde/misc.c
@@ -0,0 +1,50 @@
+#include <mach.h>
+#include <device/device.h>
+
+#include <ddekit/printf.h>
+
+#include "linux-errno.h"
+
+int
+linux_to_mach_error (int err)
+{
+  switch (err)
+    {
+    case 0:
+      return D_SUCCESS;
+
+    case -EPERM:
+      return D_INVALID_OPERATION;
+
+    case -EIO:
+      return D_IO_ERROR;
+
+    case -ENXIO:
+      return D_NO_SUCH_DEVICE;
+
+    case -EACCES:
+      return D_INVALID_OPERATION;
+
+    case -EFAULT:
+      return D_INVALID_SIZE;
+
+    case -EBUSY:
+      return D_ALREADY_OPEN;
+
+    case -EINVAL:
+      return D_INVALID_SIZE;
+
+    case -EROFS:
+      return D_READ_ONLY;
+
+    case -EWOULDBLOCK:
+      return D_WOULD_BLOCK;
+
+    case -ENOMEM:
+      return D_NO_MEMORY;
+
+    default:
+      ddekit_printf ("linux_to_mach_error: unknown code %d\n", err);
+      return D_IO_ERROR;
+    }
+}
diff --git a/libmachdevdde/net.c b/libmachdevdde/net.c
new file mode 100644
index 00000000..85ba2d58
--- /dev/null
+++ b/libmachdevdde/net.c
@@ -0,0 +1,663 @@
+/*
+ * Linux network driver support.
+ *
+ * Copyright (C) 1996 The University of Utah and the Computer Systems
+ * Laboratory at the University of Utah (CSL)
+ *
+ * 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.
+ *
+ *      Author: Shantanu Goel, University of Utah CSL
+ */
+
+/*
+ * INET               An implementation of the TCP/IP protocol suite for the LINUX
+ *              operating system.  INET is implemented using the  BSD Socket
+ *              interface as the means of communication with the user level.
+ *
+ *              Ethernet-type device handling.
+ *
+ * Version:     @(#)eth.c       1.0.7   05/25/93
+ *
+ * Authors:     Ross Biro, <b...@leland.stanford.edu>
+ *              Fred N. van Kempen, <wal...@uwalt.nl.mugnet.org>
+ *              Mark Evans, <evan...@uhura.aston.ac.uk>
+ *              Florian  La Roche, <rz...@rz.uni-sb.de>
+ *              Alan Cox, <gw4...@gw4pts.ampr.org>
+ * 
+ * Fixes:
+ *              Mr Linux        : Arp problems
+ *              Alan Cox        : Generic queue tidyup (very tiny here)
+ *              Alan Cox        : eth_header ntohs should be htons
+ *              Alan Cox        : eth_rebuild_header missing an htons and
+ *                                minor other things.
+ *              Tegge           : Arp bug fixes. 
+ *              Florian         : Removed many unnecessary functions, code cleanup
+ *                                and changes for new arp and skbuff.
+ *              Alan Cox        : Redid header building to reflect new format.
+ *              Alan Cox        : ARP only when compiled with CONFIG_INET
+ *              Greg Page       : 802.2 and SNAP stuff.
+ *              Alan Cox        : MAC layer pointers/new format.
+ *              Paul Gortmaker  : eth_copy_and_sum shouldn't csum padding.
+ *              Alan Cox        : Protect against forwarding explosions with
+ *                                older network drivers and IFF_ALLMULTI
+ *
+ *              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 of the License, or (at your option) any later version.
+ */
+#include <assert.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <error.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 "if_ether.h"
+#include "util.h"
+#include "mach_glue.h"
+#include "if_hdr.h"
+
+#define ether_header ethhdr
+
+/* One of these is associated with each instance of a device.  */
+struct net_data
+{
+  struct port_info port;	/* device port */
+  struct emul_device device;	/* generic device structure */
+  struct ifnet ifnet;		/* Mach ifnet structure (needed for filters) */
+  struct net_device *dev;	/* Linux network device structure */
+  struct net_data *next;
+};
+
+struct skb_reply
+{
+  mach_port_t reply;
+  mach_msg_type_name_t reply_type;
+  int pkglen;
+};
+
+static struct net_data *nd_head;
+
+/* Forward declarations.  */
+
+extern struct device_emulation_ops linux_net_emulation_ops;
+
+static mach_msg_type_t header_type = 
+{
+  MACH_MSG_TYPE_BYTE,
+  8,
+  NET_HDW_HDR_MAX,
+  TRUE,
+  FALSE,
+  FALSE,
+  0
+};
+
+static mach_msg_type_t packet_type = 
+{
+  MACH_MSG_TYPE_BYTE,	/* name */
+  8,			/* size */
+  0,			/* number */
+  TRUE,			/* inline */
+  FALSE,			/* longform */
+  FALSE			/* deallocate */
+};
+
+static struct net_data *search_nd (struct net_device *dev)
+{
+  struct net_data *nd = nd_head;
+
+  //TODO protected by locks.
+  while (nd)
+    {
+      if (nd->dev == dev)
+	return nd;
+      nd = nd->next;
+    }
+  return NULL;
+}
+
+/* Linux kernel network support routines.  */
+
+/* actions before freeing the sk_buff SKB.
+ * If it returns 1, the packet will be deallocated later. */
+static int 
+pre_kfree_skb (struct sk_buff *skb, void *data)
+{
+  struct skb_reply *reply = data;
+  extern void wakeup_io_done_thread ();
+
+  /* Queue sk_buff on done list if there is a
+     page list attached or we need to send a reply.
+     Wakeup the iodone thread to process the list.  */
+  if (reply && MACH_PORT_VALID (reply->reply))
+    {
+      if (MACH_PORT_VALID (reply->reply))
+	{
+	  ds_device_write_reply (reply->reply, reply->reply_type,
+				 0, reply->pkglen);
+	  reply->reply = MACH_PORT_NULL;
+	}
+    }
+  /* deallocate skb_reply before freeing the packet. */
+  free (data);
+  return 0;
+}
+
+/*
+ * Deliver the message to all right pfinet servers that
+ * connects to the virtual network interface.
+ */
+int
+deliver_msg(struct net_rcv_msg *msg, if_filter_list_t *ifp)
+{
+  mach_msg_return_t err;
+  queue_head_t *if_port_list;
+  net_rcv_port_t infp, nextfp;
+
+  msg->msg_hdr.msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_COPY_SEND, 0);
+  /* remember message sizes must be rounded up */
+  msg->msg_hdr.msgh_local_port = MACH_PORT_NULL;
+  msg->msg_hdr.msgh_kind = MACH_MSGH_KIND_NORMAL;
+  msg->msg_hdr.msgh_id = NET_RCV_MSG_ID;
+
+  if_port_list = &ifp->if_rcv_port_list;
+  FILTER_ITERATE (if_port_list, infp, nextfp, &infp->input) 
+    {
+      mach_port_t dest;
+      net_hash_entry_t entp, *hash_headp;
+      int ret_count;
+
+      entp = (net_hash_entry_t) 0;
+      ret_count = bpf_do_filter (infp,
+				 msg->packet + sizeof (struct packet_header),
+				 msg->net_rcv_msg_packet_count, msg->header,
+				 sizeof (struct ethhdr), &hash_headp, &entp);
+      if (entp == (net_hash_entry_t) 0)
+	dest = infp->rcv_port;
+      else
+	dest = entp->rcv_port;
+
+      if (ret_count) 
+	{
+	  msg->msg_hdr.msgh_remote_port = dest;
+	  err = mach_msg ((mach_msg_header_t *)msg,
+			  MACH_SEND_MSG|MACH_SEND_TIMEOUT,
+			  msg->msg_hdr.msgh_size, 0, MACH_PORT_NULL,
+			  0, MACH_PORT_NULL);
+	  if (err != MACH_MSG_SUCCESS)
+	    {
+	      /* TODO: remove from filter */
+	    }
+	}
+    }
+  FILTER_ITERATE_END
+
+    return 0;
+}
+
+/* Accept packet SKB received on an interface.  */
+static void
+netif_rx_handle (char *data, int len, struct net_device *dev)
+{
+  int pack_size;
+  struct net_rcv_msg net_msg;
+  struct ether_header *eh;
+  struct packet_header *ph;
+  struct net_data *nd;
+
+  nd = search_nd(dev);
+  assert (nd);
+
+  pack_size = len - sizeof (struct ethhdr);
+  /* remember message sizes must be rounded up */
+  net_msg.msg_hdr.msgh_size =
+    (((mach_msg_size_t) (sizeof (struct net_rcv_msg)
+			 - sizeof net_msg.sent
+			 + sizeof (struct packet_header)
+			 - NET_RCV_MAX + pack_size)) + 3) & ~3;
+
+  /* Copy packet into message buffer.  */
+  eh = (struct ether_header *) (net_msg.header);
+  ph = (struct packet_header *) (net_msg.packet);
+  memcpy (eh, data, sizeof (struct ether_header));
+  /* packet is prefixed with a struct packet_header,
+     see include/device/net_status.h.  */
+  memcpy (ph + 1, data + sizeof (struct ether_header), pack_size);
+  ph->type = eh->h_proto;
+  ph->length = pack_size + sizeof (struct packet_header);
+
+  net_msg.sent = FALSE; /* Mark packet as received.  */
+
+  net_msg.header_type = header_type;
+  net_msg.packet_type = packet_type;
+  net_msg.net_rcv_msg_packet_count = ph->length;
+  deliver_msg (&net_msg, &nd->ifnet.port_list);
+}
+
+/* Mach device interface routines.  */
+
+/* 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);
+}
+
+/*    
+ * Initialize send and receive queues on an interface.
+ */   
+void if_init_queues(ifp)
+     register struct ifnet *ifp;
+{     
+//  IFQ_INIT(&ifp->if_snd);
+  queue_init(&ifp->port_list.if_rcv_port_list);
+  queue_init(&ifp->port_list.if_snd_port_list);
+  pthread_mutex_init(&ifp->if_rcv_port_list_lock, NULL);
+  pthread_mutex_init(&ifp->if_snd_port_list_lock, 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 net_device *dev;
+  struct net_data *nd;
+  struct ifnet *ifp;
+
+  /* Search for the device.  */
+  dev = search_netdev (name);
+  if (!dev)
+    {
+      fprintf (stderr, "after search_netdev: cannot find %s\n", name);
+      return D_NO_SUCH_DEVICE;
+    }
+
+  /* Allocate and initialize device data if this is the first open.  */
+  nd = search_nd (dev);
+  if (!nd)
+    {
+      char *name;
+
+      err = create_device_port (sizeof (*nd), &nd);
+      if (err)
+	{
+	  fprintf (stderr, "after create_device_port: cannot create a port\n");
+	  goto out;
+	}
+	
+      nd->dev = dev;
+      nd->device.emul_data = nd;
+      nd->device.emul_ops = &linux_net_emulation_ops;
+      nd->next = nd_head;
+      nd_head = nd;
+
+      ifp = &nd->ifnet;
+      name = netdev_name (dev);
+      ifp->if_unit = name[strlen (name) - 1] - '0';
+      ifp->if_flags = IFF_UP | IFF_RUNNING;
+      ifp->if_mtu = netdev_mtu (dev);
+      ifp->if_header_size = netdev_header_len (dev);
+      ifp->if_header_format = netdev_type (dev);
+      ifp->if_address_size = netdev_addr_len (dev);
+      ifp->if_address = netdev_addr (dev);
+      if_init_queues (ifp);
+
+      if ((err = dev_open(dev)) < 0)
+	{
+	  fprintf (stderr, "after dev_open: cannot open the device\n");
+	  err = linux_to_mach_error (err);
+	}
+
+    out:
+      if (err)
+	{
+	  if (nd)
+	    {
+	      ports_destroy_right (nd);
+	      nd = NULL;
+	    }
+	}
+      else
+	{
+#if 0
+	  /* IPv6 heavily relies on multicasting (especially router and
+	     neighbor solicits and advertisements), so enable reception of
+	     those multicast packets by setting `LINUX_IFF_ALLMULTI'.  */
+	  dev->flags |= LINUX_IFF_UP | LINUX_IFF_RUNNING | LINUX_IFF_ALLMULTI;
+	  skb_queue_head_init (&dev->buffs[0]);
+
+	  if (dev->set_multicast_list)
+	    dev->set_multicast_list (dev);
+#endif
+	}
+    }
+
+  if (nd)
+    {
+      *devp = ports_get_right (nd);
+      *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 net_data *nd = d;
+  struct net_device *dev = nd->dev;
+  struct skb_reply *skb_reply = malloc (sizeof (*skb_reply));
+  error_t err;
+
+  if (skb_reply == NULL)
+    return D_NO_MEMORY;
+
+  skb_reply->pkglen = count;
+  skb_reply->reply = reply_port;
+  skb_reply->reply_type = reply_port_type;
+
+  err = linux_pkg_xmit (data, count, skb_reply, pre_kfree_skb, dev);
+  vm_deallocate (mach_task_self (), (vm_address_t) data, count);
+  if (err)
+    return linux_to_mach_error (err);
+
+  /* Send packet to filters.  */
+  // TODO should I deliver the packet to other network stacks?
+#if 0
+  {
+    struct packet_header *packet;
+    struct ether_header *header;
+    ipc_kmsg_t kmsg;
+
+    kmsg = net_kmsg_get ();
+
+    if (kmsg != IKM_NULL)
+      {
+        /* Suitable for Ethernet only.  */
+        header = (struct ether_header *) (net_kmsg (kmsg)->header);
+        packet = (struct packet_header *) (net_kmsg (kmsg)->packet);
+        memcpy (header, skb->data, sizeof (struct ether_header));
+
+        /* packet is prefixed with a struct packet_header,
+           see include/device/net_status.h.  */
+        memcpy (packet + 1, skb->data + sizeof (struct ether_header),
+                skb->len - sizeof (struct ether_header));
+        packet->length = skb->len - sizeof (struct ether_header)
+                         + sizeof (struct packet_header);
+        packet->type = header->ether_type;
+        net_kmsg (kmsg)->sent = TRUE; /* Mark packet as sent.  */
+        s = splimp ();
+        net_packet (&dev->net_data->ifnet, kmsg, packet->length,
+                    ethernet_priority (kmsg));
+        splx (s);
+      }
+  }
+#endif
+
+  return MIG_NO_REPLY;
+}
+
+/*
+ * Other network operations
+ */
+static io_return_t
+net_getstat(ifp, flavor, status, count)
+	struct ifnet	*ifp;
+	dev_flavor_t	flavor;
+	dev_status_t	status;		/* pointer to OUT array */
+	natural_t	*count;		/* OUT */
+{
+#define ETHERMTU 1500
+	switch (flavor) {
+	    case NET_STATUS:
+	    {
+		register struct net_status *ns = (struct net_status *)status;
+
+		if (*count < NET_STATUS_COUNT)
+		    return (D_INVALID_OPERATION);
+		
+		ns->min_packet_size = ifp->if_header_size;
+		ns->max_packet_size = ifp->if_header_size + ifp->if_mtu;
+		ns->header_format   = ifp->if_header_format;
+		ns->header_size	    = ifp->if_header_size;
+		ns->address_size    = ifp->if_address_size;
+		ns->flags	    = ifp->if_flags;
+		ns->mapped_size	    = 0;
+
+		*count = NET_STATUS_COUNT;
+		break;
+	    }
+	    case NET_ADDRESS:
+	    {
+		register int	addr_byte_count;
+		register int	addr_int_count;
+		register int	i;
+
+		addr_byte_count = ETH_ALEN;
+		addr_int_count = (addr_byte_count + (sizeof(int)-1))
+					 / sizeof(int);
+
+		if (*count < addr_int_count)
+		{
+		  /* XXX debug hack. */
+		  printf ("net_getstat: count: %d, addr_int_count: %d\n",
+			  *count, addr_int_count);
+		  return (D_INVALID_OPERATION);
+		}
+
+		memcpy(status, ifp->if_address, addr_byte_count);
+		if (addr_byte_count < addr_int_count * sizeof(int))
+		    memset((char *)status + addr_byte_count, 0, 
+			  (addr_int_count * sizeof(int)
+				      - addr_byte_count));
+
+		for (i = 0; i < addr_int_count; i++) {
+		    register int word;
+
+		    word = status[i];
+		    status[i] = htonl(word);
+		}
+		*count = addr_int_count;
+		break;
+	    }
+	    default:
+		return (D_INVALID_OPERATION);
+	}
+	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 net_data *net = (struct net_data *) d;
+
+  if (flavor == NET_FLAGS)
+    {
+      if (*count != 1)
+	return D_INVALID_SIZE;
+
+      *(int *) status = netdev_flags (net->dev);
+      return D_SUCCESS;
+    }
+
+#if 0
+  if(flavor >= SIOCIWFIRST && flavor <= SIOCIWLAST)
+    {
+      /* handle wireless ioctl */
+      if(! IW_IS_GET(flavor))
+	return D_INVALID_OPERATION;
+
+      if(*count * sizeof(int) < sizeof(struct ifreq))
+	return D_INVALID_OPERATION;
+
+      struct net_data *nd = d;
+      struct linux_device *dev = nd->dev;
+
+      if(! dev->do_ioctl)
+	return D_INVALID_OPERATION;
+
+      int result;
+
+      if (flavor == SIOCGIWRANGE || flavor == SIOCGIWENCODE
+	  || flavor == SIOCGIWESSID || flavor == SIOCGIWNICKN
+	  || flavor == SIOCGIWSPY)
+	{
+	  /*
+	   * These ioctls require an `iw_point' as their argument (i.e.
+	   * they want to return some data to userspace. 
+	   * Therefore supply some sane values and carry the data back
+	   * to userspace right behind the `struct iwreq'.
+	   */
+	  struct iw_point *iwp = &((struct iwreq *) status)->u.data;
+	  iwp->length = *count * sizeof (dev_status_t) - sizeof (struct ifreq);
+	  iwp->pointer = (void *) status + sizeof (struct ifreq);
+
+	  result = dev->do_ioctl (dev, (struct ifreq *) status, flavor);
+
+	  *count = ((sizeof (struct ifreq) + iwp->length)
+		    / sizeof (dev_status_t));
+	  if (iwp->length % sizeof (dev_status_t))
+	    (*count) ++;
+	}
+      else
+	{
+	  *count = sizeof(struct ifreq) / sizeof(int);
+	  result = dev->do_ioctl(dev, (struct ifreq *) status, flavor);
+	}
+
+      return result ? D_IO_ERROR : D_SUCCESS;
+    }
+  else
+#endif
+    {
+      /* common get_status request */
+      return net_getstat (&net->ifnet, flavor, status, count);
+    }
+}
+
+static io_return_t
+device_set_status(void *d, dev_flavor_t flavor, dev_status_t status,
+		  mach_msg_type_number_t count)
+{
+  if (flavor == NET_FLAGS)
+    {
+      if (count != 1)
+        return D_INVALID_SIZE;
+
+      int flags = *(int *) status;
+      struct net_data *net = (struct net_data *) d;
+
+      dev_change_flags (net->dev, flags);
+
+      return D_SUCCESS;
+    }
+    return D_INVALID_OPERATION;
+
+#if 0
+  if(flavor < SIOCIWFIRST || flavor > SIOCIWLAST)
+    return D_INVALID_OPERATION;
+
+  if(! IW_IS_SET(flavor))
+    return D_INVALID_OPERATION;
+  
+  if(count * sizeof(int) < sizeof(struct ifreq))
+    return D_INVALID_OPERATION;
+
+  struct net_data *nd = d;
+  struct linux_device *dev = nd->dev;
+
+  if(! dev->do_ioctl)
+    return D_INVALID_OPERATION;
+
+  if((flavor == SIOCSIWENCODE || flavor == SIOCSIWESSID
+      || flavor == SIOCSIWNICKN || flavor == SIOCSIWSPY)
+     && ((struct iwreq *) status)->u.data.pointer)
+    {
+      struct iw_point *iwp = &((struct iwreq *) status)->u.data;
+
+      /* safety check whether the status array is long enough ... */
+      if(count * sizeof(int) < sizeof(struct ifreq) + iwp->length)
+	return D_INVALID_OPERATION;
+
+      /* make sure, iwp->pointer points to the correct address */
+      if(iwp->pointer) iwp->pointer = (void *) status + sizeof(struct ifreq);
+    }
+  
+  int result = dev->do_ioctl(dev, (struct ifreq *) status, flavor);
+  return result ? D_IO_ERROR : D_SUCCESS;
+#endif
+}
+
+
+static io_return_t
+device_set_filter (void *d, mach_port_t port, int priority,
+		   filter_t * filter, unsigned filter_count)
+{
+  return net_set_filter (&((struct net_data *) d)->ifnet.port_list,
+			 port, priority, filter, filter_count);
+}
+
+/* Do any initialization required for network devices.  */
+static void linux_net_emulation_init ()
+{
+  skb_done_head_init();
+  l4dde26_register_rx_callback(netif_rx_handle);
+}
+
+struct device_emulation_ops linux_net_emulation_ops =
+{
+  linux_net_emulation_init,
+  NULL,
+  NULL,
+  dev_to_port,
+  device_open,
+  NULL,
+  device_write,
+  NULL,
+  NULL,
+  NULL,
+  device_set_status,
+  device_get_status,
+  device_set_filter,
+  NULL,
+  NULL,
+  NULL,
+  NULL
+};
+
+void register_net()
+{
+	extern void reg_dev_emul (struct device_emulation_ops *ops);
+	reg_dev_emul (&linux_net_emulation_ops);
+}
diff --git a/libmachdevdde/queue.c b/libmachdevdde/queue.c
new file mode 100644
index 00000000..a43a21b0
--- /dev/null
+++ b/libmachdevdde/queue.c
@@ -0,0 +1,131 @@
+/* 
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ * 
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ * 
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ * 
+ * Carnegie Mellon requests users of this software to return to
+ * 
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ * 
+ * any improvements or extensions that they make and grant Carnegie Mellon
+ * the rights to redistribute these changes.
+ */
+/*
+ *	Routines to implement queue package.
+ */
+
+#include "queue.h"
+
+
+
+/*
+ *	Insert element at head of queue.
+ */
+void enqueue_head(
+	register queue_t	que,
+	register queue_entry_t	elt)
+{
+	elt->next = que->next;
+	elt->prev = que;
+	elt->next->prev = elt;
+	que->next = elt;
+}
+
+/*
+ *	Insert element at tail of queue.
+ */
+void enqueue_tail(
+	register queue_t	que,
+	register queue_entry_t	elt)
+{
+	elt->next = que;
+	elt->prev = que->prev;
+	elt->prev->next = elt;
+	que->prev = elt;
+}
+
+/*
+ *	Remove and return element at head of queue.
+ */
+queue_entry_t dequeue_head(
+	register queue_t	que)
+{
+	register queue_entry_t	elt;
+
+	if (que->next == que)
+		return((queue_entry_t)0);
+
+	elt = que->next;
+	elt->next->prev = que;
+	que->next = elt->next;
+	return(elt);
+}
+
+/*
+ *	Remove and return element at tail of queue.
+ */
+queue_entry_t dequeue_tail(
+	register queue_t	que)
+{
+	register queue_entry_t	elt;
+
+	if (que->prev == que)
+		return((queue_entry_t)0);
+
+	elt = que->prev;
+	elt->prev->next = que;
+	que->prev = elt->prev;
+	return(elt);
+}
+
+/*
+ *	Remove arbitrary element from queue.
+ *	Does not check whether element is on queue - the world
+ *	will go haywire if it isn't.
+ */
+
+/*ARGSUSED*/
+void remqueue(
+	queue_t			que,
+	register queue_entry_t	elt)
+{
+	elt->next->prev = elt->prev;
+	elt->prev->next = elt->next;
+}
+
+/*
+ *	Routines to directly imitate the VAX hardware queue
+ *	package.
+ */
+void insque(
+	register struct queue_entry *entry,
+	register struct queue_entry *pred)
+{
+	entry->next = pred->next;
+	entry->prev = pred;
+	(pred->next)->prev = entry;
+	pred->next = entry;
+}
+
+struct queue_entry
+*remque(
+	register struct queue_entry *elt)
+{
+	(elt->next)->prev = elt->prev;
+	(elt->prev)->next = elt->next;
+	return(elt);
+}
+
diff --git a/libmachdevdde/queue.h b/libmachdevdde/queue.h
new file mode 100644
index 00000000..86ef74dc
--- /dev/null
+++ b/libmachdevdde/queue.h
@@ -0,0 +1,370 @@
+/*
+ * Mach Operating System
+ * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
+ * All Rights Reserved.
+ *
+ * Permission to use, copy, modify and distribute this software and its
+ * documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
+ * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ *  Software Distribution Coordinator  or  software.distribut...@cs.cmu.edu
+ *  School of Computer Science
+ *  Carnegie Mellon University
+ *  Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie Mellon rights
+ * to redistribute these changes.
+ */
+/*
+ *	File:	queue.h
+ *	Author:	Avadis Tevanian, Jr.
+ *	Date:	1985
+ *
+ *	Type definitions for generic queues.
+ *
+ */
+
+#ifndef	_KERN_QUEUE_H_
+#define	_KERN_QUEUE_H_
+
+#include <pthread.h>
+
+/*
+ *	Queue of abstract objects.  Queue is maintained
+ *	within that object.
+ *
+ *	Supports fast removal from within the queue.
+ *
+ *	How to declare a queue of elements of type "foo_t":
+ *		In the "*foo_t" type, you must have a field of
+ *		type "queue_chain_t" to hold together this queue.
+ *		There may be more than one chain through a
+ *		"foo_t", for use by different queues.
+ *
+ *		Declare the queue as a "queue_t" type.
+ *
+ *		Elements of the queue (of type "foo_t", that is)
+ *		are referred to by reference, and cast to type
+ *		"queue_entry_t" within this module.
+ */
+
+/*
+ *	A generic doubly-linked list (queue).
+ */
+
+struct queue_entry {
+	struct queue_entry	*next;		/* next element */
+	struct queue_entry	*prev;		/* previous element */
+};
+
+typedef struct queue_entry	*queue_t;
+typedef	struct queue_entry	queue_head_t;
+typedef	struct queue_entry	queue_chain_t;
+typedef	struct queue_entry	*queue_entry_t;
+
+/*
+ *	enqueue puts "elt" on the "queue".
+ *	dequeue returns the first element in the "queue".
+ *	remqueue removes the specified "elt" from the specified "queue".
+ */
+
+#define enqueue(queue,elt)	enqueue_tail(queue, elt)
+#define	dequeue(queue)		dequeue_head(queue)
+
+void		enqueue_head(queue_t, queue_entry_t);
+void		enqueue_tail(queue_t, queue_entry_t);
+queue_entry_t	dequeue_head(queue_t);
+queue_entry_t	dequeue_tail(queue_t);
+void		remqueue(queue_t, queue_entry_t);
+void		insque(queue_entry_t, queue_entry_t);
+
+/*
+ *	Macro:		queue_init
+ *	Function:
+ *		Initialize the given queue.
+ *	Header:
+ *		void queue_init(q)
+ *			queue_t		q;	*MODIFIED*
+ */
+#define	queue_init(q)	((q)->next = (q)->prev = q)
+
+/*
+ *	Macro:		queue_first
+ *	Function:
+ *		Returns the first entry in the queue,
+ *	Header:
+ *		queue_entry_t queue_first(q)
+ *			queue_t	q;		*IN*
+ */
+#define	queue_first(q)	((q)->next)
+
+/*
+ *	Macro:		queue_next
+ *	Function:
+ *		Returns the entry after an item in the queue.
+ *	Header:
+ *		queue_entry_t queue_next(qc)
+ *			queue_t qc;
+ */
+#define	queue_next(qc)	((qc)->next)
+
+/*
+ *	Macro:		queue_last
+ *	Function:
+ *		Returns the last entry in the queue.
+ *	Header:
+ *		queue_entry_t queue_last(q)
+ *			queue_t	q;		 *IN*
+ */
+#define	queue_last(q)	((q)->prev)
+
+/*
+ *	Macro:		queue_prev
+ *	Function:
+ *		Returns the entry before an item in the queue.
+ *	Header:
+ *		queue_entry_t queue_prev(qc)
+ *			queue_t qc;
+ */
+#define	queue_prev(qc)	((qc)->prev)
+
+/*
+ *	Macro:		queue_end
+ *	Function:
+ *		Tests whether a new entry is really the end of
+ *		the queue.
+ *	Header:
+ *		boolean_t queue_end(q, qe)
+ *			queue_t q;
+ *			queue_entry_t qe;
+ */
+#define	queue_end(q, qe)	((q) == (qe))
+
+/*
+ *	Macro:		queue_empty
+ *	Function:
+ *		Tests whether a queue is empty.
+ *	Header:
+ *		boolean_t queue_empty(q)
+ *			queue_t q;
+ */
+#define	queue_empty(q)		queue_end((q), queue_first(q))
+
+
+/*----------------------------------------------------------------*/
+/*
+ * Macros that operate on generic structures.  The queue
+ * chain may be at any location within the structure, and there
+ * may be more than one chain.
+ */
+
+/*
+ *	Macro:		queue_enter
+ *	Function:
+ *		Insert a new element at the tail of the queue.
+ *	Header:
+ *		void queue_enter(q, elt, type, field)
+ *			queue_t q;
+ *			<type> elt;
+ *			<type> is what's in our queue
+ *			<field> is the chain field in (*<type>)
+ */
+#define queue_enter(head, elt, type, field)			\
+{ 								\
+	register queue_entry_t prev;				\
+								\
+	prev = (head)->prev;					\
+	if ((head) == prev) {					\
+		(head)->next = (queue_entry_t) (elt);		\
+	}							\
+	else {							\
+		((type)prev)->field.next = (queue_entry_t)(elt);\
+	}							\
+	(elt)->field.prev = prev;				\
+	(elt)->field.next = head;				\
+	(head)->prev = (queue_entry_t) elt;			\
+}
+
+/*
+ *	Macro:		queue_enter_first
+ *	Function:
+ *		Insert a new element at the head of the queue.
+ *	Header:
+ *		void queue_enter_first(q, elt, type, field)
+ *			queue_t q;
+ *			<type> elt;
+ *			<type> is what's in our queue
+ *			<field> is the chain field in (*<type>)
+ */
+#define queue_enter_first(head, elt, type, field)		\
+{ 								\
+	register queue_entry_t next;				\
+								\
+	next = (head)->next;					\
+	if ((head) == next) {					\
+		(head)->prev = (queue_entry_t) (elt);		\
+	}							\
+	else {							\
+		((type)next)->field.prev = (queue_entry_t)(elt);\
+	}							\
+	(elt)->field.next = next;				\
+	(elt)->field.prev = head;				\
+	(head)->next = (queue_entry_t) elt;			\
+}
+
+/*
+ *	Macro:		queue_field [internal use only]
+ *	Function:
+ *		Find the queue_chain_t (or queue_t) for the
+ *		given element (thing) in the given queue (head)
+ */
+#define	queue_field(head, thing, type, field)			\
+		(((head) == (thing)) ? (head) : &((type)(thing))->field)
+
+/*
+ *	Macro:		queue_remove
+ *	Function:
+ *		Remove an arbitrary item from the queue.
+ *	Header:
+ *		void queue_remove(q, qe, type, field)
+ *			arguments as in queue_enter
+ */
+#define	queue_remove(head, elt, type, field)			\
+{								\
+	register queue_entry_t	next, prev;			\
+								\
+	next = (elt)->field.next;				\
+	prev = (elt)->field.prev;				\
+								\
+	if ((head) == next)					\
+		(head)->prev = prev;				\
+	else							\
+		((type)next)->field.prev = prev;		\
+								\
+	if ((head) == prev)					\
+		(head)->next = next;				\
+	else							\
+		((type)prev)->field.next = next;		\
+}
+
+/*
+ *	Macro:		queue_remove_first
+ *	Function:
+ *		Remove and return the entry at the head of
+ *		the queue.
+ *	Header:
+ *		queue_remove_first(head, entry, type, field)
+ *		entry is returned by reference
+ */
+#define	queue_remove_first(head, entry, type, field)		\
+{								\
+	register queue_entry_t	next;				\
+								\
+	(entry) = (type) ((head)->next);			\
+	next = (entry)->field.next;				\
+								\
+	if ((head) == next)					\
+		(head)->prev = (head);				\
+	else							\
+		((type)(next))->field.prev = (head);		\
+	(head)->next = next;					\
+}
+
+/*
+ *	Macro:		queue_remove_last
+ *	Function:
+ *		Remove and return the entry at the tail of
+ *		the queue.
+ *	Header:
+ *		queue_remove_last(head, entry, type, field)
+ *		entry is returned by reference
+ */
+#define	queue_remove_last(head, entry, type, field)		\
+{								\
+	register queue_entry_t	prev;				\
+								\
+	(entry) = (type) ((head)->prev);			\
+	prev = (entry)->field.prev;				\
+								\
+	if ((head) == prev)					\
+		(head)->next = (head);				\
+	else							\
+		((type)(prev))->field.next = (head);		\
+	(head)->prev = prev;					\
+}
+
+/*
+ *	Macro:		queue_assign
+ */
+#define	queue_assign(to, from, type, field)			\
+{								\
+	((type)((from)->prev))->field.next = (to);		\
+	((type)((from)->next))->field.prev = (to);		\
+	*to = *from;						\
+}
+
+/*
+ *	Macro:		queue_iterate
+ *	Function:
+ *		iterate over each item in the queue.
+ *		Generates a 'for' loop, setting elt to
+ *		each item in turn (by reference).
+ *	Header:
+ *		queue_iterate(q, elt, type, field)
+ *			queue_t q;
+ *			<type> elt;
+ *			<type> is what's in our queue
+ *			<field> is the chain field in (*<type>)
+ */
+#define queue_iterate(head, elt, type, field)			\
+	for ((elt) = (type) queue_first(head);			\
+	     !queue_end((head), (queue_entry_t)(elt));		\
+	     (elt) = (type) queue_next(&(elt)->field))
+
+
+
+/*----------------------------------------------------------------*/
+/*
+ *	Define macros for queues with locks.
+ */
+struct mpqueue_head {
+	struct queue_entry	head;		/* header for queue */
+	pthread_mutex_t		lock;		/* lock for queue */
+};
+
+typedef struct mpqueue_head	mpqueue_head_t;
+
+#define	round_mpq(size)		(size)
+
+#define mpqueue_init(q) \
+	{ \
+		queue_init(&(q)->head); \
+		pthread_mutex_init(&(q)->lock, NULL); \
+	}
+
+#define mpenqueue_tail(q, elt) \
+		pthread_mutex_lock(&(q)->lock); \
+		enqueue_tail(&(q)->head, elt); \
+		pthread_mutex_unlock(&(q)->lock);
+
+#define mpdequeue_head(q, elt) \
+		pthread_mutex_lock(&(q)->lock); \
+		if (queue_empty(&(q)->head)) \
+			*(elt) = 0; \
+		else \
+			*(elt) = dequeue_head(&(q)->head); \
+		pthread_mutex_unlock(&(q)->lock);
+
+/*
+ *	Old queue stuff, will go away soon.
+ */
+
+#endif	/* _KERN_QUEUE_H_ */
diff --git a/libmachdevdde/util.h b/libmachdevdde/util.h
new file mode 100644
index 00000000..1c62b0d6
--- /dev/null
+++ b/libmachdevdde/util.h
@@ -0,0 +1,35 @@
+#ifndef __UTIL_H__
+#define __UTIL_H__
+
+#include <stdio.h>
+
+#define panic(format, ...) do				\
+{							\
+  char buf[1024];                                       \
+  snprintf (buf, 1024, "devnode: %s", format);       \
+  fprintf (stderr , buf, ## __VA_ARGS__);		\
+  fflush (stderr);					\
+  abort ();			    \
+} while (0)
+
+#define DEBUG
+
+#ifdef DEBUG
+
+#define debug(format, ...) do				\
+{							\
+  char buf[1024];                                       \
+  snprintf (buf, 1024, "pcnet32: %s: %s\n", __func__, format);       \
+  fprintf (stderr , buf, ## __VA_ARGS__);		\
+  fflush (stderr);					\
+} while (0)
+
+#else
+
+#define debug(format, ...) do {} while (0)
+
+#endif
+
+int linux_to_mach_error (int err);
+
+#endif
-- 
2.25.1

Reply via email to