summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillem Jover <guillem@debian.org>2006-01-08 18:12:25 +0000
committerGuillem Jover <guillem@debian.org>2006-01-08 18:12:25 +0000
commit45faef2722453c583ee8e281a1d903c5324e163c (patch)
treec6c002d93816317eeb53d3b54f778c89933b1d9c
parentde320583f24be016934cb90875bc4edb6742e012 (diff)
* Fix io port access. (Closes: #46709)
- debian/patches/40_user-tss.patch: New file. - debian/patches/41_io_unlock_ioremove.patch: Likewise. - debian/patches/42_disable_ioperm.disabled: Likewise. - debian/patches/43_debvice_port_fix.patch: Likewise. - debian/patches/44_more_ports.patch: Likewise. - debian/patches/45_io_per_task.patch: Likewise. - debian/patches/46_io_device.patch: Likewise. Thanks to Samuel Thibault <samuel.thibault@ens-lyon.org>.
-rw-r--r--debian/changelog11
-rw-r--r--debian/patches/40_user-tss.patch43
-rw-r--r--debian/patches/41_io_unlock_ioremove.patch26
-rw-r--r--debian/patches/42_disable_ioperm.disabled53
-rw-r--r--debian/patches/43_debvice_port_fix.patch57
-rw-r--r--debian/patches/44_more_ports.patch50
-rw-r--r--debian/patches/45_io_per_task.patch591
-rw-r--r--debian/patches/46_io_device.patch117
8 files changed, 947 insertions, 1 deletions
diff --git a/debian/changelog b/debian/changelog
index a02af3a..0c8f37a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,17 @@
-gnumach (1:20050801-3) unstable; urgency=low
+gnumach (1:20050801-3) UNRELEASED; urgency=low
* Added ChangeLog entries.
- debian/patches/13_ide_dma.patch: Modify
- debian/patches/14_alloc_params.patch: Likewise.
+ * Fix io port access. (Closes: #46709)
+ - debian/patches/40_user-tss.patch: New file.
+ - debian/patches/41_io_unlock_ioremove.patch: Likewise.
+ - debian/patches/42_disable_ioperm.disabled: Likewise.
+ - debian/patches/43_debvice_port_fix.patch: Likewise.
+ - debian/patches/44_more_ports.patch: Likewise.
+ - debian/patches/45_io_per_task.patch: Likewise.
+ - debian/patches/46_io_device.patch: Likewise.
+ Thanks to Samuel Thibault <samuel.thibault@ens-lyon.org>.
-- Guillem Jover <guillem@debian.org> Sat, 7 Jan 2006 01:06:40 +0200
diff --git a/debian/patches/40_user-tss.patch b/debian/patches/40_user-tss.patch
new file mode 100644
index 0000000..b55f361
--- /dev/null
+++ b/debian/patches/40_user-tss.patch
@@ -0,0 +1,43 @@
+#DPATCHLEVEL=0
+
+2005-12-26 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * i386/i386/iopb.c: Include "vm_param.h" for kvtolin().
+ (io_tss_init): Fix address and limit of user TSS.
+
+
+--- i386/i386/iopb.c 2005-05-01 18:04:47.000000000 +0200
++++ i386/i386/iopb.c 2005-12-26 19:50:22.000000000 +0100
+@@ -43,6 +43,7 @@
+ #include "iopb.h"
+ #include "seg.h"
+ #include "gdt.h"
++#include "vm_param.h"
+
+ /*
+ * A set of ports for an IO device.
+@@ -242,8 +243,8 @@ 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;
++ vm_offset_t addr = kvtolin (io_tss);
++ vm_size_t limit = (char *)&io_tss->barrier - (char *)io_tss;
+
+ bzero(&io_tss->tss, sizeof(struct i386_tss));
+ io_tss->tss.io_bit_map_offset
+@@ -252,11 +253,11 @@ io_tss_init(
+ 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)
++ io_tss->iopb_desc[0] = (limit & 0xffff)
+ | ((addr & 0xffff) << 16);
+ io_tss->iopb_desc[1] = ((addr & 0x00ff0000) >> 16)
+ | ((ACC_TSS|ACC_PL_K|ACC_P) << 8)
+- | ((size-1) & 0x000f0000)
++ | (limit & 0x000f0000)
+ | (addr & 0xff000000);
+ }
+
diff --git a/debian/patches/41_io_unlock_ioremove.patch b/debian/patches/41_io_unlock_ioremove.patch
new file mode 100644
index 0000000..e71ed41
--- /dev/null
+++ b/debian/patches/41_io_unlock_ioremove.patch
@@ -0,0 +1,26 @@
+#DPATCHLEVEL=0
+
+2005-12-28 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * i386/i386/iopb.c (i386_io_port_remove): Fix unlocking when io mapping
+ is not found.
+
+
+Index: i386/i386/iopb.c
+===================================================================
+RCS file: /cvsroot/hurd/gnumach/i386/i386/Attic/iopb.c,v
+retrieving revision 1.1.1.1
+diff -u -r1.1.1.1 iopb.c
+--- i386/i386/iopb.c 25 Feb 1997 21:27:09 -0000 1.1.1.1
++++ i386/i386/iopb.c 28 Dec 2005 16:18:40 -0000
+@@ -468,6 +468,10 @@
+ /*
+ * No mapping.
+ */
++
++ simple_unlock(&pcb->lock);
++ simple_unlock(&iopb_lock);
++
+ return KERN_INVALID_ARGUMENT;
+ }
+
diff --git a/debian/patches/42_disable_ioperm.disabled b/debian/patches/42_disable_ioperm.disabled
new file mode 100644
index 0000000..2a292ec
--- /dev/null
+++ b/debian/patches/42_disable_ioperm.disabled
@@ -0,0 +1,53 @@
+#DPATCHLEVEL=0
+
+2001-10-07 Marcus Brinkmann <marcus@gnu.org>
+
+ * i386/i386/iopb.c (iopb_create, i386_io_port_add): Disable io
+ permissions by default.
+
+2004-11-16 Guillem Jover <guillem@hadrons.org>
+
+ * i386/i386/ktss.c (ktss_init): Disable io permissions by default.
+
+
+--- i386/i386/iopb.c Tue Feb 25 22:27:09 1997
++++ i386/i386/iopb.c Sun Oct 7 05:00:09 2001
+@@ -270,7 +270,7 @@
+ register iopb_tss_t ts;
+
+ ts = (iopb_tss_t) kalloc(sizeof (struct iopb_tss));
+- io_tss_init(ts, TRUE); /* XXX */
++ io_tss_init(ts, FALSE);
+ return ts;
+ }
+
+@@ -357,7 +360,7 @@
+ simple_unlock(&iopb_lock);
+
+ new_io_tss = (iopb_tss_t) kalloc(sizeof(struct iopb_tss));
+- io_tss_init(new_io_tss, TRUE); /* XXX */
++ io_tss_init(new_io_tss, FALSE);
+
+ goto Retry;
+ }
+--- i386/i386/ktss.c 25 Feb 1997 21:27:10 -0000 1.1.1.1
++++ i386/i386/ktss.c 16 Nov 2004 06:55:28 -0000
+@@ -44,7 +44,7 @@
+
+ /* Initialize the master TSS descriptor. */
+ fill_gdt_descriptor(KERNEL_TSS,
+- kvtolin(&ktss), sizeof(ktss)+65536/8+1-1,
++ kvtolin(&ktss), sizeof(ktss)-1,
+ ACC_PL_K|ACC_TSS, 0);
+
+ /* Initialize the master TSS. */
+@@ -52,9 +52,6 @@
+ ktss.esp0 = (unsigned)(exception_stack+1024);
+ ktss.io_bit_map_offset = sizeof(ktss);
+
+- /* Set the last byte in the I/O bitmap to all 1's. */
+- ((unsigned char*)&ktss)[sizeof(ktss)+65536/8] = 0xff;
+-
+ /* Load the TSS. */
+ ltr(KERNEL_TSS);
+ }
diff --git a/debian/patches/43_debvice_port_fix.patch b/debian/patches/43_debvice_port_fix.patch
new file mode 100644
index 0000000..49460a9
--- /dev/null
+++ b/debian/patches/43_debvice_port_fix.patch
@@ -0,0 +1,57 @@
+#DPATCHLEVEL=1
+
+2006-01-02 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * i386/i386/iopb.c (i386_io_port_add): Fix getting device parameter.
+ (i386_io_port_remove): Same as above.
+
+
+diff -urp gnumach-mine-2-default_noio/i386/i386/iopb.c gnumach-mine-3-device_port_fix/i386/i386/iopb.c
+--- gnumach-mine-2-default_noio/i386/i386/iopb.c 2006-01-02 18:38:31.000000000 +0100
++++ gnumach-mine-3-device_port_fix/i386/i386/iopb.c 2006-01-02 18:42:45.000000000 +0100
+@@ -308,12 +308,22 @@
+ /*
+ * Add an IO mapping to a thread.
+ */
++#ifdef i386
++kern_return_t
++i386_io_port_add(
++ thread_t thread,
++ device_t d)
++#else
+ kern_return_t
+ i386_io_port_add(
+ thread_t thread,
+ mach_device_t device)
++#endif
+ {
+ pcb_t pcb;
++#ifdef i386
++ mach_device_t device = d->emul_data;
++#endif
+ iopb_tss_t io_tss, new_io_tss;
+ io_port_t io_port;
+ io_use_t iu, old_iu;
+@@ -407,12 +417,22 @@
+ /*
+ * Remove an IO mapping from a thread.
+ */
++#ifdef i386
++kern_return_t
++i386_io_port_remove(thread, d)
++ thread_t thread;
++ device_t d;
++#else
+ kern_return_t
+ i386_io_port_remove(thread, device)
+ thread_t thread;
+ mach_device_t device;
++#endif
+ {
+ pcb_t pcb;
++#ifdef i386
++ mach_device_t device = d->emul_data;
++#endif
+ iopb_tss_t io_tss;
+ io_port_t io_port;
+ io_use_t iu;
diff --git a/debian/patches/44_more_ports.patch b/debian/patches/44_more_ports.patch
new file mode 100644
index 0000000..39fa0ea
--- /dev/null
+++ b/debian/patches/44_more_ports.patch
@@ -0,0 +1,50 @@
+#DPATCHLEVEL=1
+
+2006-01-02 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * i386/i386at/iopl.c (iopl_port_list): Add timer controler port.
+ * i386/i386at/kd.c (vga_port_list): Renamed to ...
+ (kd_port_list): ... this. Add timer and speaker ports.
+
+
+diff -urp gnumach-mine-3-device_port_fix/i386/i386at/iopl.c gnumach-mine-4-more_ports/i386/i386at/iopl.c
+--- gnumach-mine-3-device_port_fix/i386/i386at/iopl.c 2006-01-02 18:43:09.000000000 +0100
++++ gnumach-mine-4-more_ports/i386/i386at/iopl.c 2006-01-02 18:45:17.000000000 +0100
+@@ -47,7 +47,7 @@
+ */
+ io_reg_t iopl_port_list[] = {
+ /* timer 2 */
+- 0x42,
++ 0x42, 0x43,
+ /* speaker output */
+ 0x61,
+ /* ATI - savage */
+
+2006-01-02 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * kd.c(vga_port_list): Rename to...
+ (kd_port_list): this, set static, add timer and speaker ports.
+
+diff -urp gnumach-mine-3-device_port_fix/i386/i386at/kd.c gnumach-mine-4-more_ports/i386/i386at/kd.c
+--- gnumach-mine-3-device_port_fix/i386/i386at/kd.c 2006-01-02 18:43:12.000000000 +0100
++++ gnumach-mine-4-more_ports/i386/i386at/kd.c 2006-01-02 19:14:48.000000000 +0100
+@@ -348,7 +348,9 @@
+ /*
+ * IO port sets for different controllers.
+ */
+-io_reg_t vga_port_list[] = {
++static io_reg_t kd_port_list[] = {
++ 0x42, 0x43, /* Timer */
++ 0x61, /* Speaker */
+ 0x3b4, 0x3b5, 0x3b8, 0x3b9, 0x3ba, /* MDA/EGA */
+ 0x3d4, 0x3d5, 0x3d8, 0x3d9, 0x3da, /* CGA/EGA */
+ 0x3c0, 0x3c1, 0x3c2, 0x3c3, 0x3c4, 0x3c5, 0x3c6, 0x3c7,
+@@ -362,7 +364,7 @@ kd_io_map_open(device)
+ mach_device_t device;
+ {
+ kd_io_device = device;
+- io_port_create(device, vga_port_list);
++ io_port_create(device, kd_port_list);
+ }
+
+ kd_io_map_close()
diff --git a/debian/patches/45_io_per_task.patch b/debian/patches/45_io_per_task.patch
new file mode 100644
index 0000000..b9290b9
--- /dev/null
+++ b/debian/patches/45_io_per_task.patch
@@ -0,0 +1,591 @@
+#DPATCHLEVEL=1
+
+2006-01-02 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * i386/i386/iopb.c: IO ports permissions are now task-based.
+ (i386_io_port_add): Fix TSS access and locking accordingly.
+ (i386_io_port_remove): Likewise.
+ (i386_io_port_list): Likewise.
+ (iopb_check_mapping): Likewise.
+ * i386/i386/pcb.c (switch_ktss): Now takes next thread as parameter
+ for TSS switch to be task-based. Fix all callers.
+ (switch_context): Likewise.
+ (pcb_module_init): Move iopb initialization to ...
+ (machine_task_module_init): ... here. New function.
+ (pcb_terminate): Move iopb termination to ...
+ (machine_task_terminate): ... here. New function.
+ (machine_task_init): New function.
+ (machine_task_collect): Likewise.
+ (thread_setstatus): TSS is now task-based, fix TSS and locking
+ accordingly.
+ (thread_getstatus): Likewise.
+ * i386/i386/thread.h (i386_machine_state): Move io_tss member to ...
+ (machine_task): ... here. New structure.
+
+ * i386/i386at/iopl.c (iopl_emulate): TSS is now task-based, fix TSS
+ and locking accordingly.
+
+ * kern/task.c (task_init): Call new machine_task_module_init() function.
+ (task_create): Call new machine_task_init() function.
+ (task_deallocate): Call new machine_task_terminate() function.
+ (task_collect_scan): Call new machine_task_collect() function.
+ * kern/task.h: Include <machine/thread.h> for machine_task_t.
+ (task): Add new machine member.
+
+
+diff -urp gnumach-mine-4-more_ports/i386/i386/iopb.c gnumach-mine-5-io_per_task/i386/i386/iopb.c
+--- gnumach-mine-4-more_ports/i386/i386/iopb.c 2006-01-02 18:42:45.000000000 +0100
++++ gnumach-mine-5-io_per_task/i386/i386/iopb.c 2005-12-29 23:42:34.000000000 +0100
+@@ -65,8 +65,8 @@
+
+ /*
+ * Cross-reference:
+- * all threads that have IO ports mapped
+- * all IO ports that have threads mapped
++ * all tasks that have IO ports mapped
++ * all IO ports that have tasks mapped
+ */
+ struct io_use {
+ queue_chain_t psq; /* Links from port set */
+@@ -306,7 +306,7 @@
+ }
+
+ /*
+- * Add an IO mapping to a thread.
++ * Add an IO mapping to a task.
+ */
+ #ifdef i386
+ kern_return_t
+@@ -320,7 +320,7 @@ i386_io_port_add(
+ mach_device_t device)
+ #endif
+ {
+- pcb_t pcb;
++ task_t task;
+ #ifdef i386
+ mach_device_t device = d->emul_data;
+ #endif
+@@ -332,7 +332,7 @@ i386_io_port_add(
+ || device == DEVICE_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+- pcb = thread->pcb;
++ task = thread->task;
+
+ new_io_tss = 0;
+ iu = (io_use_t) kalloc(sizeof(struct io_use));
+@@ -355,16 +355,16 @@ i386_io_port_add(
+
+ /* Have the IO port. */
+
+- /* Make sure the thread has a TSS. */
++ /* Make sure the task has a TSS. */
+
+- simple_lock(&pcb->lock);
+- io_tss = pcb->ims.io_tss;
++ task_lock(task);
++ io_tss = task->machine.io_tss;
+ if (io_tss == 0) {
+ if (new_io_tss == 0) {
+ /*
+ * Allocate an IO-tss.
+ */
+- simple_unlock(&pcb->lock);
++ task_unlock(task);
+ simple_unlock(&iopb_lock);
+
+ new_io_tss = (iopb_tss_t) kalloc(sizeof(struct iopb_tss));
+@@ -373,7 +373,12 @@ i386_io_port_add(
+ goto Retry;
+ }
+ io_tss = new_io_tss;
+- pcb->ims.io_tss = io_tss;
++ task->machine.io_tss = io_tss;
++
++ /* Update hardware if needed. */
++ if (task == current_thread()->task)
++ switch_ktss(thread);
++
+ new_io_tss = 0;
+ }
+
+@@ -386,7 +391,7 @@ i386_io_port_add(
+ /*
+ * Already mapped.
+ */
+- simple_unlock(&pcb->lock);
++ task_unlock(task);
+ simple_unlock(&iopb_lock);
+
+ kfree((vm_offset_t)iu, sizeof(struct io_use));
+@@ -405,7 +410,7 @@ i386_io_port_add(
+ 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);
++ task_unlock(task);
+ simple_unlock(&iopb_lock);
+
+ if (new_io_tss)
+@@ -415,7 +420,7 @@ i386_io_port_add(
+ }
+
+ /*
+- * Remove an IO mapping from a thread.
++ * Remove an IO mapping from a task.
+ */
+ #ifdef i386
+ kern_return_t
+@@ -429,7 +434,7 @@ i386_io_port_remove(thread, device)
+ mach_device_t device;
+ #endif
+ {
+- pcb_t pcb;
++ task_t task;
+ #ifdef i386
+ mach_device_t device = d->emul_data;
+ #endif
+@@ -441,7 +446,7 @@ i386_io_port_remove(thread, device)
+ || device == DEVICE_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+- pcb = thread->pcb;
++ task = thread->task;
+
+ simple_lock(&iopb_lock);
+
+@@ -456,10 +461,10 @@ i386_io_port_remove(thread, device)
+ return KERN_INVALID_ARGUMENT;
+ }
+
+- simple_lock(&pcb->lock);
+- io_tss = pcb->ims.io_tss;
++ task_lock(task);
++ io_tss = task->machine.io_tss;
+ if (io_tss == 0) {
+- simple_unlock(&pcb->lock);
++ task_unlock(task);
+ simple_unlock(&iopb_lock);
+ return KERN_INVALID_ARGUMENT; /* not mapped */
+ }
+@@ -477,7 +482,7 @@ i386_io_port_remove(thread, device)
+ 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);
++ task_unlock(task);
+ simple_unlock(&iopb_lock);
+
+ kfree((vm_offset_t)iu, sizeof(struct io_use));
+@@ -486,6 +491,9 @@ i386_io_port_remove(thread, device)
+ }
+ }
+
++ task_unlock(task);
++ simple_unlock(&iopb_lock);
++
+ /*
+ * No mapping.
+ */
+@@ -493,7 +501,7 @@ i386_io_port_remove(thread, device)
+ }
+
+ /*
+- * Return the IO ports mapped into a thread.
++ * Return the IO ports mapped into a task.
+ */
+ extern ipc_port_t mach_convert_device_to_port(/* device_t */);
+
+@@ -503,7 +511,7 @@ i386_io_port_list(thread, list, list_cou
+ mach_device_t **list;
+ unsigned int *list_count;
+ {
+- register pcb_t pcb;
++ task_t task;
+ register iopb_tss_t io_tss;
+ unsigned int count, alloc_count;
+ mach_device_t *devices;
+@@ -514,7 +522,7 @@ i386_io_port_list(thread, list, list_cou
+ if (thread == THREAD_NULL)
+ return KERN_INVALID_ARGUMENT;
+
+- pcb = thread->pcb;
++ task = thread->task;
+
+ alloc_count = 16; /* a guess */
+
+@@ -537,8 +545,8 @@ i386_io_port_list(thread, list, list_cou
+ count = 0;
+
+ simple_lock(&iopb_lock);
+- simple_lock(&pcb->lock);
+- io_tss = pcb->ims.io_tss;
++ task_lock(task);
++ io_tss = task->machine.io_tss;
+ if (io_tss != 0) {
+ register io_use_t iu;
+
+@@ -550,7 +558,7 @@ i386_io_port_list(thread, list, list_cou
+ }
+ }
+ }
+- simple_unlock(&pcb->lock);
++ task_unlock(task);
+ simple_unlock(&iopb_lock);
+ } while (count > alloc_count);
+
+@@ -596,7 +604,7 @@ i386_io_port_list(thread, list, list_cou
+ }
+
+ /*
+- * Check whether an IO device is mapped to a particular thread.
++ * Check whether an IO device is mapped to a particular task.
+ * Used to support the 'iopl' device automatic mapping.
+ */
+ boolean_t
+@@ -604,11 +612,11 @@ iopb_check_mapping(thread, device)
+ thread_t thread;
+ mach_device_t device;
+ {
+- pcb_t pcb;
++ task_t task;
+ io_port_t io_port;
+ io_use_t iu;
+
+- pcb = thread->pcb;
++ task = thread->task;
+
+ simple_lock(&iopb_lock);
+
+@@ -622,15 +630,18 @@ iopb_check_mapping(thread, device)
+
+ /* Look up the mapping in the device`s mapping list. */
+
++ task_lock(task);
+ queue_iterate(&io_port->io_use_list, iu, io_use_t, psq) {
+- if (iu->ts == pcb->ims.io_tss) {
++ if (iu->ts == task->machine.io_tss) {
+ /*
+ * Device is mapped.
+ */
++ task_unlock(task);
+ simple_unlock(&iopb_lock);
+ return TRUE;
+ }
+ }
++ task_unlock(task);
+ simple_unlock(&iopb_lock);
+ return FALSE;
+ }
+diff -urp gnumach-mine-4-more_ports/i386/i386/pcb.c gnumach-mine-5-io_per_task/i386/i386/pcb.c
+--- gnumach-mine-4-more_ports/i386/i386/pcb.c 2006-01-02 18:42:57.000000000 +0100
++++ gnumach-mine-5-io_per_task/i386/i386/pcb.c 2005-12-31 00:04:21.000000000 +0100
+@@ -131,12 +131,13 @@
+ #define gdt_desc_p(mycpu,sel) \
+ ((struct real_descriptor *)&curr_gdt(mycpu)[sel_idx(sel)])
+
+-void switch_ktss(pcb)
+- register pcb_t pcb;
++void switch_ktss(thread)
++ register thread_t thread;
+ {
+ int mycpu = cpu_number();
++ register pcb_t pcb = thread->pcb;
+ {
+- register iopb_tss_t tss = pcb->ims.io_tss;
++ register iopb_tss_t tss = thread->task->machine.io_tss;
+ vm_offset_t pcb_stack_top;
+
+ /*
+@@ -234,7 +235,7 @@ void stack_handoff(old, new)
+ /*
+ * Load the rest of the user state for the new thread
+ */
+- switch_ktss(new->pcb);
++ switch_ktss(new);
+
+ /*
+ * Switch to new thread
+@@ -259,7 +260,7 @@ void stack_handoff(old, new)
+ void load_context(new)
+ register thread_t new;
+ {
+- switch_ktss(new->pcb);
++ switch_ktss(new);
+ Load_context(new);
+ }
+
+@@ -296,7 +297,7 @@ thread_t switch_context(old, continuatio
+ /*
+ * Load the rest of the user state for the new thread
+ */
+- switch_ktss(new->pcb);
++ switch_ktss(new);
+
+ return Switch_context(old, continuation, new);
+ }
+@@ -309,7 +310,6 @@ void pcb_module_init()
+ 0, "i386 pcb state");
+
+ fpu_module_init();
+- iopb_init();
+ }
+
+ void pcb_init(thread)
+@@ -353,8 +353,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)
+@@ -374,6 +372,30 @@ void pcb_collect(thread)
+ {
+ }
+
++void machine_task_module_init(void)
++{
++ iopb_init();
++}
++
++void machine_task_init(new_task)
++ task_t new_task;
++{
++ new_task->machine.io_tss = 0;
++}
++
++void machine_task_terminate(task)
++ task_t task;
++{
++ if (task->machine.io_tss != 0)
++ iopb_destroy(task->machine.io_tss);
++}
++
++void machine_task_collect(task)
++ task_t task;
++{
++ /* TODO: compare io_tss with 0xff, XXX: not if it is still in use, and
++ * beware of races with threads adding io perms! */
++}
+
+ /*
+ * thread_setstatus:
+@@ -508,28 +530,40 @@ 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;
++ register iopb_tss_t tss, old_tss;
++ task_t task;
+
+ if (count < i386_ISA_PORT_MAP_STATE_COUNT)
+ return(KERN_INVALID_ARGUMENT);
+
+-#if 0
+ /*
+ * If the thread has no ktss yet,
+ * we must allocate one.
+ */
+
+ state = (struct i386_isa_port_map_state *) tstate;
+- tss = thread->pcb->ims.io_tss;
++ task = thread->task;
++ task_lock(task);
++ tss = task->machine.io_tss;
+ if (tss == 0) {
++ task_unlock(task);
+ tss = iopb_create();
+- thread->pcb->ims.io_tss = tss;
++ task_lock(task);
++ old_tss = task->machine.io_tss;
++ if (old_tss == 0) {
++ task->machine.io_tss = tss;
++ } else {
++ task_unlock(task);
++ iopb_destroy(tss);
++ tss = old_tss;
++ task_lock(task);
++ }
+ }
+
+ bcopy((char *) state->pm,
+ (char *) tss->bitmap,
+ sizeof state->pm);
+-#endif
++ task_unlock(task);
+ break;
+ }
+
+@@ -666,16 +700,21 @@ 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;
++ task_t task;
+
+ 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;
++ task = thread->task;
++ task_lock(task);
++ tss = task->machine.io_tss;
+
+ if (tss == 0) {
+ int i;
+
++ task_unlock(task);
++
+ /*
+ * The thread has no ktss, so no IO permissions.
+ */
+@@ -690,6 +729,7 @@ kern_return_t thread_getstatus(thread, f
+ bcopy((char *) tss->bitmap,
+ (char *) state->pm,
+ sizeof state->pm);
++ task_unlock(task);
+ }
+
+ *count = i386_ISA_PORT_MAP_STATE_COUNT;
+diff -urp gnumach-mine-4-more_ports/i386/i386/io_emulate.c gnumach-mine-5-io_per_task/i386/i386/io_emulate.c
+--- gnumach-mine-4-more_ports/i386/i386/io_emulate.c 2006-01-02 18:41:46.000000000 +0100
++++ gnumach-mine-5-io_per_task/i386/i386/io_emulate.c 2005-12-28 17:40:28.000000000 +0100
+@@ -102,7 +102,7 @@ emulate_io(regs, opcode, io_port)
+ * Make the thread use its IO_TSS to get the IO permissions;
+ * it may not have had one before this.
+ */
+- switch_ktss(thread->pcb);
++ switch_ktss(thread);
+
+ return EM_IO_RETRY;
+ }
+diff -urp gnumach-mine-4-more_ports/i386/i386/thread.h gnumach-mine-5-io_per_task/i386/i386/thread.h
+--- gnumach-mine-4-more_ports/i386/i386/thread.h 2006-01-02 18:43:01.000000000 +0100
++++ gnumach-mine-5-io_per_task/i386/i386/thread.h 2005-12-28 17:44:13.000000000 +0100
+@@ -157,12 +157,15 @@
+ */
+
+ struct i386_machine_state {
+- iopb_tss_t io_tss;
+ struct user_ldt * ldt;
+ struct i386_fpsave_state *ifps;
+ struct v86_assist_state v86s;
+ };
+
++typedef struct machine_task {
++ iopb_tss_t io_tss;
++} machine_task_t;
++
+ typedef struct pcb {
+ struct i386_interrupt_state iis[2]; /* interrupt and NMI */
+ struct i386_saved_state iss;
+diff -urp gnumach-mine-4-more_ports/i386/i386/user_ldt.c gnumach-mine-5-io_per_task/i386/i386/user_ldt.c
+--- gnumach-mine-4-more_ports/i386/i386/user_ldt.c 2006-01-02 18:43:04.000000000 +0100
++++ gnumach-mine-5-io_per_task/i386/i386/user_ldt.c 2005-12-28 17:40:37.000000000 +0100
+@@ -247,7 +247,7 @@ i386_set_ldt(thread, first_selector, des
+ * make sure it is properly set.
+ */
+ if (thread == current_thread())
+- switch_ktss(pcb);
++ switch_ktss(thread);
+ }
+
+ /*
+
+diff -urp gnumach-mine-4-more_ports/i386/i386at/iopl.c gnumach-mine-5-io_per_task/i386/i386at/iopl.c
+--- gnumach-mine-4-more_ports/i386/i386at/iopl.c 2006-01-02 18:45:17.000000000 +0100
++++ gnumach-mine-5-io_per_task/i386/i386at/iopl.c 2006-01-02 16:30:19.000000000 +0100
+@@ -217,10 +217,15 @@ iopl_emulate(regs, opcode, io_port)
+ int io_port;
+ {
+ iopb_tss_t iopb;
++ task_t task;
+
+- iopb = current_thread()->pcb->ims.io_tss;
+- if (iopb == 0)
++ task = current_thread()->task;
++ task_lock(task);
++ iopb = task->machine.io_tss;
++ if (iopb == 0) {
++ task_unlock(task);
+ return FALSE; /* no IO mapped */
++ }
+
+ /*
+ * Handle outb to the timer control port,
+@@ -235,11 +240,14 @@ iopl_emulate(regs, opcode, io_port)
+ && (opcode == 0xe6 || opcode == 0xee) /* outb */
+ && (io_byte & 0xc0) == 0x80) /* timer 2 */
+ {
++ task_unlock(task);
+ outb(io_port, io_byte);
+ return TRUE;
+ }
++ task_unlock(task);
+ return FALSE; /* invalid IO to port 42 */
+ }
++ task_unlock(task);
+
+ /*
+ * If the thread has the IOPL device mapped, and
+
+
+diff -urp gnumach-mine-4-more_ports/kern/task.c gnumach-mine-5-io_per_task/kern/task.c
+--- gnumach-mine-4-more_ports/kern/task.c 2006-01-02 18:43:17.000000000 +0100
++++ gnumach-mine-5-io_per_task/kern/task.c 2005-12-28 17:10:07.000000000 +0100
+@@ -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 -urp gnumach-mine-4-more_ports/kern/task.h gnumach-mine-5-io_per_task/kern/task.h
+--- gnumach-mine-4-more_ports/kern/task.h 2006-01-02 18:43:22.000000000 +0100
++++ gnumach-mine-5-io_per_task/kern/task.h 2005-12-28 17:44:11.000000000 +0100
+@@ -49,6 +49,7 @@
+ #include <kern/pc_sample.h>
+ #include <kern/processor.h>
+ #include <kern/syscall_emulation.h>
++#include <machine/thread.h>
+ #include <vm/vm_map.h>
+
+ #if NET_ATM
+@@ -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 --git a/debian/patches/46_io_device.patch b/debian/patches/46_io_device.patch
new file mode 100644
index 0000000..731d30f
--- /dev/null
+++ b/debian/patches/46_io_device.patch
@@ -0,0 +1,117 @@
+2006-01-07 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * i386/i386/iopb.c: Include <device/io_req.h> for io_req_t. New "io"
+ device.
+ (ioopen): New function.
+ (ioclose): Likewise.
+ (io_bitmap_set): Treat special (-1) bit list as "all ports".
+ (io_bitmap_clear): Likewise.
+
+
+diff -urp gnumach-mine-5-io_per_task/i386/i386/iopb.c gnumach-mine-6-io_device/i386/i386/iopb.c
+--- gnumach-mine-5-io_per_task/i386/i386/iopb.c 2005-12-29 23:42:34.000000000 +0100
++++ gnumach-mine-6-io_device/i386/i386/iopb.c 2006-01-07 00:19:24.000000000 +0100
+@@ -38,6 +38,7 @@
+ #include <kern/thread.h>
+
+ #include <device/dev_hdr.h>
++#include <device/io_req.h>
+
+ #include "io_port.h"
+ #include "iopb.h"
+@@ -82,6 +83,32 @@
+ decl_simple_lock_data(, iopb_lock)
+
+ /*
++ * Special "all I/O ports" device.
++ */
++mach_device_t io_device = 0;
++
++int ioopen(dev, flag, ior)
++ int dev;
++ int flag;
++ io_req_t ior;
++{
++ io_device = ior->io_device;
++
++ io_port_create(io_device, (io_reg_t *)(-1));
++ return (0);
++}
++
++int
++ioclose(dev, flags)
++ int dev;
++ int flags;
++{
++ io_port_destroy(io_device);
++ io_device = 0;
++ return 0;
++}
++
++/*
+ * Initialize the package.
+ */
+ void
+@@ -130,9 +157,12 @@ io_bitmap_set(
+ {
+ io_reg_t io_bit;
+
+- while ((io_bit = *bit_list++) != IO_REG_NULL) {
+- bp[io_bit>>3] &= ~(1 << (io_bit & 0x7));
+- }
++ if (bit_list == (io_reg_t *)(-1))
++ memset(bp, 0, IOPB_BYTES);
++ else
++ while ((io_bit = *bit_list++) != IO_REG_NULL) {
++ bp[io_bit>>3] &= ~(1 << (io_bit & 0x7));
++ }
+ }
+
+ /*
+@@ -145,9 +175,12 @@ io_bitmap_clear(
+ {
+ io_reg_t io_bit;
+
+- while ((io_bit = *bit_list++) != IO_REG_NULL) {
+- bp[io_bit>>3] |= (1 << (io_bit & 0x7));
+- }
++ if (bit_list == (io_reg_t *)(-1))
++ memset(bp, ~0, IOPB_BYTES);
++ else
++ while ((io_bit = *bit_list++) != IO_REG_NULL) {
++ bp[io_bit>>3] |= (1 << (io_bit & 0x7));
++ }
+ }
+
+ /*
+
+2006-01-07 Samuel Thibault <samuel.thibault@ens-lyon.org>
+
+ * conf.c: New "io" device.
+ (dev_name_list): Added "io" device.
+
+diff -urp gnumach-mine-5-io_per_task/i386/i386at/conf.c gnumach-mine-6-io_device/i386/i386at/conf.c
+--- gnumach-mine-5-io_per_task/i386/i386at/conf.c 2006-01-06 23:43:24.000000000 +0100
++++ gnumach-mine-6-io_device/i386/i386at/conf.c 2006-01-06 23:43:44.000000000 +0100
+@@ -182,6 +182,9 @@
+ extern vm_offset_t ioplmmap();
+ #define ioplname "iopl"
+
++extern int ioopen(), ioclose();
++#define ioname "io"
++
+ extern int kmsgopen(), kmsgclose(), kmsgread(), kmsggetstat();
+ #define kmsgname "kmsg"
+
+@@ -367,6 +370,11 @@ struct dev_ops dev_name_list[] =
+ nodev, nulldev, nulldev, 0,
+ nodev },
+
++ { ioname, ioopen, ioclose, nodev,
++ nodev, nodev, nodev, nodev,
++ nodev, nulldev, nulldev, 0,
++ nodev },
++
+ #if 0
+ #if NHD > 0
+ { pchdname, pchdopen, hdclose, pchdread,