summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog102
-rw-r--r--i386/Makefrag.am9
-rw-r--r--i386/i386/io_perm.c317
-rw-r--r--i386/i386/io_perm.h65
-rw-r--r--i386/i386/io_port.h43
-rw-r--r--i386/i386/iopb.c618
-rw-r--r--i386/i386/iopb.h62
-rw-r--r--i386/i386/ktss.c14
-rw-r--r--i386/i386/ktss.h2
-rw-r--r--i386/i386/locore.S9
-rw-r--r--i386/i386/machine_task.c81
-rw-r--r--i386/i386/mp_desc.c17
-rw-r--r--i386/i386/mp_desc.h4
-rw-r--r--i386/i386/pcb.c105
-rw-r--r--i386/i386/task.h61
-rw-r--r--i386/i386/thread.h2
-rw-r--r--i386/i386/tss.h13
-rw-r--r--i386/i386at/kd.c36
-rw-r--r--i386/include/mach/i386/mach_i386.defs52
-rw-r--r--i386/include/mach/i386/mach_i386_types.h16
-rw-r--r--include/stddef.h29
-rw-r--r--kern/task.c5
-rw-r--r--kern/task.h4
23 files changed, 809 insertions, 857 deletions
diff --git a/ChangeLog b/ChangeLog
index f39c42d..d9a6a29 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,105 @@
+2007-05-07 Thomas Schwinge <tschwinge@gnu.org>
+
+ [bug #15295 --- ``Mach lets processes write to I/O ports'']
+
+ * i386/Makefrag.am (libkernel_a_SOURCES): Add `i386/i386/io_perm.c',
+ `i386/i386/io_perm.h', `i386/i386/machine_task.c', `i386/i386/task.h'
+ and remove `i386/i386/io_port.h', `i386/i386/iopb.c',
+ `i386/i386/iopb.h'.
+
+ * i386/i386/io_port.h: Remove file.
+ * i386/i386at/kd.c: Don't include <i386/io_port.h>.
+ (vga_port_list, kd_io_device, kd_io_map_open, kd_io_map_close): Don't
+ define and don't use anymore.
+
+ * include/stddef.h: New file.
+
+ * i386/i386/io_perm.c: Include <string.h>, <device/device_emul.h>,
+ <ipc/ipc_space.h> and don't include <oskit/ds_oskit.h>.
+ (io_perm_device_emulation_ops): New variable.
+ (dev_open_alloc, setup_no_senders): Remove declarations.
+ (convert_io_perm_to_port, convert_port_to_io_perm, io_perm_deallocate):
+ Rewrite.
+ (no_senders): New function.
+ (i386_io_perm_create, i386_io_perm_modify): Rewrite partially, to adapt
+ to the GNU Mach environment.
+ * i386/i386/io_perm.h: Include <device/dev_hdr.h> and
+ <ipc/ipc_types.h>.
+ (io_perm, io_perm_t): New structure and accompanying type definition.
+ (IO_PERM_NULL): Define.
+ * i386/i386/locore.S (ktss): Move variable to...
+ * i386/i386/ktss.c: ... here, make it a ``struct task_tss''.
+ (ktss_init): Initialize the `task_tss' structure and the i/o permission
+ bit map.
+ * i386/i386/ktss.h: Adapt to that.
+ * i386/i386/machine_task.c (machine_task_module_init): Adapt the `zinit'
+ call to the GNU Mach environment.
+ * i386/i386/mp_desc.c: Include <machine/ktss.h>.
+ * i386/i386/tss.h: Include <machine/io_perm.h>.
+ (task_tss): New structure, equivalent to the OSKit-Mach one.
+ * i386/include/mach/i386/mach_i386.defs: Don't include
+ <device/device_types.defs>.
+ (device_list_t): Remove type.
+ * i386/include/mach/i386/mach_i386_types.h (device_list_t): Remove type
+ definition.
+
+2007-05-07 Marcus Brinkmann <marcus@gnu.org>
+
+ [bug #15295 --- ``Mach lets processes write to I/O ports'']
+
+ * i386/i386/iopb.h, i386/i386/iopb.c: Obsolete files removed.
+
+ * i386/i386/pcb.c (switch_context): Update the I/O permission
+ bitmap from stack_handoff() here (not only in stack_handoff()).
+
+ * i386/i386/machine_task.c (machine_task_module_init): Set
+ ZONE_COLLECTABLE and ZONE_EXHAUSTIBLE flags for the iopb zone.
+ Requested by Roland McGrath <roland@frob.com>.
+
+ * i386/i386/io_perm.h: New file.
+ * i386/i386/io_perm.c: New file.
+ * i386/i386/machine_task.c: New file.
+ * i386/i386/mp_desc.h: (struct mp_desc_table): Change type of ktss to
+ struct task_tss.
+ (mp_ktss): Likewise for array of pointers to the struct.
+ * i386/i386/mp_desc.c: Include `machine/tss.h' and `machine/io_perm.h'.
+ (mp_ktss): Change type to array of struct task_tss.
+ (mp_desc_init): Cast pointer to x86_tss into pointer to task_tss,
+ and use size of struct task_tss instead size of struct x86_tss.
+ Initialize the task_tss structure.
+ * i386/i386/pcb.c: Include `stddef.h' and `machine/tss.h'.
+ (iopb_create, iopb_destroy): Prototypes removed.
+ (curr_ktss): Cast pointer to base_tss to pointer to struct
+ task_tss.
+ (switch_ktss): Always use kernel TSS.
+ (update_ktss_iopb): New function.
+ (stack_handoff): Call update_ktss_iopb.
+ (pcb_module_init): Do not call iopb_init.
+ (pcb_terminate): Do not call iopb_destroy.
+ (thread_setstatus): Remove local variable tss.
+ (thread_getstatus): Rewrite i386_ISA_PORT_MAP_STATE case handler.
+ * i386/i386/task.h: New file.
+ * i386/i386/thread.h: Do not include `i386/iopb.h'.
+ (struct i386_machine_state): Remove member io_tss.
+ * i386/include/mach/i386/mach_i386.defs [KERNEL_SERVER]: Include
+ `machine/io_perm.h'. Define intran, outtran and destructor.
+ (io_port_t): New type.
+ (io_perm_t): Likewise.
+ (i386_io_port_add): Interface removed.
+ (i386_io_port_remove): Likewise.
+ (i386_io_port_list): Likewise.
+ (i386_io_perm_create): New interface.
+ (i386_io_perm_modify): Likewise.
+ * i386/include/mach/i386/mach_i386_types.h [MACH_KERNEL]: Include
+ `i386/io_perm.h'.
+ [!MACH_KERNEL]: Define types io_port_t and io_perm_t.
+ * kern/task.c (task_init): Call machine_task_module_init.
+ (task_create): Call machine_task_init.
+ (task_deallocate): Call machine_task_terminate.
+ (task_collect_scan): Call machine_task_collect.
+ * task.h: Include `machine/task.h'.
+ (struct task): Add member machine.
+
2007-05-06 Thomas Schwinge <tschwinge@gnu.org>
* device/kmsg.c: Include <device/ds_routines.h>.
diff --git a/i386/Makefrag.am b/i386/Makefrag.am
index 50eaecf..3e17bb4 100644
--- a/i386/Makefrag.am
+++ b/i386/Makefrag.am
@@ -26,7 +26,6 @@ libkernel_a_SOURCES += \
i386/i386at/cons_conf.c \
i386/i386at/cram.h \
i386/i386at/disk.h \
- i386/i386at/rtc.c \
i386/i386at/i8250.h \
i386/i386at/idt.h \
i386/i386at/immc.c \
@@ -44,6 +43,7 @@ libkernel_a_SOURCES += \
i386/i386at/kdsoft.h \
i386/i386at/model_dep.c \
i386/i386at/pic_isa.c \
+ i386/i386at/rtc.c \
i386/i386at/rtc.h \
i386/include/mach/sa/stdarg.h
@@ -85,9 +85,8 @@ libkernel_a_SOURCES += \
i386/i386/idt.c \
i386/i386/idt_inittab.S \
i386/i386/io_map.c \
- i386/i386/io_port.h \
- i386/i386/iopb.c \
- i386/i386/iopb.h \
+ i386/i386/io_perm.c \
+ i386/i386/io_perm.h \
i386/i386/ipl.h \
i386/i386/ktss.c \
i386/i386/ktss.h \
@@ -101,6 +100,7 @@ libkernel_a_SOURCES += \
i386/i386/loose_ends.c \
i386/i386/mach_param.h \
i386/i386/machine_routines.h \
+ i386/i386/machine_task.c \
i386/i386/machspl.h \
i386/i386/mp_desc.c \
i386/i386/mp_desc.h \
@@ -120,6 +120,7 @@ libkernel_a_SOURCES += \
i386/i386/setjmp.h \
i386/i386/spl.S \
i386/i386/spl.h \
+ i386/i386/task.h \
i386/i386/thread.h \
i386/i386/time_stamp.h \
i386/i386/timer.h \
diff --git a/i386/i386/io_perm.c b/i386/i386/io_perm.c
new file mode 100644
index 0000000..3a03408
--- /dev/null
+++ b/i386/i386/io_perm.c
@@ -0,0 +1,317 @@
+/* Manipulate I/O permission bitmap objects.
+
+ Copyright (C) 2002, 2007 Free Software Foundation, Inc.
+
+ Written by Marcus Brinkmann. Glued into GNU Mach by Thomas Schwinge.
+
+ This file is part of GNU Mach.
+
+ GNU Mach is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+/*
+ * Mach Operating System
+ * Copyright (c) 1993,1992,1991,1990 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.
+ */
+
+#include <string.h>
+
+#include <mach/boolean.h>
+#include <mach/kern_return.h>
+
+#include <ipc/ipc_port.h>
+#include <ipc/ipc_space.h>
+
+#include <kern/zalloc.h>
+#include <kern/lock.h>
+#include <kern/queue.h>
+#include <kern/thread.h>
+
+#include <device/dev_hdr.h>
+#include <device/device_emul.h>
+#include <device/device_port.h>
+
+#include "io_perm.h"
+#include "gdt.h"
+
+/* Our device emulation ops. See below, at the bottom of this file. */
+static struct device_emulation_ops io_perm_device_emulation_ops;
+
+
+/* The outtran which allows MIG to convert an io_perm_t object to a port
+ representing it. */
+ipc_port_t
+convert_io_perm_to_port (io_perm_t io_perm)
+{
+ if (io_perm == IO_PERM_NULL)
+ return IP_NULL;
+
+ ipc_port_t port;
+
+ port = ipc_port_make_send (io_perm->port);
+
+ return port;
+}
+
+
+/* The intran which allows MIG to convert a port representing an
+ io_perm_t object to the object itself. */
+io_perm_t
+convert_port_to_io_perm (ipc_port_t port)
+{
+ device_t device;
+
+ device = dev_port_lookup (port);
+
+ if (device == DEVICE_NULL)
+ return IO_PERM_NULL;
+
+ io_perm_t io_perm;
+
+ io_perm = device->emul_data;
+
+ return io_perm;
+}
+
+#if TODO_REMOVE_ME
+/* TODO. Fix this comment. */
+/* The destructor which is called when the last send right to a port
+ representing an io_perm_t object vanishes. */
+void
+io_perm_deallocate (io_perm_t io_perm)
+{
+ /* TODO. Is there anything to deallocate in here? I don't think so, as we
+ don't allocate anything in `convert_port_to_io_perm'. */
+}
+#endif
+
+/* Our ``no senders'' handling routine. Deallocate the object. */
+static
+void
+no_senders (mach_no_senders_notification_t *notification)
+{
+ io_perm_t io_perm;
+
+ io_perm = convert_port_to_io_perm
+ ((ipc_port_t) notification->not_header.msgh_remote_port);
+
+ assert (io_perm != IO_PERM_NULL);
+
+ ip_lock (io_perm->port); /* TODO. Actually needed? */
+ ipc_kobject_set (io_perm->port, IKO_NULL, IKOT_NONE);
+ ipc_port_dealloc_kernel (io_perm->port);
+
+ kfree ((vm_offset_t) io_perm, sizeof *io_perm);
+}
+
+
+/* Initialize bitmap by setting all bits to OFF == 1. */
+static inline void
+io_bitmap_init (unsigned char *iopb)
+{
+ memset (iopb, ~0, IOPB_BYTES);
+}
+
+
+/* Set selected bits in bitmap to ON == 0. */
+static inline void
+io_bitmap_set (unsigned char *iopb, io_port_t from, io_port_t to)
+{
+ do
+ iopb[from >> 3] &= ~(1 << (from & 0x7));
+ while (from++ != to);
+}
+
+
+/* Set selected bits in bitmap to OFF == 1. */
+static inline void
+io_bitmap_clear (unsigned char *iopb, io_port_t from, io_port_t to)
+{
+ do
+ iopb[from >> 3] |= (1 << (from & 0x7));
+ while (from++ != to);
+}
+
+
+/* Request a new port IO_PERM that represents the capability to access
+ the I/O ports [FROM; TO] directly. MASTER_PORT is the master device port.
+
+ The function returns KERN_INVALID_ARGUMENT if TARGET_TASK is not a task,
+ or FROM is greater than TO.
+
+ The function is exported. */
+kern_return_t
+i386_io_perm_create (ipc_port_t master_port, io_port_t from, io_port_t to,
+ io_perm_t *new)
+{
+ if (master_port != master_device_port)
+ return KERN_INVALID_ARGUMENT;
+
+ /* We do not have to check FROM and TO for the limits [0;IOPB_MAX], as
+ they're short integers and all values are within these very limits. */
+ if (from > to)
+ return KERN_INVALID_ARGUMENT;
+
+ io_perm_t io_perm;
+
+ io_perm = (io_perm_t) kalloc (sizeof *io_perm);
+ if (io_perm == NULL)
+ return KERN_RESOURCE_SHORTAGE;
+
+ io_perm->from = from;
+ io_perm->to = to;
+
+ io_perm->port = ipc_port_alloc_kernel ();
+ if (io_perm->port == IP_NULL)
+ {
+ kfree ((vm_offset_t) io_perm, sizeof *io_perm);
+ return KERN_RESOURCE_SHORTAGE;
+ }
+
+ /* Set up the dummy device. */
+ ipc_kobject_set(io_perm->port,
+ (ipc_kobject_t) &io_perm->device, IKOT_DEVICE);
+ io_perm->device.emul_data = io_perm;
+ io_perm->device.emul_ops = &io_perm_device_emulation_ops;
+
+ ipc_port_t notify;
+
+ notify = ipc_port_make_sonce(io_perm->port);
+ ip_lock(device->port);
+ ipc_port_nsrequest(io_perm->port, 1, notify, &notify);
+ assert(notify == IP_NULL);
+
+ *new = io_perm;
+
+ return KERN_SUCCESS;
+}
+
+
+/* From pcb.c. */
+extern void update_ktss_iopb (unsigned char *new_iopb, int last);
+
+
+/* Modify the I/O permissions for TARGET_TASK. If ENABLE is TRUE, the
+ permission to acces the I/O ports specified by IO_PERM is granted,
+ otherwise it is withdrawn.
+
+ The function returns KERN_INVALID_ARGUMENT if TARGET_TASK is not a valid
+ task or IO_PERM not a valid I/O permission port.
+
+ The function is exported. */
+kern_return_t
+i386_io_perm_modify (task_t target_task, io_perm_t io_perm, boolean_t enable)
+{
+ io_port_t from, to;
+ unsigned char *iopb;
+ io_port_t iopb_size;
+
+ if (target_task == TASK_NULL || io_perm == IO_PERM_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ from = io_perm->from;
+ to = io_perm->to;
+
+ simple_lock (&target_task->machine.iopb_lock);
+ iopb = target_task->machine.iopb;
+ iopb_size = target_task->machine.iopb_size;
+
+ if (!enable && !iopb_size)
+ {
+ simple_unlock (&target_task->machine.iopb_lock);
+ return KERN_SUCCESS;
+ }
+
+ if (!iopb)
+ {
+ simple_unlock (&target_task->machine.iopb_lock);
+ iopb = (unsigned char *) zalloc (machine_task_iopb_zone);
+ simple_lock (&target_task->machine.iopb_lock);
+ if (target_task->machine.iopb)
+ {
+ if (iopb)
+ zfree (machine_task_iopb_zone, (vm_offset_t) iopb);
+ iopb = target_task->machine.iopb;
+ iopb_size = target_task->machine.iopb_size;
+ }
+ else if (iopb)
+ {
+ target_task->machine.iopb = iopb;
+ io_bitmap_init (iopb);
+ }
+ else
+ {
+ simple_unlock (&target_task->machine.iopb_lock);
+ return KERN_RESOURCE_SHORTAGE;
+ }
+ }
+
+ if (enable)
+ {
+ io_bitmap_set (iopb, from, to);
+ if ((to >> 3) + 1 > iopb_size)
+ target_task->machine.iopb_size = (to >> 3) + 1;
+ }
+ else
+ {
+ if ((from >> 3) + 1 > iopb_size)
+ {
+ simple_unlock (&target_task->machine.iopb_lock);
+ return KERN_SUCCESS;
+ }
+
+ io_bitmap_clear (iopb, from, to);
+ while (iopb_size > 0 && iopb[iopb_size - 1] == 0xff)
+ iopb_size--;
+ target_task->machine.iopb_size = iopb_size;
+ }
+
+#if NCPUS>1
+#warning SMP support missing (notify all CPUs running threads in that of the I/O bitmap change).
+#endif
+ if (target_task == current_task())
+ update_ktss_iopb (iopb, target_task->machine.iopb_size);
+
+ simple_unlock (&target_task->machine.iopb_lock);
+ return KERN_SUCCESS;
+}
+
+/* We are some sort of Mach device... */
+static struct device_emulation_ops io_perm_device_emulation_ops =
+{
+ /* ... in order to be easily able to receive a ``no senders'' notification
+ which we then use to deallocate ourselves. */
+ .no_senders = no_senders
+};
diff --git a/i386/i386/io_perm.h b/i386/i386/io_perm.h
new file mode 100644
index 0000000..a68e103
--- /dev/null
+++ b/i386/i386/io_perm.h
@@ -0,0 +1,65 @@
+/* Data types for I/O permission bitmap objects.
+
+ Copyright (C) 2002, 2007 Free Software Foundation, Inc.
+
+ Written by Marcus Brinkmann. Glued into GNU Mach by Thomas Schwinge.
+
+ This file is part of GNU Mach.
+
+ GNU Mach is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _I386_IO_PERM_H_
+#define _I386_IO_PERM_H_
+
+#include <device/dev_hdr.h>
+#include <ipc/ipc_types.h>
+
+
+/* The highest possible I/O port. */
+#define IOPB_MAX 0xffff
+
+/* The number of bytes needed to hold all permission bits. */
+#define IOPB_BYTES (((IOPB_MAX + 1) + 7) / 8)
+
+/* An offset that points outside of the permission bitmap, used to
+ disable all permission. */
+#define IOPB_INVAL 0x2fff
+
+
+/* The type of an I/O port address. */
+typedef unsigned short io_port_t;
+
+
+struct io_perm
+{
+ /* We use a ``struct device'' for easy management. */
+ struct device device;
+
+ ipc_port_t port;
+
+ io_port_t from, to;
+};
+
+typedef struct io_perm *io_perm_t;
+
+#define IO_PERM_NULL ((io_perm_t) 0)
+
+extern io_perm_t convert_port_to_io_perm (ipc_port_t);
+extern ipc_port_t convert_io_perm_to_port (io_perm_t);
+#if TODO_REMOVE_ME
+extern void io_perm_deallocate (io_perm_t);
+#endif
+
+#endif
diff --git a/i386/i386/io_port.h b/i386/i386/io_port.h
deleted file mode 100644
index 3344103..0000000
--- a/i386/i386/io_port.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Mach Operating System
- * Copyright (c) 1991 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.
- */
-
-#ifndef _I386_IO_PORT_H_
-#define _I386_IO_PORT_H_
-/*
- * IO register definitions.
- */
-typedef unsigned short io_reg_t;
-
-#define IO_REG_NULL (0x00ff) /* reserved */
-
-/*
- * Allocate and destroy io port sets for users to map into
- * threads.
- */
-extern void io_port_create(mach_device_t, io_reg_t *);
-extern void io_port_destroy(mach_device_t);
-
-#endif /* _I386_IO_PORT_H_ */
diff --git a/i386/i386/iopb.c b/i386/i386/iopb.c
deleted file mode 100644
index f1e859a..0000000
--- a/i386/i386/iopb.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Mach Operating System
- * Copyright (c) 1993,1992,1991,1990 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.
- */
-/*
- * Code to manipulate IO permission bitmaps.
- */
-
-#include <string.h>
-
-#include <mach/boolean.h>
-#include <mach/kern_return.h>
-
-#include <ipc/ipc_port.h>
-
-#include <kern/kalloc.h>
-#include <kern/lock.h>
-#include <kern/queue.h>
-#include <kern/thread.h>
-
-#include <device/dev_hdr.h>
-
-#include "io_port.h"
-#include "iopb.h"
-#include "seg.h"
-#include "gdt.h"
-#include "vm_param.h"
-
-/*
- * A set of ports for an IO device.
- */
-struct io_port {
- mach_device_t device; /* Mach device */
- queue_chain_t dev_list; /* link in device list */
- queue_chain_t io_use_list; /* List of threads that use it */
- io_reg_t *io_port_list; /* list of IO ports that use it */
- /* list ends with IO_REG_NULL */
-};
-typedef struct io_port *io_port_t;
-
-/*
- * Lookup table for device -> io_port mapping
- * (a linked list - I don't expect too many)
- */
-queue_head_t device_to_io_port_list;
-
-/*
- * Cross-reference:
- * all threads that have IO ports mapped
- * all IO ports that have threads mapped
- */
-struct io_use {
- queue_chain_t psq; /* Links from port set */
- queue_chain_t tsq; /* links from tss */
- io_port_t ps; /* Port set */
- iopb_tss_t ts; /* Task segment */
-};
-typedef struct io_use *io_use_t;
-
-/*
- * Big lock for the whole mess.
- */
-decl_simple_lock_data(, iopb_lock)
-
-/*
- * Initialize the package.
- */
-void
-iopb_init(void)
-{
- queue_init(&device_to_io_port_list);
- simple_lock_init(&iopb_lock);
-}
-
-/*
- * Initialize bitmap (set all bits to OFF == 1)
- */
-void
-io_bitmap_init(
- isa_iopb bp,
- boolean_t on_off)
-{
- register unsigned char *b = bp;
- register int s;
- unsigned char c;
-
- /*
- * Disallow access to ports 0x00 .. 0xff
- */
- for (s = 0; s < (0xff+1)/8; s++) {
- *b++ = ~0; /* no access */
- }
-
- if (on_off)
- c = 0;
- else
- c = ~0;
-
- for (; s < sizeof(isa_iopb); s++) {
- *b++ = c;
- }
-}
-
-/*
- * Set selected bits in bitmap to ON == 0
- */
-void
-io_bitmap_set(
- isa_iopb bp,
- io_reg_t *bit_list)
-{
- io_reg_t io_bit;
-
- while ((io_bit = *bit_list++) != IO_REG_NULL) {
- bp[io_bit>>3] &= ~(1 << (io_bit & 0x7));
- }
-}
-
-/*
- * Set selected bits in bitmap to OFF == 1
- */
-void
-io_bitmap_clear(
- isa_iopb bp,
- io_reg_t *bit_list)
-{
- io_reg_t io_bit;
-
- while ((io_bit = *bit_list++) != IO_REG_NULL) {
- bp[io_bit>>3] |= (1 << (io_bit & 0x7));
- }
-}
-
-/*
- * Lookup an io-port set by device
- */
-io_port_t
-device_to_io_port_lookup(
- mach_device_t device)
-{
- register io_port_t io_port;
-
- queue_iterate(&device_to_io_port_list, io_port, io_port_t, dev_list) {
- if (io_port->device == device) {
- return io_port;
- }
- }
- return 0;
-}
-
-/*
- * [exported]
- * Create an io_port set
- */
-void
-io_port_create(
- mach_device_t device,
- io_reg_t *io_port_list)
-{
- register io_port_t io_port;
-
- io_port = (io_port_t) kalloc(sizeof(struct io_port));
-
- simple_lock(&iopb_lock);
- if (device_to_io_port_lookup(device) != 0) {
- simple_unlock(&iopb_lock);
- kfree((vm_offset_t) io_port, sizeof(struct io_port));
- return;
- }
-
- io_port->device = device;
- queue_init(&io_port->io_use_list);
- io_port->io_port_list = io_port_list;
-
- /*
- * Enter in lookup list.
- */
- queue_enter(&device_to_io_port_list, io_port, io_port_t, dev_list);
-
- simple_unlock(&iopb_lock);
-}
-
-/*
- * [exported]
- * Destroy an io port set, removing any IO mappings.
- */
-void
-io_port_destroy(
- mach_device_t device)
-{
- io_port_t io_port;
- io_use_t iu;
-
- simple_lock(&iopb_lock);
- io_port = device_to_io_port_lookup(device);
- if (io_port == 0) {
- simple_unlock(&iopb_lock);
- return;
- }
-
- queue_iterate(&io_port->io_use_list, iu, io_use_t, psq) {
- iopb_tss_t io_tss;
- io_tss = iu->ts;
- io_bitmap_clear(io_tss->bitmap, io_port->io_port_list);
- queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
- }
- queue_remove(&device_to_io_port_list, io_port, io_port_t, dev_list);
- simple_unlock(&iopb_lock);
-
- while (!queue_empty(&io_port->io_use_list)) {
- iu = (io_use_t) queue_first(&io_port->io_use_list);
- queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
- kfree((vm_offset_t)iu, sizeof(struct io_use));
- }
-
- kfree((vm_offset_t)io_port, sizeof(struct io_port));
-}
-
-/*
- * Initialize an IO TSS.
- */
-void
-io_tss_init(
- iopb_tss_t io_tss,
- boolean_t access_all) /* allow access or not */
-{
- vm_offset_t addr = kvtolin (io_tss);
- vm_size_t limit = (char *)&io_tss->barrier - (char *)io_tss;
-
- memset(&io_tss->tss, 0, sizeof(struct i386_tss));
- io_tss->tss.io_bit_map_offset
- = (char *)&io_tss->bitmap - (char *)io_tss;
- io_tss->tss.ss0 = KERNEL_DS;
- io_bitmap_init(io_tss->bitmap, access_all);
- io_tss->barrier = ~0;
- queue_init(&io_tss->io_port_list);
- io_tss->iopb_desc[0] = (limit & 0xffff)
- | ((addr & 0xffff) << 16);
- io_tss->iopb_desc[1] = ((addr & 0x00ff0000) >> 16)
- | ((ACC_TSS|ACC_PL_K|ACC_P) << 8)
- | (limit & 0x000f0000)
- | (addr & 0xff000000);
-}
-
-/*
- * [exported]
- * Create an IOPB_TSS
- */
-iopb_tss_t
-iopb_create(void)
-{
- register iopb_tss_t ts;
-
- ts = (iopb_tss_t) kalloc(sizeof (struct iopb_tss));
- io_tss_init(ts, TRUE); /* XXX */
- return ts;
-}
-
-/*
- * [exported]
- * Destroy an IOPB_TSS
- */
-void
-iopb_destroy(
- iopb_tss_t io_tss)
-{
- io_use_t iu;
- io_port_t io_port;
-
- simple_lock(&iopb_lock);
-
- queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
- io_port = iu->ps;
- /* skip bitmap clear - entire bitmap will vanish */
- queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
- }
-
- simple_unlock(&iopb_lock);
-
- while (!queue_empty(&io_tss->io_port_list)) {
- iu = (io_use_t) queue_first(&io_tss->io_port_list);
- queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
- kfree((vm_offset_t)iu, sizeof(struct io_use));
- }
-
- kfree((vm_offset_t)io_tss, sizeof(struct iopb_tss));
-}
-
-/*
- * Add an IO mapping to a thread.
- */
-kern_return_t
-i386_io_port_add(
- thread_t thread,
- mach_device_t device)
-{
- pcb_t pcb;
- iopb_tss_t io_tss, new_io_tss;
- io_port_t io_port;
- io_use_t iu, old_iu;
-
- if (thread == THREAD_NULL
- || device == DEVICE_NULL)
- return KERN_INVALID_ARGUMENT;
-
- pcb = thread->pcb;
-
- new_io_tss = 0;
- iu = (io_use_t) kalloc(sizeof(struct io_use));
-
- Retry:
- simple_lock(&iopb_lock);
-
- /* find the io_port_t for the device */
- io_port = device_to_io_port_lookup(device);
- if (io_port == 0) {
- /*
- * Device does not have IO ports available.
- */
- simple_unlock(&iopb_lock);
- if (new_io_tss)
- kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
- kfree((vm_offset_t) iu, sizeof(struct io_use));
- return KERN_INVALID_ARGUMENT;
- }
-
- /* Have the IO port. */
-
- /* Make sure the thread has a TSS. */
-
- simple_lock(&pcb->lock);
- io_tss = pcb->ims.io_tss;
- if (io_tss == 0) {
- if (new_io_tss == 0) {
- /*
- * Allocate an IO-tss.
- */
- simple_unlock(&pcb->lock);
- simple_unlock(&iopb_lock);
-
- new_io_tss = (iopb_tss_t) kalloc(sizeof(struct iopb_tss));
- io_tss_init(new_io_tss, TRUE); /* XXX */
-
- goto Retry;
- }
- io_tss = new_io_tss;
- pcb->ims.io_tss = io_tss;
- new_io_tss = 0;
- }
-
- /*
- * Have io_port and io_tss.
- * See whether device is already mapped.
- */
- queue_iterate(&io_tss->io_port_list, old_iu, io_use_t, tsq) {
- if (old_iu->ps == io_port) {
- /*
- * Already mapped.
- */
- simple_unlock(&pcb->lock);
- simple_unlock(&iopb_lock);
-
- kfree((vm_offset_t)iu, sizeof(struct io_use));
- if (new_io_tss)
- kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
- return KERN_SUCCESS;
- }
- }
-
- /*
- * Add mapping.
- */
- iu->ps = io_port;
- iu->ts = io_tss;
- queue_enter(&io_port->io_use_list, iu, io_use_t, psq);
- queue_enter(&io_tss->io_port_list, iu, io_use_t, tsq);
- io_bitmap_set(io_tss->bitmap, io_port->io_port_list);
-
- simple_unlock(&pcb->lock);
- simple_unlock(&iopb_lock);
-
- if (new_io_tss)
- kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
- return KERN_SUCCESS;
-
-}
-
-/*
- * Remove an IO mapping from a thread.
- */
-kern_return_t
-i386_io_port_remove(thread, device)
- thread_t thread;
- mach_device_t device;
-{
- pcb_t pcb;
- iopb_tss_t io_tss;
- io_port_t io_port;
- io_use_t iu;
-
- if (thread == THREAD_NULL
- || device == DEVICE_NULL)
- return KERN_INVALID_ARGUMENT;
-
- pcb = thread->pcb;
-
- simple_lock(&iopb_lock);
-
- /* find the io_port_t for the device */
-
- io_port = device_to_io_port_lookup(device);
- if (io_port == 0) {
- /*
- * Device does not have IO ports available.
- */
- simple_unlock(&iopb_lock);
- return KERN_INVALID_ARGUMENT;
- }
-
- simple_lock(&pcb->lock);
- io_tss = pcb->ims.io_tss;
- if (io_tss == 0) {
- simple_unlock(&pcb->lock);
- simple_unlock(&iopb_lock);
- return KERN_INVALID_ARGUMENT; /* not mapped */
- }
-
- /*
- * Find the mapping.
- */
- queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
- if (iu->ps == io_port) {
- /*
- * Found mapping. Remove it.
- */
- io_bitmap_clear(io_tss->bitmap, io_port->io_port_list);
-
- queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
- queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
-
- simple_unlock(&pcb->lock);
- simple_unlock(&iopb_lock);
-
- kfree((vm_offset_t)iu, sizeof(struct io_use));
-
- return KERN_SUCCESS;
- }
- }
-
- /*
- * No mapping.
- */
- return KERN_INVALID_ARGUMENT;
-}
-
-/*
- * Return the IO ports mapped into a thread.
- */
-extern ipc_port_t mach_convert_device_to_port(/* device_t */);
-
-kern_return_t
-i386_io_port_list(thread, list, list_count)
- thread_t thread;
- mach_device_t **list;
- unsigned int *list_count;
-{
- register pcb_t pcb;
- register iopb_tss_t io_tss;
- unsigned int count, alloc_count;
- mach_device_t *devices;
- vm_size_t size_needed, size;
- vm_offset_t addr;
- int i;
-
- if (thread == THREAD_NULL)
- return KERN_INVALID_ARGUMENT;
-
- pcb = thread->pcb;
-
- alloc_count = 16; /* a guess */
-
- do {
- size_needed = alloc_count * sizeof(ipc_port_t);
- if (size_needed <= size)
- break;
-
- if (size != 0)
- kfree(addr,size);
-
- assert(size_needed > 0);
- size = size_needed;
-
- addr = kalloc(size);
- if (addr == 0)
- return KERN_RESOURCE_SHORTAGE;
-
- devices = (mach_device_t *)addr;
- count = 0;
-
- simple_lock(&iopb_lock);
- simple_lock(&pcb->lock);
- io_tss = pcb->ims.io_tss;
- if (io_tss != 0) {
- register io_use_t iu;
-
- queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
- if (++count < alloc_count) {
- *devices = iu->ps->device;
- device_reference(*devices);
- devices++;
- }
- }
- }
- simple_unlock(&pcb->lock);
- simple_unlock(&iopb_lock);
- } while (count > alloc_count);
-
- if (count == 0) {
- /*
- * No IO ports
- */
- *list = 0;
- *list_count = 0;
-
- if (size != 0)
- kfree(addr, size);
- }
- else {
- /*
- * If we allocated too much, must copy.
- */
- size_needed = count * sizeof(ipc_port_t);
- if (size_needed < size) {
- vm_offset_t new_addr;
-
- new_addr = kalloc(size_needed);
- if (new_addr == 0) {
- for (i = 0; i < count; i++)
- device_deallocate(devices[i]);
- kfree(addr, size);
- return KERN_RESOURCE_SHORTAGE;
- }
-
- memcpy((void *)new_addr, (void *)addr, size_needed);
- kfree(addr, size);
- devices = (mach_device_t *)new_addr;
- }
-
- for (i = 0; i < count; i++)
- ((ipc_port_t *)devices)[i] =
- mach_convert_device_to_port(devices[i]);
- }
- *list = devices;
- *list_count = count;
-
- return KERN_SUCCESS;
-}
-
-/*
- * Check whether an IO device is mapped to a particular thread.
- * Used to support the 'iopl' device automatic mapping.
- */
-boolean_t
-iopb_check_mapping(thread, device)
- thread_t thread;
- mach_device_t device;
-{
- pcb_t pcb;
- io_port_t io_port;
- io_use_t iu;
-
- pcb = thread->pcb;
-
- simple_lock(&iopb_lock);
-
- /* Find the io port for the device */
-
- io_port = device_to_io_port_lookup(device);
- if (io_port == 0) {
- simple_unlock(&iopb_lock);
- return FALSE;
- }
-
- /* Look up the mapping in the device`s mapping list. */
-
- queue_iterate(&io_port->io_use_list, iu, io_use_t, psq) {
- if (iu->ts == pcb->ims.io_tss) {
- /*
- * Device is mapped.
- */
- simple_unlock(&iopb_lock);
- return TRUE;
- }
- }
- simple_unlock(&iopb_lock);
- return FALSE;
-}
diff --git a/i386/i386/iopb.h b/i386/i386/iopb.h
deleted file mode 100644
index 0a3e574..0000000
--- a/i386/i386/iopb.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Mach Operating System
- * Copyright (c) 1991,1990 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.
- */
-
-#ifndef _I386_IOPB_H_
-#define _I386_IOPB_H_
-
-#include <i386/tss.h>
-#include <kern/queue.h>
-
-/*
- * IO permission bitmap.
- *
- * Allows only IO ports 0 .. 0x3ff: for ISA machines.
- */
-
-#define iopb_howmany(a,b) (((a)+(b)-1)/(b))
-
-#define IOPB_MAX 0xffff /* ISA bus allows ports 0..3ff */
- /* but accelerator cards are funky */
-#define IOPB_BYTES (iopb_howmany(IOPB_MAX+1,8))
-
-typedef unsigned char isa_iopb[IOPB_BYTES];
-
-/*
- * An IO permission map is a task segment with an IO permission bitmap.
- */
-
-struct iopb_tss {
- struct i386_tss tss; /* task state segment */
- isa_iopb bitmap; /* bitmap of mapped IO ports */
- unsigned int barrier; /* bitmap barrier for CPU slop */
- queue_head_t io_port_list; /* list of mapped IO ports */
- int iopb_desc[2]; /* descriptor for this TSS */
-};
-
-typedef struct iopb_tss *iopb_tss_t;
-
-#endif /* _I386_IOPB_H_ */
-
diff --git a/i386/i386/ktss.c b/i386/i386/ktss.c
index 53c8be9..03d9a04 100644
--- a/i386/i386/ktss.c
+++ b/i386/i386/ktss.c
@@ -36,6 +36,9 @@
#include "gdt.h"
#include "ktss.h"
+/* A kernel TSS with a complete I/O bitmap. */
+struct task_tss ktss;
+
void
ktss_init()
{
@@ -44,16 +47,15 @@ ktss_init()
/* Initialize the master TSS descriptor. */
fill_gdt_descriptor(KERNEL_TSS,
- kvtolin(&ktss), sizeof(ktss)+65536/8+1-1,
+ kvtolin(&ktss), sizeof(struct task_tss) - 1,
ACC_PL_K|ACC_TSS, 0);
/* Initialize the master TSS. */
- ktss.ss0 = KERNEL_DS;
- ktss.esp0 = (unsigned)(exception_stack+1024);
- ktss.io_bit_map_offset = sizeof(ktss);
-
+ ktss.tss.ss0 = KERNEL_DS;
+ ktss.tss.esp0 = (unsigned)(exception_stack+1024);
+ ktss.tss.io_bit_map_offset = IOPB_INVAL;
/* Set the last byte in the I/O bitmap to all 1's. */
- ((unsigned char*)&ktss)[sizeof(ktss)+65536/8] = 0xff;
+ ktss.barrier = 0xff;
/* Load the TSS. */
ltr(KERNEL_TSS);
diff --git a/i386/i386/ktss.h b/i386/i386/ktss.h
index 8979115..3522e86 100644
--- a/i386/i386/ktss.h
+++ b/i386/i386/ktss.h
@@ -25,6 +25,6 @@
#include "tss.h"
-extern struct i386_tss ktss;
+extern struct task_tss ktss;
#endif /* _I386_KTSS_ */
diff --git a/i386/i386/locore.S b/i386/i386/locore.S
index 300c8c3..422dc1a 100644
--- a/i386/i386/locore.S
+++ b/i386/i386/locore.S
@@ -1441,12 +1441,3 @@ Entry(cpu_shutdown)
xor %ecx,%ecx /* generate a divide by zero */
div %ecx,%eax /* reboot now */
ret /* this will "never" be executed */
-
-
-/*
- * Allocate enough space for a kernel TSS with a complete I/O bitmap,
- * for making v86-mode BIOS calls. XXX
- */
- .data
- .globl EXT(ktss)
- .comm EXT(ktss),0x68+65536/8+1
diff --git a/i386/i386/machine_task.c b/i386/i386/machine_task.c
new file mode 100644
index 0000000..35b89e0
--- /dev/null
+++ b/i386/i386/machine_task.c
@@ -0,0 +1,81 @@
+/* Machine specific data for a task on i386.
+
+ Copyright (C) 2002, 2007 Free Software Foundation, Inc.
+
+ Written by Marcus Brinkmann. Glued into GNU Mach by Thomas Schwinge.
+
+ This file is part of GNU Mach.
+
+ GNU Mach is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include <kern/lock.h>
+#include <mach/mach_types.h>
+#include <kern/zalloc.h>
+#include <kern/mach_param.h>
+#include <machine/task.h>
+
+#include <machine/io_perm.h>
+
+
+/* The zone which holds our IO permission bitmaps. */
+zone_t machine_task_iopb_zone;
+
+
+/* Initialize the machine task module. The function is called once at
+ start up by task_init in kern/task.c. */
+void
+machine_task_module_init (void)
+{
+ machine_task_iopb_zone = zinit (IOPB_BYTES, 0,
+ TASK_MAX * IOPB_BYTES,
+ IOPB_BYTES,
+ ZONE_COLLECTABLE | ZONE_EXHAUSTIBLE,
+ "i386 machine task iopb");
+}
+
+
+/* Initialize the machine specific part of task TASK. */
+void
+machine_task_init (task_t task)
+{
+ task->machine.iopb_size = 0;
+ task->machine.iopb = 0;
+ simple_lock_init (&task->machine.iopb_lock);
+}
+
+
+/* Destroy the machine specific part of task TASK and release all
+ associated resources. */
+void
+machine_task_terminate (task_t task)
+{
+ if (task->machine.iopb)
+ zfree (machine_task_iopb_zone, (vm_offset_t) task->machine.iopb);
+}
+
+
+/* Try to release as much memory from the machine specific data in
+ task TASK. */
+void
+machine_task_collect (task_t task)
+{
+ simple_lock (&task->machine.iopb_lock);
+ if (task->machine.iopb_size == 0 && task->machine.iopb)
+ {
+ zfree (machine_task_iopb_zone, (vm_offset_t) task->machine.iopb);
+ task->machine.iopb = 0;
+ }
+ simple_unlock (&task->machine.iopb_lock);
+}
diff --git a/i386/i386/mp_desc.c b/i386/i386/mp_desc.c
index 1e95f81..e1ac9c3 100644
--- a/i386/i386/mp_desc.c
+++ b/i386/i386/mp_desc.c
@@ -35,6 +35,9 @@
#include <i386/mp_desc.h>
#include <i386/lock.h>
+#include <machine/ktss.h>
+#include <machine/tss.h>
+#include <machine/io_perm.h>
/*
* The i386 needs an interrupt stack to keep the PCB stack from being
@@ -82,7 +85,7 @@ struct mp_desc_table *mp_desc_table[NCPUS] = { 0 };
/*
* Pointer to TSS for access in load_context.
*/
-struct i386_tss *mp_ktss[NCPUS] = { 0 };
+struct task_tss *mp_ktss[NCPUS] = { 0 };
/*
* Pointer to GDT to reset the KTSS busy bit.
@@ -95,7 +98,6 @@ struct real_descriptor *mp_gdt[NCPUS] = { 0 };
extern struct real_gate idt[IDTSZ];
extern struct real_descriptor gdt[GDTSZ];
extern struct real_descriptor ldt[LDTSZ];
-extern struct i386_tss ktss;
/*
* Allocate and initialize the per-processor descriptor tables.
@@ -112,7 +114,7 @@ mp_desc_init(mycpu)
* Master CPU uses the tables built at boot time.
* Just set the TSS and GDT pointers.
*/
- mp_ktss[mycpu] = &ktss;
+ mp_ktss[mycpu] = (struct task_tss *) &ktss;
mp_gdt[mycpu] = gdt;
return 0;
}
@@ -140,7 +142,7 @@ mp_desc_init(mycpu)
ldt,
sizeof(ldt));
memset(&mpt->ktss, 0,
- sizeof(struct i386_tss));
+ sizeof(struct task_tss));
/*
* Fix up the entries in the GDT to point to
@@ -152,11 +154,12 @@ mp_desc_init(mycpu)
ACC_P|ACC_PL_K|ACC_LDT, 0);
fill_descriptor(&mpt->gdt[sel_idx(KERNEL_TSS)],
(unsigned)&mpt->ktss,
- sizeof(struct i386_tss) - 1,
+ sizeof(struct task_tss) - 1,
ACC_P|ACC_PL_K|ACC_TSS, 0);
- mpt->ktss.ss0 = KERNEL_DS;
- mpt->ktss.io_bit_map_offset = 0x0FFF; /* no IO bitmap */
+ mpt->ktss.tss.ss0 = KERNEL_DS;
+ mpt->ktss.tss.io_bit_map_offset = IOPB_INVAL;
+ mpt->ktss.barrier = 0xFF;
return mpt;
}
diff --git a/i386/i386/mp_desc.h b/i386/i386/mp_desc.h
index e9a69d2..8ae272b 100644
--- a/i386/i386/mp_desc.h
+++ b/i386/i386/mp_desc.h
@@ -52,7 +52,7 @@ struct mp_desc_table {
struct real_gate idt[IDTSZ]; /* IDT */
struct real_descriptor gdt[GDTSZ]; /* GDT */
struct real_descriptor ldt[LDTSZ]; /* LDT */
- struct i386_tss ktss;
+ struct task_tss ktss;
};
/*
@@ -63,7 +63,7 @@ extern struct mp_desc_table *mp_desc_table[NCPUS];
/*
* The kernel TSS gets its own pointer.
*/
-extern struct i386_tss *mp_ktss[NCPUS];
+extern struct task_tss *mp_ktss[NCPUS];
/*
* So does the GDT.
diff --git a/i386/i386/pcb.c b/i386/i386/pcb.c
index 1b24557..58b4ea9 100644
--- a/i386/i386/pcb.c
+++ b/i386/i386/pcb.c
@@ -24,6 +24,7 @@
* the rights to redistribute these changes.
*/
+#include <stddef.h>
#include <string.h>
#include <mach/std_types.h>
@@ -43,7 +44,6 @@
#include <i386/thread.h>
#include <i386/proc_reg.h>
#include <i386/seg.h>
-#include <i386/tss.h>
#include <i386/user_ldt.h>
#include <i386/fpu.h>
#include "eflags.h"
@@ -52,6 +52,8 @@
#include "ktss.h"
#include "pcb.h"
+#include <machine/tss.h>
+
#if NCPUS > 1
#include <i386/mp_desc.h>
#endif
@@ -59,8 +61,6 @@
extern thread_t Switch_context();
extern void Thread_continue();
-extern iopb_tss_t iopb_create();
-extern void iopb_destroy();
extern void user_ldt_free();
zone_t pcb_zone;
@@ -126,7 +126,7 @@ vm_offset_t stack_detach(thread)
#define curr_ktss(mycpu) (mp_ktss[mycpu])
#else
#define curr_gdt(mycpu) ((void)(mycpu), gdt)
-#define curr_ktss(mycpu) ((void)(mycpu), &ktss)
+#define curr_ktss(mycpu) ((void)(mycpu), (struct task_tss *)&ktss)
#endif
#define gdt_desc_p(mycpu,sel) \
@@ -137,7 +137,6 @@ void switch_ktss(pcb)
{
int mycpu = cpu_number();
{
- register iopb_tss_t tss = pcb->ims.io_tss;
vm_offset_t pcb_stack_top;
/*
@@ -153,25 +152,7 @@ void switch_ktss(pcb)
? (int) (&pcb->iss + 1)
: (int) (&pcb->iss.v86_segs);
- if (tss == 0) {
- /*
- * No per-thread IO permissions.
- * Use standard kernel TSS.
- */
- if (!(gdt_desc_p(mycpu,KERNEL_TSS)->access & ACC_TSS_BUSY))
- set_tr(KERNEL_TSS);
- curr_ktss(mycpu)->esp0 = pcb_stack_top;
- }
- else {
- /*
- * Set the IO permissions. Use this thread`s TSS.
- */
- *gdt_desc_p(mycpu,USER_TSS)
- = *(struct real_descriptor *)tss->iopb_desc;
- tss->tss.esp0 = pcb_stack_top;
- set_tr(USER_TSS);
- gdt_desc_p(mycpu,KERNEL_TSS)->access &= ~ ACC_TSS_BUSY;
- }
+ curr_ktss(mycpu)->tss.esp0 = pcb_stack_top;
}
{
@@ -207,6 +188,24 @@ void switch_ktss(pcb)
}
+/* If NEW_IOPB is not null, the SIZE denotes the number of bytes in
+ the new bitmap. Expects iopb_lock to be held. */
+void
+update_ktss_iopb (unsigned char *new_iopb, io_port_t size)
+{
+ struct task_tss *tss = curr_ktss (cpu_number ());
+
+ if (new_iopb && size > 0)
+ {
+ tss->tss.io_bit_map_offset
+ = offsetof (struct task_tss, barrier) - size;
+ memcpy (((char *) tss) + tss->tss.io_bit_map_offset,
+ new_iopb, size);
+ }
+ else
+ tss->tss.io_bit_map_offset = IOPB_INVAL;
+}
+
/*
* stack_handoff:
*
@@ -236,6 +235,19 @@ void stack_handoff(old, new)
old, mycpu);
PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
new, mycpu);
+
+ simple_lock (&new_task->machine.iopb_lock);
+#if NCPUS>1
+#warning SMP support missing (avoid races with io_perm_modify).
+#else
+ /* This optimization only works on a single processor
+ machine, where old_task's iopb can not change while
+ we are switching. */
+ if (old_task->machine.iopb || new_task->machine.iopb)
+#endif
+ update_ktss_iopb (new_task->machine.iopb,
+ new_task->machine.iopb_size);
+ simple_unlock (&new_task->machine.iopb_lock);
}
}
@@ -298,6 +310,19 @@ thread_t switch_context(old, continuation, new)
old, mycpu);
PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
new, mycpu);
+
+ simple_lock (&new_task->machine.iopb_lock);
+#if NCPUS>1
+#warning SMP support missing (avoid races with io_perm_modify).
+#else
+ /* This optimization only works on a single processor
+ machine, where old_task's iopb can not change while
+ we are switching. */
+ if (old_task->machine.iopb || new_task->machine.iopb)
+#endif
+ update_ktss_iopb (new_task->machine.iopb,
+ new_task->machine.iopb_size);
+ simple_unlock (&new_task->machine.iopb_lock);
}
}
@@ -317,7 +342,6 @@ void pcb_module_init()
0, "i386 pcb state");
fpu_module_init();
- iopb_init();
}
void pcb_init(thread)
@@ -361,8 +385,6 @@ void pcb_terminate(thread)
counter(if (--c_threads_current < c_threads_min)
c_threads_min = c_threads_current);
- if (pcb->ims.io_tss != 0)
- iopb_destroy(pcb->ims.io_tss);
if (pcb->ims.ifps != 0)
fp_free(pcb->ims.ifps);
if (pcb->ims.ldt != 0)
@@ -516,7 +538,6 @@ kern_return_t thread_setstatus(thread, flavor, tstate, count)
*/
case i386_ISA_PORT_MAP_STATE: {
register struct i386_isa_port_map_state *state;
- register iopb_tss_t tss;
if (count < i386_ISA_PORT_MAP_STATE_COUNT)
return(KERN_INVALID_ARGUMENT);
@@ -673,32 +694,20 @@ kern_return_t thread_getstatus(thread, flavor, tstate, count)
*/
case i386_ISA_PORT_MAP_STATE: {
register struct i386_isa_port_map_state *state;
- register iopb_tss_t tss;
if (*count < i386_ISA_PORT_MAP_STATE_COUNT)
return(KERN_INVALID_ARGUMENT);
state = (struct i386_isa_port_map_state *) tstate;
- tss = thread->pcb->ims.io_tss;
-
- if (tss == 0) {
- int i;
- /*
- * The thread has no ktss, so no IO permissions.
- */
-
- for (i = 0; i < sizeof state->pm; i++)
- state->pm[i] = 0xff;
- } else {
- /*
- * The thread has its own ktss.
- */
-
- memcpy(state->pm,
- tss->bitmap,
- sizeof state->pm);
- }
+ simple_lock (&thread->task->machine.iopb_lock);
+ if (thread->task->machine.iopb == 0)
+ memset (state->pm, 0xff, sizeof state->pm);
+ else
+ memcpy((char *) state->pm,
+ (char *) thread->task->machine.iopb,
+ sizeof state->pm);
+ simple_unlock (&thread->task->machine.iopb_lock);
*count = i386_ISA_PORT_MAP_STATE_COUNT;
break;
diff --git a/i386/i386/task.h b/i386/i386/task.h
new file mode 100644
index 0000000..ca8de04
--- /dev/null
+++ b/i386/i386/task.h
@@ -0,0 +1,61 @@
+/* Data types for machine specific parts of tasks on i386.
+
+ Copyright (C) 2002, 2007 Free Software Foundation, Inc.
+
+ Written by Marcus Brinkmann. Glued into GNU Mach by Thomas Schwinge.
+
+ This file is part of GNU Mach.
+
+ GNU Mach is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#ifndef _I386_TASK_H_
+#define _I386_TASK_H_
+
+#include <kern/kern_types.h>
+#include <kern/zalloc.h>
+
+/* The machine specific data of a task. */
+struct machine_task
+{
+ /* A lock protecting iopb_size and iopb. */
+ decl_simple_lock_data (, iopb_lock);
+
+ /* The highest I/O port number enabled. */
+ int iopb_size;
+
+ /* The I/O permission bitmap. */
+ unsigned char *iopb;
+};
+typedef struct machine_task machine_task_t;
+
+
+extern zone_t machine_task_iopb_zone;
+
+/* Initialize the machine task module. The function is called once at
+ start up by task_init in kern/task.c. */
+void machine_task_module_init (void);
+
+/* Initialize the machine specific part of task TASK. */
+void machine_task_init (task_t);
+
+/* Destroy the machine specific part of task TASK and release all
+ associated resources. */
+void machine_task_terminate (task_t);
+
+/* Try to release as much memory from the machine specific data in
+ task TASK. */
+void machine_task_collect (task_t);
+
+#endif /* _I386_TASK_H_ */
diff --git a/i386/i386/thread.h b/i386/i386/thread.h
index 337190e..0caf6d6 100644
--- a/i386/i386/thread.h
+++ b/i386/i386/thread.h
@@ -39,7 +39,6 @@
#include <kern/lock.h>
-#include <i386/iopb.h>
#include <i386/tss.h>
#include "gdt.h"
@@ -158,7 +157,6 @@ struct i386_interrupt_state {
*/
struct i386_machine_state {
- iopb_tss_t io_tss;
struct user_ldt * ldt;
struct i386_fpsave_state *ifps;
struct v86_assist_state v86s;
diff --git a/i386/i386/tss.h b/i386/i386/tss.h
index 0d02f70..ee0d612 100644
--- a/i386/i386/tss.h
+++ b/i386/i386/tss.h
@@ -29,6 +29,8 @@
#include <mach/inline.h>
+#include <machine/io_perm.h>
+
/*
* i386 Task State Segment
*/
@@ -66,6 +68,17 @@ struct i386_tss {
bit map */
};
+
+/* The structure extends the above TSS structure by an I/O permission bitmap
+ and the barrier. */
+struct task_tss
+ {
+ struct i386_tss tss;
+ unsigned char iopb[IOPB_BYTES];
+ unsigned char barrier;
+};
+
+
/* Load the current task register. */
MACH_INLINE void
ltr(unsigned short segment)
diff --git a/i386/i386at/kd.c b/i386/i386at/kd.c
index 10e1d4e..9dbbd46 100644
--- a/i386/i386at/kd.c
+++ b/i386/i386at/kd.c
@@ -84,7 +84,6 @@ WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include <device/tty.h>
#include <device/io_req.h>
#include <device/buf.h> /* for struct uio (!) */
-#include <i386/io_port.h>
#include <vm/vm_kern.h>
#include <i386/vm_param.h>
#include <i386/machspl.h>
@@ -333,33 +332,6 @@ unsigned char key_map[NUMKEYS][WIDTH_KMAP] = {
short kd_index_reg = EGA_IDX_REG;
short kd_io_reg = EGA_IO_REG;
-/*
- * IO port sets for different controllers.
- */
-io_reg_t vga_port_list[] = {
- 0x3b4, 0x3b5, 0x3b8, 0x3b9, 0x3ba, /* MDA/EGA */
- 0x3d4, 0x3d5, 0x3d8, 0x3d9, 0x3da, /* CGA/EGA */
- 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7,
- 0x3c8, 0x3c9, 0x3ca, 0x3cb, 0x3cc, 0x3cd, 0x3ce, 0x3cf,
- IO_REG_NULL
-};
-
-mach_device_t kd_io_device = 0;
-
-void
-kd_io_map_open(device)
- mach_device_t device;
-{
- kd_io_device = device;
- io_port_create(device, vga_port_list);
-}
-
-void
-kd_io_map_close()
-{
- io_port_destroy(kd_io_device);
- kd_io_device = 0;
-}
/*
* Globals used only for bitmap-based controllers. See kdsoft.h for
@@ -508,11 +480,6 @@ kdopen(dev, flag, ior)
tp->t_ospeed = tp->t_ispeed = B9600;
tp->t_flags = ODDP|EVENP|ECHO|CRMOD|XTABS;
kdinit();
-
- /* XXX kd_io_map_open allocates memory */
- simple_unlock(&tp->t_lock);
- kd_io_map_open(ior->io_device);
- simple_lock(&tp->t_lock);
}
tp->t_state |= TS_CARR_ON;
simple_unlock(&tp->t_lock);
@@ -549,10 +516,7 @@ int flag;
splx(s);
}
- kd_io_map_close();
-
return;
-
}
diff --git a/i386/include/mach/i386/mach_i386.defs b/i386/include/mach/i386/mach_i386.defs
index 5c9f367..0703d59 100644
--- a/i386/include/mach/i386/mach_i386.defs
+++ b/i386/include/mach/i386/mach_i386.defs
@@ -35,26 +35,31 @@ subsystem
#include <mach/std_types.defs>
#include <mach/mach_types.defs>
-#include <device/device_types.defs>
-
-type device_list_t = ^array[] of device_t;
type descriptor_t = struct[2] of int;
type descriptor_list_t = array[*] of descriptor_t;
import <mach/machine/mach_i386_types.h>;
-routine i386_io_port_add(
- target_thread : thread_t;
- device : device_t);
+#if KERNEL_SERVER
+simport <machine/io_perm.h>;
+#endif
-routine i386_io_port_remove(
- target_thread : thread_t;
- device : device_t);
+type io_port_t = MACH_MSG_TYPE_INTEGER_16;
+type io_perm_t = mach_port_t
+ ctype: mach_port_t
+#if KERNEL_SERVER
+ intran: io_perm_t convert_port_to_io_perm(mach_port_t)
+ outtran: mach_port_t convert_io_perm_to_port(io_perm_t)
+#if TODO_REMOVE_ME
+ destructor: io_perm_deallocate(io_perm_t)
+#endif
+#endif /* KERNEL_SERVER */
+ ;
-routine i386_io_port_list(
- target_thread : thread_t;
- out device_list : device_list_t);
+skip; /* i386_io_port_add */
+skip; /* i386_io_port_remove */
+skip; /* i386_io_port_list */
routine i386_set_ldt(
target_thread : thread_t;
@@ -67,8 +72,27 @@ routine i386_get_ldt(
selector_count : int;
out desc_list : descriptor_list_t);
-skip; /* i386_io_perm_create */
-skip; /* i386_io_perm_modify */
+/* Request a new port IO_PERM that represents the capability to access
+ the I/O ports [FROM; TO] directly. MASTER_PORT is the master device port.
+
+ The function returns KERN_INVALID_ARGUMENT if TARGET_TASK is not a task,
+ or FROM is greater than TO. */
+routine i386_io_perm_create(
+ master_port : mach_port_t;
+ from : io_port_t;
+ to : io_port_t;
+ out io_perm : io_perm_t);
+
+/* Modify the I/O permissions for TARGET_TASK. If ENABLE is TRUE, the
+ permission to access the I/O ports specified by IO_PERM is granted,
+ otherwise it is withdrawn.
+
+ The function returns KERN_INVALID_ARGUMENT if TARGET_TASK is not a valid
+ task or IO_PERM not a valid I/O permission port. */
+routine i386_io_perm_modify(
+ target_task : task_t;
+ io_perm : io_perm_t;
+ enable : boolean_t);
/* Modify one of a few available thread-specific segment descriptor slots.
The SELECTOR must be a value from a previous call (on any thread),
diff --git a/i386/include/mach/i386/mach_i386_types.h b/i386/include/mach/i386/mach_i386_types.h
index 43780a3..b03c0b0 100644
--- a/i386/include/mach/i386/mach_i386_types.h
+++ b/i386/include/mach/i386/mach_i386_types.h
@@ -31,11 +31,6 @@
#define _MACH_MACH_I386_TYPES_H_
/*
- * Array of devices.
- */
-typedef device_t *device_list_t;
-
-/*
* i386 segment descriptor.
*/
struct descriptor {
@@ -46,4 +41,15 @@ struct descriptor {
typedef struct descriptor descriptor_t;
typedef struct descriptor *descriptor_list_t;
+/*
+ * i386 I/O port
+ */
+
+#ifdef MACH_KERNEL
+#include <i386/io_perm.h>
+#else
+typedef unsigned short io_port_t;
+typedef mach_port_t io_perm_t;
+#endif
+
#endif /* _MACH_MACH_I386_TYPES_H_ */
diff --git a/include/stddef.h b/include/stddef.h
new file mode 100644
index 0000000..dd67734
--- /dev/null
+++ b/include/stddef.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Mach.
+ *
+ * GNU Mach is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef _STDDEF_H_
+#define _STDDEF_H_
+
+/* From GCC's `/lib/gcc/X/X/include/stddef.h'. */
+
+/* Offset of member MEMBER in a struct of type TYPE. */
+#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
+
+#endif /* _STDDEF_H_ */
diff --git a/kern/task.c b/kern/task.c
index 1c4c673..45c59c5 100644
--- a/kern/task.c
+++ b/kern/task.c
@@ -67,6 +67,7 @@ void task_init(void)
0, "tasks");
eml_init();
+ machine_task_module_init ();
/*
* Create the kernel task as the first task.
@@ -145,6 +146,7 @@ kern_return_t task_create(
eml_task_reference(new_task, parent_task);
ipc_task_init(new_task, parent_task);
+ machine_task_init (new_task);
new_task->total_user_time.seconds = 0;
new_task->total_user_time.microseconds = 0;
@@ -220,6 +222,8 @@ void task_deallocate(
if (c != 0)
return;
+ machine_task_terminate (task);
+
eml_task_deallocate(task);
pset = task->processor_set;
@@ -1092,6 +1096,7 @@ void task_collect_scan(void)
pset_unlock(pset);
simple_unlock(&all_psets_lock);
+ machine_task_collect (task);
pmap_collect(task->map->pmap);
if (prev_task != TASK_NULL)
diff --git a/kern/task.h b/kern/task.h
index dce3a76..1337a98 100644
--- a/kern/task.h
+++ b/kern/task.h
@@ -46,6 +46,7 @@
#include <kern/processor.h>
#include <kern/syscall_emulation.h>
#include <vm/vm_types.h>
+#include <machine/task.h>
struct task {
/* Synchronization/destruction information */
@@ -98,6 +99,9 @@ struct task {
vm_offset_t fast_tas_base[TASK_FAST_TAS_NRAS];
vm_offset_t fast_tas_end[TASK_FAST_TAS_NRAS];
#endif /* FAST_TAS */
+
+ /* Hardware specific data. */
+ machine_task_t machine;
};
#define task_lock(task) simple_lock(&(task)->lock)