summaryrefslogtreecommitdiff
path: root/i386/i386/iopb.c
diff options
context:
space:
mode:
Diffstat (limited to 'i386/i386/iopb.c')
-rw-r--r--i386/i386/iopb.c618
1 files changed, 0 insertions, 618 deletions
diff --git a/i386/i386/iopb.c b/i386/i386/iopb.c
deleted file mode 100644
index f1e859a..0000000
--- a/i386/i386/iopb.c
+++ /dev/null
@@ -1,618 +0,0 @@
-/*
- * Mach Operating System
- * Copyright (c) 1993,1992,1991,1990 Carnegie Mellon University
- * All Rights Reserved.
- *
- * Permission to use, copy, modify and distribute this software and its
- * documentation is hereby granted, provided that both the copyright
- * notice and this permission notice appear in all copies of the
- * software, derivative works or modified versions, and any portions
- * thereof, and that both notices appear in supporting documentation.
- *
- * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
- * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
- * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
- *
- * Carnegie Mellon requests users of this software to return to
- *
- * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
- * School of Computer Science
- * Carnegie Mellon University
- * Pittsburgh PA 15213-3890
- *
- * any improvements or extensions that they make and grant Carnegie Mellon
- * the rights to redistribute these changes.
- */
-/*
- * Code to manipulate IO permission bitmaps.
- */
-
-#include <string.h>
-
-#include <mach/boolean.h>
-#include <mach/kern_return.h>
-
-#include <ipc/ipc_port.h>
-
-#include <kern/kalloc.h>
-#include <kern/lock.h>
-#include <kern/queue.h>
-#include <kern/thread.h>
-
-#include <device/dev_hdr.h>
-
-#include "io_port.h"
-#include "iopb.h"
-#include "seg.h"
-#include "gdt.h"
-#include "vm_param.h"
-
-/*
- * A set of ports for an IO device.
- */
-struct io_port {
- mach_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;
-
-/*
- * Big lock for the whole mess.
- */
-decl_simple_lock_data(, iopb_lock)
-
-/*
- * Initialize the package.
- */
-void
-iopb_init(void)
-{
- queue_init(&device_to_io_port_list);
- simple_lock_init(&iopb_lock);
-}
-
-/*
- * Initialize bitmap (set all bits to OFF == 1)
- */
-void
-io_bitmap_init(
- isa_iopb bp,
- boolean_t on_off)
-{
- register unsigned char *b = bp;
- register int s;
- unsigned char c;
-
- /*
- * Disallow access to ports 0x00 .. 0xff
- */
- for (s = 0; s < (0xff+1)/8; s++) {
- *b++ = ~0; /* no access */
- }
-
- if (on_off)
- c = 0;
- else
- c = ~0;
-
- for (; s < sizeof(isa_iopb); s++) {
- *b++ = c;
- }
-}
-
-/*
- * Set selected bits in bitmap to ON == 0
- */
-void
-io_bitmap_set(
- 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));
- }
-}
-
-/*
- * 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(
- mach_device_t device)
-{
- 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;
-}
-
-/*
- * [exported]
- * Create an io_port set
- */
-void
-io_port_create(
- mach_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(
- mach_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 = kvtolin (io_tss);
- vm_size_t limit = (char *)&io_tss->barrier - (char *)io_tss;
-
- memset(&io_tss->tss, 0, sizeof(struct i386_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] = (limit & 0xffff)
- | ((addr & 0xffff) << 16);
- io_tss->iopb_desc[1] = ((addr & 0x00ff0000) >> 16)
- | ((ACC_TSS|ACC_PL_K|ACC_P) << 8)
- | (limit & 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,
- mach_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;
- mach_device_t device;
-{
- 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;
- }
-
- 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 */
- }
-
- /*
- * 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);
-
- kfree((vm_offset_t)iu, sizeof(struct io_use));
-
- return KERN_SUCCESS;
- }
- }
-
- /*
- * No mapping.
- */
- return KERN_INVALID_ARGUMENT;
-}
-
-/*
- * Return the IO ports mapped into a thread.
- */
-extern ipc_port_t mach_convert_device_to_port(/* device_t */);
-
-kern_return_t
-i386_io_port_list(thread, list, list_count)
- thread_t thread;
- mach_device_t **list;
- unsigned int *list_count;
-{
- register pcb_t pcb;
- register iopb_tss_t io_tss;
- unsigned int count, alloc_count;
- mach_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 = (mach_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;
- }
-
- memcpy((void *)new_addr, (void *)addr, size_needed);
- kfree(addr, size);
- devices = (mach_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;
-
- 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;
- mach_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;
-}