bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

I/O permission bitmap patch for oskit-mach


From: Marcus Brinkmann
Subject: I/O permission bitmap patch for oskit-mach
Date: Thu, 28 Feb 2002 19:10:35 -0500
User-agent: Mutt/1.3.25i

Hi,

here is the latest version of the patch.  It should actually be quite
close to a final version.  Roland, if there is anything I haven't
addressed please let me know.  I have tested it for functionality,
but I have not done stress testing (we will certainly get to that).

Design flaw: Changes don't propagate immediately to other threads in
the same task running on another processor.  This applies to enable as
well as disable operations!  Espen Skoglund pointed out that we only
need to propagate disable operations, enable operations could be picked
up in the fault handler (for extra performance).

In real life, it might be easy for us to make sure that it doesn't happen
by enabling the ports before creating other threads, and by never deleting
them.  This should work fine for the console server, and it should also
be fine for single threaded apps like X.

As a special exception, the changelog entry is included in the diff,
because that is right now more convenient to me.

I have started to give new files the GPL copyright and the 19 lines
header.  Also one file or so has the GPL in addition to the original license.
That can be negotiated ;), but I think we should start to put new code
under the GPL.

Thanks,
Marcus

diff -x CVS -ruN oskit-mach.warn/ChangeLog.oskit oskit-mach/ChangeLog.oskit
--- oskit-mach.warn/ChangeLog.oskit     Thu Feb 28 22:50:43 2002
+++ oskit-mach/ChangeLog.oskit  Thu Feb 28 03:26:07 2002
@@ -1,3 +1,62 @@
+2002-02-27  Marcus Brinkmann  <marcus@finnegan>
+
+       * 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.
+       
 2001-12-12  Roland McGrath  <roland@frob.com>
 
        * oskit/ds_routines.c (ds_device_read): Remove old debugging crap.
diff -x CVS -ruN oskit-mach.warn/bogus/mach_machine_routines.h 
oskit-mach/bogus/mach_machine_routines.h
--- oskit-mach.warn/bogus/mach_machine_routines.h       Tue Feb 25 22:28:04 1997
+++ oskit-mach/bogus/mach_machine_routines.h    Sat Oct 13 06:25:26 2001
@@ -1 +1 @@
-#define MACH_MACHINE_ROUTINES 0
+#define MACH_MACHINE_ROUTINES 1
diff -x CVS -ruN oskit-mach.warn/i386/Makefrag oskit-mach/i386/Makefrag
--- oskit-mach.warn/i386/Makefrag       Sat Feb  3 11:27:32 2001
+++ oskit-mach/i386/Makefrag    Sun Oct 21 04:39:09 2001
@@ -20,7 +20,7 @@
 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 -x CVS -ruN oskit-mach.warn/i386/i386/io_perm.c 
