[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: I/O permission bitmap patch for oskit-mach
From: |
Marcus Brinkmann |
Subject: |
Re: I/O permission bitmap patch for oskit-mach |
Date: |
Fri, 8 Mar 2002 01:39:49 +0100 |
User-agent: |
Mutt/1.3.27i |
On Wed, Mar 06, 2002 at 02:58:56AM -0500, Roland McGrath wrote:
> Please add -p to your diff switches.
At one time I will learn it, sorry. I did it this time.
> For ktss, don't use a weak alias, use a strong one.
Done (I needed to put "ktss" in parenthesis).
> I don't see a reason to zalloc the struct machine_task. Why not just have
> the struct task member be a struct instead of a pointer?
Done. I didn't pursue the opaqueness anyway (the struct was already defined
in the header).
> For the SMP problem, it would certainly be simple to hack the existing
> check_io_fault code to notice when the task's iopb has changed, reload it,
> and retry the instruction. But I am really not concerned about this
> problem cropping up in practice--certainly it won't before we finish making
> SMP work at all! :)
:)
> In io_bitmap_init, just use memset. That's what it's for.
Ok, done. I also removed the second argument, we always initialize to no
permission by default. Now the function became pretty pointless, but, oh well.
> Might as well use io_port_t for fields like iopb_size.
Done.
I also included another patch I forgot, that is making dev_open_alloc and
setup_no_senders non-static, because I need them when setting up the pseudo
device, and fixed three warnings. It compiles, but I did not run it
(changes are quite small, I can give it a last try before we check it in or
so).
Thanks,
Marcus
diff -ruNp oskit-mach/ChangeLog.oskit oskit-mach.new/ChangeLog.oskit
--- oskit-mach/ChangeLog.oskit Fri Mar 8 00:29:11 2002
+++ oskit-mach.new/ChangeLog.oskit Fri Mar 8 01:22:47 2002
@@ -1,3 +1,64 @@
+2002-02-27 Marcus Brinkmann <marcus@gnu.org>
+
+ * bogus/mach_machine_routines.h (MACH_MACHINE_ROUTINES): Set to 1.
+ * i386/i386/io_perm.h: New file.
+ * i386/i386/io_perm.c: New file.
+ * i386/i386/machine_task.c: New file.
+ * i386/Makefrag (i386-files): Add io_perm.c and machine_task.c.
+ * i386/i386/mp_desc.h: Include `machine/tss.h' instead
+ `oskit/x86/tss.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/i386/tss.h: New file.
+ * i386/include/mach/i386/mach_i386.defs: Do not include
+ `mach/machine/mach_i386_types.h'.
+ [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_removed): 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.
+ * oskit/x86/main.c: Include `i386/io_perm.h' and `machine/tss.h'.
+ (ktss): New static global variable that replaces base_tss at link
+ time.
+ (main): Set up the base_tss to include an I/O permission bitmap.
+ * oskit/ds_oskit.h [__i386__]: Include `machine/io_perm.h'.
+ (struct device) [__i386__]: Add a structure with io_perm range
+ to the com union.
+ * oskit/ds_routines.c (dev_open_alloc): Remove static attribute.
+ (setup_no_senders): Likewise.
+
2002-02-28 Marcus Brinkmann <marcus@gnu.org>
* oskit/ds_routines.c (device_deallocate): Allow DEVICE->com_device
diff -ruNp oskit-mach/bogus/mach_machine_routines.h
oskit-mach.new/bogus/mach_machine_routines.h
--- oskit-mach/bogus/mach_machine_routines.h Tue Feb 25 22:28:04 1997
+++ oskit-mach.new/bogus/mach_machine_routines.h Fri Mar 8 00:34:38 2002
@@ -1 +1 @@
-#define MACH_MACHINE_ROUTINES 0
+#define MACH_MACHINE_ROUTINES 1
diff -ruNp oskit-mach/i386/Makefrag oskit-mach.new/i386/Makefrag
--- oskit-mach/i386/Makefrag Tue Feb 27 04:10:18 2001
+++ oskit-mach.new/i386/Makefrag Fri Mar 8 00:34:38 2002
@@ -20,7 +20,7 @@ DEFINES += -D__ELF__=1 -Di386=1 -DAT386=
i386at-files = int_init.c pic_isa.c
i386-files = ast_check.c fpu.c gdt.c idt.c ldt.c \
mp_desc.c pcb.c phys.c pic.c pit.c trap.c user_ldt.c \
- hardclock.c # loose_ends.c
+ hardclock.c io_perm.c machine_task.c # loose_ends.c
intel-files = pmap.c read_fault.c
# Assembler source
diff -ruNp oskit-mach/i386/i386/io_perm.c oskit-mach.new/i386/i386/io_perm.c
--- oskit-mach/i386/i386/io_perm.c Thu Jan 1 01:00:00 1970
+++ oskit-mach.new/i386/i386/io_perm.c Fri Mar 8 01:27:36 2002
@@ -0,0 +1,242 @@
+/* io_perm.c - Code to manipulate I/O permission bitmap objects.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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.
+
+ GNU Mach 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., 59 Temple Place - Suite 330, Boston, MA 02111, 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 <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 <device/device_port.h>
+
+#include <oskit/ds_oskit.h>
+
+#include "io_perm.h"
+#include "gdt.h"
+
+
+/* XXX From oskit/ds_routines.c */
+device_t dev_open_alloc (void);
+void setup_no_senders (device_t dev);
+
+
+/* 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)
+{
+ return convert_device_to_port ((device_t) io_perm);
+}
+
+
+/* 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)
+{
+ return (io_perm_t) dev_port_lookup (port);
+}
+
+
+/* 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)
+{
+ device_deallocate ((device_t) io_perm);
+}
+
+
+/* Initialize bitmap by setting all bits to OFF == 1. */
+void
+io_bitmap_init (unsigned char *iopb)
+{
+ memset (iopb, ~0, IOPB_BYTES);
+}
+
+
+/* Set selected bits in bitmap to ON == 0. */
+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. */
+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 || from > to)
+ return KERN_INVALID_ARGUMENT;
+
+ *new = (io_perm_t) dev_open_alloc ();
+ if (! *new)
+ return KERN_RESOURCE_SHORTAGE;
+
+ /* Set up the dummy device. */
+ (*new)->com_device = 0;
+ (*new)->mode = 0;
+ (*new)->ops = &no_device_ops;
+ setup_no_senders ((device_t) *new);
+
+ (*new)->com.io_perm.from = from;
+ (*new)->com.io_perm.to = to;
+
+ 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 || (device_t) io_perm == DEVICE_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+ from = io_perm->com.io_perm.from;
+ to = io_perm->com.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 *) kalloc (IOPB_BYTES);
+ simple_lock (&target_task->machine.iopb_lock);
+ if (target_task->machine.iopb)
+ {
+ if (iopb)
+ kfree ((vm_offset_t) iopb, IOPB_BYTES);
+ 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
+ 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, io_perm->com.io_perm.from,
+ io_perm->com.io_perm.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;
+}
diff -ruNp oskit-mach/i386/i386/io_perm.h oskit-mach.new/i386/i386/io_perm.h
--- oskit-mach/i386/i386/io_perm.h Thu Jan 1 01:00:00 1970
+++ oskit-mach.new/i386/i386/io_perm.h Fri Mar 8 00:34:38 2002
@@ -0,0 +1,48 @@
+/* io_perm.h - Data types for I/O permission bitmap objects.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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.
+
+ GNU Mach 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _I386_IO_PERM_H_
+#define _I386_IO_PERM_H_
+
+/* The highest possible I/O port. ISA bus allows ports 0..3ff, but
+ accelerator cards are funky. */
+#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 device is defined in <oskit/ds_oskit.h>, which includes this
+ file for the io_port_t type definition above. */
+typedef struct device *io_perm_t;
+
+extern io_perm_t convert_port_to_io_perm (/* struct ipc_port * */);
+extern struct ipc_port *convert_io_perm_to_port(/* io_perm_t */);
+extern void io_perm_deallocate(/* io_perm_t */);
+
+#endif
diff -ruNp oskit-mach/i386/i386/machine_task.c
oskit-mach.new/i386/i386/machine_task.c
--- oskit-mach/i386/i386/machine_task.c Thu Jan 1 01:00:00 1970
+++ oskit-mach.new/i386/i386/machine_task.c Fri Mar 8 00:44:35 2002
@@ -0,0 +1,70 @@
+/* machine_task.h - Machine specific data for a task on i386.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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.
+
+ GNU Mach 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#include <kern/lock.h>
+#include <mach/mach_types.h>
+#include <kern/mach_param.h>
+#include <machine/task.h>
+
+#include <machine/io_perm.h>
+
+/* The zone which holds our machine_task_t structures. */
+static zone_t machine_task_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 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)
+ kfree ((vm_offset_t) task->machine.iopb, IOPB_BYTES);
+}
+
+
+/* Try to release as much memory from the machine specific data in
+ task TASK. */
+void
+machine_task_collect (task_t task)
+{
+ if (task->machine.iopb_size == 0 && task->machine.iopb)
+ {
+ kfree ((vm_offset_t) task->machine.iopb, IOPB_BYTES);
+ task->machine.iopb = 0;
+ }
+}
diff -ruNp oskit-mach/i386/i386/mp_desc.c oskit-mach.new/i386/i386/mp_desc.c
--- oskit-mach/i386/i386/mp_desc.c Sun Mar 3 18:39:22 2002
+++ oskit-mach.new/i386/i386/mp_desc.c Fri Mar 8 00:34:38 2002
@@ -52,7 +52,8 @@ vm_offset_t int_stack_high;
#include <oskit/x86/base_idt.h>
#include "gdt.h"
#include <oskit/x86/base_tss.h>
-
+#include <machine/tss.h>
+#include <machine/io_perm.h>
/*
* The i386 needs an interrupt stack to keep the PCB stack from being
@@ -83,7 +84,7 @@ struct mp_desc_table *mp_desc_table[NCPU
/*
* Pointer to TSS for access in load_context.
*/
-struct x86_tss *mp_ktss[NCPUS];
+struct task_tss *mp_ktss[NCPUS];
/*
* Pointer to GDT to reset the KTSS busy bit.
@@ -105,7 +106,7 @@ mp_desc_init(mycpu)
* Master CPU uses the tables built at boot time.
* Just set the TSS and GDT pointers.
*/
- mp_ktss[mycpu] = &base_tss;
+ mp_ktss[mycpu] = (struct task_tss *) &base_tss;
mp_gdt[mycpu] = gdt;
return 0;
}
@@ -138,7 +139,7 @@ mp_desc_init(mycpu)
ACC_P|ACC_PL_K|ACC_LDT, 0);
fill_descriptor(&mpt->gdt[sel_idx(KERNEL_TSS)],
(unsigned)kvtolin(&mpt->ktss),
- sizeof(struct x86_tss) - 1,
+ sizeof(struct task_tss) - 1,
ACC_P|ACC_PL_K|ACC_TSS, 0);
/*
@@ -150,8 +151,9 @@ mp_desc_init(mycpu)
(unsigned)kvtolin(&mpt->cpu_number), sizeof(int) - 1,
ACC_P|ACC_PL_K|ACC_DATA, 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 -ruNp oskit-mach/i386/i386/mp_desc.h oskit-mach.new/i386/i386/mp_desc.h
--- oskit-mach/i386/i386/mp_desc.h Tue Apr 10 20:39:05 2001
+++ oskit-mach.new/i386/i386/mp_desc.h Fri Mar 8 00:34:38 2002
@@ -43,7 +43,7 @@
#include <mach/std_types.h>
#include <oskit/x86/base_idt.h> /* IDTSZ */
-#include <oskit/x86/tss.h>
+#include <machine/tss.h>
#include "gdt.h"
#include "ldt.h"
@@ -57,7 +57,7 @@ struct mp_desc_table {
struct x86_gate idt[IDTSZ]; /* IDT */
struct x86_desc gdt[GDTSZ]; /* GDT */
struct x86_desc ldt[LDTSZ]; /* LDT */
- struct x86_tss ktss;
+ struct task_tss ktss;
};
/*
@@ -68,7 +68,7 @@ extern struct mp_desc_table *mp_desc_tab
/*
* The kernel TSS gets its own pointer.
*/
-extern struct x86_tss *mp_ktss[NCPUS];
+extern struct task_tss *mp_ktss[NCPUS];
/*
* So does the GDT.
diff -ruNp oskit-mach/i386/i386/pcb.c oskit-mach.new/i386/i386/pcb.c
--- oskit-mach/i386/i386/pcb.c Tue Oct 31 00:57:25 2000
+++ oskit-mach.new/i386/i386/pcb.c Fri Mar 8 01:20:13 2002
@@ -24,6 +24,8 @@
* the rights to redistribute these changes.
*/
+#include <stddef.h>
+
#include <cpus.h>
#include <mach_debug.h>
@@ -52,6 +54,8 @@
#include <oskit/x86/base_tss.h>
#include <oskit/x86/proc_reg.h>
+#include <machine/tss.h>
+
#if NCPUS > 1
#include <i386/mp_desc.h>
#endif
@@ -59,8 +63,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 +128,7 @@ vm_offset_t stack_detach(thread)
#define curr_ktss(mycpu) (mp_ktss[mycpu])
#else
#define curr_gdt(mycpu) (gdt)
-#define curr_ktss(mycpu) (&base_tss)
+#define curr_ktss(mycpu) ((struct task_tss *)&base_tss)
#endif
#define gdt_desc_p(mycpu,sel) \
@@ -137,7 +139,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 +154,7 @@ void switch_ktss(pcb)
? (int) (&pcb->iss + 1)
: (int) (&pcb->iss.v86_es);
- 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 x86_desc *)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;
}
{
@@ -200,6 +183,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:
*
@@ -229,6 +230,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);
}
}
@@ -310,7 +324,6 @@ void pcb_module_init()
0, "i386 pcb state");
fpu_module_init();
- iopb_init();
}
void pcb_init(thread)
@@ -354,8 +367,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)
@@ -509,7 +520,6 @@ kern_return_t thread_setstatus(thread, f
*/
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);
@@ -666,32 +676,20 @@ kern_return_t thread_getstatus(thread, f
*/
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.
- */
-
- bcopy((char *) tss->bitmap,
- (char *) state->pm,
- 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 -ruNp oskit-mach/i386/i386/task.h oskit-mach.new/i386/i386/task.h
--- oskit-mach/i386/i386/task.h Thu Jan 1 01:00:00 1970
+++ oskit-mach.new/i386/i386/task.h Fri Mar 8 00:41:59 2002
@@ -0,0 +1,57 @@
+/* task.h - Data types for machine specific parts of tasks on i386.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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.
+
+ GNU Mach 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _I386_TASK_H_
+#define _I386_TASK_H_
+
+#include <kern/kern_types.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;
+
+
+/* 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 -ruNp oskit-mach/i386/i386/thread.h oskit-mach.new/i386/i386/thread.h
--- oskit-mach/i386/i386/thread.h Tue Apr 10 20:39:06 2001
+++ oskit-mach.new/i386/i386/thread.h Fri Mar 8 00:34:38 2002
@@ -39,8 +39,6 @@
#include <kern/lock.h>
-#include <i386/iopb.h>
-
/*
* The old `struct i386_saved_state' is replaced by the (identical)
* OSKit `struct trap_state'.
@@ -129,7 +127,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 -ruNp oskit-mach/i386/i386/tss.h oskit-mach.new/i386/i386/tss.h
--- oskit-mach/i386/i386/tss.h Thu Jan 1 01:00:00 1970
+++ oskit-mach.new/i386/i386/tss.h Fri Mar 8 00:34:38 2002
@@ -0,0 +1,36 @@
+/* tss.h - Data type for TSS with an I/O permission bitmap.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+ Written by Marcus Brinkmann.
+
+ 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.
+
+ GNU Mach 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., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */
+
+#ifndef _I386_TSS_H_
+#define _I386_TSS_H_
+
+#include <oskit/x86/tss.h>
+#include <machine/io_perm.h>
+
+/* The structure extends the TSS structure provided by OSKit by an I/O
+ permission bitmap and the barrier. */
+struct task_tss
+{
+ struct x86_tss tss;
+ unsigned char iopb[IOPB_BYTES];
+ unsigned char barrier;
+};
+
+#endif /* _I386_TSS_H_ */
diff -ruNp oskit-mach/i386/include/mach/i386/mach_i386.defs
oskit-mach.new/i386/include/mach/i386/mach_i386.defs
--- oskit-mach/i386/include/mach/i386/mach_i386.defs Tue Apr 10 20:39:09 2001
+++ oskit-mach.new/i386/include/mach/i386/mach_i386.defs Fri Mar 8
00:34:38 2002
@@ -42,19 +42,25 @@ type device_list_t = ^array[] of device_
type descriptor_t = struct[2] of int;
type descriptor_list_t = array[*] of descriptor_t;
-import <mach/machine/mach_i386_types.h>;
+#if KERNEL_SERVER
+simport <machine/io_perm.h>;
+#endif
-routine i386_io_port_add(
- 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)
+ destructor: io_perm_deallocate(io_perm_t)
+#endif /* KERNEL_SERVER */
+ ;
-routine i386_io_port_remove(
- target_thread : thread_t;
- device : device_t);
+import <mach/machine/mach_i386_types.h>;
-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;
@@ -66,3 +72,25 @@ routine i386_get_ldt(
first_selector : int;
selector_count : int;
out desc_list : descriptor_list_t);
+
+/* 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 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. */
+routine i386_io_perm_modify(
+ target_task : task_t;
+ io_perm : io_perm_t;
+ enable : boolean_t);
diff -ruNp oskit-mach/i386/include/mach/i386/mach_i386_types.h
oskit-mach.new/i386/include/mach/i386/mach_i386_types.h
--- oskit-mach/i386/include/mach/i386/mach_i386_types.h Tue Feb 25 22:27:00 1997
+++ oskit-mach.new/i386/include/mach/i386/mach_i386_types.h Fri Mar 8
00:34:38 2002
@@ -46,4 +46,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 -ruNp oskit-mach/kern/task.c oskit-mach.new/kern/task.c
--- oskit-mach/kern/task.c Mon May 24 18:47:15 1999
+++ oskit-mach.new/kern/task.c Fri Mar 8 00:34:38 2002
@@ -78,6 +78,7 @@ void task_init(void)
0, "tasks");
eml_init();
+ machine_task_module_init ();
/*
* Create the kernel task as the first task.
@@ -160,6 +161,7 @@ kern_return_t task_create(
#if NET_ATM
new_task->nw_ep_owned = 0;
#endif
+ machine_task_init (new_task);
new_task->total_user_time.seconds = 0;
new_task->total_user_time.microseconds = 0;
@@ -247,6 +249,8 @@ void task_deallocate(
}
#endif /* NORMA_TASK */
+ machine_task_terminate (task);
+
eml_task_deallocate(task);
pset = task->processor_set;
@@ -1126,6 +1130,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 -ruNp oskit-mach/kern/task.h oskit-mach.new/kern/task.h
--- oskit-mach/kern/task.h Tue Apr 10 20:39:18 2001
+++ oskit-mach.new/kern/task.h Fri Mar 8 00:34:38 2002
@@ -50,6 +50,7 @@
#include <kern/processor.h>
#include <kern/syscall_emulation.h>
#include <vm/vm_map.h>
+#include <machine/task.h>
#if NET_ATM
typedef struct nw_ep_owned {
@@ -117,6 +118,9 @@ struct task {
#if NET_ATM
nw_ep_owned_t nw_ep_owned;
#endif /* NET_ATM */
+
+ /* Hardware specific data. */
+ machine_task_t machine;
};
#define task_lock(task) simple_lock(&(task)->lock)
diff -ruNp oskit-mach/oskit/ds_oskit.h oskit-mach.new/oskit/ds_oskit.h
--- oskit-mach/oskit/ds_oskit.h Fri Mar 8 00:29:11 2002
+++ oskit-mach.new/oskit/ds_oskit.h Fri Mar 8 00:34:38 2002
@@ -54,6 +54,9 @@ struct device_ops {
#include <oskit/io/asyncio.h>
#include <oskit/dev/net.h>
#include <oskit/io/netio.h>
+#if defined(__i386__)
+#include <machine/io_perm.h>
+#endif
struct device {
const struct device_ops *ops;
@@ -105,6 +108,12 @@ struct device {
oskit_netio_t recvi; /* my life as a COM object: incoming packets */
struct ifnet ifnet; /* cruft for net_io.c */
} net;
+#if defined(__i386__)
+ struct
+ {
+ io_port_t from, to;
+ } io_perm;
+#endif
} com;
};
diff -ruNp oskit-mach/oskit/ds_routines.c oskit-mach.new/oskit/ds_routines.c
--- oskit-mach/oskit/ds_routines.c Fri Mar 8 00:29:12 2002
+++ oskit-mach.new/oskit/ds_routines.c Fri Mar 8 01:27:44 2002
@@ -292,7 +292,7 @@ dev_port_lookup(port)
/*** Opening devices. ***/
-static device_t
+device_t
dev_open_alloc (void)
{
device_t dev = (device_t) zalloc (dev_hdr_zone);
@@ -317,7 +317,7 @@ dev_open_alloc (void)
}
-static void
+void
setup_no_senders (device_t dev)
{
ipc_port_t notify;
diff -ruNp oskit-mach/oskit/x86/main.c oskit-mach.new/oskit/x86/main.c
--- oskit-mach/oskit/x86/main.c Sun Mar 3 18:39:27 2002
+++ oskit-mach.new/oskit/x86/main.c Fri Mar 8 01:18:51 2002
@@ -43,6 +43,14 @@
#include <kern/cpu_number.h>
+/* The BASE_TSS in OSKit has no I/O permission bitmap, but we want
+ one. So we replace it with an extended TSS at link-time. */
+#include <machine/tss.h>
+#include <machine/io_perm.h>
+static struct task_tss ktss;
+extern struct x86_tss base_tss __attribute__ ((alias ("ktss")));
+#define base_tss ktss
+
/* As of 2000-12-21 the oskit has an incorrect value for this constant
in <oskit/x86/proc_reg.h>, so we redefine it with the correct one. */
#undef CR4_PGE
@@ -145,6 +153,14 @@ main (int argc, char **argv)
int_init();
ldt_init();
+ /* Set up the BASE_TSS to include an I/O permission bitmap. */
+ fill_descriptor(&base_gdt[sel_idx(BASE_TSS)],
+ kvtolin(&base_tss),
+ sizeof(struct task_tss) - 1,
+ ACC_P|ACC_PL_K|ACC_TSS, 0);
+ base_tss.tss.io_bit_map_offset = IOPB_INVAL;
+ base_tss.barrier = 0xFF;
+ /* This will also reload the TSS. */
base_cpu_load();
/* Arrange a callback to our special exit function below, so we can
--
`Rhubarb is no Egyptian god.' Debian http://www.debian.org brinkmd@debian.org
Marcus Brinkmann GNU http://www.gnu.org marcus@gnu.org
Marcus.Brinkmann@ruhr-uni-bochum.de
http://www.marcus-brinkmann.de