From 87857e6c2d33aecd30ddbf2538170e2e51a901ba Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Fri, 26 Feb 2016 15:32:22 +0100 Subject: add patch series --- debian/patches/700001-70_dde.patch.patch | 819 +++++++++++++++++++++ ...-disabling-the-irq-via-device_intr_enable.patch | 91 +++ ...mment-on-the-userspace-interrupt-handling.patch | 284 +++++++ ...anups-of-the-userspace-interrupt-handling.patch | 169 +++++ debian/patches/700005-Fix-synchronization.patch | 33 + debian/patches/700006-Reorder.patch | 90 +++ debian/patches/700007-Use-the-slab-allocator.patch | 63 ++ ...rence-counting-use-dead-name-notification.patch | 371 ++++++++++ debian/patches/700009-Fix-xen-build.patch | 37 + debian/patches/series | 9 + 10 files changed, 1966 insertions(+) create mode 100644 debian/patches/700001-70_dde.patch.patch create mode 100644 debian/patches/700002-Disable-disabling-the-irq-via-device_intr_enable.patch create mode 100644 debian/patches/700003-Rework-comment-on-the-userspace-interrupt-handling.patch create mode 100644 debian/patches/700004-Some-cleanups-of-the-userspace-interrupt-handling.patch create mode 100644 debian/patches/700005-Fix-synchronization.patch create mode 100644 debian/patches/700006-Reorder.patch create mode 100644 debian/patches/700007-Use-the-slab-allocator.patch create mode 100644 debian/patches/700008-Fix-reference-counting-use-dead-name-notification.patch create mode 100644 debian/patches/700009-Fix-xen-build.patch (limited to 'debian/patches') 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 +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 ++#include ++#include ++#include ++ ++#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 ++ ++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 ++#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 ++ ); ++ ++/* ++ * 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 +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 + #include + #include ++#include + + #if MACH_DEBUG + #include +@@ -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, ®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->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, ®s); ++ 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 +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 +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 + #include + ++#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 + #include + #include ++#include + + #if MACH_KDB + #include +@@ -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 + #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,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, ®s); +@@ -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 +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 +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 +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 +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 +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 + #include + #include ++#include + #include + #include + #include +@@ -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 + #include ++#include + #include + #include ++#include + + #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 + #include + #include ++#include + + #include + #include +@@ -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 +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 + #include + #include ++#include + #include + #include + #include +@@ -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 -- cgit v1.2.3