oskit-mach/i386/i386/io_perm.c
--- oskit-mach.warn/i386/i386/io_perm.c Thu Jan  1 01:00:00 1970
+++ oskit-mach/i386/i386/io_perm.c      Thu Feb 28 04:04:20 2002
@@ -0,0 +1,252 @@
+/* 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"
+
+
+/* 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 (set all bits to OFF == 1).  */
+void
+io_bitmap_init (unsigned char *iopb, boolean_t on_off)
+{
+  int s;
+  unsigned char c;
+
+  /*  Disallow access to ports 0x00 .. 0xff.  */
+  for (s = 0; s < (0xff+1)/8; s++)
+    *iopb++ = ~0;      /* No access.  */
+
+  if (on_off)
+    c = 0;
+  else
+    c = ~0;
+
+  for (; s < IOPB_BYTES; s++)
+    *iopb++ = c;
+}
+
+
+/* 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;
+  unsigned short 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, FALSE);
+       }
+      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
+    {
+      unsigned short new_size = iopb_size;
+
+      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 -x CVS -ruN oskit-mach.warn/i386/i386/io_perm.h 
oskit-mach/i386/i386/io_perm.h
--- oskit-mach.warn/i386/i386/io_perm.h Thu Jan  1 01:00:00 1970
+++ oskit-mach/i386/i386/io_perm.h      Thu Feb 28 03:57:43 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 -x CVS -ruN oskit-mach.warn/i386/i386/machine_task.c 
oskit-mach/i386/i386/machine_task.c
--- oskit-mach.warn/i386/i386/machine_task.c    Thu Jan  1 01:00:00 1970
+++ oskit-mach/i386/i386/machine_task.c Thu Feb 28 04:11:58 2002
@@ -0,0 +1,89 @@
+/* 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/zalloc.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)
+{
+  machine_task_zone = zinit (sizeof(struct machine_task),
+                           TASK_MAX * sizeof(struct machine_task),
+                           TASK_CHUNK * sizeof(struct machine_task),
+                           0, "i386 machine task");
+}
+
+
+/* Initialize the machine specific part of task TASK.  */
+void
+machine_task_init (task_t task)
+{
+  machine_task_t machine;
+
+  machine = (machine_task_t) zalloc(machine_task_zone);
+  if (machine == 0)
+    panic("machine_task_init");
+
+  machine->iopb_size = 0;
+  machine->iopb = 0;
+  simple_lock_init (&machine->iopb_lock);
+
+  task->machine = machine;
+}
+
+
+/* Destroy the machine specific part of task TASK and release all
+   associated resources.  */
+void
+machine_task_terminate (task_t task)
+{
+  machine_task_t machine = task->machine;
+
+  if (machine->iopb)
+    kfree ((vm_offset_t) machine->iopb, IOPB_BYTES);
+
+  zfree (machine_task_zone, (vm_offset_t) machine);
+}
+
+
+/* Try to release as much memory from the machine specific data in
+   task TASK.  */
+void
+machine_task_collect (task_t task)
+{
+  machine_task_t machine = task->machine;
+
+  if (machine->iopb_size == 0 && machine->iopb)
+    {
+      kfree ((vm_offset_t) machine->iopb, IOPB_BYTES);
+      machine->iopb = 0;
+    }
+}
diff -x CVS -ruN oskit-mach.warn/i386/i386/mp_desc.c 
oskit-mach/i386/i386/mp_desc.c
--- oskit-mach.warn/i386/i386/mp_desc.c Thu Feb 28 22:46:44 2002
+++ oskit-mach/i386/i386/mp_desc.c      Fri Mar  1 00:30:08 2002
@@ -52,7 +52,8 @@
 #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 @@
 /*
  * 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 @@
                 * 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 @@
                        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 @@
                        (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 -x CVS -ruN oskit-mach.warn/i386/i386/mp_desc.h 
oskit-mach/i386/i386/mp_desc.h
--- oskit-mach.warn/i386/i386/mp_desc.h Thu Apr  5 08:52:46 2001
+++ oskit-mach/i386/i386/mp_desc.h      Sun Dec  9 02:43:46 2001
@@ -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 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 @@
 /*
  * 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 -x CVS -ruN oskit-mach.warn/i386/i386/pcb.c oskit-mach/i386/i386/pcb.c
--- oskit-mach.warn/i386/i386/pcb.c     Sun Oct 29 09:53:32 2000
+++ oskit-mach/i386/i386/pcb.c  Thu Feb 28 03:18:31 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 @@
 #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 @@
 {
        int                     mycpu = cpu_number();
     {
-       register iopb_tss_t     tss = pcb->ims.io_tss;
        vm_offset_t             pcb_stack_top;
 
        /*
@@ -153,25 +154,7 @@
                        ? (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 @@
 
 }
 
+/* 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, unsigned short 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 @@
                                     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 @@
                         0, "i386 pcb state");
 
        fpu_module_init();
-       iopb_init();
 }
 
 void pcb_init(thread)
@@ -354,8 +367,6 @@
        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 @@
             */
            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 @@
             */
            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 -x CVS -ruN oskit-mach.warn/i386/i386/task.h oskit-mach/i386/i386/task.h
