summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Zammit <damien@zamaudio.com>2019-11-11 20:35:17 +1100
committerDamien Zammit <damien@zamaudio.com>2019-11-11 20:42:51 +1100
commitaf33188fc5a13ad7ad8e6160e9bc1884a8d4af29 (patch)
treeff740bbfee86a4ad39cd28292b5114763e9c2dd3
parente45601b0780b2c81a6448cdafd952cb98112b9f4 (diff)
deb base
-rw-r--r--Makefrag.am11
-rw-r--r--configure.ac1
-rw-r--r--device/ds_routines.c55
-rw-r--r--device/ds_routines.h3
-rw-r--r--device/intr.c209
-rw-r--r--device/ramdisk.c160
-rw-r--r--device/ramdisk.h47
-rw-r--r--i386/i386at/conf.c3
-rw-r--r--i386/i386at/interrupt.S7
-rw-r--r--i386/i386at/kd.c4
-rw-r--r--i386/include/mach/i386/fp_reg.h2
-rw-r--r--include/device/intr.h17
-rw-r--r--include/mach/experimental.defs100
-rw-r--r--kern/boot_script.c8
-rw-r--r--kern/bootstrap.c18
-rw-r--r--kern/experimental.srv3
-rw-r--r--kern/ipc_kobject.c3
-rw-r--r--kern/startup.c4
-rw-r--r--linux/dev/arch/i386/kernel/irq.c81
-rw-r--r--linux/src/include/linux/compiler-gcc9.h67
-rw-r--r--version.c.in2
-rw-r--r--vm/vm_map.c3
-rw-r--r--vm/vm_user.c94
23 files changed, 899 insertions, 3 deletions
diff --git a/Makefrag.am b/Makefrag.am
index 754d87e2..f01707fe 100644
--- a/Makefrag.am
+++ b/Makefrag.am
@@ -227,6 +227,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
@@ -311,12 +312,15 @@ 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 \
device/net_io.c \
device/net_io.h \
device/param.h \
+ device/ramdisk.c \
+ device/ramdisk.h \
device/subrs.c \
device/subrs.h \
device/tty.h
@@ -359,6 +363,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
@@ -381,6 +386,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 \
@@ -531,6 +537,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 += \
@@ -543,6 +550,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 \
@@ -552,6 +562,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/configure.ac b/configure.ac
index d4daa932..815f5818 100644
--- a/configure.ac
+++ b/configure.ac
@@ -19,6 +19,7 @@ AC_PREREQ([2.57])
m4_include([version.m4])
AC_INIT([AC_PACKAGE_NAME], [AC_PACKAGE_VERSION], [AC_PACKAGE_BUGREPORT],
[AC_PACKAGE_TARNAME])
+AC_SUBST([PACKAGE_VERSION_SUFFIX])
AC_CONFIG_SRCDIR([kern/ipc_kobject.c])
AC_CONFIG_AUX_DIR([build-aux])
diff --git a/device/ds_routines.c b/device/ds_routines.c
index 1fabec3c..c1cb9d43 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 c0543cbc..e9f115fc 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 00000000..476625cb
--- /dev/null
+++ b/device/intr.c
@@ -0,0 +1,209 @@
+#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
+#include <i386/spl.h>
+#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;
+
+ spl_t s = splhi();
+ cli ();
+ e = search_intr (line, dest);
+ assert (e);
+ e->interrupts++;
+ tot_num_intr++;
+ splx(s);
+
+ 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;
+ spl_t s;
+
+ new = (struct intr_entry *) kalloc (sizeof (*new));
+ if (new == NULL)
+ return D_NO_MEMORY;
+
+ /* check whether the intr entry has been in the queue. */
+
+ s = splhi();
+ 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:
+ splx(s);
+ 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);
+ spl_t s;
+
+ for (;;)
+ {
+ assert_wait ((event_t) &intr_thread, FALSE);
+ s = splhi();
+ 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)
+ {
+ clear_wait (current_thread (), 0, 0);
+ del = 1;
+ break;
+ }
+
+ if (e->interrupts)
+ {
+ clear_wait (current_thread (), 0, 0);
+ line = e->line;
+ dest = e->dest;
+ e->interrupts--;
+ tot_num_intr--;
+
+ splx(s);
+ deliver_intr (line, dest);
+ s = splhi();
+ 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);
+
+ splx(s);
+ kfree ((vm_offset_t) e, sizeof (*e));
+ s = splhi();
+ cli();
+ }
+ }
+ splx(s);
+ 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/device/ramdisk.c b/device/ramdisk.c
new file mode 100644
index 00000000..daf70436
--- /dev/null
+++ b/device/ramdisk.c
@@ -0,0 +1,160 @@
+#include <mach/vm_param.h>
+#include <machine/vm_param.h>
+#include <vm/vm_kern.h>
+#include <vm/vm_user.h>
+#include <device/device_types.h>
+#include <device/ds_routines.h>
+#include <device/conf.h>
+#include <device/ramdisk.h>
+#include <kern/printf.h>
+#include <string.h>
+
+static struct ramdisk {
+ void *data;
+ vm_size_t size;
+} ramdisk[RAMDISK_MAX];
+
+static int ramdisk_num = 0;
+
+/* Initial ramdisks are created from the boot scripts */
+int ramdisk_create(vm_size_t size, const void *initdata, int *out_no)
+{
+ struct ramdisk *rd = &ramdisk[ramdisk_num];
+ int err;
+
+ if(ramdisk_num >= RAMDISK_MAX)
+ return -1;
+
+ /* allocate the memory */
+ rd->size = round_page(size);
+ err = kmem_alloc(kernel_map, (vm_offset_t *) &rd->data, rd->size);
+ if(err != KERN_SUCCESS)
+ return err;
+
+ /* initialize */
+ if(initdata)
+ memcpy(rd->data, initdata, rd->size);
+ else
+ memset(rd->data, 0, rd->size);
+
+ /* report */
+ if(out_no) *out_no = ramdisk_num;
+ printf("%s%d: %lu bytes @%p\n", RAMDISK_NAME, ramdisk_num,
+ (unsigned long) rd->size, rd->data);
+
+ ramdisk_num++;
+ return KERN_SUCCESS;
+}
+
+/* On d_open() we just check whether the ramdisk exists */
+int ramdisk_open(dev_t dev, int mode, io_req_t ior)
+{
+ return (dev < ramdisk_num) ? D_SUCCESS : D_NO_SUCH_DEVICE;
+}
+
+/* d_getstat() is used to query the device characteristics */
+int ramdisk_getstat(dev_t dev, dev_flavor_t flavor, dev_status_t status,
+ mach_msg_type_number_t *status_count)
+{
+ switch(flavor) {
+ case DEV_GET_SIZE:
+ status[DEV_GET_SIZE_DEVICE_SIZE] = ramdisk[dev].size;
+ status[DEV_GET_SIZE_RECORD_SIZE] = RAMDISK_BLOCKSZ;
+ *status_count = DEV_GET_SIZE_COUNT;
+ return D_SUCCESS;
+
+ case DEV_GET_RECORDS:
+ status[DEV_GET_RECORDS_DEVICE_RECORDS]
+ = ramdisk[dev].size / RAMDISK_BLOCKSZ;
+ status[DEV_GET_RECORDS_RECORD_SIZE] = RAMDISK_BLOCKSZ;
+ *status_count = DEV_GET_RECORDS_COUNT;
+ return D_SUCCESS;
+ }
+ return D_INVALID_OPERATION;
+}
+
+/* TODO: implement freeramdisk with setstat() ? */
+
+/* Check the given io request and compute a pointer to the ramdisk data and the
+ * amount to be handled. */
+static int ramdisk_ioreq(int dev, io_req_t ior, void **data, int *amt)
+{
+ vm_offset_t ofs = ior->io_recnum * RAMDISK_BLOCKSZ;
+ if(ofs >= ramdisk[dev].size)
+ return D_INVALID_RECNUM;
+
+ *data = (char*) ramdisk[dev].data + ofs;
+ *amt = ior->io_count;
+ if(ofs + *amt > ramdisk[dev].size)
+ *amt = ramdisk[dev].size - ofs;
+
+ return KERN_SUCCESS;
+}
+
+/* Copy data from a vm_map_copy by mapping it temporarily. */
+static int mem_map_cpy(void *dst, vm_map_copy_t src, int amt)
+{
+ vm_offset_t srcaddr;
+ int err;
+
+ err = vm_map_copyout(device_io_map, &srcaddr, src);
+ if (err != KERN_SUCCESS)
+ return err;
+
+ memcpy(dst, (void *) srcaddr, amt);
+ vm_deallocate(device_io_map, srcaddr, amt);
+ return KERN_SUCCESS;
+}
+
+int ramdisk_read(dev_t dev, io_req_t ior)
+{
+ void *data;
+ int amt, err;
+
+ err = ramdisk_ioreq(dev, ior, &data, &amt);
+ if(err != KERN_SUCCESS)
+ return err;
+
+ err = device_read_alloc (ior, ior->io_count);
+ if (err != KERN_SUCCESS)
+ return err;
+
+ memcpy(ior->io_data, data, amt);
+ ior->io_residual = ior->io_count - amt;
+
+ return D_SUCCESS;
+}
+
+int ramdisk_write(dev_t dev, io_req_t ior)
+{
+ void *data;
+ int amt, err;
+
+ err = ramdisk_ioreq(dev, ior, &data, &amt);
+ if(err != KERN_SUCCESS)
+ return err;
+
+ if (!(ior->io_op & IO_INBAND)) {
+ /* Out-of-band data is transmitted as a vm_map_copy */
+ err = mem_map_cpy(data, (vm_map_copy_t) ior->io_data, amt);
+ if(err != KERN_SUCCESS)
+ return err;
+ } else {
+ /* In-band data can be accessed directly */
+ memcpy(data, ior->io_data, amt);
+ }
+
+ ior->io_residual = ior->io_count - amt;
+ return D_SUCCESS;
+}
+
+vm_offset_t ramdisk_mmap(dev_t dev, vm_offset_t off, vm_prot_t prot)
+{
+ if(dev >= ramdisk_num)
+ return -1;
+ if(off >= ramdisk[dev].size)
+ return -1;
+
+ return pmap_phys_to_frame(kvtophys((vm_offset_t) ramdisk[dev].data + off));
+}
+
diff --git a/device/ramdisk.h b/device/ramdisk.h
new file mode 100644
index 00000000..3a232460
--- /dev/null
+++ b/device/ramdisk.h
@@ -0,0 +1,47 @@
+#ifndef _KERN_RAMDISK_H_
+#define _KERN_RAMDISK_H_
+
+#include <vm/pmap.h>
+#include <device/io_req.h>
+#include <device/conf.h>
+
+/* Maximum number of ramdisk devices */
+#define RAMDISK_MAX 4
+
+/* The block size used (userspace requires 512) */
+#define RAMDISK_BLOCKSZ 512
+
+/* Name associated to the ramdisk major */
+#define RAMDISK_NAME "rd"
+#define RAMDISK_NAMESZ (sizeof RAMDISK_NAME + sizeof (int) * 3 + 1)
+
+/* Create a new ramdisk of the given size. On success, if out_no and/or out_ptr
+ * are not NULL, the device number and pointer to the ramdisk's data are stored
+ * there. Returns D_SUCCESS or D_NO_MEMORY. */
+int ramdisk_create(vm_size_t size, const void *initdata, int *out_no);
+
+/* Device operations */
+int ramdisk_open(dev_t, int, io_req_t);
+int ramdisk_getstat(dev_t, dev_flavor_t, dev_status_t, mach_msg_type_number_t *);
+int ramdisk_read(dev_t, io_req_t);
+int ramdisk_write(dev_t, io_req_t);
+vm_offset_t ramdisk_mmap(dev_t, vm_offset_t, vm_prot_t);
+
+/* dev_ops initializer to be used from <machine>/conf.c */
+#define RAMDISK_DEV_OPS { \
+ .d_name = RAMDISK_NAME, \
+ .d_open = ramdisk_open, \
+ .d_close = nulldev_close, \
+ .d_read = ramdisk_read, \
+ .d_write = ramdisk_write, \
+ .d_getstat = ramdisk_getstat, \
+ .d_setstat = nulldev_setstat, \
+ .d_mmap = ramdisk_mmap, \
+ .d_async_in = nodev, \
+ .d_reset = nulldev, \
+ .d_port_death = nulldev_portdeath, \
+ .d_subdev = 0, \
+ .d_dev_info = nodev, \
+ }
+
+#endif
diff --git a/i386/i386at/conf.c b/i386/i386at/conf.c
index fe7c7c09..7b82ff47 100644
--- a/i386/i386at/conf.c
+++ b/i386/i386at/conf.c
@@ -31,6 +31,7 @@
#include <device/conf.h>
#include <kern/mach_clock.h>
#include <i386at/model_dep.h>
+#include <device/ramdisk.h>
#define timename "time"
@@ -135,6 +136,8 @@ struct dev_ops dev_name_list[] =
nodev },
#endif /* MACH_HYP */
+ RAMDISK_DEV_OPS,
+
#ifdef MACH_KMSG
{ kmsgname, kmsgopen, kmsgclose, kmsgread,
nulldev_write, kmsggetstat, nulldev_setstat, nomap,
diff --git a/i386/i386at/interrupt.S b/i386/i386at/interrupt.S
index 076e34bc..9f159c5c 100644
--- a/i386/i386at/interrupt.S
+++ b/i386/i386at/interrupt.S
@@ -41,11 +41,18 @@ ENTRY(interrupt)
cli /* XXX no more nested interrupts */
popl %eax /* restore irq number */
movl %eax,%ecx /* copy irq number */
+ movb $0xff,%al /* mask for all interrupts */
+ outb %al,$(PIC_MASTER_OCW) /* mask master out */
+ outb %al,$(PIC_SLAVE_OCW) /* mask slave out */
+ movl %ecx,%eax /* restore eax */
movb $(NON_SPEC_EOI),%al /* non-specific EOI */
outb %al,$(PIC_MASTER_ICW) /* ack interrupt to master */
cmpl $8,%ecx /* do we need to ack slave? */
jl 1f /* no, skip it */
outb %al,$(PIC_SLAVE_ICW)
1:
+ movb $0,%al /* empty mask */
+ outb %al,$(PIC_MASTER_OCW) /* unmask master */
+ outb %al,$(PIC_SLAVE_OCW) /* unmask slave */
ret /* return */
END(interrupt)
diff --git a/i386/i386at/kd.c b/i386/i386at/kd.c
index 8e9222a0..c448adab 100644
--- a/i386/i386at/kd.c
+++ b/i386/i386at/kd.c
@@ -1733,6 +1733,10 @@ kd_parserest(u_char *cp)
kd_erase(number[0]);
esc_spt = esc_seq;
break;
+ case 'n':
+ /* Ignore status/cursor report request */
+ esc_spt = esc_seq;
+ break;
case '\0':
break; /* not enough yet */
default:
diff --git a/i386/include/mach/i386/fp_reg.h b/i386/include/mach/i386/fp_reg.h
index 56730555..f4906238 100644
--- a/i386/include/mach/i386/fp_reg.h
+++ b/i386/include/mach/i386/fp_reg.h
@@ -117,6 +117,7 @@ struct i386_xfp_save {
#define FPS_C3 0x4000 /* condition code bit 3 */
#define FPS_BUSY 0x8000 /* FPU busy */
+#ifdef MACH_KERNEL
/*
* Kind of floating-point support provided by kernel.
*/
@@ -125,5 +126,6 @@ struct i386_xfp_save {
#define FP_287 2 /* 80287 */
#define FP_387 3 /* 80387 or 80486 */
#define FP_387X 4 /* FXSAVE/RSTOR-capable */
+#endif
#endif /* _MACH_I386_FP_REG_H_ */
diff --git a/include/device/intr.h b/include/device/intr.h
new file mode 100644
index 00000000..a02b64c9
--- /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 00000000..ca1eb922
--- /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/boot_script.c b/kern/boot_script.c
index b2ae901c..503a18de 100644
--- a/kern/boot_script.c
+++ b/kern/boot_script.c
@@ -88,12 +88,20 @@ prompt_resume_task (struct cmd *cmd, const long *val)
return boot_script_prompt_task_resume (cmd);
}
+/* Create an initial ramdisk */
+static int
+ramdisk_create (struct cmd *cmd, long *val)
+{
+ return boot_script_ramdisk_create (cmd, (char **) val);
+}
+
/* List of builtin symbols. */
static struct sym builtin_symbols[] =
{
{ "task-create", VAL_FUNC, (long) create_task, VAL_TASK, 0 },
{ "task-resume", VAL_FUNC, (long) resume_task, VAL_NONE, 1 },
{ "prompt-task-resume", VAL_FUNC, (long) prompt_resume_task, VAL_NONE, 1 },
+ { "ramdisk-create", VAL_FUNC, (long) ramdisk_create, VAL_STR, 0 },
};
#define NUM_BUILTIN (sizeof (builtin_symbols) / sizeof (builtin_symbols[0]))
diff --git a/kern/bootstrap.c b/kern/bootstrap.c
index 8b88d17d..d0afa1ef 100644
--- a/kern/bootstrap.c
+++ b/kern/bootstrap.c
@@ -51,6 +51,7 @@
#include <vm/vm_user.h>
#include <vm/pmap.h>
#include <device/device_port.h>
+#include <device/ramdisk.h>
#if MACH_KDB
#include <machine/db_machdep.h>
@@ -817,6 +818,23 @@ boot_script_free (void *ptr, unsigned int size)
}
int
+boot_script_ramdisk_create (struct cmd *cmd, char **name)
+{
+ struct multiboot_module *mod = cmd->hook;
+ vm_size_t size = mod->mod_end - mod->mod_start;
+ kern_return_t rc;
+ int no;
+
+ rc = ramdisk_create (size, (void *) phystokv (mod->mod_start), &no);
+ if (rc != KERN_SUCCESS)
+ return BOOT_SCRIPT_MACH_ERROR;
+
+ *name = boot_script_malloc (RAMDISK_NAMESZ);
+ sprintf(*name, RAMDISK_NAME "%d", no);
+ return 0;
+}
+
+int
boot_script_task_create (struct cmd *cmd)
{
kern_return_t rc = task_create_kernel(TASK_NULL, FALSE, &cmd->task);
diff --git a/kern/experimental.srv b/kern/experimental.srv
new file mode 100644
index 00000000..2ccfd783
--- /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 709ec9ec..c65458ba 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 19bd7bf6..fa9571c1 100644
--- a/kern/startup.c
+++ b/kern/startup.c
@@ -79,6 +79,7 @@ boolean_t reboot_on_panic = TRUE;
/* XX */
extern char *kernel_cmdline;
+extern void intr_thread();
/*
* Running in virtual memory, on the interrupt stack.
@@ -223,6 +224,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 75f8f812..c61b3751 100644
--- a/linux/dev/arch/i386/kernel/irq.c
+++ b/linux/dev/arch/i386/kernel/irq.c
@@ -76,6 +76,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] =
@@ -95,6 +96,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]++;
@@ -106,7 +108,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 a 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;
}
@@ -210,6 +242,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);
@@ -226,6 +259,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.
*/
@@ -254,6 +332,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/src/include/linux/compiler-gcc9.h b/linux/src/include/linux/compiler-gcc9.h
new file mode 100644
index 00000000..d9fba09e
--- /dev/null
+++ b/linux/src/include/linux/compiler-gcc9.h
@@ -0,0 +1,67 @@
+#ifndef __LINUX_COMPILER_H
+#error "Please don't include <linux/compiler-gcc8.h> directly, include <linux/compiler.h> instead."
+#endif
+
+#define __used __attribute__((__used__))
+#define __must_check __attribute__((warn_unused_result))
+#define __compiler_offsetof(a, b) __builtin_offsetof(a, b)
+
+/* Mark functions as cold. gcc will assume any path leading to a call
+ to them will be unlikely. This means a lot of manual unlikely()s
+ are unnecessary now for any paths leading to the usual suspects
+ like BUG(), printk(), panic() etc. [but let's keep them for now for
+ older compilers]
+
+ Early snapshots of gcc 4.3 don't support this and we can't detect this
+ in the preprocessor, but we can live with this because they're unreleased.
+ Maketime probing would be overkill here.
+
+ gcc also has a __attribute__((__hot__)) to move hot functions into
+ a special section, but I don't see any sense in this right now in
+ the kernel context */
+#define __cold __attribute__((__cold__))
+
+#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNTER__)
+
+#ifndef __CHECKER__
+# define __compiletime_warning(message) __attribute__((warning(message)))
+# define __compiletime_error(message) __attribute__((error(message)))
+#endif /* __CHECKER__ */
+
+/*
+ * Mark a position in code as unreachable. This can be used to
+ * suppress control flow warnings after asm blocks that transfer
+ * control elsewhere.
+ *
+ * Early snapshots of gcc 4.5 don't support this and we can't detect
+ * this in the preprocessor, but we can live with this because they're
+ * unreleased. Really, we need to have autoconf for the kernel.
+ */
+#define unreachable() __builtin_unreachable()
+
+/* Mark a function definition as prohibited from being cloned. */
+#define __noclone __attribute__((__noclone__))
+
+/*
+ * Tell the optimizer that something else uses this function or variable.
+ */
+#define __visible __attribute__((externally_visible))
+
+/*
+ * GCC 'asm goto' miscompiles certain code sequences:
+ *
+ * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=58670
+ *
+ * Work it around via a compiler barrier quirk suggested by Jakub Jelinek.
+ *
+ * (asm goto is automatically volatile - the naming reflects this.)
+ */
+#define asm_volatile_goto(x...) do { asm goto(x); asm (""); } while (0)
+
+#ifdef CONFIG_ARCH_USE_BUILTIN_BSWAP
+#define __HAVE_BUILTIN_BSWAP32__
+#define __HAVE_BUILTIN_BSWAP64__
+#define __HAVE_BUILTIN_BSWAP16__
+#endif /* CONFIG_ARCH_USE_BUILTIN_BSWAP */
+
+#define KASAN_ABI_VERSION 4
diff --git a/version.c.in b/version.c.in
index d894d7fc..2c57314f 100644
--- a/version.c.in
+++ b/version.c.in
@@ -1,2 +1,2 @@
/* @configure_input@ */
-const char version[] = "@PACKAGE_NAME@ @PACKAGE_VERSION@";
+const char version[] = "@PACKAGE_NAME@ @PACKAGE_VERSION@@PACKAGE_VERSION_SUFFIX@";
diff --git a/vm/vm_map.c b/vm/vm_map.c
index ffc8934b..4a133eb3 100644
--- a/vm/vm_map.c
+++ b/vm/vm_map.c
@@ -1035,7 +1035,8 @@ kern_return_t vm_map_enter(
* extend from below.]
*/
- if ((object == VM_OBJECT_NULL) &&
+ if (0 &&
+ (object == VM_OBJECT_NULL) &&
(entry != vm_map_to_entry(map)) &&
(entry->vme_end == start) &&
(!entry->is_shared) &&
diff --git a/vm/vm_user.c b/vm/vm_user.c
index b6a069a5..2f41d322 100644
--- a/vm/vm_user.c
+++ b/vm/vm_user.c
@@ -531,3 +531,97 @@ kern_return_t vm_msync(
return vm_map_msync(map, (vm_offset_t) address, size, sync_flags);
}
+
+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;
+{
+ vm_size_t alloc_size;
+ unsigned int npages;
+ unsigned int i;
+ unsigned int order;
+ vm_page_t pages;
+ vm_object_t object;
+ kern_return_t kr;
+ vm_address_t vaddr;
+
+ if (host_priv == HOST_NULL)
+ return KERN_INVALID_HOST;
+
+ if (map == VM_MAP_NULL)
+ return KERN_INVALID_TASK;
+
+ size = vm_page_round(size);
+
+ if (size == 0)
+ return KERN_INVALID_ARGUMENT;
+
+ object = vm_object_allocate(size);
+
+ if (object == NULL)
+ return KERN_RESOURCE_SHORTAGE;
+
+ /*
+ * XXX The page allocator returns blocks with a power-of-two size.
+ * The requested size may not be a power-of-two, requiring some
+ * work to release back the pages that aren't needed.
+ */
+ order = vm_page_order(size);
+ alloc_size = (1 << (order + PAGE_SHIFT));
+ npages = vm_page_atop(alloc_size);
+
+ pages = vm_page_grab_contig(alloc_size, VM_PAGE_SEL_DIRECTMAP);
+
+ if (pages == NULL) {
+ vm_object_deallocate(object);
+ return KERN_RESOURCE_SHORTAGE;
+ }
+
+ vm_object_lock(object);
+ vm_page_lock_queues();
+
+ for (i = 0; i < vm_page_atop(size); i++) {
+ /*
+ * XXX We can safely handle contiguous pages as an array,
+ * but this relies on knowing the implementation of the
+ * page allocator.
+ */
+ pages[i].busy = FALSE;
+ vm_page_insert(&pages[i], object, vm_page_ptoa(i));
+ vm_page_wire(&pages[i]);
+ }
+
+ vm_page_unlock_queues();
+ vm_object_unlock(object);
+
+ for (i = vm_page_atop(size); i < npages; i++) {
+ vm_page_release(&pages[i], FALSE, FALSE);
+ }
+
+ vaddr = 0;
+ kr = vm_map_enter(map, &vaddr, size, 0, TRUE, object, 0, FALSE,
+ VM_PROT_READ | VM_PROT_WRITE,
+ VM_PROT_READ | VM_PROT_WRITE, VM_INHERIT_DEFAULT);
+
+ if (kr != KERN_SUCCESS) {
+ vm_object_deallocate(object);
+ return kr;
+ }
+
+ kr = vm_map_pageable(map, vaddr, vaddr + size,
+ VM_PROT_READ | VM_PROT_WRITE,
+ TRUE, TRUE);
+
+ if (kr != KERN_SUCCESS) {
+ vm_map_remove(map, vaddr, vaddr + size);
+ return kr;
+ }
+
+ *result_vaddr = vaddr;
+ *result_paddr = pages->phys_addr;
+
+ return KERN_SUCCESS;
+}