diff options
author | Thomas Schwinge <tschwinge@gnu.org> | 2007-05-07 22:04:54 +0000 |
---|---|---|
committer | Thomas Schwinge <tschwinge@gnu.org> | 2009-06-18 00:27:10 +0200 |
commit | 2c1f7f5ef7e2252312ecfa77b2352e89669006bf (patch) | |
tree | 503d5b28de51384b4789b75a8ec506132c795349 | |
parent | 029ea3ffa9e56d33eef2e859c98848f722f63b1c (diff) |
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.
-rw-r--r-- | ChangeLog | 102 | ||||
-rw-r--r-- | i386/Makefrag.am | 9 | ||||
-rw-r--r-- | i386/i386/io_perm.c | 317 | ||||
-rw-r--r-- | i386/i386/io_perm.h | 65 | ||||
-rw-r--r-- | i386/i386/io_port.h | 43 | ||||
-rw-r--r-- | i386/i386/iopb.c | 618 | ||||
-rw-r--r-- | i386/i386/iopb.h | 62 | ||||
-rw-r--r-- | i386/i386/ktss.c | 14 | ||||
-rw-r--r-- | i386/i386/ktss.h | 2 | ||||
-rw-r--r-- | i386/i386/locore.S | 9 | ||||
-rw-r--r-- | i386/i386/machine_task.c | 81 | ||||
-rw-r--r-- | i386/i386/mp_desc.c | 17 | ||||
-rw-r--r-- | i386/i386/mp_desc.h | 4 | ||||
-rw-r--r-- | i386/i386/pcb.c | 105 | ||||
-rw-r--r-- | i386/i386/task.h | 61 | ||||
-rw-r--r-- | i386/i386/thread.h | 2 | ||||
-rw-r--r-- | i386/i386/tss.h | 13 | ||||
-rw-r--r-- | i386/i386at/kd.c | 36 | ||||
-rw-r--r-- | i386/include/mach/i386/mach_i386.defs | 52 | ||||
-rw-r--r-- | i386/include/mach/i386/mach_i386_types.h | 16 | ||||
-rw-r--r-- | include/stddef.h | 29 | ||||
-rw-r--r-- | kern/task.c | 5 | ||||
-rw-r--r-- | kern/task.h | 4 |
23 files changed, 809 insertions, 857 deletions
@@ -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, ¬ify); + 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) |