Hello! On Wed, Apr 25, 2007 at 03:07:34PM +0200, I wrote: > Now that it finally works, I can now polish and test my patch a bit. :-)
Here we go. There are a few places marked with ``TODO''. Please comment on them. If someone wants to see my testing equipment, I'll happily provide it. I worked on integrating Marcus's work into the GNU Mach branch and did not really check that all the low level details are correct -- I would assume that checking those has been done at the time Marcus's patch was installed into the OSKit-Mach branch. With this patch, glibc's `ioperm' call will ``automagically'' begin to work, as soon as it's been recompiled with the modified GNU Mach header and definition files in place. #v+ 2007-04-25 Thomas Schwinge <[EMAIL PROTECTED]> * i386/i386/io_port.h: Remove file. * i386/i386at/kd.c: TODO. * i386/Makefrag.am (libkernel_a_SOURCES): Add `i386/i386/io_perm.c', `i386/i386/io_perm.h', `i386/i386/machine_task.c', `i386/i386/task.h' and remove `i386/i386/io_port.h', `i386/i386/iopb.c', `i386/i386/iopb.h'. * include/stddef.h: New file. * i386/i386/io_perm.c: Include <string.h>, <device/device_emul.h> and don't include <oskit/ds_oskit.h>. (io_perm_device_emulation_ops): New variable. (dev_open_alloc, setup_no_senders): Remove declarations. (convert_io_perm_to_port, convert_port_to_io_perm, io_perm_deallocate): Rewrite. (no_senders): New function. (i386_io_perm_create, i386_io_perm_modify): Rewrite partially, to adapt to the GNU Mach environment. * i386/i386/io_perm.h: Include <device/dev_hdr.h> and <ipc/ipc_types.h>. (io_perm, io_perm_t): New structure and accompanying type definition. (IO_PERM_NULL): Define. * i386/i386/locore.S (ktss): Move variable to... * i386/i386/ktss.c: ... here, make it a ``struct task_tss''. (ktss_init): Initialize the `task_tss' structure and the i/o permission bit map. * i386/i386/ktss.h: Adapt to that. * i386/i386/machine_task.c (machine_task_module_init): Adapt the `zinit' call to the GNU Mach environment. * i386/i386/mp_desc.c: Include <machine/ktss.h>. * i386/i386/tss.h: Include <machine/io_perm.h>. (task_tss): New structure, equivalent to the OSKit-Mach one. * i386/include/mach/i386/mach_i386.defs: Don't include <device/device_types.defs>. (device_list_t): Remove type. * i386/include/mach/i386/mach_i386_types.h (device_list_t): Remove type definition. 2007-04-25 Marcus Brinkmann <[EMAIL PROTECTED]> * i386/i386/iopb.h, i386/i386/iopb.c: Obsolete files removed. * i386/i386/pcb.c (switch_context): Update the I/O permission bitmap from stack_handoff() here (not only in stack_handoff()). * i386/i386/machine_task.c (machine_task_module_init): Set ZONE_COLLECTABLE and ZONE_EXHAUSTIBLE flags for the iopb zone. Requested by Roland McGrath <[EMAIL PROTECTED]>. * i386/i386/io_perm.h: New file. * i386/i386/io_perm.c: New file. * i386/i386/machine_task.c: New file. * i386/i386/mp_desc.h: (struct mp_desc_table): Change type of ktss to struct task_tss. (mp_ktss): Likewise for array of pointers to the struct. * i386/i386/mp_desc.c: Include `machine/tss.h' and `machine/io_perm.h'. (mp_ktss): Change type to array of struct task_tss. (mp_desc_init): Cast pointer to x86_tss into pointer to task_tss, and use size of struct task_tss instead size of struct x86_tss. Initialize the task_tss structure. * i386/i386/pcb.c: Include `stddef.h' and `machine/tss.h'. (iopb_create, iopb_destroy): Prototypes removed. (curr_ktss): Cast pointer to base_tss to pointer to struct task_tss. (switch_ktss): Always use kernel TSS. (update_ktss_iopb): New function. (stack_handoff): Call update_ktss_iopb. (pcb_module_init): Do not call iopb_init. (pcb_terminate): Do not call iopb_destroy. (thread_setstatus): Remove local variable tss. (thread_getstatus): Rewrite i386_ISA_PORT_MAP_STATE case handler. * i386/i386/task.h: New file. * i386/i386/thread.h: Do not include `i386/iopb.h'. (struct i386_machine_state): Remove member io_tss. * i386/include/mach/i386/mach_i386.defs [KERNEL_SERVER]: Include `machine/io_perm.h'. Define intran, outtran and destructor. (io_port_t): New type. (io_perm_t): Likewise. (i386_io_port_add): Interface removed. (i386_io_port_remove): Likewise. (i386_io_port_list): Likewise. (i386_io_perm_create): New interface. (i386_io_perm_modify): Likewise. * i386/include/mach/i386/mach_i386_types.h [MACH_KERNEL]: Include `i386/io_perm.h'. [!MACH_KERNEL]: Define types io_port_t and io_perm_t. * kern/task.c (task_init): Call machine_task_module_init. (task_create): Call machine_task_init. (task_deallocate): Call machine_task_terminate. (task_collect_scan): Call machine_task_collect. * task.h: Include `machine/task.h'. (struct task): Add member machine. Index: i386/Makefrag.am =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/Attic/Makefrag.am,v retrieving revision 1.1.2.9 diff -u -p -r1.1.2.9 Makefrag.am --- i386/Makefrag.am 1 Apr 2007 22:10:39 -0000 1.1.2.9 +++ i386/Makefrag.am 25 Apr 2007 16:36:32 -0000 @@ -85,9 +85,8 @@ libkernel_a_SOURCES += \ i386/i386/idt.c \ i386/i386/idt_inittab.S \ i386/i386/io_map.c \ - i386/i386/io_port.h \ - i386/i386/iopb.c \ - i386/i386/iopb.h \ + i386/i386/io_perm.c \ + i386/i386/io_perm.h \ i386/i386/ipl.h \ i386/i386/ktss.c \ i386/i386/ktss.h \ @@ -101,6 +100,7 @@ libkernel_a_SOURCES += \ i386/i386/loose_ends.c \ i386/i386/mach_param.h \ i386/i386/machine_routines.h \ + i386/i386/machine_task.c \ i386/i386/machspl.h \ i386/i386/mp_desc.c \ i386/i386/mp_desc.h \ @@ -120,6 +120,7 @@ libkernel_a_SOURCES += \ i386/i386/setjmp.h \ i386/i386/spl.S \ i386/i386/spl.h \ + i386/i386/task.h \ i386/i386/thread.h \ i386/i386/time_stamp.h \ i386/i386/timer.h \ Index: i386/i386/io_perm.c =================================================================== RCS file: i386/i386/io_perm.c diff -N i386/i386/io_perm.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ i386/i386/io_perm.c 25 Apr 2007 16:36:32 -0000 @@ -0,0 +1,313 @@ +/* Manipulate I/O permission bitmap objects. + + Copyright (C) 2002, 2007 Free Software Foundation, Inc. + + Written by Marcus Brinkmann. Glued into GNU Mach by Thomas Schwinge. + + This file is part of GNU Mach. + + GNU Mach is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +/* + * Mach Operating System + * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University + * All Rights Reserved. + * + * Permission to use, copy, modify and distribute this software and its + * documentation is hereby granted, provided that both the copyright + * notice and this permission notice appear in all copies of the + * software, derivative works or modified versions, and any portions + * thereof, and that both notices appear in supporting documentation. + * + * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR + * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. + * + * Carnegie Mellon requests users of this software to return to + * + * Software Distribution Coordinator or [EMAIL PROTECTED] + * School of Computer Science + * Carnegie Mellon University + * Pittsburgh PA 15213-3890 + * + * any improvements or extensions that they make and grant Carnegie Mellon + * the rights to redistribute these changes. + */ + +#include <string.h> + +#include <mach/boolean.h> +#include <mach/kern_return.h> + +#include <ipc/ipc_port.h> + +#include <kern/zalloc.h> +#include <kern/lock.h> +#include <kern/queue.h> +#include <kern/thread.h> + +#include <device/dev_hdr.h> +#include <device/device_emul.h> +#include <device/device_port.h> + +#include "io_perm.h" +#include "gdt.h" + +/* Our device emulation ops. See below, at the bottom of this file. */ +static struct device_emulation_ops io_perm_device_emulation_ops; + + +/* The outtran which allows MIG to convert an io_perm_t object to a port + representing it. */ +ipc_port_t +convert_io_perm_to_port (io_perm_t io_perm) +{ + if (io_perm == IO_PERM_NULL) + return IP_NULL; + + ipc_port_t port; + + port = ipc_port_make_send (io_perm->port); + + return port; +} + + +/* The intran which allows MIG to convert a port representing an + io_perm_t object to the object itself. */ +io_perm_t +convert_port_to_io_perm (ipc_port_t port) +{ + device_t device; + + device = dev_port_lookup (port); + + if (device == DEVICE_NULL) + return IO_PERM_NULL; + + io_perm_t io_perm; + + io_perm = device->emul_data; + + return io_perm; +} + +#if REMOVE_ME +/* TODO. Fix this comment. */ +/* The destructor which is called when the last send right to a port + representing an io_perm_t object vanishes. */ +void +io_perm_deallocate (io_perm_t io_perm) +{ + /* TODO. Is there anything to deallocate in here? I don't think so, as we + don't allocate anything in `convert_port_to_io_perm'. */ +} +#endif + +/* Our ``no senders'' handling routine. Deallocate the object. */ +static +void +no_senders (mach_no_senders_notification_t *notification) +{ + io_perm_t io_perm; + + io_perm = convert_port_to_io_perm + ((ipc_port_t) notification->not_header.msgh_remote_port); + + assert (io_perm != IO_PERM_NULL); + + ip_lock (io_perm->port); /* TODO. Actually needed? */ + ipc_kobject_set (io_perm->port, IKO_NULL, IKOT_NONE); + ipc_port_dealloc_kernel (io_perm->port); + + kfree ((vm_offset_t) io_perm, sizeof *io_perm); +} + + +/* Initialize bitmap by setting all bits to OFF == 1. */ +static inline void +io_bitmap_init (unsigned char *iopb) +{ + memset (iopb, ~0, IOPB_BYTES); +} + + +/* Set selected bits in bitmap to ON == 0. */ +static inline void +io_bitmap_set (unsigned char *iopb, io_port_t from, io_port_t to) +{ + do + iopb[from >> 3] &= ~(1 << (from & 0x7)); + while (from++ != to); +} + + +/* Set selected bits in bitmap to OFF == 1. */ +static inline void +io_bitmap_clear (unsigned char *iopb, io_port_t from, io_port_t to) +{ + do + iopb[from >> 3] |= (1 << (from & 0x7)); + while (from++ != to); +} + + +/* Request a new port IO_PERM that represents the capability to access + the I/O ports [FROM; TO] directly. MASTER_PORT is the master device port. + + The function returns KERN_INVALID_ARGUMENT if TARGET_TASK is not a task, + or FROM is greater than TO. + + The function is exported. */ +kern_return_t +i386_io_perm_create (ipc_port_t master_port, io_port_t from, io_port_t to, + io_perm_t *new) +{ + /* TODO. Check for limits [0;IOPB_MAX)? */ + if (master_port != master_device_port || from > to) + return KERN_INVALID_ARGUMENT; + + io_perm_t io_perm; + + io_perm = (io_perm_t) kalloc (sizeof *io_perm); + if (io_perm == NULL) + return KERN_RESOURCE_SHORTAGE; + + io_perm->from = from; + io_perm->to = to; + + io_perm->port = ipc_port_alloc_kernel (); + if (io_perm->port == IP_NULL) + { + kfree ((vm_offset_t) io_perm, sizeof *io_perm); + return KERN_RESOURCE_SHORTAGE; + } + + /* Set up the dummy device. */ + ipc_kobject_set(io_perm->port, + (ipc_kobject_t) &io_perm->device, IKOT_DEVICE); + io_perm->device.emul_data = io_perm; + io_perm->device.emul_ops = &io_perm_device_emulation_ops; + + ipc_port_t notify; + + notify = ipc_port_make_sonce(io_perm->port); + ip_lock(device->port); + ipc_port_nsrequest(io_perm->port, 1, notify, ¬ify); + assert(notify == IP_NULL); + + *new = io_perm; + + return KERN_SUCCESS; +} + + +/* From pcb.c. */ +extern void update_ktss_iopb (unsigned char *new_iopb, int last); + + +/* Modify the I/O permissions for TARGET_TASK. If ENABLE is TRUE, the + permission to acces the I/O ports specified by IO_PERM is granted, + otherwise it is withdrawn. + + The function returns KERN_INVALID_ARGUMENT if TARGET_TASK is not a valid + task or IO_PERM not a valid I/O permission port. + + The function is exported. */ +kern_return_t +i386_io_perm_modify (task_t target_task, io_perm_t io_perm, boolean_t enable) +{ + io_port_t from, to; + unsigned char *iopb; + io_port_t iopb_size; + + if (target_task == TASK_NULL || io_perm == IO_PERM_NULL) + return KERN_INVALID_ARGUMENT; + + from = io_perm->from; + to = io_perm->to; + + simple_lock (&target_task->machine.iopb_lock); + iopb = target_task->machine.iopb; + iopb_size = target_task->machine.iopb_size; + + if (!enable && !iopb_size) + { + simple_unlock (&target_task->machine.iopb_lock); + return KERN_SUCCESS; + } + + if (!iopb) + { + simple_unlock (&target_task->machine.iopb_lock); + /* TODO. Does this have to be deallocated again? (Thinking about + `no_senders'.) Probably not, because glibc's `ioperm' call would be + rather difficult to implement then.*/ + iopb = (unsigned char *) zalloc (machine_task_iopb_zone); + simple_lock (&target_task->machine.iopb_lock); + if (target_task->machine.iopb) + { + if (iopb) + zfree (machine_task_iopb_zone, (vm_offset_t) iopb); + iopb = target_task->machine.iopb; + iopb_size = target_task->machine.iopb_size; + } + else if (iopb) + { + target_task->machine.iopb = iopb; + io_bitmap_init (iopb); + } + else + /* TODO. Need some unlocking here? */ + return KERN_RESOURCE_SHORTAGE; + } + + if (enable) + { + io_bitmap_set (iopb, from, to); + if ((to >> 3) + 1 > iopb_size) + target_task->machine.iopb_size = (to >> 3) + 1; + } + else + { + if ((from >> 3) + 1 > iopb_size) + { + simple_unlock (&target_task->machine.iopb_lock); + return KERN_SUCCESS; + } + + io_bitmap_clear (iopb, from, to); + while (iopb_size > 0 && iopb[iopb_size - 1] == 0xff) + iopb_size--; + target_task->machine.iopb_size = iopb_size; + } + +#if NCPUS>1 +#warning SMP support missing (notify all CPUs running threads in that of the I/O bitmap change). +#endif + if (target_task == current_task()) + update_ktss_iopb (iopb, target_task->machine.iopb_size); + + simple_unlock (&target_task->machine.iopb_lock); + return KERN_SUCCESS; +} + +/* We are some sort of Mach device... */ +static struct device_emulation_ops io_perm_device_emulation_ops = +{ + /* ... in order to be easily able to receive a ``no senders'' notification + which we then use to deallocate ourselves. */ + .no_senders = no_senders +}; Index: i386/i386/io_perm.h =================================================================== RCS file: i386/i386/io_perm.h diff -N i386/i386/io_perm.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ i386/i386/io_perm.h 25 Apr 2007 16:36:32 -0000 @@ -0,0 +1,66 @@ +/* Data types for I/O permission bitmap objects. + + Copyright (C) 2002, 2007 Free Software Foundation, Inc. + + Written by Marcus Brinkmann. Glued into GNU Mach by Thomas Schwinge. + + This file is part of GNU Mach. + + GNU Mach is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _I386_IO_PERM_H_ +#define _I386_IO_PERM_H_ + +#include <device/dev_hdr.h> +#include <ipc/ipc_types.h> + + +/* The highest possible I/O port. 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 io_perm +{ + /* We use a ``struct device'' for easy management. */ + struct device device; + + ipc_port_t port; + + io_port_t from, to; +}; + +typedef struct io_perm *io_perm_t; + +#define IO_PERM_NULL ((io_perm_t) 0) + +extern io_perm_t convert_port_to_io_perm (ipc_port_t); +extern ipc_port_t convert_io_perm_to_port (io_perm_t); +#if REMOVE_ME +extern void io_perm_deallocate (io_perm_t); +#endif + +#endif Index: i386/i386/ktss.c =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386/Attic/ktss.c,v retrieving revision 1.1.1.1.4.1 diff -u -p -r1.1.1.1.4.1 ktss.c --- i386/i386/ktss.c 13 Nov 2006 21:30:36 -0000 1.1.1.1.4.1 +++ i386/i386/ktss.c 25 Apr 2007 16:36:32 -0000 @@ -36,6 +36,9 @@ #include "gdt.h" #include "ktss.h" +/* A kernel TSS with a complete I/O bitmap. */ +struct task_tss ktss; + void ktss_init() { @@ -44,16 +47,15 @@ ktss_init() /* Initialize the master TSS descriptor. */ fill_gdt_descriptor(KERNEL_TSS, - kvtolin(&ktss), sizeof(ktss)+65536/8+1-1, + kvtolin(&ktss), sizeof(struct task_tss) - 1, ACC_PL_K|ACC_TSS, 0); /* Initialize the master TSS. */ - ktss.ss0 = KERNEL_DS; - ktss.esp0 = (unsigned)(exception_stack+1024); - ktss.io_bit_map_offset = sizeof(ktss); - + ktss.tss.ss0 = KERNEL_DS; + ktss.tss.esp0 = (unsigned)(exception_stack+1024); + ktss.tss.io_bit_map_offset = IOPB_INVAL; /* Set the last byte in the I/O bitmap to all 1's. */ - ((unsigned char*)&ktss)[sizeof(ktss)+65536/8] = 0xff; + ktss.barrier = 0xff; /* Load the TSS. */ ltr(KERNEL_TSS); Index: i386/i386/ktss.h =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386/Attic/ktss.h,v retrieving revision 1.2 diff -u -p -r1.2 ktss.h --- i386/i386/ktss.h 5 Apr 2001 06:39:20 -0000 1.2 +++ i386/i386/ktss.h 25 Apr 2007 16:36:32 -0000 @@ -25,6 +25,6 @@ #include "tss.h" -extern struct i386_tss ktss; +extern struct task_tss ktss; #endif /* _I386_KTSS_ */ Index: i386/i386/locore.S =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386/locore.S,v retrieving revision 1.6.2.7 diff -u -p -r1.6.2.7 locore.S --- i386/i386/locore.S 20 Dec 2006 21:13:45 -0000 1.6.2.7 +++ i386/i386/locore.S 25 Apr 2007 16:36:33 -0000 @@ -1441,12 +1441,3 @@ Entry(cpu_shutdown) xor %ecx,%ecx /* generate a divide by zero */ div %ecx,%eax /* reboot now */ ret /* this will "never" be executed */ - - -/* - * Allocate enough space for a kernel TSS with a complete I/O bitmap, - * for making v86-mode BIOS calls. XXX - */ - .data - .globl EXT(ktss) - .comm EXT(ktss),0x68+65536/8+1 Index: i386/i386/machine_task.c =================================================================== RCS file: i386/i386/machine_task.c diff -N i386/i386/machine_task.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ i386/i386/machine_task.c 25 Apr 2007 16:36:33 -0000 @@ -0,0 +1,79 @@ +/* Machine specific data for a task on i386. + + Copyright (C) 2002, 2007 Free Software Foundation, Inc. + + Written by Marcus Brinkmann. Glued into GNU Mach by Thomas Schwinge. + + This file is part of GNU Mach. + + GNU Mach is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#include <kern/lock.h> +#include <mach/mach_types.h> +#include <kern/zalloc.h> +#include <kern/mach_param.h> +#include <machine/task.h> + +#include <machine/io_perm.h> + + +/* The zone which holds our IO permission bitmaps. */ +zone_t machine_task_iopb_zone; + + +/* Initialize the machine task module. The function is called once at + start up by task_init in kern/task.c. */ +void +machine_task_module_init (void) +{ + machine_task_iopb_zone = zinit (IOPB_BYTES, 0, + TASK_MAX * IOPB_BYTES, + IOPB_BYTES, + ZONE_COLLECTABLE | ZONE_EXHAUSTIBLE, + "i386 machine task iopb"); +} + + +/* Initialize the machine specific part of task TASK. */ +void +machine_task_init (task_t task) +{ + task->machine.iopb_size = 0; + task->machine.iopb = 0; + simple_lock_init (&task->machine.iopb_lock); +} + + +/* Destroy the machine specific part of task TASK and release all + associated resources. */ +void +machine_task_terminate (task_t task) +{ + if (task->machine.iopb) + zfree (machine_task_iopb_zone, (vm_offset_t) task->machine.iopb); +} + + +/* Try to release as much memory from the machine specific data in + task TASK. */ +void +machine_task_collect (task_t task) +{ + if (task->machine.iopb_size == 0 && task->machine.iopb) + { + zfree (machine_task_iopb_zone, (vm_offset_t) task->machine.iopb); + task->machine.iopb = 0; + } +} Index: i386/i386/mp_desc.c =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386/mp_desc.c,v retrieving revision 1.1.1.1.4.4 diff -u -p -r1.1.1.1.4.4 mp_desc.c --- i386/i386/mp_desc.c 10 Nov 2006 01:22:57 -0000 1.1.1.1.4.4 +++ i386/i386/mp_desc.c 25 Apr 2007 16:36:33 -0000 @@ -35,6 +35,9 @@ #include <i386/mp_desc.h> #include <i386/lock.h> +#include <machine/ktss.h> +#include <machine/tss.h> +#include <machine/io_perm.h> /* * The i386 needs an interrupt stack to keep the PCB stack from being @@ -82,7 +85,7 @@ struct mp_desc_table *mp_desc_table[NCPU /* * Pointer to TSS for access in load_context. */ -struct i386_tss *mp_ktss[NCPUS] = { 0 }; +struct task_tss *mp_ktss[NCPUS] = { 0 }; /* * Pointer to GDT to reset the KTSS busy bit. @@ -95,7 +98,6 @@ struct real_descriptor *mp_gdt[NCPUS] = extern struct real_gate idt[IDTSZ]; extern struct real_descriptor gdt[GDTSZ]; extern struct real_descriptor ldt[LDTSZ]; -extern struct i386_tss ktss; /* * Allocate and initialize the per-processor descriptor tables. @@ -112,7 +114,7 @@ mp_desc_init(mycpu) * Master CPU uses the tables built at boot time. * Just set the TSS and GDT pointers. */ - mp_ktss[mycpu] = &ktss; + mp_ktss[mycpu] = (struct task_tss *) &ktss; mp_gdt[mycpu] = gdt; return 0; } @@ -140,7 +142,7 @@ mp_desc_init(mycpu) ldt, sizeof(ldt)); memset(&mpt->ktss, 0, - sizeof(struct i386_tss)); + sizeof(struct task_tss)); /* * Fix up the entries in the GDT to point to @@ -152,11 +154,12 @@ mp_desc_init(mycpu) ACC_P|ACC_PL_K|ACC_LDT, 0); fill_descriptor(&mpt->gdt[sel_idx(KERNEL_TSS)], (unsigned)&mpt->ktss, - sizeof(struct i386_tss) - 1, + sizeof(struct task_tss) - 1, ACC_P|ACC_PL_K|ACC_TSS, 0); - mpt->ktss.ss0 = KERNEL_DS; - mpt->ktss.io_bit_map_offset = 0x0FFF; /* no IO bitmap */ + mpt->ktss.tss.ss0 = KERNEL_DS; + mpt->ktss.tss.io_bit_map_offset = IOPB_INVAL; + mpt->ktss.barrier = 0xFF; return mpt; } Index: i386/i386/mp_desc.h =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386/mp_desc.h,v retrieving revision 1.2.2.1 diff -u -p -r1.2.2.1 mp_desc.h --- i386/i386/mp_desc.h 15 Oct 2006 14:59:03 -0000 1.2.2.1 +++ i386/i386/mp_desc.h 25 Apr 2007 16:36:33 -0000 @@ -52,7 +52,7 @@ struct mp_desc_table { struct real_gate idt[IDTSZ]; /* IDT */ struct real_descriptor gdt[GDTSZ]; /* GDT */ struct real_descriptor ldt[LDTSZ]; /* LDT */ - struct i386_tss ktss; + struct task_tss ktss; }; /* @@ -63,7 +63,7 @@ extern struct mp_desc_table *mp_desc_tab /* * The kernel TSS gets its own pointer. */ -extern struct i386_tss *mp_ktss[NCPUS]; +extern struct task_tss *mp_ktss[NCPUS]; /* * So does the GDT. Index: i386/i386/pcb.c =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386/pcb.c,v retrieving revision 1.2.4.9 diff -u -p -r1.2.4.9 pcb.c --- i386/i386/pcb.c 4 Jan 2007 23:51:02 -0000 1.2.4.9 +++ i386/i386/pcb.c 25 Apr 2007 16:36:33 -0000 @@ -24,6 +24,7 @@ * the rights to redistribute these changes. */ +#include <stddef.h> #include <string.h> #include <mach/std_types.h> @@ -43,7 +44,6 @@ #include <i386/thread.h> #include <i386/proc_reg.h> #include <i386/seg.h> -#include <i386/tss.h> #include <i386/user_ldt.h> #include <i386/fpu.h> #include "eflags.h" @@ -52,6 +52,8 @@ #include "ktss.h" #include "pcb.h" +#include <machine/tss.h> + #if NCPUS > 1 #include <i386/mp_desc.h> #endif @@ -59,8 +61,6 @@ extern thread_t Switch_context(); extern void Thread_continue(); -extern iopb_tss_t iopb_create(); -extern void iopb_destroy(); extern void user_ldt_free(); zone_t pcb_zone; @@ -126,7 +126,7 @@ vm_offset_t stack_detach(thread) #define curr_ktss(mycpu) (mp_ktss[mycpu]) #else #define curr_gdt(mycpu) ((void)(mycpu), gdt) -#define curr_ktss(mycpu) ((void)(mycpu), &ktss) +#define curr_ktss(mycpu) ((void)(mycpu), (struct task_tss *)&ktss) #endif #define gdt_desc_p(mycpu,sel) \ @@ -137,7 +137,6 @@ void switch_ktss(pcb) { int mycpu = cpu_number(); { - register iopb_tss_t tss = pcb->ims.io_tss; vm_offset_t pcb_stack_top; /* @@ -153,25 +152,7 @@ void switch_ktss(pcb) ? (int) (&pcb->iss + 1) : (int) (&pcb->iss.v86_segs); - if (tss == 0) { - /* - * No per-thread IO permissions. - * Use standard kernel TSS. - */ - if (!(gdt_desc_p(mycpu,KERNEL_TSS)->access & ACC_TSS_BUSY)) - set_tr(KERNEL_TSS); - curr_ktss(mycpu)->esp0 = pcb_stack_top; - } - else { - /* - * Set the IO permissions. Use this thread`s TSS. - */ - *gdt_desc_p(mycpu,USER_TSS) - = *(struct real_descriptor *)tss->iopb_desc; - tss->tss.esp0 = pcb_stack_top; - set_tr(USER_TSS); - gdt_desc_p(mycpu,KERNEL_TSS)->access &= ~ ACC_TSS_BUSY; - } + curr_ktss(mycpu)->tss.esp0 = pcb_stack_top; } { @@ -207,6 +188,24 @@ void switch_ktss(pcb) } +/* If NEW_IOPB is not null, the SIZE denotes the number of bytes in + the new bitmap. Expects iopb_lock to be held. */ +void +update_ktss_iopb (unsigned char *new_iopb, io_port_t size) +{ + struct task_tss *tss = curr_ktss (cpu_number ()); + + if (new_iopb && size > 0) + { + tss->tss.io_bit_map_offset + = offsetof (struct task_tss, barrier) - size; + memcpy (((char *) tss) + tss->tss.io_bit_map_offset, + new_iopb, size); + } + else + tss->tss.io_bit_map_offset = IOPB_INVAL; +} + /* * stack_handoff: * @@ -236,6 +235,19 @@ void stack_handoff(old, new) old, mycpu); PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map), new, mycpu); + + simple_lock (&new_task->machine.iopb_lock); +#if NCPUS>1 +#warning SMP support missing (avoid races with io_perm_modify). +#else + /* This optimization only works on a single processor + machine, where old_task's iopb can not change while + we are switching. */ + if (old_task->machine.iopb || new_task->machine.iopb) +#endif + update_ktss_iopb (new_task->machine.iopb, + new_task->machine.iopb_size); + simple_unlock (&new_task->machine.iopb_lock); } } @@ -298,6 +310,19 @@ thread_t switch_context(old, continuatio old, mycpu); PMAP_ACTIVATE_USER(vm_map_pmap(new_task->map), new, mycpu); + + simple_lock (&new_task->machine.iopb_lock); +#if NCPUS>1 +#warning SMP support missing (avoid races with io_perm_modify). +#else + /* This optimization only works on a single processor + machine, where old_task's iopb can not change while + we are switching. */ + if (old_task->machine.iopb || new_task->machine.iopb) +#endif + update_ktss_iopb (new_task->machine.iopb, + new_task->machine.iopb_size); + simple_unlock (&new_task->machine.iopb_lock); } } @@ -317,7 +342,6 @@ void pcb_module_init() 0, "i386 pcb state"); fpu_module_init(); - iopb_init(); } void pcb_init(thread) @@ -361,8 +385,6 @@ void pcb_terminate(thread) counter(if (--c_threads_current < c_threads_min) c_threads_min = c_threads_current); - if (pcb->ims.io_tss != 0) - iopb_destroy(pcb->ims.io_tss); if (pcb->ims.ifps != 0) fp_free(pcb->ims.ifps); if (pcb->ims.ldt != 0) @@ -516,7 +538,6 @@ kern_return_t thread_setstatus(thread, 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); @@ -673,32 +694,20 @@ kern_return_t thread_getstatus(thread, f */ case i386_ISA_PORT_MAP_STATE: { register struct i386_isa_port_map_state *state; - register iopb_tss_t tss; if (*count < i386_ISA_PORT_MAP_STATE_COUNT) return(KERN_INVALID_ARGUMENT); state = (struct i386_isa_port_map_state *) tstate; - tss = thread->pcb->ims.io_tss; - - if (tss == 0) { - int i; - /* - * The thread has no ktss, so no IO permissions. - */ - - for (i = 0; i < sizeof state->pm; i++) - state->pm[i] = 0xff; - } else { - /* - * The thread has its own ktss. - */ - - memcpy(state->pm, - tss->bitmap, - sizeof state->pm); - } + simple_lock (&thread->task->machine.iopb_lock); + if (thread->task->machine.iopb == 0) + memset (state->pm, 0xff, sizeof state->pm); + else + memcpy((char *) state->pm, + (char *) thread->task->machine.iopb, + sizeof state->pm); + simple_unlock (&thread->task->machine.iopb_lock); *count = i386_ISA_PORT_MAP_STATE_COUNT; break; Index: i386/i386/task.h =================================================================== RCS file: i386/i386/task.h diff -N i386/i386/task.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ i386/i386/task.h 25 Apr 2007 16:36:33 -0000 @@ -0,0 +1,61 @@ +/* Data types for machine specific parts of tasks on i386. + + Copyright (C) 2002, 2007 Free Software Foundation, Inc. + + Written by Marcus Brinkmann. Glued into GNU Mach by Thomas Schwinge. + + This file is part of GNU Mach. + + GNU Mach is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the + Free Software Foundation; either version 2, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +#ifndef _I386_TASK_H_ +#define _I386_TASK_H_ + +#include <kern/kern_types.h> +#include <kern/zalloc.h> + +/* The machine specific data of a task. */ +struct machine_task +{ + /* A lock protecting iopb_size and iopb. */ + decl_simple_lock_data (, iopb_lock); + + /* The highest I/O port number enabled. */ + int iopb_size; + + /* The I/O permission bitmap. */ + unsigned char *iopb; +}; +typedef struct machine_task machine_task_t; + + +extern zone_t machine_task_iopb_zone; + +/* Initialize the machine task module. The function is called once at + start up by task_init in kern/task.c. */ +void machine_task_module_init (void); + +/* Initialize the machine specific part of task TASK. */ +void machine_task_init (task_t); + +/* Destroy the machine specific part of task TASK and release all + associated resources. */ +void machine_task_terminate (task_t); + +/* Try to release as much memory from the machine specific data in + task TASK. */ +void machine_task_collect (task_t); + +#endif /* _I386_TASK_H_ */ Index: i386/i386/thread.h =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386/thread.h,v retrieving revision 1.3.2.1 diff -u -p -r1.3.2.1 thread.h --- i386/i386/thread.h 5 Nov 2006 20:39:24 -0000 1.3.2.1 +++ i386/i386/thread.h 25 Apr 2007 16:36:33 -0000 @@ -39,7 +39,6 @@ #include <kern/lock.h> -#include <i386/iopb.h> #include <i386/tss.h> #include "gdt.h" @@ -158,7 +157,6 @@ struct i386_interrupt_state { */ struct i386_machine_state { - iopb_tss_t io_tss; struct user_ldt * ldt; struct i386_fpsave_state *ifps; struct v86_assist_state v86s; Index: i386/i386/tss.h =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386/tss.h,v retrieving revision 1.1 diff -u -p -r1.1 tss.h --- i386/i386/tss.h 25 Feb 1997 21:27:12 -0000 1.1 +++ i386/i386/tss.h 25 Apr 2007 16:36:33 -0000 @@ -29,6 +29,8 @@ #include <mach/inline.h> +#include <machine/io_perm.h> + /* * i386 Task State Segment */ @@ -66,6 +68,17 @@ struct i386_tss { bit map */ }; + +/* The structure extends the above TSS structure by an I/O permission bitmap + and the barrier. */ +struct task_tss + { + struct i386_tss tss; + unsigned char iopb[IOPB_BYTES]; + unsigned char barrier; +}; + + /* Load the current task register. */ MACH_INLINE void ltr(unsigned short segment) Index: i386/i386at/kd.c =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/i386at/Attic/kd.c,v retrieving revision 1.5.2.12 diff -u -p -r1.5.2.12 kd.c --- i386/i386at/kd.c 5 Feb 2007 21:09:36 -0000 1.5.2.12 +++ i386/i386at/kd.c 25 Apr 2007 16:36:34 -0000 @@ -84,7 +84,9 @@ WITH THE USE OR PERFORMANCE OF THIS SOFT #include <device/tty.h> #include <device/io_req.h> #include <device/buf.h> /* for struct uio (!) */ +#if REMOVE_ME #include <i386/io_port.h> +#endif #include <vm/vm_kern.h> #include <i386/vm_param.h> #include <i386/machspl.h> @@ -333,6 +335,7 @@ unsigned char key_map[NUMKEYS][WIDTH_KMA short kd_index_reg = EGA_IDX_REG; short kd_io_reg = EGA_IO_REG; +#if REMOVE_ME /* * IO port sets for different controllers. */ @@ -360,6 +363,7 @@ kd_io_map_close() io_port_destroy(kd_io_device); kd_io_device = 0; } +#endif /* REMOVE_ME */ /* * Globals used only for bitmap-based controllers. See kdsoft.h for @@ -509,10 +513,12 @@ kdopen(dev, flag, ior) tp->t_flags = ODDP|EVENP|ECHO|CRMOD|XTABS; kdinit(); +#if REMOVE_ME /* XXX kd_io_map_open allocates memory */ simple_unlock(&tp->t_lock); kd_io_map_open(ior->io_device); simple_lock(&tp->t_lock); +#endif } tp->t_state |= TS_CARR_ON; simple_unlock(&tp->t_lock); @@ -549,7 +555,9 @@ int flag; splx(s); } +#if REMOVE_ME kd_io_map_close(); +#endif return; Index: i386/include/mach/i386/mach_i386.defs =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/include/mach/i386/mach_i386.defs,v retrieving revision 1.2.2.2 diff -u -p -r1.2.2.2 mach_i386.defs --- i386/include/mach/i386/mach_i386.defs 25 Apr 2007 13:59:03 -0000 1.2.2.2 +++ i386/include/mach/i386/mach_i386.defs 25 Apr 2007 16:36:34 -0000 @@ -35,26 +35,31 @@ subsystem #include <mach/std_types.defs> #include <mach/mach_types.defs> -#include <device/device_types.defs> - -type device_list_t = ^array[] of device_t; type descriptor_t = struct[2] of int; type descriptor_list_t = array[*] of descriptor_t; import <mach/machine/mach_i386_types.h>; -routine i386_io_port_add( - target_thread : thread_t; - device : device_t); - -routine i386_io_port_remove( - target_thread : thread_t; - device : device_t); - -routine i386_io_port_list( - target_thread : thread_t; - out device_list : device_list_t); +#if KERNEL_SERVER +simport <machine/io_perm.h>; +#endif + +type io_port_t = MACH_MSG_TYPE_INTEGER_16; +type io_perm_t = mach_port_t + ctype: mach_port_t +#if KERNEL_SERVER + intran: io_perm_t convert_port_to_io_perm(mach_port_t) + outtran: mach_port_t convert_io_perm_to_port(io_perm_t) +#if REMOVE_ME + destructor: io_perm_deallocate(io_perm_t) +#endif +#endif /* KERNEL_SERVER */ + ; + +skip; /* i386_io_port_add */ +skip; /* i386_io_port_remove */ +skip; /* i386_io_port_list */ routine i386_set_ldt( target_thread : thread_t; @@ -67,8 +72,27 @@ routine i386_get_ldt( selector_count : int; out desc_list : descriptor_list_t); -skip; /* i386_io_perm_create */ -skip; /* i386_io_perm_modify */ +/* Request a new port IO_PERM that represents the capability to access + the I/O ports [FROM; TO] directly. MASTER_PORT is the master device port. + + The function returns KERN_INVALID_ARGUMENT if TARGET_TASK is not a task, + or FROM is greater than TO. */ +routine i386_io_perm_create( + master_port : mach_port_t; + from : io_port_t; + to : io_port_t; + out io_perm : io_perm_t); + +/* Modify the I/O permissions for TARGET_TASK. If ENABLE is TRUE, the + permission to access the I/O ports specified by IO_PERM is granted, + otherwise it is withdrawn. + + The function returns KERN_INVALID_ARGUMENT if TARGET_TASK is not a valid + task or IO_PERM not a valid I/O permission port. */ +routine i386_io_perm_modify( + target_task : task_t; + io_perm : io_perm_t; + enable : boolean_t); /* Modify one of a few available thread-specific segment descriptor slots. The SELECTOR must be a value from a previous call (on any thread), Index: i386/include/mach/i386/mach_i386_types.h =================================================================== RCS file: /cvsroot/hurd/gnumach/i386/include/mach/i386/mach_i386_types.h,v retrieving revision 1.1.1.1 diff -u -p -r1.1.1.1 mach_i386_types.h --- i386/include/mach/i386/mach_i386_types.h 25 Feb 1997 21:27:00 -0000 1.1.1.1 +++ i386/include/mach/i386/mach_i386_types.h 25 Apr 2007 16:36:34 -0000 @@ -31,11 +31,6 @@ #define _MACH_MACH_I386_TYPES_H_ /* - * Array of devices. - */ -typedef device_t *device_list_t; - -/* * i386 segment descriptor. */ struct descriptor { @@ -46,4 +41,15 @@ struct descriptor { typedef struct descriptor descriptor_t; typedef struct descriptor *descriptor_list_t; +/* + * i386 I/O port + */ + +#ifdef MACH_KERNEL +#include <i386/io_perm.h> +#else +typedef unsigned short io_port_t; +typedef mach_port_t io_perm_t; +#endif + #endif /* _MACH_MACH_I386_TYPES_H_ */ Index: include/stddef.h =================================================================== RCS file: include/stddef.h diff -N include/stddef.h --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ include/stddef.h 25 Apr 2007 16:36:35 -0000 @@ -0,0 +1,29 @@ +/* + * Copyright (C) 2007 Free Software Foundation, Inc. + * + * This file is part of GNU Mach. + * + * GNU Mach is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef _STDDEF_H_ +#define _STDDEF_H_ + +/* From GCC's `/lib/gcc/X/X/include/stddef.h'. */ + +/* Offset of member MEMBER in a struct of type TYPE. */ +#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER) + +#endif /* _STDDEF_H_ */ Index: kern/task.c =================================================================== RCS file: /cvsroot/hurd/gnumach/kern/task.c,v retrieving revision 1.3.4.7 diff -u -p -r1.3.4.7 task.c --- kern/task.c 4 Jan 2007 23:51:02 -0000 1.3.4.7 +++ kern/task.c 25 Apr 2007 16:36:35 -0000 @@ -67,6 +67,7 @@ void task_init(void) 0, "tasks"); eml_init(); + machine_task_module_init (); /* * Create the kernel task as the first task. @@ -145,6 +146,7 @@ kern_return_t task_create( eml_task_reference(new_task, parent_task); ipc_task_init(new_task, parent_task); + machine_task_init (new_task); new_task->total_user_time.seconds = 0; new_task->total_user_time.microseconds = 0; @@ -220,6 +222,8 @@ void task_deallocate( if (c != 0) return; + machine_task_terminate (task); + eml_task_deallocate(task); pset = task->processor_set; @@ -1092,6 +1096,7 @@ void task_collect_scan(void) pset_unlock(pset); simple_unlock(&all_psets_lock); + machine_task_collect (task); pmap_collect(task->map->pmap); if (prev_task != TASK_NULL) Index: kern/task.h =================================================================== RCS file: /cvsroot/hurd/gnumach/kern/task.h,v retrieving revision 1.3.2.3 diff -u -p -r1.3.2.3 task.h --- kern/task.h 15 Oct 2006 14:59:04 -0000 1.3.2.3 +++ kern/task.h 25 Apr 2007 16:36:35 -0000 @@ -46,6 +46,7 @@ #include <kern/processor.h> #include <kern/syscall_emulation.h> #include <vm/vm_map.h> +#include <machine/task.h> struct task { /* Synchronization/destruction information */ @@ -98,6 +99,9 @@ struct task { vm_offset_t fast_tas_base[TASK_FAST_TAS_NRAS]; vm_offset_t fast_tas_end[TASK_FAST_TAS_NRAS]; #endif /* FAST_TAS */ + + /* Hardware specific data. */ + machine_task_t machine; }; #define task_lock(task) simple_lock(&(task)->lock) #v- Regards, Thomas
signature.asc
Description: Digital signature
_______________________________________________ Bug-hurd mailing list Bug-hurd@gnu.org http://lists.gnu.org/mailman/listinfo/bug-hurd