summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJustus Winter <justus@gnupg.org>2016-02-26 15:32:22 +0100
committerJustus Winter <justus@gnupg.org>2016-02-26 15:32:22 +0100
commit87857e6c2d33aecd30ddbf2538170e2e51a901ba (patch)
tree245a3e4e82310a0db064cd4b0ae4ca4cf216ca49
parent8d6a974d04faaefdcca3951859b7c4b0abc6e6c2 (diff)
add patch series
-rw-r--r--debian/patches/700001-70_dde.patch.patch819
-rw-r--r--debian/patches/700002-Disable-disabling-the-irq-via-device_intr_enable.patch91
-rw-r--r--debian/patches/700003-Rework-comment-on-the-userspace-interrupt-handling.patch284
-rw-r--r--debian/patches/700004-Some-cleanups-of-the-userspace-interrupt-handling.patch169
-rw-r--r--debian/patches/700005-Fix-synchronization.patch33
-rw-r--r--debian/patches/700006-Reorder.patch90
-rw-r--r--debian/patches/700007-Use-the-slab-allocator.patch63
-rw-r--r--debian/patches/700008-Fix-reference-counting-use-dead-name-notification.patch371
-rw-r--r--debian/patches/700009-Fix-xen-build.patch37
-rw-r--r--debian/patches/series9
10 files changed, 1966 insertions, 0 deletions
diff --git a/debian/patches/700001-70_dde.patch.patch b/debian/patches/700001-70_dde.patch.patch
new file mode 100644
index 0000000..6ecc4f2
--- /dev/null
+++ b/debian/patches/700001-70_dde.patch.patch
@@ -0,0 +1,819 @@
+From 9ad7eb46b65b7324dd5f2c6f5568b6a0e033a5f4 Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Thu, 25 Feb 2016 18:46:32 +0100
+Subject: [PATCH gnumach 1/9] 70_dde.patch
+
+---
+ Makefrag.am | 9 ++
+ device/ds_routines.c | 55 +++++++++++
+ device/ds_routines.h | 3 +
+ device/intr.c | 198 +++++++++++++++++++++++++++++++++++++++
+ include/device/intr.h | 17 ++++
+ include/mach/experimental.defs | 100 ++++++++++++++++++++
+ kern/experimental.srv | 3 +
+ kern/ipc_kobject.c | 3 +
+ kern/startup.c | 4 +
+ linux/dev/arch/i386/kernel/irq.c | 81 +++++++++++++++-
+ linux/dev/drivers/block/genhd.c | 4 +-
+ vm/vm_user.c | 103 ++++++++++++++++++++
+ 12 files changed, 578 insertions(+), 2 deletions(-)
+ create mode 100644 device/intr.c
+ create mode 100644 include/device/intr.h
+ create mode 100644 include/mach/experimental.defs
+ create mode 100644 kern/experimental.srv
+
+diff --git a/Makefrag.am b/Makefrag.am
+index 9a68af8..de11a71 100644
+--- a/Makefrag.am
++++ b/Makefrag.am
+@@ -220,6 +220,7 @@ EXTRA_DIST += \
+ kern/mach.srv \
+ kern/mach4.srv \
+ kern/gnumach.srv \
++ kern/experimental.srv \
+ kern/mach_debug.srv \
+ kern/mach_host.srv \
+ kern/task_notify.cli
+@@ -304,6 +305,7 @@ libkernel_a_SOURCES += \
+ device/device_types_kernel.h \
+ device/ds_routines.c \
+ device/ds_routines.h \
++ device/intr.c \
+ device/if_ether.h \
+ device/if_hdr.h \
+ device/io_req.h \
+@@ -352,6 +354,7 @@ include_device_HEADERS = \
+ include/device/device_types.defs \
+ include/device/device_types.h \
+ include/device/disk_status.h \
++ include/device/intr.h \
+ include/device/net_status.h \
+ include/device/tape_status.h \
+ include/device/tty_status.h
+@@ -374,6 +377,7 @@ include_mach_HEADERS = \
+ include/mach/memory_object_default.defs \
+ include/mach/notify.defs \
+ include/mach/std_types.defs \
++ include/mach/experimental.defs \
+ include/mach/alert.h \
+ include/mach/boolean.h \
+ include/mach/boot.h \
+@@ -522,6 +526,7 @@ nodist_lib_dep_tr_for_defs_a_SOURCES += \
+ kern/mach.server.defs.c \
+ kern/mach4.server.defs.c \
+ kern/gnumach.server.defs.c \
++ kern/experimental.server.defs.c \
+ kern/mach_debug.server.defs.c \
+ kern/mach_host.server.defs.c
+ nodist_libkernel_a_SOURCES += \
+@@ -534,6 +539,9 @@ nodist_libkernel_a_SOURCES += \
+ kern/gnumach.server.h \
+ kern/gnumach.server.c \
+ kern/gnumach.server.msgids \
++ kern/experimental.server.h \
++ kern/experimental.server.c \
++ kern/experimental.server.msgids \
+ kern/mach_debug.server.h \
+ kern/mach_debug.server.c \
+ kern/mach_debug.server.msgids \
+@@ -543,6 +551,7 @@ nodist_libkernel_a_SOURCES += \
+ # kern/mach.server.defs
+ # kern/mach4.server.defs
+ # kern/gnumach.server.defs
++# kern/experimental.server.defs
+ # kern/mach_debug.server.defs
+ # kern/mach_host.server.defs
+
+diff --git a/device/ds_routines.c b/device/ds_routines.c
+index dbff7f8..4f6b345 100644
+--- a/device/ds_routines.c
++++ b/device/ds_routines.c
+@@ -318,6 +318,43 @@ ds_device_map (device_t dev, vm_prot_t prot, vm_offset_t offset,
+ offset, size, pager, unmap);
+ }
+
++io_return_t
++experimental_device_intr_register (ipc_port_t master_port, int line,
++ int id, int flags, ipc_port_t receive_port)
++{
++#ifdef MACH_XEN
++ return D_INVALID_OPERATION;
++#else /* MACH_XEN */
++ extern int install_user_intr_handler (unsigned int line,
++ unsigned long flags,
++ ipc_port_t dest);
++ io_return_t ret;
++
++ /* Open must be called on the master device port. */
++ if (master_port != master_device_port)
++ return D_INVALID_OPERATION;
++
++ /* XXX: move to arch-specific */
++ if (line < 0 || line >= 16)
++ return D_INVALID_OPERATION;
++
++ ret = insert_intr_entry (line, receive_port);
++ if (ret)
++ return ret;
++ // TODO The original port should be replaced
++ // when the same device driver calls it again,
++ // in order to handle the case that the device driver crashes and restarts.
++ ret = install_user_intr_handler (line, flags, receive_port);
++
++ /* If the port is installed successfully, increase its reference by 1.
++ * Thus, the port won't be destroyed after its task is terminated. */
++ if (ret == 0)
++ ip_reference (receive_port);
++
++ return ret;
++#endif /* MACH_XEN */
++}
++
+ boolean_t
+ ds_notify (mach_msg_header_t *msg)
+ {
+@@ -1798,6 +1835,24 @@ device_writev_trap (mach_device_t device, dev_mode_t mode,
+ return (result);
+ }
+
++kern_return_t
++experimental_device_intr_enable(ipc_port_t master_port, int line, char status)
++{
++#ifdef MACH_XEN
++ return D_INVALID_OPERATION;
++#else /* MACH_XEN */
++ if (master_port != master_device_port)
++ return D_INVALID_OPERATION;
++
++ if (status)
++ /* TODO: better name for generic-to-arch-specific call */
++ enable_irq (line);
++ else
++ disable_irq (line);
++ return 0;
++#endif /* MACH_XEN */
++}
++
+ struct device_emulation_ops mach_device_emulation_ops =
+ {
+ (void*) mach_device_reference,
+diff --git a/device/ds_routines.h b/device/ds_routines.h
+index c0543cb..e9f115f 100644
+--- a/device/ds_routines.h
++++ b/device/ds_routines.h
+@@ -83,4 +83,7 @@ io_return_t ds_device_writev_trap(
+ io_buf_vec_t *iovec,
+ vm_size_t count);
+
++/* XXX arch-specific */
++extern ipc_port_t intr_rcv_ports[16];
++
+ #endif /* DS_ROUTINES_H */
+diff --git a/device/intr.c b/device/intr.c
+new file mode 100644
+index 0000000..6fca328
+--- /dev/null
++++ b/device/intr.c
+@@ -0,0 +1,198 @@
++#include <device/intr.h>
++#include <device/ds_routines.h>
++#include <kern/queue.h>
++#include <kern/printf.h>
++
++#ifndef MACH_XEN
++// TODO this is only for x86 system
++#define sti() __asm__ __volatile__ ("sti": : :"memory")
++#define cli() __asm__ __volatile__ ("cli": : :"memory")
++
++static boolean_t deliver_intr (int line, ipc_port_t dest_port);
++
++struct intr_entry
++{
++ queue_chain_t chain;
++ ipc_port_t dest;
++ int line;
++ /* The number of interrupts occur since last run of intr_thread. */
++ int interrupts;
++};
++
++static queue_head_t intr_queue;
++/* The total number of unprocessed interrupts. */
++static int tot_num_intr;
++
++static struct intr_entry *
++search_intr (int line, ipc_port_t dest)
++{
++ struct intr_entry *e;
++ queue_iterate (&intr_queue, e, struct intr_entry *, chain)
++ {
++ if (e->dest == dest && e->line == line)
++ return e;
++ }
++ return NULL;
++}
++
++/* This function can only be used in the interrupt handler. */
++void
++queue_intr (int line, ipc_port_t dest)
++{
++ extern void intr_thread ();
++ struct intr_entry *e;
++
++ cli ();
++ e = search_intr (line, dest);
++ assert (e);
++ e->interrupts++;
++ tot_num_intr++;
++ sti ();
++
++ thread_wakeup ((event_t) &intr_thread);
++}
++
++/* insert an interrupt entry in the queue.
++ * This entry exists in the queue until
++ * the corresponding interrupt port is removed.*/
++int
++insert_intr_entry (int line, ipc_port_t dest)
++{
++ int err = 0;
++ struct intr_entry *e, *new;
++ int free = 0;
++
++ new = (struct intr_entry *) kalloc (sizeof (*new));
++ if (new == NULL)
++ return D_NO_MEMORY;
++
++ /* check whether the intr entry has been in the queue. */
++ cli ();
++ e = search_intr (line, dest);
++ if (e)
++ {
++ printf ("the interrupt entry for line %d and port %p has been inserted\n",
++ line, dest);
++ free = 1;
++ err = D_ALREADY_OPEN;
++ goto out;
++ }
++ new->line = line;
++ new->dest = dest;
++ new->interrupts = 0;
++ queue_enter (&intr_queue, new, struct intr_entry *, chain);
++out:
++ sti ();
++ if (free)
++ kfree ((vm_offset_t) new, sizeof (*new));
++ return err;
++}
++
++/* this function should be called when line is disabled. */
++void mark_intr_removed (int line, ipc_port_t dest)
++{
++ struct intr_entry *e;
++
++ e = search_intr (line, dest);
++ if (e)
++ e->dest = NULL;
++}
++
++void
++intr_thread ()
++{
++ struct intr_entry *e;
++ int line;
++ ipc_port_t dest;
++ queue_init (&intr_queue);
++
++ for (;;)
++ {
++ assert_wait ((event_t) &intr_thread, FALSE);
++ cli ();
++ while (tot_num_intr)
++ {
++ int del = 0;
++
++ queue_iterate (&intr_queue, e, struct intr_entry *, chain)
++ {
++ /* if an entry doesn't have dest port,
++ * we should remove it. */
++ if (e->dest == NULL)
++ {
++ del = 1;
++ break;
++ }
++
++ if (e->interrupts)
++ {
++ line = e->line;
++ dest = e->dest;
++ e->interrupts--;
++ tot_num_intr--;
++
++ sti ();
++ deliver_intr (line, dest);
++ cli ();
++ }
++ }
++
++ /* remove the entry without dest port from the queue and free it. */
++ if (del)
++ {
++ assert (!queue_empty (&intr_queue));
++ queue_remove (&intr_queue, e, struct intr_entry *, chain);
++ sti ();
++ kfree ((vm_offset_t) e, sizeof (*e));
++ cli ();
++ }
++ }
++ sti ();
++ thread_block (NULL);
++ }
++}
++
++static boolean_t
++deliver_intr (int line, ipc_port_t dest_port)
++{
++ ipc_kmsg_t kmsg;
++ mach_intr_notification_t *n;
++ mach_port_t dest = (mach_port_t) dest_port;
++
++ if (dest == MACH_PORT_NULL)
++ return FALSE;
++
++ kmsg = ikm_alloc(sizeof *n);
++ if (kmsg == IKM_NULL)
++ return FALSE;
++
++ ikm_init(kmsg, sizeof *n);
++ n = (mach_intr_notification_t *) &kmsg->ikm_header;
++
++ mach_msg_header_t *m = &n->intr_header;
++ mach_msg_type_t *t = &n->intr_type;
++
++ m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0);
++ m->msgh_size = sizeof *n;
++ m->msgh_seqno = INTR_NOTIFY_MSGH_SEQNO;
++ m->msgh_local_port = MACH_PORT_NULL;
++ m->msgh_remote_port = MACH_PORT_NULL;
++ m->msgh_id = MACH_INTR_NOTIFY;
++
++ t->msgt_name = MACH_MSG_TYPE_INTEGER_32;
++ t->msgt_size = 32;
++ t->msgt_number = 1;
++ t->msgt_inline = TRUE;
++ t->msgt_longform = FALSE;
++ t->msgt_deallocate = FALSE;
++ t->msgt_unused = 0;
++
++ n->intr_header.msgh_remote_port = dest;
++ n->line = line;
++
++ ipc_port_copy_send (dest_port);
++ ipc_mqueue_send_always(kmsg);
++
++ return TRUE;
++}
++#endif /* MACH_XEN */
+diff --git a/include/device/intr.h b/include/device/intr.h
+new file mode 100644
+index 0000000..a02b64c
+--- /dev/null
++++ b/include/device/intr.h
+@@ -0,0 +1,17 @@
++#ifndef __INTR_H__
++
++#define __INTR_H__
++
++#include <device/device_types.h>
++
++typedef struct
++{
++ mach_msg_header_t intr_header;
++ mach_msg_type_t intr_type;
++ int line;
++} mach_intr_notification_t;
++
++#define INTR_NOTIFY_MSGH_SEQNO 0
++#define MACH_INTR_NOTIFY 424242
++
++#endif
+diff --git a/include/mach/experimental.defs b/include/mach/experimental.defs
+new file mode 100644
+index 0000000..ca1eb92
+--- /dev/null
++++ b/include/mach/experimental.defs
+@@ -0,0 +1,100 @@
++/*
++ * 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.Distribution@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.
++ */
++
++subsystem
++#if KERNEL_USER
++ KernelUser
++#endif /* KERNEL_USER */
++#if KERNEL_SERVER
++ KernelServer
++#endif /* KERNEL_SERVER */
++ experimental 424242;
++
++#include <mach/std_types.defs>
++#include <mach/mach_types.defs>
++
++serverprefix experimental_;
++
++type notify_port_t = MACH_MSG_TYPE_MOVE_SEND_ONCE
++ ctype: mach_port_t;
++
++skip; /*simpleroutine mach_intr_notify(
++ notify : notify_port_t;
++ name : int);*/
++
++routine device_intr_register(
++ master_port : mach_port_t;
++ in line : int;
++ in id : int;
++ in flags : int;
++ in receive_port : mach_port_send_t
++ );
++
++/*
++ * enable/disable the specified line.
++ */
++/* XXX: Naming a function taht can disable something "xxx_enable" is confusing. */
++/* Is the disable part actually used at all? AIUI, the kernel IRQ handler
++should always disable the line; and the userspace driver only has to
++reenable it, after acknowledging and handling the interrupt...
++*/
++routine device_intr_enable(
++ master_port : mach_port_t;
++ line : int;
++ status : char);
++
++/*
++ * This routine is created for allocating DMA buffers.
++ * We are going to get a contiguous physical memory
++ * and its physical address in addition to the virtual address.
++ */
++
++ /* XXX
++ This RPC lacks a few additional constraints like boundaries, alignment
++and maybe phase. We may not use them now, but they're important for
++portability (e.g. if GNU Mach supports PAE, drivers that can't use
++physical memory beyond the 4 GiB limit must be able to express it).
++
++> What do you mean by "phase"?
++
++Offset from the alignment. But I don't think it's useful at all in this
++case. Minimum and maximum addresses and alignment should do. Maybe
++boundary crossing but usually, specifying the right alignment and size
++is enough.
++
++For upstream
++inclusion, we need to do it properly: the RPC should return a special
++memory object (similar to device_map() ), which can then be mapped into
++the process address space with vm_map() like any other memory object.
++
++phys_address_t?
++ */
++routine vm_allocate_contiguous(
++ host_priv : host_priv_t;
++ target_task : vm_task_t;
++ out vaddr : vm_address_t;
++ out paddr : vm_address_t;
++ size : vm_size_t);
+diff --git a/kern/experimental.srv b/kern/experimental.srv
+new file mode 100644
+index 0000000..2ccfd78
+--- /dev/null
++++ b/kern/experimental.srv
+@@ -0,0 +1,3 @@
++#define KERNEL_SERVER 1
++
++#include <mach/experimental.defs>
+diff --git a/kern/ipc_kobject.c b/kern/ipc_kobject.c
+index 709ec9e..c65458b 100644
+--- a/kern/ipc_kobject.c
++++ b/kern/ipc_kobject.c
+@@ -56,6 +56,7 @@
+ #include <device/device_pager.server.h>
+ #include <kern/mach4.server.h>
+ #include <kern/gnumach.server.h>
++#include <kern/experimental.server.h>
+
+ #if MACH_DEBUG
+ #include <kern/mach_debug.server.h>
+@@ -159,6 +160,7 @@ ipc_kobject_server(request)
+ * to perform the kernel function
+ */
+ {
++ extern mig_routine_t experimental_server_routine();
+ check_simple_locks();
+ if ((routine = mach_server_routine(&request->ikm_header)) != 0
+ || (routine = mach_port_server_routine(&request->ikm_header)) != 0
+@@ -170,6 +172,7 @@ ipc_kobject_server(request)
+ #endif /* MACH_DEBUG */
+ || (routine = mach4_server_routine(&request->ikm_header)) != 0
+ || (routine = gnumach_server_routine(&request->ikm_header)) != 0
++ || (routine = experimental_server_routine(&request->ikm_header)) != 0
+ #if MACH_MACHINE_ROUTINES
+ || (routine = MACHINE_SERVER_ROUTINE(&request->ikm_header)) != 0
+ #endif /* MACH_MACHINE_ROUTINES */
+diff --git a/kern/startup.c b/kern/startup.c
+index bd29694..05de5e6 100644
+--- a/kern/startup.c
++++ b/kern/startup.c
+@@ -79,6 +79,7 @@ boolean_t reboot_on_panic = TRUE;
+ /* XX */
+ extern vm_offset_t phys_first_addr, phys_last_addr;
+ extern char *kernel_cmdline;
++extern void intr_thread();
+
+ /*
+ * Running in virtual memory, on the interrupt stack.
+@@ -221,6 +222,9 @@ void start_kernel_threads(void)
+ (void) kernel_thread(kernel_task, reaper_thread, (char *) 0);
+ (void) kernel_thread(kernel_task, swapin_thread, (char *) 0);
+ (void) kernel_thread(kernel_task, sched_thread, (char *) 0);
++#ifndef MACH_XEN
++ (void) kernel_thread(kernel_task, intr_thread, (char *)0);
++#endif /* MACH_XEN */
+
+ #if NCPUS > 1
+ /*
+diff --git a/linux/dev/arch/i386/kernel/irq.c b/linux/dev/arch/i386/kernel/irq.c
+index 7753814..b7dfa1a 100644
+--- a/linux/dev/arch/i386/kernel/irq.c
++++ b/linux/dev/arch/i386/kernel/irq.c
+@@ -83,6 +83,7 @@ struct linux_action
+ void *dev_id;
+ struct linux_action *next;
+ unsigned long flags;
++ volatile ipc_port_t delivery_port;
+ };
+
+ static struct linux_action *irq_action[16] =
+@@ -102,6 +103,7 @@ linux_intr (int irq)
+ {
+ struct pt_regs regs;
+ struct linux_action *action = *(irq_action + irq);
++ struct linux_action **prev = &irq_action[irq];
+ unsigned long flags;
+
+ kstat.interrupts[irq]++;
+@@ -113,7 +115,37 @@ linux_intr (int irq)
+
+ while (action)
+ {
+- action->handler (irq, action->dev_id, &regs);
++ // TODO I might need to check whether the interrupt belongs to
++ // the current device. But I don't do it for now.
++ if (action->delivery_port)
++ {
++ /* The reference of the port was increased
++ * when the port was installed.
++ * If the reference is 1, it means the port should
++ * have been destroyed and I destroy it now. */
++ if (action->delivery_port
++ && action->delivery_port->ip_references == 1)
++ {
++ mark_intr_removed (irq, action->delivery_port);
++ ipc_port_release (action->delivery_port);
++ *prev = action->next;
++ printk ("irq handler %d: release an dead delivery port\n", irq);
++ linux_kfree(action);
++ action = *prev;
++ continue;
++ }
++ else
++ {
++ /* We disable the irq here and it will be enabled
++ * after the interrupt is handled by the user space driver. */
++ disable_irq (irq);
++ queue_intr (irq, action->delivery_port);
++ }
++
++ }
++ else if (action->handler)
++ action->handler (irq, action->dev_id, &regs);
++ prev = &action->next;
+ action = action->next;
+ }
+
+@@ -233,6 +265,7 @@ setup_x86_irq (int irq, struct linux_action *new)
+ }
+ while (old);
+ shared = 1;
++ printk("store a new irq %d\n", irq);
+ }
+
+ save_flags (flags);
+@@ -250,6 +283,51 @@ setup_x86_irq (int irq, struct linux_action *new)
+ return 0;
+ }
+
++int
++install_user_intr_handler (unsigned int irq, unsigned long flags,
++ ipc_port_t dest)
++{
++ struct linux_action *action;
++ struct linux_action *old;
++ int retval;
++
++ assert (irq < 16);
++
++ /* Test whether the irq handler has been set */
++ // TODO I need to protect the array when iterating it.
++ old = irq_action[irq];
++ while (old)
++ {
++ if (old->delivery_port == dest)
++ {
++ printk ("The interrupt handler has been installed on line %d", irq);
++ return linux_to_mach_error (-EAGAIN);
++ }
++ old = old->next;
++ }
++
++ /*
++ * Hmm... Should I use `kalloc()' ?
++ * By OKUJI Yoshinori.
++ */
++ action = (struct linux_action *)
++ linux_kmalloc (sizeof (struct linux_action), GFP_KERNEL);
++ if (action == NULL)
++ return linux_to_mach_error (-ENOMEM);
++
++ action->handler = NULL;
++ action->next = NULL;
++ action->dev_id = NULL;
++ action->flags = flags;
++ action->delivery_port = dest;
++
++ retval = setup_x86_irq (irq, action);
++ if (retval)
++ linux_kfree (action);
++
++ return linux_to_mach_error (retval);
++}
++
+ /*
+ * Attach a handler to an IRQ.
+ */
+@@ -278,6 +356,7 @@ request_irq (unsigned int irq, void (*handler) (int, void *, struct pt_regs *),
+ action->next = NULL;
+ action->dev_id = dev_id;
+ action->flags = flags;
++ action->delivery_port = NULL;
+
+ retval = setup_x86_irq (irq, action);
+ if (retval)
+diff --git a/linux/dev/drivers/block/genhd.c b/linux/dev/drivers/block/genhd.c
+index 3a86138..4a36f7f 100644
+--- a/linux/dev/drivers/block/genhd.c
++++ b/linux/dev/drivers/block/genhd.c
+@@ -812,7 +812,9 @@ void device_setup(void)
+ #ifdef MACH
+ linux_intr_pri = SPL6;
+ #endif
+- net_dev_init();
++ extern char *kernel_cmdline;
++ if (!strstr(kernel_cmdline, " nonetdev"))
++ net_dev_init();
+ #endif
+ #ifndef MACH
+ console_map_init();
+diff --git a/vm/vm_user.c b/vm/vm_user.c
+index e65f6d5..788f43a 100644
+--- a/vm/vm_user.c
++++ b/vm/vm_user.c
+@@ -449,3 +449,106 @@ kern_return_t vm_wire(port, map, start, size, access)
+ round_page(start+size),
+ access);
+ }
++
++kern_return_t experimental_vm_allocate_contiguous(host_priv, map, result_vaddr, result_paddr, size)
++ host_t host_priv;
++ vm_map_t map;
++ vm_address_t *result_vaddr;
++ vm_address_t *result_paddr;
++ vm_size_t size;
++{
++ unsigned int npages;
++ unsigned int i;
++ unsigned int order;
++ vm_page_t pages;
++ vm_object_t object;
++ vm_map_entry_t entry;
++ kern_return_t kr;
++ vm_address_t vaddr;
++ vm_offset_t offset = 0;
++
++ if (host_priv == HOST_NULL)
++ return KERN_INVALID_HOST;
++
++ if (map == VM_MAP_NULL)
++ return KERN_INVALID_TASK;
++
++ /*
++ * XXX The page allocator returns blocks with a power-of-two size.
++ * The requested size may not be a power-of-two, causing the pages
++ * at the end of a block to be unused. In order to keep track of
++ * those pages, they must all be inserted in the VM object created
++ * by this function.
++ */
++ order = vm_page_order(size);
++ size = (1 << (order + PAGE_SHIFT));
++
++ /* We allocate the contiguous physical pages for the buffer. */
++
++ npages = size / PAGE_SIZE;
++ pages = vm_page_grab_contig(size, VM_PAGE_SEL_DIRECTMAP);
++ if (pages == NULL)
++ {
++ return KERN_RESOURCE_SHORTAGE;
++ }
++
++#if 0
++ kr = vm_page_grab_contig(npages, pages, NULL, TRUE);
++ if (kr)
++ {
++ kfree (pages, npages * sizeof (vm_page_t));
++ return kr;
++ }
++#endif
++
++ /* Allocate the object
++ * and find the virtual address for the DMA buffer */
++
++ object = vm_object_allocate(size);
++ vm_map_lock(map);
++ /* TODO user_wired_count might need to be set as 1 */
++ kr = vm_map_find_entry(map, &vaddr, size, (vm_offset_t) 0,
++ VM_OBJECT_NULL, &entry);
++ if (kr != KERN_SUCCESS)
++ {
++ vm_map_unlock(map);
++ vm_object_deallocate(object);
++ vm_page_free_contig(pages, size);
++ return kr;
++ }
++
++ entry->object.vm_object = object;
++ entry->offset = 0;
++
++ /* We can unlock map now. */
++ vm_map_unlock(map);
++
++ /* We have physical pages we need and now we need to do the mapping. */
++
++ pmap_pageable (map->pmap, vaddr, vaddr + size, FALSE);
++
++ *result_vaddr = vaddr;
++ *result_paddr = pages->phys_addr;
++
++ for (i = 0; i < npages; i++)
++ {
++ vm_object_lock(object);
++ vm_page_lock_queues();
++ vm_page_insert(&pages[i], object, offset);
++ vm_page_wire(&pages[i]);
++ vm_page_unlock_queues();
++ vm_object_unlock(object);
++
++ /* Enter it in the kernel pmap */
++ PMAP_ENTER(map->pmap, vaddr, &pages[i], VM_PROT_DEFAULT, TRUE);
++
++ vm_object_lock(object);
++ PAGE_WAKEUP_DONE(&pages[i]);
++ vm_object_unlock(object);
++
++ vaddr += PAGE_SIZE;
++ offset += PAGE_SIZE;
++ }
++
++ return KERN_SUCCESS;
++}
+--
+2.1.4
+
diff --git a/debian/patches/700002-Disable-disabling-the-irq-via-device_intr_enable.patch b/debian/patches/700002-Disable-disabling-the-irq-via-device_intr_enable.patch
new file mode 100644
index 0000000..d3ceaba
--- /dev/null
+++ b/debian/patches/700002-Disable-disabling-the-irq-via-device_intr_enable.patch
@@ -0,0 +1,91 @@
+From f7c2f4ba69c3ae7df8fddcc2969e2c21e109dbd1 Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Thu, 25 Feb 2016 18:56:43 +0100
+Subject: [PATCH gnumach 2/9] Disable disabling the irq via device_intr_enable
+
+---
+ device/ds_routines.c | 9 ++++-----
+ device/intr.c | 3 ++-
+ include/mach/experimental.defs | 22 +++++++++++++++-------
+ 3 files changed, 21 insertions(+), 13 deletions(-)
+
+diff --git a/device/ds_routines.c b/device/ds_routines.c
+index 4f6b345..9d399ee 100644
+--- a/device/ds_routines.c
++++ b/device/ds_routines.c
+@@ -1844,11 +1844,10 @@ experimental_device_intr_enable(ipc_port_t master_port, int line, char status)
+ if (master_port != master_device_port)
+ return D_INVALID_OPERATION;
+
+- if (status)
+- /* TODO: better name for generic-to-arch-specific call */
+- enable_irq (line);
+- else
+- disable_irq (line);
++ if (! status)
++ return D_INVALID_OPERATION;
++
++ enable_irq (line);
+ return 0;
+ #endif /* MACH_XEN */
+ }
+diff --git a/device/intr.c b/device/intr.c
+index 6fca328..02e0bab 100644
+--- a/device/intr.c
++++ b/device/intr.c
+@@ -35,11 +35,12 @@ search_intr (int line, ipc_port_t dest)
+ return NULL;
+ }
+
++void intr_thread (void);
++
+ /* This function can only be used in the interrupt handler. */
+ void
+ queue_intr (int line, ipc_port_t dest)
+ {
+- extern void intr_thread ();
+ struct intr_entry *e;
+
+ cli ();
+diff --git a/include/mach/experimental.defs b/include/mach/experimental.defs
+index ca1eb92..11c51d6 100644
+--- a/include/mach/experimental.defs
++++ b/include/mach/experimental.defs
+@@ -52,19 +52,27 @@ routine device_intr_register(
+ in flags : int;
+ in receive_port : mach_port_send_t
+ );
++/* JW: It doesn't look safe to pass flags through. dde sets
++ * SA_SHIRQ.
++ *
++ * ID seems unused. dde hands in 0.
++ */
+
+ /*
+- * enable/disable the specified line.
++ * enable the specified line.
++ */
++/* Is the disable part actually used at all? -- No. */
++/* AIUI, the kernel IRQ handler should always disable the line; and
++ * the userspace driver only has to reenable it, after acknowledging
++ * and handling the interrupt...
++ *
++ * -- Indeed, and we should change the interface so that the irq is
++ * also re-enabled if the driver crashes.
+ */
+-/* XXX: Naming a function taht can disable something "xxx_enable" is confusing. */
+-/* Is the disable part actually used at all? AIUI, the kernel IRQ handler
+-should always disable the line; and the userspace driver only has to
+-reenable it, after acknowledging and handling the interrupt...
+-*/
+ routine device_intr_enable(
+ master_port : mach_port_t;
+ line : int;
+- status : char);
++ status : char /* MUST be true-ish */);
+
+ /*
+ * This routine is created for allocating DMA buffers.
+--
+2.1.4
+
diff --git a/debian/patches/700003-Rework-comment-on-the-userspace-interrupt-handling.patch b/debian/patches/700003-Rework-comment-on-the-userspace-interrupt-handling.patch
new file mode 100644
index 0000000..8ad50ef
--- /dev/null
+++ b/debian/patches/700003-Rework-comment-on-the-userspace-interrupt-handling.patch
@@ -0,0 +1,284 @@
+From 652cbc1f88f02f92096051a7ce13dcbf77e55fc4 Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Thu, 25 Feb 2016 20:54:22 +0100
+Subject: [PATCH gnumach 3/9] Rework/comment on the userspace interrupt
+ handling
+
+---
+ device/ds_routines.c | 8 +++----
+ device/interrupt.h | 14 ++++++++++++
+ device/intr.c | 37 +++++++++++++++---------------
+ kern/startup.c | 2 +-
+ linux/dev/arch/i386/kernel/irq.c | 49 ++++++++++++++++++----------------------
+ 5 files changed, 58 insertions(+), 52 deletions(-)
+ create mode 100644 device/interrupt.h
+
+diff --git a/device/ds_routines.c b/device/ds_routines.c
+index 9d399ee..7a5dda5 100644
+--- a/device/ds_routines.c
++++ b/device/ds_routines.c
+@@ -325,9 +325,7 @@ experimental_device_intr_register (ipc_port_t master_port, int line,
+ #ifdef MACH_XEN
+ return D_INVALID_OPERATION;
+ #else /* MACH_XEN */
+- extern int install_user_intr_handler (unsigned int line,
+- unsigned long flags,
+- ipc_port_t dest);
++ struct intr_entry *entry;
+ io_return_t ret;
+
+ /* Open must be called on the master device port. */
+@@ -338,13 +336,13 @@ experimental_device_intr_register (ipc_port_t master_port, int line,
+ if (line < 0 || line >= 16)
+ return D_INVALID_OPERATION;
+
+- ret = insert_intr_entry (line, receive_port);
++ ret = insert_intr_entry (line, receive_port, &entry);
+ if (ret)
+ return ret;
+ // TODO The original port should be replaced
+ // when the same device driver calls it again,
+ // in order to handle the case that the device driver crashes and restarts.
+- ret = install_user_intr_handler (line, flags, receive_port);
++ ret = install_user_intr_handler (line, flags, entry);
+
+ /* If the port is installed successfully, increase its reference by 1.
+ * Thus, the port won't be destroyed after its task is terminated. */
+diff --git a/device/interrupt.h b/device/interrupt.h
+new file mode 100644
+index 0000000..0de43c2
+--- /dev/null
++++ b/device/interrupt.h
+@@ -0,0 +1,14 @@
++#ifndef DEVICE_INTERRUPT_H
++#define DEVICE_INTERRUPT_H
++
++struct intr_entry;
++boolean_t queue_intr (struct intr_entry *e);
++int insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry);
++
++int install_user_intr_handler (unsigned int line,
++ unsigned long flags,
++ struct intr_entry *entry);
++
++void intr_thread (void);
++
++#endif /* DEVICE_INTERRUPT_H */
+diff --git a/device/intr.c b/device/intr.c
+index 02e0bab..986f0ee 100644
+--- a/device/intr.c
++++ b/device/intr.c
+@@ -3,6 +3,8 @@
+ #include <kern/queue.h>
+ #include <kern/printf.h>
+
++#include "interrupt.h"
++
+ #ifndef MACH_XEN
+ // TODO this is only for x86 system
+ #define sti() __asm__ __volatile__ ("sti": : :"memory")
+@@ -35,29 +37,35 @@ search_intr (int line, ipc_port_t dest)
+ return NULL;
+ }
+
+-void intr_thread (void);
+-
+ /* This function can only be used in the interrupt handler. */
+-void
+-queue_intr (int line, ipc_port_t dest)
++boolean_t
++queue_intr (struct intr_entry *e)
+ {
+- struct intr_entry *e;
+-
++ /* The reference of the port was increased when the port was
++ * installed. If the reference is 1, it means the port should have
++ * been destroyed and I destroy it now. */
++ if (e->dest && e->dest->ip_references == 1)
++ {
++ ipc_port_release (e->dest);
++ e->dest = NULL;
++ printk ("irq handler %d: release an dead delivery port\n", e->line);
++ return FALSE;
++ }
++
+ cli ();
+- e = search_intr (line, dest);
+- assert (e);
+ e->interrupts++;
+ tot_num_intr++;
+ sti ();
+
+ thread_wakeup ((event_t) &intr_thread);
++ return TRUE;
+ }
+
+ /* insert an interrupt entry in the queue.
+ * This entry exists in the queue until
+ * the corresponding interrupt port is removed.*/
+ int
+-insert_intr_entry (int line, ipc_port_t dest)
++insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
+ {
+ int err = 0;
+ struct intr_entry *e, *new;
+@@ -86,19 +94,10 @@ out:
+ sti ();
+ if (free)
+ kfree ((vm_offset_t) new, sizeof (*new));
++ *entry = new;
+ return err;
+ }
+
+-/* this function should be called when line is disabled. */
+-void mark_intr_removed (int line, ipc_port_t dest)
+-{
+- struct intr_entry *e;
+-
+- e = search_intr (line, dest);
+- if (e)
+- e->dest = NULL;
+-}
+-
+ void
+ intr_thread ()
+ {
+diff --git a/kern/startup.c b/kern/startup.c
+index 05de5e6..0a571ff 100644
+--- a/kern/startup.c
++++ b/kern/startup.c
+@@ -62,6 +62,7 @@
+ #include <machine/model_dep.h>
+ #include <mach/version.h>
+ #include <device/device_init.h>
++#include <device/interrupt.h>
+
+ #if MACH_KDB
+ #include <device/cons.h>
+@@ -79,7 +80,6 @@ boolean_t reboot_on_panic = TRUE;
+ /* XX */
+ extern vm_offset_t phys_first_addr, phys_last_addr;
+ extern char *kernel_cmdline;
+-extern void intr_thread();
+
+ /*
+ * Running in virtual memory, on the interrupt stack.
+diff --git a/linux/dev/arch/i386/kernel/irq.c b/linux/dev/arch/i386/kernel/irq.c
+index b7dfa1a..15f95c3 100644
+--- a/linux/dev/arch/i386/kernel/irq.c
++++ b/linux/dev/arch/i386/kernel/irq.c
+@@ -49,6 +49,7 @@
+
+ #include <linux/dev/glue/glue.h>
+ #include <machine/machspl.h>
++#include <device/interrupt.h>
+
+ #if 0
+ /* XXX: This is the way it's done in linux 2.2. GNU Mach currently uses intr_count. It should be made using local_{bh/irq}_count instead (through hardirq_enter/exit) for SMP support. */
+@@ -83,7 +84,7 @@ struct linux_action
+ void *dev_id;
+ struct linux_action *next;
+ unsigned long flags;
+- volatile ipc_port_t delivery_port;
++ struct intr_entry *userspace_handler;
+ };
+
+ static struct linux_action *irq_action[16] =
+@@ -117,31 +118,19 @@ linux_intr (int irq)
+ {
+ // TODO I might need to check whether the interrupt belongs to
+ // the current device. But I don't do it for now.
+- if (action->delivery_port)
++ if (action->userspace_handler)
+ {
+- /* The reference of the port was increased
+- * when the port was installed.
+- * If the reference is 1, it means the port should
+- * have been destroyed and I destroy it now. */
+- if (action->delivery_port
+- && action->delivery_port->ip_references == 1)
+- {
+- mark_intr_removed (irq, action->delivery_port);
+- ipc_port_release (action->delivery_port);
+- *prev = action->next;
+- printk ("irq handler %d: release an dead delivery port\n", irq);
+- linux_kfree(action);
+- action = *prev;
+- continue;
+- }
+- else
+- {
+ /* We disable the irq here and it will be enabled
+ * after the interrupt is handled by the user space driver. */
+ disable_irq (irq);
+- queue_intr (irq, action->delivery_port);
+- }
+-
++ if (! queue_intr (action->userspace_handler))
++ {
++ *prev = action->next;
++ linux_kfree(action);
++ action = *prev;
++ enable_irq (irq);
++ continue;
++ }
+ }
+ else if (action->handler)
+ action->handler (irq, action->dev_id, &regs);
+@@ -285,26 +274,32 @@ setup_x86_irq (int irq, struct linux_action *new)
+
+ int
+ install_user_intr_handler (unsigned int irq, unsigned long flags,
+- ipc_port_t dest)
++ struct intr_entry *entry)
+ {
+ struct linux_action *action;
++#if 0
+ struct linux_action *old;
++#endif
+ int retval;
+
+ assert (irq < 16);
+
+- /* Test whether the irq handler has been set */
++#if 0
++ /* Test whether the irq handler has already been set. */
++ /* JW: Actually, that cannot happen. We test for that in
++ device_intr_register before calling this function. */
+ // TODO I need to protect the array when iterating it.
+ old = irq_action[irq];
+ while (old)
+ {
+- if (old->delivery_port == dest)
++ if (old->delivery_port == entry->dest)
+ {
+ printk ("The interrupt handler has been installed on line %d", irq);
+ return linux_to_mach_error (-EAGAIN);
+ }
+ old = old->next;
+ }
++#endif
+
+ /*
+ * Hmm... Should I use `kalloc()' ?
+@@ -319,7 +314,7 @@ install_user_intr_handler (unsigned int irq, unsigned long flags,
+ action->next = NULL;
+ action->dev_id = NULL;
+ action->flags = flags;
+- action->delivery_port = dest;
++ action->userspace_handler = entry;
+
+ retval = setup_x86_irq (irq, action);
+ if (retval)
+@@ -356,7 +351,7 @@ request_irq (unsigned int irq, void (*handler) (int, void *, struct pt_regs *),
+ action->next = NULL;
+ action->dev_id = dev_id;
+ action->flags = flags;
+- action->delivery_port = NULL;
++ action->userspace_handler = NULL;
+
+ retval = setup_x86_irq (irq, action);
+ if (retval)
+--
+2.1.4
+
diff --git a/debian/patches/700004-Some-cleanups-of-the-userspace-interrupt-handling.patch b/debian/patches/700004-Some-cleanups-of-the-userspace-interrupt-handling.patch
new file mode 100644
index 0000000..3a0f341
--- /dev/null
+++ b/debian/patches/700004-Some-cleanups-of-the-userspace-interrupt-handling.patch
@@ -0,0 +1,169 @@
+From e1e25cd0a5f5778cf4f1e83321c8d081e2067683 Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Thu, 25 Feb 2016 22:38:40 +0100
+Subject: [PATCH gnumach 4/9] Some cleanups of the userspace interrupt handling
+
+---
+ device/intr.c | 93 +++++++++++++++++++++++++++++------------------------------
+ 1 file changed, 46 insertions(+), 47 deletions(-)
+
+diff --git a/device/intr.c b/device/intr.c
+index 986f0ee..177c095 100644
+--- a/device/intr.c
++++ b/device/intr.c
+@@ -25,18 +25,6 @@ static queue_head_t intr_queue;
+ /* The total number of unprocessed interrupts. */
+ static int tot_num_intr;
+
+-static struct intr_entry *
+-search_intr (int line, ipc_port_t dest)
+-{
+- struct intr_entry *e;
+- queue_iterate (&intr_queue, e, struct intr_entry *, chain)
+- {
+- if (e->dest == dest && e->line == line)
+- return e;
+- }
+- return NULL;
+-}
+-
+ /* This function can only be used in the interrupt handler. */
+ boolean_t
+ queue_intr (struct intr_entry *e)
+@@ -46,9 +34,10 @@ queue_intr (struct intr_entry *e)
+ * been destroyed and I destroy it now. */
+ if (e->dest && e->dest->ip_references == 1)
+ {
++ /* JW: I don't like running this from an interrupt handler. */
+ ipc_port_release (e->dest);
+ e->dest = NULL;
+- printk ("irq handler %d: release an dead delivery port\n", e->line);
++ printf ("irq handler %d: release an dead delivery port\n", e->line);
+ return FALSE;
+ }
+
+@@ -74,21 +63,22 @@ insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
+ new = (struct intr_entry *) kalloc (sizeof (*new));
+ if (new == NULL)
+ return D_NO_MEMORY;
+-
+- /* check whether the intr entry has been in the queue. */
+- cli ();
+- e = search_intr (line, dest);
+- if (e)
+- {
+- printf ("the interrupt entry for line %d and port %p has been inserted\n",
+- line, dest);
+- free = 1;
+- err = D_ALREADY_OPEN;
+- goto out;
+- }
+ new->line = line;
+ new->dest = dest;
+ new->interrupts = 0;
++
++ /* check whether the intr entry has been in the queue. */
++ cli ();
++ queue_iterate (&intr_queue, e, struct intr_entry *, chain)
++ if (e->dest == dest && e->line == line)
++ {
++ printf ("the interrupt entry for line %d and port %p "
++ "has already been inserted before.\n",
++ line, dest);
++ free = 1;
++ err = D_ALREADY_OPEN;
++ goto out;
++ }
+ queue_enter (&intr_queue, new, struct intr_entry *, chain);
+ out:
+ sti ();
+@@ -98,6 +88,30 @@ out:
+ return err;
+ }
+
++mach_intr_notification_t mach_intr_notification_template;
++
++static void
++init_mach_intr_notification (mach_intr_notification_t *n)
++{
++ mach_msg_header_t *m = &n->intr_header;
++ mach_msg_type_t *t = &n->intr_type;
++
++ m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0);
++ m->msgh_size = sizeof *n;
++ m->msgh_seqno = INTR_NOTIFY_MSGH_SEQNO;
++ m->msgh_local_port = MACH_PORT_NULL;
++ m->msgh_remote_port = MACH_PORT_NULL;
++ m->msgh_id = MACH_INTR_NOTIFY;
++
++ t->msgt_name = MACH_MSG_TYPE_INTEGER_32;
++ t->msgt_size = 32;
++ t->msgt_number = 1;
++ t->msgt_inline = TRUE;
++ t->msgt_longform = FALSE;
++ t->msgt_deallocate = FALSE;
++ t->msgt_unused = 0;
++}
++
+ void
+ intr_thread ()
+ {
+@@ -105,10 +119,10 @@ intr_thread ()
+ int line;
+ ipc_port_t dest;
+ queue_init (&intr_queue);
+-
++ init_mach_intr_notification (&mach_intr_notification_template);
++
+ for (;;)
+ {
+- assert_wait ((event_t) &intr_thread, FALSE);
+ cli ();
+ while (tot_num_intr)
+ {
+@@ -148,7 +162,9 @@ intr_thread ()
+ }
+ }
+ sti ();
+- thread_block (NULL);
++
++ assert_wait ((event_t) &intr_thread, FALSE);
++ thread_block (thread_no_continuation);
+ }
+ }
+
+@@ -163,29 +179,12 @@ deliver_intr (int line, ipc_port_t dest_port)
+ return FALSE;
+
+ kmsg = ikm_alloc(sizeof *n);
+- if (kmsg == IKM_NULL)
++ if (kmsg == IKM_NULL)
+ return FALSE;
+
+ ikm_init(kmsg, sizeof *n);
+ n = (mach_intr_notification_t *) &kmsg->ikm_header;
+-
+- mach_msg_header_t *m = &n->intr_header;
+- mach_msg_type_t *t = &n->intr_type;
+-
+- m->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0);
+- m->msgh_size = sizeof *n;
+- m->msgh_seqno = INTR_NOTIFY_MSGH_SEQNO;
+- m->msgh_local_port = MACH_PORT_NULL;
+- m->msgh_remote_port = MACH_PORT_NULL;
+- m->msgh_id = MACH_INTR_NOTIFY;
+-
+- t->msgt_name = MACH_MSG_TYPE_INTEGER_32;
+- t->msgt_size = 32;
+- t->msgt_number = 1;
+- t->msgt_inline = TRUE;
+- t->msgt_longform = FALSE;
+- t->msgt_deallocate = FALSE;
+- t->msgt_unused = 0;
++ *n = mach_intr_notification_template;
+
+ n->intr_header.msgh_remote_port = dest;
+ n->line = line;
+--
+2.1.4
+
diff --git a/debian/patches/700005-Fix-synchronization.patch b/debian/patches/700005-Fix-synchronization.patch
new file mode 100644
index 0000000..d337731
--- /dev/null
+++ b/debian/patches/700005-Fix-synchronization.patch
@@ -0,0 +1,33 @@
+From 6632518b1183e15f2016ec53088e3f26f151a96d Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Fri, 26 Feb 2016 13:21:12 +0100
+Subject: [PATCH gnumach 5/9] Fix synchronization
+
+---
+ device/intr.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/device/intr.c b/device/intr.c
+index 177c095..1e5a3ea 100644
+--- a/device/intr.c
++++ b/device/intr.c
+@@ -123,6 +123,7 @@ intr_thread ()
+
+ for (;;)
+ {
++ assert_wait ((event_t) &intr_thread, FALSE);
+ cli ();
+ while (tot_num_intr)
+ {
+@@ -162,8 +163,6 @@ intr_thread ()
+ }
+ }
+ sti ();
+-
+- assert_wait ((event_t) &intr_thread, FALSE);
+ thread_block (thread_no_continuation);
+ }
+ }
+--
+2.1.4
+
diff --git a/debian/patches/700006-Reorder.patch b/debian/patches/700006-Reorder.patch
new file mode 100644
index 0000000..d869427
--- /dev/null
+++ b/debian/patches/700006-Reorder.patch
@@ -0,0 +1,90 @@
+From 552d46db26f7c90b178eaa9be45bba8d72875d76 Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Fri, 26 Feb 2016 13:27:28 +0100
+Subject: [PATCH gnumach 6/9] Reorder
+
+---
+ device/intr.c | 55 +++++++++++++++++++++++++++----------------------------
+ 1 file changed, 27 insertions(+), 28 deletions(-)
+
+diff --git a/device/intr.c b/device/intr.c
+index 1e5a3ea..b0dcd83 100644
+--- a/device/intr.c
++++ b/device/intr.c
+@@ -10,8 +10,6 @@
+ #define sti() __asm__ __volatile__ ("sti": : :"memory")
+ #define cli() __asm__ __volatile__ ("cli": : :"memory")
+
+-static boolean_t deliver_intr (int line, ipc_port_t dest_port);
+-
+ struct intr_entry
+ {
+ queue_chain_t chain;
+@@ -112,6 +110,33 @@ init_mach_intr_notification (mach_intr_notification_t *n)
+ t->msgt_unused = 0;
+ }
+
++static boolean_t
++deliver_intr (int line, ipc_port_t dest_port)
++{
++ ipc_kmsg_t kmsg;
++ mach_intr_notification_t *n;
++ mach_port_t dest = (mach_port_t) dest_port;
++
++ if (dest == MACH_PORT_NULL)
++ return FALSE;
++
++ kmsg = ikm_alloc(sizeof *n);
++ if (kmsg == IKM_NULL)
++ return FALSE;
++
++ ikm_init(kmsg, sizeof *n);
++ n = (mach_intr_notification_t *) &kmsg->ikm_header;
++ *n = mach_intr_notification_template;
++
++ n->intr_header.msgh_remote_port = dest;
++ n->line = line;
++
++ ipc_port_copy_send (dest_port);
++ ipc_mqueue_send_always(kmsg);
++
++ return TRUE;
++}
++
+ void
+ intr_thread ()
+ {
+@@ -167,30 +192,4 @@ intr_thread ()
+ }
+ }
+
+-static boolean_t
+-deliver_intr (int line, ipc_port_t dest_port)
+-{
+- ipc_kmsg_t kmsg;
+- mach_intr_notification_t *n;
+- mach_port_t dest = (mach_port_t) dest_port;
+-
+- if (dest == MACH_PORT_NULL)
+- return FALSE;
+-
+- kmsg = ikm_alloc(sizeof *n);
+- if (kmsg == IKM_NULL)
+- return FALSE;
+-
+- ikm_init(kmsg, sizeof *n);
+- n = (mach_intr_notification_t *) &kmsg->ikm_header;
+- *n = mach_intr_notification_template;
+-
+- n->intr_header.msgh_remote_port = dest;
+- n->line = line;
+-
+- ipc_port_copy_send (dest_port);
+- ipc_mqueue_send_always(kmsg);
+-
+- return TRUE;
+-}
+ #endif /* MACH_XEN */
+--
+2.1.4
+
diff --git a/debian/patches/700007-Use-the-slab-allocator.patch b/debian/patches/700007-Use-the-slab-allocator.patch
new file mode 100644
index 0000000..1e00b0c
--- /dev/null
+++ b/debian/patches/700007-Use-the-slab-allocator.patch
@@ -0,0 +1,63 @@
+From ad33ca5d3fbc25618d26b7af4d9a67be041c779a Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Fri, 26 Feb 2016 13:43:11 +0100
+Subject: [PATCH gnumach 7/9] Use the slab allocator
+
+---
+ device/intr.c | 12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+diff --git a/device/intr.c b/device/intr.c
+index b0dcd83..0fa43c5 100644
+--- a/device/intr.c
++++ b/device/intr.c
+@@ -10,6 +10,9 @@
+ #define sti() __asm__ __volatile__ ("sti": : :"memory")
+ #define cli() __asm__ __volatile__ ("cli": : :"memory")
+
++/* The cache which holds our proxy memory objects. */
++static struct kmem_cache intr_entry_cache;
++
+ struct intr_entry
+ {
+ queue_chain_t chain;
+@@ -58,7 +61,7 @@ insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
+ struct intr_entry *e, *new;
+ int free = 0;
+
+- new = (struct intr_entry *) kalloc (sizeof (*new));
++ new = (struct intr_entry *) kmem_cache_alloc (&intr_entry_cache);
+ if (new == NULL)
+ return D_NO_MEMORY;
+ new->line = line;
+@@ -81,7 +84,7 @@ insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
+ out:
+ sti ();
+ if (free)
+- kfree ((vm_offset_t) new, sizeof (*new));
++ kmem_cache_free (&intr_entry_cache, (vm_offset_t) new);
+ *entry = new;
+ return err;
+ }
+@@ -146,6 +149,9 @@ intr_thread ()
+ queue_init (&intr_queue);
+ init_mach_intr_notification (&mach_intr_notification_template);
+
++ kmem_cache_init (&intr_entry_cache, "intr_entry",
++ sizeof (struct intr_entry), 0, NULL, 0);
++
+ for (;;)
+ {
+ assert_wait ((event_t) &intr_thread, FALSE);
+@@ -183,7 +189,7 @@ intr_thread ()
+ assert (!queue_empty (&intr_queue));
+ queue_remove (&intr_queue, e, struct intr_entry *, chain);
+ sti ();
+- kfree ((vm_offset_t) e, sizeof (*e));
++ kmem_cache_free (&intr_entry_cache, (vm_offset_t) e);
+ cli ();
+ }
+ }
+--
+2.1.4
+
diff --git a/debian/patches/700008-Fix-reference-counting-use-dead-name-notification.patch b/debian/patches/700008-Fix-reference-counting-use-dead-name-notification.patch
new file mode 100644
index 0000000..7e1f8a6
--- /dev/null
+++ b/debian/patches/700008-Fix-reference-counting-use-dead-name-notification.patch
@@ -0,0 +1,371 @@
+From e5921e151ef397b25db7fe85a325728503a77e9b Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Fri, 26 Feb 2016 15:24:45 +0100
+Subject: [PATCH gnumach 8/9] Fix reference counting; use dead-name
+ notification
+
+---
+ device/ds_routines.c | 15 ++---
+ device/interrupt.h | 4 +-
+ device/intr.c | 168 +++++++++++++++++++++++++++++++++++++--------------
+ kern/ipc_kobject.c | 8 +++
+ kern/ipc_kobject.h | 5 +-
+ 5 files changed, 141 insertions(+), 59 deletions(-)
+
+diff --git a/device/ds_routines.c b/device/ds_routines.c
+index 7a5dda5..2b9869a 100644
+--- a/device/ds_routines.c
++++ b/device/ds_routines.c
+@@ -87,6 +87,7 @@
+ #include <device/dev_hdr.h>
+ #include <device/conf.h>
+ #include <device/io_req.h>
++#include <device/interrupt.h>
+ #include <device/ds_routines.h>
+ #include <device/net_status.h>
+ #include <device/device_port.h>
+@@ -332,6 +333,9 @@ experimental_device_intr_register (ipc_port_t master_port, int line,
+ if (master_port != master_device_port)
+ return D_INVALID_OPERATION;
+
++ if (receive_port == MACH_PORT_NULL)
++ return D_INVALID_OPERATION;
++
+ /* XXX: move to arch-specific */
+ if (line < 0 || line >= 16)
+ return D_INVALID_OPERATION;
+@@ -339,17 +343,8 @@ experimental_device_intr_register (ipc_port_t master_port, int line,
+ ret = insert_intr_entry (line, receive_port, &entry);
+ if (ret)
+ return ret;
+- // TODO The original port should be replaced
+- // when the same device driver calls it again,
+- // in order to handle the case that the device driver crashes and restarts.
+- ret = install_user_intr_handler (line, flags, entry);
+-
+- /* If the port is installed successfully, increase its reference by 1.
+- * Thus, the port won't be destroyed after its task is terminated. */
+- if (ret == 0)
+- ip_reference (receive_port);
+
+- return ret;
++ return install_user_intr_handler (line, flags, entry);
+ #endif /* MACH_XEN */
+ }
+
+diff --git a/device/interrupt.h b/device/interrupt.h
+index 0de43c2..8adc02d 100644
+--- a/device/interrupt.h
++++ b/device/interrupt.h
+@@ -3,12 +3,14 @@
+
+ struct intr_entry;
+ boolean_t queue_intr (struct intr_entry *e);
+-int insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry);
++kern_return_t insert_intr_entry (int line, ipc_port_t dest,
++ struct intr_entry **entry);
+
+ int install_user_intr_handler (unsigned int line,
+ unsigned long flags,
+ struct intr_entry *entry);
+
++boolean_t intr_entry_notify (mach_msg_header_t *msg);
+ void intr_thread (void);
+
+ #endif /* DEVICE_INTERRUPT_H */
+diff --git a/device/intr.c b/device/intr.c
+index 0fa43c5..7a1eccb 100644
+--- a/device/intr.c
++++ b/device/intr.c
+@@ -1,7 +1,9 @@
+ #include <device/intr.h>
+ #include <device/ds_routines.h>
++#include <ipc/ipc_space.h>
+ #include <kern/queue.h>
+ #include <kern/printf.h>
++#include <mach/notify.h>
+
+ #include "interrupt.h"
+
+@@ -15,12 +17,14 @@ static struct kmem_cache intr_entry_cache;
+
+ struct intr_entry
+ {
++ ipc_port_t port; /* We receive notifications on this port. */
+ queue_chain_t chain;
+ ipc_port_t dest;
+ int line;
+ /* The number of interrupts occur since last run of intr_thread. */
+ int interrupts;
+ };
++typedef struct intr_entry *intr_entry_t;
+
+ static queue_head_t intr_queue;
+ /* The total number of unprocessed interrupts. */
+@@ -30,18 +34,6 @@ static int tot_num_intr;
+ boolean_t
+ queue_intr (struct intr_entry *e)
+ {
+- /* The reference of the port was increased when the port was
+- * installed. If the reference is 1, it means the port should have
+- * been destroyed and I destroy it now. */
+- if (e->dest && e->dest->ip_references == 1)
+- {
+- /* JW: I don't like running this from an interrupt handler. */
+- ipc_port_release (e->dest);
+- e->dest = NULL;
+- printf ("irq handler %d: release an dead delivery port\n", e->line);
+- return FALSE;
+- }
+-
+ cli ();
+ e->interrupts++;
+ tot_num_intr++;
+@@ -54,20 +46,58 @@ queue_intr (struct intr_entry *e)
+ /* insert an interrupt entry in the queue.
+ * This entry exists in the queue until
+ * the corresponding interrupt port is removed.*/
+-int
++kern_return_t
+ insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
+ {
+- int err = 0;
++ kern_return_t err = 0;
+ struct intr_entry *e, *new;
+ int free = 0;
++ ipc_port_t dnnotify;
++ ipc_port_request_index_t dnindex;
+
+ new = (struct intr_entry *) kmem_cache_alloc (&intr_entry_cache);
+ if (new == NULL)
+ return D_NO_MEMORY;
++
++ /* Allocate port, keeping a reference for it. */
++ new->port = ipc_port_alloc_kernel ();
++ if (new->port == IP_NULL)
++ {
++ kmem_cache_free (&intr_entry_cache, (vm_offset_t) new);
++ return KERN_RESOURCE_SHORTAGE;
++ }
++
++ /* Associate the port with the object. */
++ ipc_kobject_set (new->port, (ipc_kobject_t) new, IKOT_INTR_ENTRY);
++
+ new->line = line;
+ new->dest = dest;
+ new->interrupts = 0;
+
++ /* Register a dead-name notification so that we are notified if the
++ userspace handler dies. */
++ dnnotify = ipc_port_make_sonce (new->port);
++ ip_lock (dest);
++ /* We use a bogus port name. We don't need it to distinguish the
++ notifications because we register just one per object. */
++ retry:
++ err = ipc_port_dnrequest (dest, (mach_port_t) 1, dnnotify, &dnindex);
++ if (err)
++ {
++ err = ipc_port_dngrow (dest);
++ /* dest is unlocked */
++ if (err != KERN_SUCCESS)
++ {
++ ipc_port_release_sonce (dnnotify);
++ kmem_cache_free (&intr_entry_cache, (vm_offset_t) new);
++ return err;
++ }
++ ip_lock (dest);
++ goto retry;
++ }
++ /* dest is locked. dnindex is only valid until we unlock it and we
++ might decide to cancel. */
++
+ /* check whether the intr entry has been in the queue. */
+ cli ();
+ queue_iterate (&intr_queue, e, struct intr_entry *, chain)
+@@ -84,11 +114,74 @@ insert_intr_entry (int line, ipc_port_t dest, struct intr_entry **entry)
+ out:
+ sti ();
+ if (free)
+- kmem_cache_free (&intr_entry_cache, (vm_offset_t) new);
++ {
++ ipc_port_dncancel (new->dest, (mach_port_t) 1, dnindex);
++ ip_unlock (new->dest);
++ ipc_port_release_sonce (dnnotify);
++ ipc_port_dealloc_kernel (new->port);
++ ipc_port_release_send (new->dest);
++ kmem_cache_free (&intr_entry_cache, (vm_offset_t) new);
++ }
++ else
++ ip_unlock (new->dest);
+ *entry = new;
+ return err;
+ }
+
++/* Lookup a intr_entry object by its port. */
++static intr_entry_t
++intr_entry_port_lookup (ipc_port_t port)
++{
++ struct intr_entry *entry;
++
++ if (!IP_VALID(port))
++ return 0;
++
++ ip_lock (port);
++ if (ip_active (port) && (ip_kotype (port) == IKOT_INTR_ENTRY))
++ entry = (struct intr_entry *) port->ip_kobject;
++ else
++ entry = 0;
++ ip_unlock (port);
++ return entry;
++}
++
++/* Process a dead-name notification for a userspace interrupt handler
++ notification port. */
++boolean_t
++intr_entry_notify (mach_msg_header_t *msg)
++{
++ if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME)
++ {
++ struct intr_entry *entry;
++ int line;
++ mach_dead_name_notification_t *dn;
++
++ dn = (mach_dead_name_notification_t *) msg;
++ entry = intr_entry_port_lookup
++ ((ipc_port_t) dn->not_header.msgh_remote_port);
++ assert (entry);
++
++ cli ();
++ line = entry->line;
++ assert (!queue_empty (&intr_queue));
++ queue_remove (&intr_queue, entry, struct intr_entry *, chain);
++ sti ();
++
++ ipc_port_dealloc_kernel (entry->port);
++ ipc_port_release_send (entry->dest);
++ kmem_cache_free (&intr_entry_cache, (vm_offset_t) entry);
++
++ printf ("irq handler %d: userspace handler died\n", line);
++ return TRUE;
++ }
++
++ printf ("intr_entry_notify: strange notification %d\n",
++ msg->msgh_id);
++ return FALSE;
++}
++
++
+ mach_intr_notification_t mach_intr_notification_template;
+
+ static void
+@@ -156,43 +249,26 @@ intr_thread ()
+ {
+ assert_wait ((event_t) &intr_thread, FALSE);
+ cli ();
+- while (tot_num_intr)
+- {
+- int del = 0;
+
+- queue_iterate (&intr_queue, e, struct intr_entry *, chain)
++ while (tot_num_intr)
++ queue_iterate (&intr_queue, e, struct intr_entry *, chain)
++ if (e->interrupts)
+ {
+- /* if an entry doesn't have dest port,
+- * we should remove it. */
+- if (e->dest == NULL)
+- {
+- del = 1;
+- break;
+- }
+-
+- if (e->interrupts)
+- {
+- line = e->line;
+- dest = e->dest;
+- e->interrupts--;
+- tot_num_intr--;
+-
+- sti ();
+- deliver_intr (line, dest);
+- cli ();
+- }
+- }
++ line = e->line;
++ dest = e->dest;
++ e->interrupts--;
++ tot_num_intr--;
+
+- /* remove the entry without dest port from the queue and free it. */
+- if (del)
+- {
+- assert (!queue_empty (&intr_queue));
+- queue_remove (&intr_queue, e, struct intr_entry *, chain);
+ sti ();
+- kmem_cache_free (&intr_entry_cache, (vm_offset_t) e);
++ deliver_intr (line, dest);
+ cli ();
++
++ /* We cannot assume that e still exists at this point
++ because we released the lock. Hence we restart the
++ iteration. */
++ break;
+ }
+- }
++
+ sti ();
+ thread_block (thread_no_continuation);
+ }
+diff --git a/kern/ipc_kobject.c b/kern/ipc_kobject.c
+index c65458b..97c632a 100644
+--- a/kern/ipc_kobject.c
++++ b/kern/ipc_kobject.c
+@@ -48,6 +48,7 @@
+ #include <vm/vm_object.h>
+ #include <vm/memory_object_proxy.h>
+ #include <device/ds_routines.h>
++#include <device/interrupt.h>
+
+ #include <kern/mach.server.h>
+ #include <ipc/mach_port.server.h>
+@@ -326,6 +327,10 @@ ipc_kobject_destroy(
+ vm_object_pager_wakeup(port);
+ break;
+
++ case IKOT_INTR_ENTRY:
++ /* Do nothing. */
++ break;
++
+ default:
+ #if MACH_ASSERT
+ printf("ipc_kobject_destroy: port 0x%p, kobj 0x%lx, type %d\n",
+@@ -368,6 +373,9 @@ ipc_kobject_notify(request_header, reply_header)
+ case IKOT_PAGER_PROXY:
+ return memory_object_proxy_notify(request_header);
+
++ case IKOT_INTR_ENTRY:
++ return intr_entry_notify(request_header);
++
+ default:
+ return FALSE;
+ }
+diff --git a/kern/ipc_kobject.h b/kern/ipc_kobject.h
+index 606a66a..6aefea7 100644
+--- a/kern/ipc_kobject.h
++++ b/kern/ipc_kobject.h
+@@ -77,9 +77,10 @@ typedef unsigned int ipc_kobject_type_t;
+ #define IKOT_CLOCK 25
+ #define IKOT_CLOCK_CTRL 26
+ #define IKOT_PAGER_PROXY 27
++#define IKOT_INTR_ENTRY 28
+ /* << new entries here */
+-#define IKOT_UNKNOWN 28 /* magic catchall */
+-#define IKOT_MAX_TYPE 29 /* # of IKOT_ types */
++#define IKOT_UNKNOWN 29 /* magic catchall */
++#define IKOT_MAX_TYPE 30 /* # of IKOT_ types */
+ /* Please keep ipc/ipc_object.c:ikot_print_array up to date */
+
+ #define is_ipc_kobject(ikot) (ikot != IKOT_NONE)
+--
+2.1.4
+
diff --git a/debian/patches/700009-Fix-xen-build.patch b/debian/patches/700009-Fix-xen-build.patch
new file mode 100644
index 0000000..fcf6e56
--- /dev/null
+++ b/debian/patches/700009-Fix-xen-build.patch
@@ -0,0 +1,37 @@
+From 7debcbf8fb5b5b99e5a0b48ec6e9672455237938 Mon Sep 17 00:00:00 2001
+From: Justus Winter <justus@gnupg.org>
+Date: Fri, 26 Feb 2016 15:32:12 +0100
+Subject: [PATCH gnumach 9/9] Fix xen build
+
+---
+ device/intr.c | 9 +++++++++
+ 1 file changed, 9 insertions(+)
+
+diff --git a/device/intr.c b/device/intr.c
+index 7a1eccb..a061d5e 100644
+--- a/device/intr.c
++++ b/device/intr.c
+@@ -1,6 +1,7 @@
+ #include <device/intr.h>
+ #include <device/ds_routines.h>
+ #include <ipc/ipc_space.h>
++#include <kern/debug.h>
+ #include <kern/queue.h>
+ #include <kern/printf.h>
+ #include <mach/notify.h>
+@@ -274,4 +275,12 @@ intr_thread ()
+ }
+ }
+
++#else /* MACH_XEN */
++
++boolean_t
++intr_entry_notify (mach_msg_header_t *msg)
++{
++ panic ("not reached");
++}
++
+ #endif /* MACH_XEN */
+--
+2.1.4
+
diff --git a/debian/patches/series b/debian/patches/series
index 8f9b1c3..af12166 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -14,3 +14,12 @@ sysenter0001-yyy-sysenter-prototype.patch
#vm-cache-policy0003-vm-evict-clean-pages-first.patch
vm-cache-policy0001-VM-cache-policy-change.patch
vm-cache-policy0002-Fix-page-cache-accounting.patch
+700001-70_dde.patch.patch
+700002-Disable-disabling-the-irq-via-device_intr_enable.patch
+700003-Rework-comment-on-the-userspace-interrupt-handling.patch
+700004-Some-cleanups-of-the-userspace-interrupt-handling.patch
+700005-Fix-synchronization.patch
+700006-Reorder.patch
+700007-Use-the-slab-allocator.patch
+700008-Fix-reference-counting-use-dead-name-notification.patch
+700009-Fix-xen-build.patch