bug-hurd
[Top][All Lists]
Advanced

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

I/O permission control in OSKit-Mach


From: Marcus Brinkmann
Subject: I/O permission control in OSKit-Mach
Date: Tue, 16 Oct 2001 04:16:42 +0200
User-agent: Mutt/1.3.22i

Hi,

here is a patch to implement I/O permission control in OSKit-Mach.

What do you get?
----------------

Two new interfaces:

/* 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);

The usage should be pretty obvious, an example follow below.  The
capability port can be destroyed after the I/O permissions have been
modified.


What features are provided?
---------------------------

I/O permissions are task based, rather than thread based.  All threads will
get permission instantly.

The io_perm_t ports represent the capability to control the permission to
access I/O ports.  A server running as root could hand out permission to
access linear port ranges for specific purposes to non-root users (like
console users to program the console).

Applications accessing I/O ports written for GNU/Linux will be able to compile
on the Hurd without changes, as soon as glibc is extended to cover the new
interfaces (see below).

The task switching mechanism will only use one TSS for processors.  I/O
permission bit maps are edited in place.


Problems, open issues
---------------------

There are some details about the implementation which are not ideal, but ok:
Once a task gets a bitmap, it is never destroyed, even if no I/O ports are
enabled (all bits set).  The bitmap is destroyed only with the task.

A task requesting some I/O permission will get a full blown 8192 bytes large
bitmap, which is copied in the processor TSS at every switch to the task.
(Linux by default only uses a half bitmap, and provides a full one at
request by calling a special function -- not ideal either, interface-wise).

Open issues:
* I don't know if and where I need to lock the task or the contained bitmap.
* I don't know if we should put the bitmap directly in the task structure,
  or wrap it in a generic machine construct like done with threads/pcb.
* I don't protect the bitmap in the task structure with [i386] (see above).
* I use kalloc, and don't deal with resource shortage, but I should.
* I would like to optimize the i386_io_port_modify call to avoid a copy of
  the whole bitmap if the running task had a bitmap that was copied before.
  (See #if 0 out'ed code in iopb.c), but this sucks in macros only in pcb.c
* I have not tested NCPU > 1, not even on single-processor machine (eg, I
  don't even know if it compiles).
* When setting the global descriptor table entry, I use kvtolin for the
  segment address.  Roland didn't do this in the multiprocessor code, a bug?
  Or am I wrong in doing the conversion?
* To glue the io_port stuff at the device struct, I use my union trick
  rather than lumping it into union com.  I implemented this before Roland
  told me to go for the simple solution, and kinda like it.  But maybe
  change it back.
* No ChangeLog entry yet!  No copyright header on new files!


Status
------

Although this is a lot of things to look out for, the patch seems to work at
least on single user systems with only one single-threaded program running (eg,
avoid problems due to missing locks).

Roland, can I count on you to take care of the glibc side eventually?


GNU Mach
--------

For GNU Mach, a kernel object would be necessary, so that a no senders
notification can be sent and the capability be destroyed.  No magic, but
annoying because it would be a bit different from the OSKit Mach
implementation (nothing visible to the outside).  I don't plan to "backport"
this change to GNU Mach currently, as it seems a usable OSKit Mach (with
user space console) is coming along nicely.


Example Code
------------

The following is a simple implementation of ioperm for glibc as it exists
for Linux (framework shamelesly stolen from sysdeps/mach/hurd/adjtime.c):

#include <mach/i386/mach_i386_types.h>

int
__ioperm (unsigned long int from, unsigned long int num, int turn_on)
{
  error_t err;
  mach_port_t master_port;
  io_perm_t io_perm;

  if (from + num - 1 > 0xffff)
    return __hurd_fail (EINVAL);

  err = __get_privileged_ports (NULL, &master_port);
  if (err)
    return __hurd_fail (EPERM);

  err = i386_io_perm_create (master_port, from, (io_port_t) from + num - 1,
                             &io_perm);
  __mach_port_deallocate (__mach_task_self (), master_port);
  if (err)
    return __hurd_fail (err);

  err = i386_io_perm_modify (__mach_task_self (), io_perm, turn_on);    
  __mach_port_deallocate (__mach_task_self (), io_perm);
  if (err)
    return __hurd_fail (err);
  return 0;
}


This is not so cool as Kalles cursor move program, so:

Exercise
--------

Reimplement Kalles cursor move test program so that it works on OSKit-Mach
with the patch.


Joke
----

  "I've finally learned what `upward compatible' means.  It means we
  get to keep all our old mistakes."

  -- Dennie van Tassel


Thanks,
Marcus

diff -pNru oskit-mach.old/bogus/mach_machine_routines.h 
oskit-mach/bogus/mach_machine_routines.h
--- oskit-mach.old/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 -pNru oskit-mach.old/i386/Makefrag oskit-mach/i386/Makefrag
--- oskit-mach.old/i386/Makefrag        Sat Feb  3 11:27:32 2001
+++ oskit-mach/i386/Makefrag    Sat Oct 13 05:43:15 2001
@@ -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 iopb.c # loose_ends.c
 intel-files = pmap.c read_fault.c
 
 # Assembler source
diff -pNru oskit-mach.old/i386/i386/io_emulate.c 
oskit-mach/i386/i386/io_emulate.c
--- oskit-mach.old/i386/i386/io_emulate.c       Fri Nov 26 00:13:20 1999
+++ oskit-mach/i386/i386/io_emulate.c   Sat Oct 13 00:56:45 2001
@@ -38,7 +38,6 @@
 #include <device/dev_hdr.h>
 
 #include <i386/thread.h>
-#include <i386/io_port.h>
 #include <i386/io_emulate.h>
 
 extern ipc_port_t      iopl_device_port;
diff -pNru oskit-mach.old/i386/i386/io_perm.h oskit-mach/i386/i386/io_perm.h
--- oskit-mach.old/i386/i386/io_perm.h  Thu Jan  1 01:00:00 1970
+++ oskit-mach/i386/i386/io_perm.h      Sat Oct 13 05:03:14 2001
@@ -0,0 +1,30 @@
+#ifndef _I386_IO_PERM_H_
+#define _I386_IO_PERM_H_
+
+#include <stddef.h>
+#include <oskit/ds_oskit.h>
+
+typedef unsigned short io_port_t;
+
+union io_perm
+{
+  struct device device;
+
+  struct io_perm_range
+  {
+    char dummy[sizeof (struct device) - offsetof (struct device, com)];
+    io_port_t from, to;
+  } range;
+};
+typedef union io_perm *io_perm_t;
+
+extern union io_perm *
+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 -pNru oskit-mach.old/i386/i386/io_port.h oskit-mach/i386/i386/io_port.h
--- oskit-mach.old/i386/i386/io_port.h  Tue Feb 25 22:27:09 1997
+++ oskit-mach/i386/i386/io_port.h      Thu Jan  1 01:00:00 1970
@@ -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(/* device_t, io_reg_t * */);
-extern void    io_port_destroy(/* device_t */);
-
-#endif /* _I386_IO_PORT_H_ */
diff -pNru oskit-mach.old/i386/i386/iopb.c oskit-mach/i386/i386/iopb.c
--- oskit-mach.old/i386/i386/iopb.c     Fri Nov 26 00:13:25 1999
+++ oskit-mach/i386/i386/iopb.c Tue Oct 16 05:07:04 2001
@@ -38,68 +38,39 @@
 #include <kern/thread.h>
 
 #include <device/dev_hdr.h>