--- oskit-mach.warn/i386/i386/task.h    Thu Jan  1 01:00:00 1970
+++ oskit-mach/i386/i386/task.h Thu Feb 28 03:20:35 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 -x CVS -ruN oskit-mach.warn/i386/i386/thread.h 
oskit-mach/i386/i386/thread.h
--- oskit-mach.warn/i386/i386/thread.h  Thu Apr  5 08:52:46 2001
+++ oskit-mach/i386/i386/thread.h       Fri Oct 19 23:05:20 2001
@@ -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_machine_state {
-       iopb_tss_t              io_tss;
        struct user_ldt *       ldt;
        struct i386_fpsave_state *ifps;
        struct v86_assist_state v86s;
diff -x CVS -ruN oskit-mach.warn/i386/i386/tss.h oskit-mach/i386/i386/tss.h
--- oskit-mach.warn/i386/i386/tss.h     Thu Jan  1 01:00:00 1970
+++ oskit-mach/i386/i386/tss.h  Thu Feb 28 03:09:28 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 -x CVS -ruN oskit-mach.warn/i386/include/mach/i386/mach_i386.defs 
oskit-mach/i386/include/mach/i386/mach_i386.defs
--- oskit-mach.warn/i386/include/mach/i386/mach_i386.defs       Thu Apr  5 
08:52:46 2001
+++ oskit-mach/i386/include/mach/i386/mach_i386.defs    Thu Feb 28 01:44:12 2002
@@ -42,19 +42,25 @@
 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 @@
                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 -x CVS -ruN oskit-mach.warn/i386/include/mach/i386/mach_i386_types.h 
oskit-mach/i386/include/mach/i386/mach_i386_types.h
--- oskit-mach.warn/i386/include/mach/i386/mach_i386_types.h    Tue Feb 25 
22:27:00 1997
+++ oskit-mach/i386/include/mach/i386/mach_i386_types.h Sat Oct 13 02:16:21 2001
@@ -46,4 +46,15 @@
 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 -x CVS -ruN oskit-mach.warn/kern/task.c oskit-mach/kern/task.c
--- oskit-mach.warn/kern/task.c Sun May 23 18:13:00 1999
+++ oskit-mach/kern/task.c      Sun Oct 21 06:03:34 2001
@@ -78,6 +78,7 @@
                        0, "tasks");
 
        eml_init();
+       machine_task_module_init ();
 
        /*
         * Create the kernel task as the first task.
@@ -160,6 +161,7 @@
 #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 @@
        }
 #endif /* NORMA_TASK */
 
+       machine_task_terminate (task);
+
        eml_task_deallocate(task);
 
        pset = task->processor_set;
@@ -1126,6 +1130,7 @@
                        pset_unlock(pset);
                        simple_unlock(&all_psets_lock);
 
+                       machine_task_collect (task);
                        pmap_collect(task->map->pmap);
 
                        if (prev_task != TASK_NULL)
diff -x CVS -ruN oskit-mach.warn/kern/task.h oskit-mach/kern/task.h
--- oskit-mach.warn/kern/task.h Thu Apr  5 08:52:47 2001
+++ oskit-mach/kern/task.h      Thu Oct 18 21:35:33 2001
@@ -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 @@
 #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 -x CVS -ruN oskit-mach.warn/oskit/ds_oskit.h oskit-mach/oskit/ds_oskit.h
--- oskit-mach.warn/oskit/ds_oskit.h    Tue Dec 11 03:54:23 2001
+++ oskit-mach/oskit/ds_oskit.h Thu Feb 28 03:25:33 2002
@@ -50,6 +50,9 @@
 #include <oskit/com/stream.h>
 #include <oskit/io/asyncio.h>
 #include <oskit/io/netio.h>
+#if defined(__i386__)
+#include <machine/io_perm.h>
+#endif
 
 struct device {
   const struct device_ops *ops;
@@ -101,6 +104,12 @@
       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 -x CVS -ruN oskit-mach.warn/oskit/x86/main.c oskit-mach/oskit/x86/main.c
--- oskit-mach.warn/oskit/x86/main.c    Thu Feb 28 22:46:52 2002
+++ oskit-mach/oskit/x86/main.c Fri Mar  1 00:30:19 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;
+#pragma weak base_tss = 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
@@ -144,7 +151,14 @@
   idt_init();
   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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]