diff options
author | Damien Zammit <damien@zamaudio.com> | 2019-11-11 20:35:17 +1100 |
---|---|---|
committer | Damien Zammit <damien@zamaudio.com> | 2019-11-11 20:42:51 +1100 |
commit | af33188fc5a13ad7ad8e6160e9bc1884a8d4af29 (patch) | |
tree | ff740bbfee86a4ad39cd28292b5114763e9c2dd3 | |
parent | e45601b0780b2c81a6448cdafd952cb98112b9f4 (diff) |
deb base
-rw-r--r-- | Makefrag.am | 11 | ||||
-rw-r--r-- | configure.ac | 1 | ||||
-rw-r--r-- | device/ds_routines.c | 55 | ||||
-rw-r--r-- | device/ds_routines.h | 3 | ||||
-rw-r--r-- | device/intr.c | 209 | ||||
-rw-r--r-- | device/ramdisk.c | 160 | ||||
-rw-r--r-- | device/ramdisk.h | 47 | ||||
-rw-r--r-- | i386/i386at/conf.c | 3 | ||||
-rw-r--r-- | i386/i386at/interrupt.S | 7 | ||||
-rw-r--r-- | i386/i386at/kd.c | 4 | ||||
-rw-r--r-- | i386/include/mach/i386/fp_reg.h | 2 | ||||
-rw-r--r-- | include/device/intr.h | 17 | ||||
-rw-r--r-- | include/mach/experimental.defs | 100 | ||||
-rw-r--r-- | kern/boot_script.c | 8 | ||||
-rw-r--r-- | kern/bootstrap.c | 18 | ||||
-rw-r--r-- | kern/experimental.srv | 3 | ||||
-rw-r--r-- | kern/ipc_kobject.c | 3 | ||||
-rw-r--r-- | kern/startup.c | 4 | ||||
-rw-r--r-- | linux/dev/arch/i386/kernel/irq.c | 81 | ||||
-rw-r--r-- | linux/src/include/linux/compiler-gcc9.h | 67 | ||||
-rw-r--r-- | version.c.in | 2 | ||||
-rw-r--r-- | vm/vm_map.c | 3 | ||||
-rw-r--r-- | vm/vm_user.c | 94 |
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, ®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 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, ®s); + 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; +} |