+#include <device/device_port.h>
 
-#include "io_port.h"
+#include "io_perm.h"
 #include "iopb.h"
 #include "gdt.h"
 
-/*
- * A set of ports for an IO device.
- */
-struct io_port {
-       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;
+ipc_port_t
+convert_io_perm_to_port (io_perm_t io_perm)
+{
+  return convert_device_to_port ((device_t) io_perm);
+}
 
-/*
- * Big lock for the whole mess.
- */
-decl_simple_lock_data(, iopb_lock)
+io_perm_t
+convert_port_to_io_perm (ipc_port_t port)
+{
+  return (io_perm_t) dev_port_lookup (port);
+}
 
-/*
- * Initialize the package.
- */
 void
-iopb_init(void)
+io_perm_deallocate (io_perm_t io_perm)
 {
-       queue_init(&device_to_io_port_list);
-       simple_lock_init(&iopb_lock);
+  device_deallocate ((device_t) io_perm);
 }
 
 /*
  * Initialize bitmap (set all bits to OFF == 1)
  */
 void
-io_bitmap_init(
-       isa_iopb        bp,
-       boolean_t       on_off)
+io_bitmap_init(iopb *bp, boolean_t on_off)
 {
-       register unsigned char  *b = bp;
-       register int            s;
-       unsigned char           c;
+  register unsigned char *b = *bp;
+  register int s;
+  unsigned char c;
 
        /*
         *      Disallow access to ports 0x00 .. 0xff
@@ -113,7 +84,7 @@ io_bitmap_init(
        else
                c = ~0;
 
-       for (; s < sizeof(isa_iopb); s++) {
+       for (; s < sizeof(iopb); s++) {
            *b++ = c;
        }
 }
@@ -122,493 +93,116 @@ io_bitmap_init(
  * Set selected bits in bitmap to ON == 0
  */
 void
-io_bitmap_set(
-       isa_iopb        bp,
-       io_reg_t        *bit_list)
+io_bitmap_set (iopb *bp, io_port_t from, io_port_t to)
 {
-       io_reg_t        io_bit;
-
-       while ((io_bit = *bit_list++) != IO_REG_NULL) {
-           bp[io_bit>>3] &= ~(1 << (io_bit & 0x7));
-       }
+  do
+    (*bp)[from >> 3] &= ~(1 << (from & 0x7));
+  while (from++ != to);
 }
 
 /*
  * 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(
-       device_t        device)
+io_bitmap_clear(iopb *bp, io_port_t from, io_port_t to)
 {
-       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;
+  do
+    (*bp)[from >> 3] |= (1 << (from & 0x7));
+  while (from++ != to);
 }
 
 /*
  * [exported]
  * Create an io_port set
  */
-void
-io_port_create(
-       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(
-       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 = (vm_offset_t) io_tss;
-       vm_size_t       size = (char *)&io_tss->barrier - (char *)io_tss;
-
-       bzero(&io_tss->tss, sizeof(struct x86_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] = ((size-1) & 0xffff)
-               | ((addr & 0xffff) << 16);
-       io_tss->iopb_desc[1] = ((addr & 0x00ff0000) >> 16)
-               | ((ACC_TSS|ACC_PL_K|ACC_P) << 8)
-               | ((size-1) & 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,
-       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;
-       device_t        device;
+i386_io_perm_create (ipc_port_t master_port, io_port_t from, io_port_t to,
+                    io_perm_t *new)
 {
-       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;
-       }
+  if (master_port != master_device_port
+      || from > to)
+    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 */
-       }
+  *new = (io_perm_t) dev_open_alloc ();
+  if (! *new)
+    return KERN_RESOURCE_SHORTAGE;
 
-       /*
-        * 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);
+  /* Set up the dummy device.  */
+  (*new)->device.com_device = 0;
+  (*new)->device.mode = 0;
+  (*new)->device.ops = &no_device_ops;
+  setup_no_senders ((device_t) *new);
 
-               kfree((vm_offset_t)iu, sizeof(struct io_use));
-
-               return KERN_SUCCESS;
-           }
-       }
+  (*new)->range.from = from;
+  (*new)->range.to = to;
 
-       /*
-        * No mapping.
-        */
-       return KERN_INVALID_ARGUMENT;
+  return KERN_SUCCESS;
 }
 
-/*
- * Return the IO ports mapped into a thread.
- */
-extern ipc_port_t      mach_convert_device_to_port(/* device_t */);
+/* From pcb.c.  */
+extern void update_ktss_iopb (iopb *old_iopb, iopb *new_iopb);
 
 kern_return_t
-i386_io_port_list(thread, list, list_count)
-       thread_t        thread;
-       device_t        **list;
-       unsigned int    *list_count;
+i386_io_perm_modify (task_t target_task, io_perm_t io_perm, boolean_t enable)
 {
-       register pcb_t  pcb;
-       register iopb_tss_t io_tss;
-       unsigned int    count, alloc_count;
-       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 = (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;
-               }
-
-               bcopy((void *)addr, (void *)new_addr, size_needed);
-               kfree(addr, size);
-               devices = (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;
-
+#if 0
+  int new_bitmap = 0;
+#endif
+
+  if (target_task == TASK_NULL || (device_t) io_perm == DEVICE_NULL)
+    return KERN_INVALID_ARGUMENT;
+
+  /* XXX Lock the target_task (bitmap) correctly! */
+  if (! target_task->iopb)
+    {
+      /* If there is no bitmap, and we don't want to enable access,
+        there is nothing to do.  */
+      if (! enable)
        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;
-       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;
+      /* XXX Deal with resource shortage! */
+      target_task->iopb = (iopb *) kalloc (sizeof (iopb));
+      io_bitmap_init (target_task->iopb, FALSE);
+#if 0
+      new_bitmap = 1;
+#endif
+    }
+
+  if (enable)
+    {
+      io_bitmap_set (target_task->iopb,
+                    io_perm->range.from, io_perm->range.to);
+
+      if (target_task == current_task())
+#if 0
+         {
+           if (new_bitmap)
+#endif
+             update_ktss_iopb (0, target_task->iopb);
+#if 0
+         else
+           io_bitmap_set (curr_ktss (cpu_number ())->iopb,
+                          io_perm->range.from, io_perm->range.to);
+         }
+#endif
+    }
+  else
+    {
+      io_bitmap_clear (target_task->iopb,
+                      io_perm->range.from, io_perm->range.to);
+
+      if (target_task == current_task())
+#if 0
+       {
+         if (new_bitmap)
+#endif
+           update_ktss_iopb (0, target_task->iopb);
+#if 0
+         else
+           io_bitmap_clear (curr_ktss (cpu_number ())->iopb,
+                            io_perm->range.from, io_perm->range.to);
+       }
+#endif
+    }
+  return KERN_SUCCESS;
 }
diff -pNru oskit-mach.old/i386/i386/iopb.h oskit-mach/i386/i386/iopb.h
--- oskit-mach.old/i386/i386/iopb.h     Fri Nov 26 00:13:30 1999
+++ oskit-mach/i386/i386/iopb.h Tue Oct 16 04:59:34 2001
@@ -27,13 +27,8 @@
 #ifndef        _I386_IOPB_H_
 #define        _I386_IOPB_H_
 
-#include <oskit/x86/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))
@@ -42,20 +37,11 @@
                                        /* 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 x86_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        unsigned char   iopb[IOPB_BYTES];
 
-typedef        struct iopb_tss *iopb_tss_t;
+/* An offset that always points past the segment.  Must be at least
+   sizeof(x86_tss) + 65536/8 + 1 - 1.  */
+#define INVALID_IO_BIT_MAP_OFFSET 0x2FFF
 
 #endif /* _I386_IOPB_H_ */
+
diff -pNru oskit-mach.old/i386/i386/mp_desc.c oskit-mach/i386/i386/mp_desc.c
--- oskit-mach.old/i386/i386/mp_desc.c  Sun Oct  7 23:28:32 2001
+++ oskit-mach/i386/i386/mp_desc.c      Tue Oct 16 01:55:54 2001
@@ -52,7 +52,7 @@ 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>
 
 /*
  * The i386 needs an interrupt stack to keep the PCB stack from being
@@ -83,7 +83,7 @@ struct mp_desc_table  *mp_desc_table[NCPU
 /*
  * Pointer to TSS for access in load_context.
  */
-struct x86_tss         *mp_ktss[NCPUS];
+struct x86_tss_ext     *mp_ktss[NCPUS];
 
 /*
  * Pointer to GDT to reset the KTSS busy bit.
@@ -105,7 +105,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 x86_tss_ext *) &base_tss;
                mp_gdt[mycpu] = gdt;
                return 0;
        }
@@ -138,7 +138,7 @@ 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 x86_tss) - 1,
+                       sizeof(struct x86_tss_ext) - 1,
                        ACC_P|ACC_PL_K|ACC_TSS, 0);
 
                /*
@@ -150,8 +150,9 @@ mp_desc_init(mycpu)
                        (unsigned)&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 = INVALID_IO_BIT_MAP_OFFSET;
+               mpt->ktss.barrier = 0xFF;
 
                return mpt;
        }
diff -pNru oskit-mach.old/i386/i386/mp_desc.h oskit-mach/i386/i386/mp_desc.h
--- oskit-mach.old/i386/i386/mp_desc.h  Thu Apr  5 08:52:46 2001
+++ oskit-mach/i386/i386/mp_desc.h      Tue Oct 16 00:59:56 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 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 x86_tss_ext 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 x86_tss_ext      *mp_ktss[NCPUS];
 
 /*
  * So does the GDT.
diff -pNru oskit-mach.old/i386/i386/pcb.c oskit-mach/i386/i386/pcb.c
--- oskit-mach.old/i386/i386/pcb.c      Sun Oct 29 09:53:32 2000
+++ oskit-mach/i386/i386/pcb.c  Tue Oct 16 04:58:34 2001
@@ -52,6 +52,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 +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)         (gdt)
-#define        curr_ktss(mycpu)        (&base_tss)
+#define        curr_ktss(mycpu)        ((struct x86_tss_ext *)&base_tss)
 #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_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 +181,23 @@ void switch_ktss(pcb)
 
 }
 
+/* One of OLD_IOPB and NEW_IOPB should not be 0.  */
+void
+update_ktss_iopb (iopb *old_iopb, iopb *new_iopb)
+{
+  struct x86_tss_ext *tss = curr_ktss (cpu_number ());
+
+  if (new_iopb)
+    {
+      if (! old_iopb)
+       tss->tss.io_bit_map_offset = sizeof (struct x86_tss);
+
+      memcpy ((char *) tss->iopb, (char *) *new_iopb, IOPB_BYTES);
+    }
+  else
+    tss->tss.io_bit_map_offset = INVALID_IO_BIT_MAP_OFFSET;
+}
+
 /*
  *     stack_handoff:
  *
@@ -229,6 +227,9 @@ void stack_handoff(old, new)
                                     old, mycpu);
                PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map),
                                   new, mycpu);
+
+               if (old->task->iopb || new_task->iopb)
+                 update_ktss_iopb (old_task->iopb, new_task->iopb);
        }
     }
 
@@ -310,7 +311,6 @@ void pcb_module_init()
                         0, "i386 pcb state");
 
        fpu_module_init();
-       iopb_init();
 }
 
 void pcb_init(thread)
@@ -354,8 +354,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 +507,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 +663,19 @@ 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);
-               }
+               /* XXXMB Locking the task (bitmap)? */
+               if (thread->task->iopb == 0)
+                 memset (state->pm, 0xff, sizeof state->pm);
+               else
+                 memcpy((char *) state->pm,
+                        (char *) thread->task->iopb,
+                        sizeof state->pm);
 
                *count = i386_ISA_PORT_MAP_STATE_COUNT;
                break;
diff -pNru oskit-mach.old/i386/i386/thread.h oskit-mach/i386/i386/thread.h
--- oskit-mach.old/i386/i386/thread.h   Thu Apr  5 08:52:46 2001
+++ oskit-mach/i386/i386/thread.h       Sat Oct 13 16:20:58 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_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 -pNru oskit-mach.old/i386/i386/tss.h oskit-mach/i386/i386/tss.h
--- oskit-mach.old/i386/i386/tss.h      Thu Jan  1 01:00:00 1970
+++ oskit-mach/i386/i386/tss.h  Tue Oct 16 01:49:37 2001
@@ -0,0 +1,11 @@
+
+#include <oskit/x86/tss.h>
+#include <machine/iopb.h>
+
+struct x86_tss_ext
+{
+  struct x86_tss tss;
+  iopb iopb;
+  unsigned char barrier;
+};
+
diff -pNru oskit-mach.old/i386/include/mach/i386/mach_i386.defs 
oskit-mach/i386/include/mach/i386/mach_i386.defs
--- oskit-mach.old/i386/include/mach/i386/mach_i386.defs        Thu Apr  5 
08:52:46 2001
+++ oskit-mach/i386/include/mach/i386/mach_i386.defs    Sat Oct 13 02:38:17 2001
@@ -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 -pNru oskit-mach.old/i386/include/mach/i386/mach_i386_types.h 
oskit-mach/i386/include/mach/i386/mach_i386_types.h
--- oskit-mach.old/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,16 @@ 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 -pNru oskit-mach.old/kern/task.c oskit-mach/kern/task.c
--- oskit-mach.old/kern/task.c  Sun May 23 18:13:00 1999
+++ oskit-mach/kern/task.c      Sat Oct 13 16:09:42 2001
@@ -160,6 +160,8 @@ kern_return_t task_create(
 #if    NET_ATM
        new_task->nw_ep_owned = 0;
 #endif
+       /* XXXMB.  */
+       new_task->iopb = 0;
 
        new_task->total_user_time.seconds = 0;
        new_task->total_user_time.microseconds = 0;
@@ -246,6 +248,10 @@ void task_deallocate(
                return;
        }
 #endif /* NORMA_TASK */
+
+       /* XXXMB */
+       if (task->iopb)
+         kfree ((vm_offset_t) task->iopb, sizeof (iopb));
 
        eml_task_deallocate(task);
 
diff -pNru oskit-mach.old/kern/task.h oskit-mach/kern/task.h
--- oskit-mach.old/kern/task.h  Thu Apr  5 08:52:47 2001
+++ oskit-mach/kern/task.h      Sat Oct 13 16:16:48 2001
@@ -51,6 +51,9 @@
 #include <kern/syscall_emulation.h>
 #include <vm/vm_map.h>
 
+/* XXXMB */
+#include <machine/iopb.h>
+
 #if    NET_ATM
 typedef struct nw_ep_owned {
   unsigned int ep;
@@ -117,6 +120,9 @@ struct task {
 #if    NET_ATM
        nw_ep_owned_t   nw_ep_owned;
 #endif /* NET_ATM */
+
+       /* XXXMB Protection, MACHINE? */
+       iopb *iopb;
 };
 
 #define task_lock(task)                simple_lock(&(task)->lock)
diff -pNru oskit-mach.old/oskit/ds_routines.c oskit-mach/oskit/ds_routines.c
--- oskit-mach.old/oskit/ds_routines.c  Wed Oct 10 23:31:03 2001
+++ oskit-mach/oskit/ds_routines.c      Sat Oct 13 05:45:37 2001
@@ -132,19 +132,20 @@ device_deallocate (device_t device)
   }
   simple_unlock (&device->ref_lock);
 
-  assert (device->com_device);
-
-  simple_lock(&dev_hash_lock);
-  simple_lock(&device->ref_lock);
-  if (--device->ref_count > 0) {
-    simple_unlock (&device->ref_lock);
-    simple_unlock (&dev_hash_lock);
-    return;
-  }
-
-  dev_hash_remove (device);
-  simple_unlock(&device->ref_lock);
-  simple_unlock(&dev_hash_lock);
+  if (device->com_device)
+    {
+      simple_lock(&dev_hash_lock);
+      simple_lock(&device->ref_lock);
+      if (--device->ref_count > 0) {
+       simple_unlock (&device->ref_lock);
+       simple_unlock (&dev_hash_lock);
+       return;
+      }
+
+      dev_hash_remove (device);
+      simple_unlock(&device->ref_lock);
+      simple_unlock(&dev_hash_lock);
+    }
 
   /* Destroy the port.  */
   ipc_kobject_set (device->port, IKO_NULL, IKOT_NONE);
@@ -285,7 +286,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);
@@ -310,7 +311,7 @@ dev_open_alloc (void)
 }
 
 
-static void
+void
 setup_no_senders (device_t dev)
 {
   ipc_port_t notify;
diff -pNru oskit-mach.old/oskit/x86/main.c oskit-mach/oskit/x86/main.c
--- oskit-mach.old/oskit/x86/main.c     Fri Dec 22 07:17:04 2000
+++ oskit-mach/oskit/x86/main.c Tue Oct 16 05:05:01 2001
@@ -41,6 +41,13 @@
 
 #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>
+static struct x86_tss_ext 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
@@ -51,7 +58,6 @@ static void my_exit (int), (*his_exit) (
 /* XXX move to intel/pmap.h */
 extern pt_entry_t *kernel_page_dir;
 
-
 #include "assert.h"
 
 extern char    version[];
@@ -142,7 +148,14 @@ main (int argc, char **argv)
   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 x86_tss_ext) - 1,
+                 ACC_P|ACC_PL_K|ACC_TSS, 0);
+  base_tss.tss.io_bit_map_offset = INVALID_IO_BIT_MAP_OFFSET;
+  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



reply via email to

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