From 24c248bd7588ef4d9519b3496a0a32d1d05cb2ca Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Fri, 15 Apr 2016 11:49:03 +0200 Subject: add patch series --- debian/patches/700001-70_new_dde.patch.patch | 1016 ++++++++++++++++++++++++++ debian/patches/700002-Port-Samuels-fix.patch | 27 + debian/patches/series | 2 + 3 files changed, 1045 insertions(+) create mode 100644 debian/patches/700001-70_new_dde.patch.patch create mode 100644 debian/patches/700002-Port-Samuels-fix.patch (limited to 'debian/patches') diff --git a/debian/patches/700001-70_new_dde.patch.patch b/debian/patches/700001-70_new_dde.patch.patch new file mode 100644 index 0000000..dc5fda3 --- /dev/null +++ b/debian/patches/700001-70_new_dde.patch.patch @@ -0,0 +1,1016 @@ +From 2c56b26fa46c2b294c01791632d4e1b9c6fc4d94 Mon Sep 17 00:00:00 2001 +From: Justus Winter +Date: Thu, 25 Feb 2016 18:46:32 +0100 +Subject: [PATCH gnumach 1/2] 70_new_dde.patch + +--- + Makefrag.am | 9 ++ + device/ds_routines.c | 27 ++++ + device/interrupt.h | 34 ++++ + device/intr.c | 341 +++++++++++++++++++++++++++++++++++++++ + include/device/intr.h | 18 +++ + include/mach/experimental.defs | 98 +++++++++++ + ipc/ipc_object.c | 3 +- + kern/experimental.srv | 3 + + kern/ipc_kobject.c | 11 ++ + kern/ipc_kobject.h | 5 +- + kern/startup.c | 4 + + linux/dev/arch/i386/kernel/irq.c | 66 +++++++- + linux/dev/drivers/block/genhd.c | 4 +- + vm/vm_user.c | 103 ++++++++++++ + 14 files changed, 721 insertions(+), 5 deletions(-) + create mode 100644 device/interrupt.h + 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 6ffc8cc..47f3a37 100644 +--- a/Makefrag.am ++++ b/Makefrag.am +@@ -222,6 +222,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 +@@ -306,6 +307,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 \ +@@ -354,6 +356,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 +@@ -376,6 +379,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 \ +@@ -524,6 +528,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 += \ +@@ -536,6 +541,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 \ +@@ -545,6 +553,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..ec26044 100644 +--- a/device/ds_routines.c ++++ b/device/ds_routines.c +@@ -87,6 +87,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -318,6 +319,26 @@ 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 */ ++ io_return_t ret; ++ ++ /* Open must be called on the master device port. */ ++ if (master_port != master_device_port) ++ return D_INVALID_OPERATION; ++ ++ if (receive_port == IP_NULL) ++ return D_INVALID_OPERATION; ++ ++ return insert_intr_entry (line, receive_port); ++#endif /* MACH_XEN */ ++} ++ + boolean_t + ds_notify (mach_msg_header_t *msg) + { +@@ -1798,6 +1819,12 @@ 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) ++{ ++ return D_INVALID_OPERATION; ++} ++ + struct device_emulation_ops mach_device_emulation_ops = + { + (void*) mach_device_reference, +diff --git a/device/interrupt.h b/device/interrupt.h +new file mode 100644 +index 0000000..855f163 +--- /dev/null ++++ b/device/interrupt.h +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (c) 2016 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 of the License, 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, see . ++ */ ++ ++#ifndef DEVICE_INTERRUPT_H ++#define DEVICE_INTERRUPT_H ++ ++struct intr_entry; ++boolean_t queue_intr (struct intr_entry *e); ++kern_return_t insert_intr_entry (int line, ipc_port_t notification_port); ++ ++boolean_t intr_entry_notify (mach_msg_header_t *msg); ++void intr_thread (void); ++ ++/* linux/dev/arch/i386/kernel/irq.c */ ++int install_user_intr_handler (unsigned int line, ++ unsigned long flags, ++ struct intr_entry *entry); ++int remove_user_intr_handler (unsigned int irq, struct intr_entry *entry); ++ ++#endif /* DEVICE_INTERRUPT_H */ +diff --git a/device/intr.c b/device/intr.c +new file mode 100644 +index 0000000..85915cd +--- /dev/null ++++ b/device/intr.c +@@ -0,0 +1,341 @@ ++/* ++ * Copyright (c) 2010-2016 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 of the License, 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, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "interrupt.h" ++ ++#ifndef MACH_XEN ++ ++/* The cache which holds our proxy memory objects. */ ++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 notification_port; ++ 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; ++ ++/* This function can only be used in the interrupt handler. */ ++boolean_t ++queue_intr (struct intr_entry *e) ++{ ++ unsigned long flags; ++ ++ cpu_intr_save (&flags); ++ e->interrupts++; ++ cpu_intr_restore (flags); ++ ++ 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.*/ ++kern_return_t ++insert_intr_entry (int line, ipc_port_t notification_port) ++{ ++ kern_return_t err = 0; ++ unsigned long flags; ++ struct intr_entry *e, *new; ++ int free = 0; ++ ipc_port_t dnnotify; ++ ipc_port_request_index_t dnindex; ++ ++ /* XXX: move to arch-specific */ ++ if (line < 0 || line >= 16) ++ return D_INVALID_OPERATION; ++ ++ 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->notification_port = notification_port; ++ 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 (notification_port); ++ /* 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 (notification_port, (mach_port_t) 1, dnnotify, &dnindex); ++ if (err) ++ { ++ err = ipc_port_dngrow (notification_port); ++ /* notification_port 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 (notification_port); ++ goto retry; ++ } ++ /* notification_port 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. */ ++ cpu_intr_save (&flags); ++ queue_iterate (&intr_queue, e, struct intr_entry *, chain) ++ if (e->notification_port == notification_port && e->line == line) ++ { ++ printf ("the interrupt entry for line %d and port %p " ++ "has already been inserted before.\n", ++ line, notification_port); ++ free = 1; ++ err = D_ALREADY_OPEN; ++ goto out; ++ } ++ queue_enter (&intr_queue, new, struct intr_entry *, chain); ++ out: ++ cpu_intr_restore (flags); ++ if (free) ++ { ++ ipc_port_dncancel (new->notification_port, (mach_port_t) 1, dnindex); ++ ip_unlock (new->notification_port); ++ ipc_port_release_sonce (dnnotify); ++ ipc_port_dealloc_kernel (new->port); ++ ipc_port_release_send (new->notification_port); ++ kmem_cache_free (&intr_entry_cache, (vm_offset_t) new); ++ } ++ else ++ ip_unlock (new->notification_port); ++ ++ if (! err) ++ err = install_user_intr_handler (line, flags, 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) ++{ ++ struct intr_entry *entry; ++ ++ if (msg->msgh_id == MACH_NOTIFY_NO_SENDERS) ++ { ++ /* XXX uses internal Linux IRQ handling function. */ ++ extern void enable_irq (unsigned int irq_nr); ++ mach_no_senders_notification_t *ns; ++ ++ ns = (mach_no_senders_notification_t *) msg; ++ entry = intr_entry_port_lookup ++ ((ipc_port_t) ns->not_header.msgh_remote_port); ++ assert (entry); ++ ++ enable_irq (entry->line); ++ return TRUE; ++ } ++ else if (msg->msgh_id == MACH_NOTIFY_DEAD_NAME) ++ { ++ int line; ++ mach_dead_name_notification_t *dn; ++ unsigned long flags; ++ ++ dn = (mach_dead_name_notification_t *) msg; ++ entry = intr_entry_port_lookup ++ ((ipc_port_t) dn->not_header.msgh_remote_port); ++ assert (entry); ++ ++ cpu_intr_save (&flags); ++ line = entry->line; ++ assert (!queue_empty (&intr_queue)); ++ queue_remove (&intr_queue, entry, struct intr_entry *, chain); ++ remove_user_intr_handler (entry->line, entry); ++ cpu_intr_restore (flags); ++ ++ ipc_port_dealloc_kernel (entry->port); ++ ipc_port_release_send (entry->notification_port); ++ 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 ++init_mach_intr_notification (mach_intr_notification_t *n) ++{ ++ mach_msg_header_t *m = &n->intr_header; ++ mach_msg_type_t *t = &n->line_type; ++ ++ m->msgh_bits = MACH_MSGH_BITS (MACH_MSG_TYPE_PORT_SEND, ++ MACH_MSG_TYPE_PORT_SEND); ++ 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; ++} ++ ++static boolean_t ++deliver_intr (int line, ipc_port_t notification_port, ipc_port_t interrupt_port) ++{ ++ ipc_kmsg_t kmsg; ++ mach_intr_notification_t *n; ++ ipc_port_t sright, sonce, old; ++ ++ if (notification_port == IP_NULL) ++ return FALSE; ++ ++ if (interrupt_port == IP_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; ++ ++ /* Arrange no-senders notification. */ ++ sright = ipc_port_make_send (interrupt_port); ++ sonce = ipc_port_make_sonce (interrupt_port); ++ ip_lock (interrupt_port); ++ ipc_port_nsrequest (interrupt_port, interrupt_port->ip_mscount, ++ sonce, &old); ++ if (old != IP_NULL) ++ ipc_port_release_sonce (old); ++ ++ n->intr_header.msgh_remote_port = (mach_port_t) notification_port; ++ n->intr_header.msgh_local_port = (mach_port_t) sright; ++ n->line = line; ++ ++ ipc_port_copy_send (notification_port); ++ ipc_mqueue_send_always (kmsg); ++ ++ return TRUE; ++} ++ ++void ++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 (;;) ++ { ++ struct intr_entry *e; ++ unsigned long flags; ++ assert_wait ((event_t) &intr_thread, FALSE); ++ cpu_intr_save (&flags); ++ ++ restart: ++ queue_iterate (&intr_queue, e, struct intr_entry *, chain) ++ if (e->interrupts) ++ { ++ int line = e->line; ++ ipc_port_t notification_port = e->notification_port; ++ ipc_port_t interrupt_port = e->port; ++ ++ assert (e->interrupts == 1); ++ e->interrupts--; ++ ++ cpu_intr_restore (flags); ++ deliver_intr (line, notification_port, interrupt_port); ++ cpu_intr_save (&flags); ++ ++ ++ /* We cannot assume that e still exists at this point ++ because we released the lock. Hence we restart the ++ iteration. */ ++ goto restart; ++ } ++ ++ cpu_intr_restore (flags); ++ thread_block (thread_no_continuation); ++ } ++} ++ ++#else /* MACH_XEN */ ++ ++boolean_t ++intr_entry_notify (mach_msg_header_t *msg) ++{ ++ panic ("not reached"); ++} ++ ++#endif /* MACH_XEN */ +diff --git a/include/device/intr.h b/include/device/intr.h +new file mode 100644 +index 0000000..34798b4 +--- /dev/null ++++ b/include/device/intr.h +@@ -0,0 +1,18 @@ ++#ifndef __INTR_H__ ++ ++#define __INTR_H__ ++ ++#include ++ ++typedef struct ++{ ++ mach_msg_header_t intr_header; ++ mach_msg_type_t line_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..16850df +--- /dev/null ++++ b/include/mach/experimental.defs +@@ -0,0 +1,98 @@ ++/* ++ * 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 ++#include ++ ++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 ++ ); ++/* JW: It doesn't look safe to pass flags through. dde sets ++ * SA_SHIRQ. ++ * ++ * ID seems unused. dde hands in 0. ++ */ ++ ++/* This no longer does anything. */ ++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/ipc/ipc_object.c b/ipc/ipc_object.c +index a6457c3..f77b7f7 100644 +--- a/ipc/ipc_object.c ++++ b/ipc/ipc_object.c +@@ -999,7 +999,8 @@ char *ikot_print_array[IKOT_MAX_TYPE] = { + "(LOCK_SET) ", + "(CLOCK) ", + "(CLOCK_CTRL) ", +- "(PAGER_PROXY) ", /* 27 */ ++ "(PAGER_PROXY) ", ++ "(INTR_ENTRY) ", /* 28 */ + /* << new entries here */ + "(UNKNOWN) " /* magic catchall */ + }; /* Please keep in sync with kern/ipc_kobject.h */ +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 +diff --git a/kern/ipc_kobject.c b/kern/ipc_kobject.c +index 709ec9e..97c632a 100644 +--- a/kern/ipc_kobject.c ++++ b/kern/ipc_kobject.c +@@ -48,6 +48,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -56,6 +57,7 @@ + #include + #include + #include ++#include + + #if MACH_DEBUG + #include +@@ -159,6 +161,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 +173,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 */ +@@ -323,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", +@@ -365,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) +diff --git a/kern/startup.c b/kern/startup.c +index bd29694..0a571ff 100644 +--- a/kern/startup.c ++++ b/kern/startup.c +@@ -62,6 +62,7 @@ + #include + #include + #include ++#include + + #if MACH_KDB + #include +@@ -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..e2c18c7 100644 +--- a/linux/dev/arch/i386/kernel/irq.c ++++ b/linux/dev/arch/i386/kernel/irq.c +@@ -49,6 +49,7 @@ + + #include + #include ++#include + + #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,6 +84,7 @@ struct linux_action + void *dev_id; + struct linux_action *next; + unsigned long flags; ++ struct intr_entry *userspace_handler; + }; + + static struct linux_action *irq_action[16] = +@@ -113,7 +115,17 @@ linux_intr (int irq) + + while (action) + { +- action->handler (irq, action->dev_id, ®s); ++ // TODO I might need to check whether the interrupt belongs to ++ // the current device. But I don't do it for now. ++ if (action->userspace_handler) ++ { ++ /* 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 (action->userspace_handler); ++ } ++ else if (action->handler) ++ action->handler (irq, action->dev_id, ®s); + action = action->next; + } + +@@ -233,6 +245,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 +263,56 @@ setup_x86_irq (int irq, struct linux_action *new) + return 0; + } + ++int ++install_user_intr_handler (unsigned int irq, unsigned long flags, ++ struct intr_entry *entry) ++{ ++ struct linux_action *action; ++ int retval; ++ ++ assert (irq < 16); ++ ++ /* ++ * 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->userspace_handler = entry; ++ ++ retval = setup_x86_irq (irq, action); ++ if (retval) ++ linux_kfree (action); ++ ++ return linux_to_mach_error (retval); ++} ++ ++int ++remove_user_intr_handler (unsigned int irq, struct intr_entry *entry) ++{ ++ struct linux_action *action, **prev; ++ ++ for (prev = &irq_action[irq], action = irq_action[irq]; ++ action; ++ prev = &action->next, action = action->next) ++ if (action->userspace_handler == entry) ++ { ++ *prev = action->next; ++ linux_kfree(action); ++ enable_irq (irq); ++ return 1; ++ } ++ ++ return 0; ++} ++ + /* + * Attach a handler to an IRQ. + */ +@@ -278,6 +341,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->userspace_handler = 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-Port-Samuels-fix.patch b/debian/patches/700002-Port-Samuels-fix.patch new file mode 100644 index 0000000..1074d69 --- /dev/null +++ b/debian/patches/700002-Port-Samuels-fix.patch @@ -0,0 +1,27 @@ +From 56b4a54e8eda7c55e5463feb51150358a9b87686 Mon Sep 17 00:00:00 2001 +From: Justus Winter +Date: Fri, 15 Apr 2016 11:46:58 +0200 +Subject: [PATCH gnumach 2/2] Port Samuels fix + +--- + device/intr.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/device/intr.c b/device/intr.c +index 85915cd..11f0772 100644 +--- a/device/intr.c ++++ b/device/intr.c +@@ -314,6 +314,10 @@ intr_thread () + assert (e->interrupts == 1); + e->interrupts--; + ++ /* The thread might go to sleep while delivering the ++ interrupt, hence we clear our event. */ ++ clear_wait (current_thread (), 0, 0); ++ + cpu_intr_restore (flags); + deliver_intr (line, notification_port, interrupt_port); + cpu_intr_save (&flags); +-- +2.1.4 + diff --git a/debian/patches/series b/debian/patches/series index 4480f3e..cfe9db5 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -9,3 +9,5 @@ task-load.patch reorder-ipc_port.patch sysenter0001-yyy-sysenter-prototype.patch +700001-70_new_dde.patch.patch +700002-Port-Samuels-fix.patch -- cgit v1.2.3