The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/osfmk/i386/iopb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26  * @OSF_COPYRIGHT@
   27  */
   28 /* 
   29  * Mach Operating System
   30  * Copyright (c) 1991,1990 Carnegie Mellon University
   31  * All Rights Reserved.
   32  * 
   33  * Permission to use, copy, modify and distribute this software and its
   34  * documentation is hereby granted, provided that both the copyright
   35  * notice and this permission notice appear in all copies of the
   36  * software, derivative works or modified versions, and any portions
   37  * thereof, and that both notices appear in supporting documentation.
   38  * 
   39  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   40  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   41  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   42  * 
   43  * Carnegie Mellon requests users of this software to return to
   44  * 
   45  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   46  *  School of Computer Science
   47  *  Carnegie Mellon University
   48  *  Pittsburgh PA 15213-3890
   49  * 
   50  * any improvements or extensions that they make and grant Carnegie Mellon
   51  * the rights to redistribute these changes.
   52  */
   53 
   54 /*
   55  */
   56 
   57 /*
   58  * Code to manipulate IO permission bitmaps.
   59  */
   60  
   61 
   62 
   63 #include <mach/boolean.h>
   64 #include <mach/kern_return.h>
   65 
   66 #include <ipc/ipc_port.h>
   67 
   68 #include <kern/kalloc.h>
   69 #include <kern/lock.h>
   70 #include <kern/queue.h>
   71 #include <kern/thread.h>
   72 #include <kern/misc_protos.h>
   73 
   74 
   75 #include <i386/io_port.h>
   76 #include <i386/iopb.h>
   77 #include <i386/seg.h>
   78 #include <i386/iopb_entries.h>
   79 
   80 void
   81 iopb_init(void)
   82 {
   83 }
   84 
   85 
   86 void
   87 iopb_destroy(iopb_tss_t      io_tss)
   88 {
   89 }
   90 
   91 #if 0                           /* Code removed until better solution comes on board */
   92 /*
   93  * A set of ports for an IO device.
   94  */
   95 struct io_port {
   96         device_t        device;         /* Mach device */
   97         queue_chain_t   dev_list;       /* link in device list */
   98         queue_chain_t   io_use_list;    /* List of threads that use it */
   99         io_reg_t        *io_port_list;  /* list of IO ports that use it */
  100                                         /* list ends with IO_REG_NULL */
  101 };
  102 typedef struct io_port  *io_port_t;
  103 
  104 /*
  105  * Lookup table for device -> io_port mapping
  106  * (a linked list - I don't expect too many)
  107  */
  108 queue_head_t    device_to_io_port_list;
  109 
  110 /*
  111  * Cross-reference:
  112  *      all threads that have IO ports mapped
  113  *      all IO ports that have threads mapped
  114  */
  115 struct io_use {
  116         queue_chain_t   psq;    /* Links from port set */
  117         queue_chain_t   tsq;    /* links from tss */
  118         io_port_t       ps;     /* Port set */
  119         iopb_tss_t      ts;     /* Task segment */
  120 };
  121 typedef struct io_use   *io_use_t;
  122 
  123 /*
  124  * Big lock for the whole mess.
  125  */
  126 decl_simple_lock_data(,iopb_lock)
  127 
  128 /* Forward */
  129 
  130 extern void             io_bitmap_init(
  131                                 isa_iopb                bp);
  132 extern void             io_bitmap_set(
  133                                 isa_iopb                bp,
  134                                 io_reg_t                *bit_list);
  135 extern void             io_bitmap_clear(
  136                                 isa_iopb                bp,
  137                                 io_reg_t                *bit_list);
  138 extern io_port_t        device_to_io_port_lookup(
  139                                 device_t                device);
  140 extern void             io_tss_init(
  141                                 iopb_tss_t              io_tss);
  142 
  143 
  144 /*
  145  * Initialize the package.
  146  */
  147 void
  148 iopb_init(void)
  149 {
  150         queue_init(&device_to_io_port_list);
  151         simple_lock_init(&iopb_lock, ETAP_IO_IOPB);
  152 }
  153 
  154 /*
  155  * Initialize bitmap (set all bits to OFF == 1)
  156  */
  157 void
  158 io_bitmap_init(
  159         isa_iopb        bp)
  160 {
  161         register unsigned char *b;
  162         register int    s;
  163 
  164         s = sizeof(isa_iopb);
  165         b = bp;
  166 
  167         do {
  168             *b++ = ~0;
  169         } while (--s >= 0);
  170 }
  171 
  172 /*
  173  * Set selected bits in bitmap to ON == 0
  174  */
  175 void
  176 io_bitmap_set(
  177         isa_iopb        bp,
  178         io_reg_t        *bit_list)
  179 {
  180         io_reg_t        io_bit;
  181 
  182         while ((io_bit = *bit_list++) != IO_REG_NULL) {
  183             bp[io_bit>>3] &= ~(1 << (io_bit & 0x7));
  184         }
  185 }
  186 
  187 /*
  188  * Set selected bits in bitmap to OFF == 1
  189  */
  190 void
  191 io_bitmap_clear(
  192         isa_iopb        bp,
  193         io_reg_t        *bit_list)
  194 {
  195         io_reg_t        io_bit;
  196 
  197         while ((io_bit = *bit_list++) != IO_REG_NULL) {
  198             bp[io_bit>>3] |= (1 << (io_bit & 0x7));
  199         }
  200 }
  201 
  202 /*
  203  * Lookup an io-port set by device
  204  */
  205 io_port_t
  206 device_to_io_port_lookup(
  207         device_t        device)
  208 {
  209         register io_port_t io_port;
  210 
  211         queue_iterate(&device_to_io_port_list, io_port, io_port_t, dev_list) {
  212             if (io_port->device == device) {
  213                 return io_port;
  214             }
  215         }
  216         return 0;
  217 }
  218 
  219 /*
  220  * [exported]
  221  * Create an io_port set
  222  */
  223 void
  224 io_port_create(
  225         device_t        device,
  226         io_reg_t        *io_port_list)
  227 {
  228         register io_port_t io_port, old_io_port;
  229 
  230         io_port = (io_port_t) kalloc(sizeof(struct io_port));
  231 
  232         simple_lock(&iopb_lock);
  233         if (device_to_io_port_lookup(device) != 0) {
  234             simple_unlock(&iopb_lock);
  235             kfree((vm_offset_t) io_port, sizeof(struct io_port));
  236             return;
  237         }
  238 
  239         io_port->device = device;
  240         queue_init(&io_port->io_use_list);
  241         io_port->io_port_list = io_port_list;
  242 
  243         /*
  244          * Enter in lookup list.
  245          */
  246         queue_enter(&device_to_io_port_list, io_port, io_port_t, dev_list);
  247 
  248         simple_unlock(&iopb_lock);
  249 }
  250 
  251 /*
  252  * [exported]
  253  * Destroy an io port set, removing any IO mappings.
  254  */
  255 void
  256 io_port_destroy(
  257         device_t        device)
  258 {
  259         io_port_t       io_port;
  260         io_use_t        iu;
  261 
  262         simple_lock(&iopb_lock);
  263         io_port = device_to_io_port_lookup(device);
  264         if (io_port == 0) {
  265             simple_unlock(&iopb_lock);
  266             return;
  267         }
  268 
  269         queue_iterate(&io_port->io_use_list, iu, io_use_t, psq) {
  270             iopb_tss_t  io_tss;
  271             io_tss = iu->ts;
  272             io_bitmap_clear(io_tss->bitmap, io_port->io_port_list);
  273             queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
  274         }
  275         queue_remove(&device_to_io_port_list, io_port, io_port_t, dev_list);
  276         simple_unlock(&iopb_lock);
  277 
  278         while (!queue_empty(&io_port->io_use_list)) {
  279             iu = (io_use_t) queue_first(&io_port->io_use_list);
  280             queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
  281             kfree((vm_offset_t)iu, sizeof(struct io_use));
  282         }
  283 
  284         kfree((vm_offset_t)io_port, sizeof(struct io_port));
  285 }
  286 
  287 /*
  288  * Initialize an IO TSS.
  289  */
  290 void
  291 io_tss_init(
  292         iopb_tss_t      io_tss)
  293 {
  294         vm_offset_t     addr = (vm_offset_t) io_tss;
  295         vm_size_t       size = (char *)&io_tss->barrier - (char *)io_tss;
  296 
  297         bzero((char *)&io_tss->tss, sizeof(struct i386_tss));
  298         io_tss->tss.io_bit_map_offset
  299                         = (char *)&io_tss->bitmap - (char *)io_tss;
  300         io_tss->tss.ss0 = KERNEL_DS;
  301         io_bitmap_init(io_tss->bitmap);
  302         io_tss->barrier = ~0;
  303         queue_init(&io_tss->io_port_list);
  304         addr += LINEAR_KERNEL_ADDRESS;
  305         io_tss->iopb_desc[0] = ((size-1) & 0xffff)
  306                 | ((addr & 0xffff) << 16);
  307         io_tss->iopb_desc[1] = ((addr & 0x00ff0000) >> 16)
  308                 | ((ACC_TSS|ACC_PL_K|ACC_P) << 8)
  309                 | ((size-1) & 0x000f0000)
  310                 | (addr & 0xff000000);
  311 }
  312 
  313 /*
  314  * [exported]
  315  * Create an IOPB_TSS
  316  */
  317 iopb_tss_t
  318 iopb_create(void)
  319 {
  320         register iopb_tss_t ts;
  321 
  322         ts = (iopb_tss_t) kalloc(sizeof (struct iopb_tss));
  323         io_tss_init(ts);
  324         return (ts);
  325 }
  326 
  327 /*
  328  * [exported]
  329  * Destroy an IOPB_TSS
  330  */
  331 void
  332 iopb_destroy(
  333         iopb_tss_t      io_tss)
  334 {
  335         io_use_t        iu;
  336         io_port_t       io_port;
  337 
  338         simple_lock(&iopb_lock);
  339 
  340         queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
  341             io_port = iu->ps;
  342             /* skip bitmap clear - entire bitmap will vanish */
  343             queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
  344         }
  345 
  346         simple_unlock(&iopb_lock);
  347 
  348         while (!queue_empty(&io_tss->io_port_list)) {
  349             iu = (io_use_t) queue_first(&io_tss->io_port_list);
  350             queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
  351             kfree((vm_offset_t)iu, sizeof(struct io_use));
  352         }
  353 
  354         kfree((vm_offset_t)io_tss, sizeof(struct iopb_tss));
  355 }
  356 
  357 /*
  358  * Add an IO mapping to a thread.
  359  */
  360 kern_return_t
  361 i386_io_port_add(
  362         thread_t        thread,
  363         device_t        device)
  364 {
  365         pcb_t           pcb;
  366         iopb_tss_t      io_tss, new_io_tss;
  367         io_port_t       io_port;
  368         io_use_t        iu, old_iu;
  369 
  370         if (thread == THREAD_NULL
  371          || device == DEVICE_NULL)
  372             return KERN_INVALID_ARGUMENT;
  373 
  374         pcb = thread->top_act->mact.pcb;
  375 
  376         new_io_tss = 0;
  377         iu = (io_use_t) kalloc(sizeof(struct io_use));
  378 
  379     Retry:
  380         simple_lock(&iopb_lock);
  381 
  382         /* find the io_port_t for the device */
  383         io_port = device_to_io_port_lookup(device);
  384         if (io_port == 0) {
  385             /*
  386              * Device does not have IO ports available.
  387              */
  388             simple_unlock(&iopb_lock);
  389             if (new_io_tss)
  390                 kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
  391             kfree((vm_offset_t) iu, sizeof(struct io_use));
  392             return KERN_INVALID_ARGUMENT;
  393         }
  394 
  395         /* Have the IO port. */
  396 
  397         /* Make sure the thread has a TSS. */
  398 
  399         simple_lock(&pcb->lock);
  400         io_tss = pcb->ims.io_tss;
  401         if (io_tss == 0) {
  402             if (new_io_tss == 0) {
  403                 /*
  404                  * Allocate an IO-tss.
  405                  */
  406                 simple_unlock(&pcb->lock);
  407                 simple_unlock(&iopb_lock);
  408 
  409                 new_io_tss = (iopb_tss_t) kalloc(sizeof(struct iopb_tss));
  410                 io_tss_init(new_io_tss);
  411 
  412                 goto Retry;
  413             }
  414             io_tss = new_io_tss;
  415             pcb->ims.io_tss = io_tss;
  416             new_io_tss = 0;
  417         }
  418 
  419         /*
  420          * Have io_port and io_tss.
  421          * See whether device is already mapped.
  422          */
  423         queue_iterate(&io_tss->io_port_list, old_iu, io_use_t, tsq) {
  424             if (old_iu->ps == io_port) {
  425                 /*
  426                  * Already mapped.
  427                  */
  428                 simple_unlock(&pcb->lock);
  429                 simple_unlock(&iopb_lock);
  430 
  431                 kfree((vm_offset_t)iu, sizeof(struct io_use));
  432                 if (new_io_tss)
  433                     kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
  434                 return KERN_SUCCESS;
  435             }
  436         }
  437 
  438         /*
  439          * Add mapping.
  440          */
  441         iu->ps = io_port;
  442         iu->ts = io_tss;
  443         queue_enter(&io_port->io_use_list, iu, io_use_t, psq);
  444         queue_enter(&io_tss->io_port_list, iu, io_use_t, tsq);
  445         io_bitmap_set(io_tss->bitmap, io_port->io_port_list);
  446 
  447         simple_unlock(&pcb->lock);
  448         simple_unlock(&iopb_lock);
  449 
  450         if (new_io_tss)
  451             kfree((vm_offset_t)new_io_tss, sizeof(struct iopb_tss));
  452         return KERN_SUCCESS;
  453 
  454 }
  455 
  456 /*
  457  * Remove an IO mapping from a thread.
  458  */
  459 kern_return_t
  460 i386_io_port_remove(
  461         thread_t        thread,
  462         device_t        device)
  463 {
  464         pcb_t           pcb;
  465         iopb_tss_t      io_tss;
  466         io_port_t       io_port;
  467         io_use_t        iu;
  468 
  469         if (thread == THREAD_NULL
  470          || device == DEVICE_NULL)
  471             return KERN_INVALID_ARGUMENT;
  472 
  473         pcb = thread->top_act->mact.pcb;
  474 
  475         simple_lock(&iopb_lock);
  476 
  477         /* find the io_port_t for the device */
  478 
  479         io_port = device_to_io_port_lookup(device);
  480         if (io_port == 0) {
  481             /*
  482              * Device does not have IO ports available.
  483              */
  484             simple_unlock(&iopb_lock);
  485             return KERN_INVALID_ARGUMENT;
  486         }
  487 
  488         simple_lock(&pcb->lock);
  489         io_tss = pcb->ims.io_tss;
  490         if (io_tss == 0) {
  491             simple_unlock(&pcb->lock);
  492             simple_unlock(&iopb_lock);
  493             return KERN_INVALID_ARGUMENT;       /* not mapped */
  494         }
  495 
  496         /*
  497          * Find the mapping.
  498          */
  499         queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
  500             if (iu->ps == io_port) {
  501                 /*
  502                  * Found mapping.  Remove it.
  503                  */
  504                 io_bitmap_clear(io_tss->bitmap, io_port->io_port_list);
  505 
  506                 queue_remove(&io_port->io_use_list, iu, io_use_t, psq);
  507                 queue_remove(&io_tss->io_port_list, iu, io_use_t, tsq);
  508 
  509                 simple_unlock(&pcb->lock);
  510                 simple_unlock(&iopb_lock);
  511 
  512                 kfree((vm_offset_t)iu, sizeof(struct io_use));
  513 
  514                 return KERN_SUCCESS;
  515             }
  516         }
  517 
  518         /*
  519          * No mapping.
  520          */
  521         return KERN_INVALID_ARGUMENT;
  522 }
  523 
  524 /*
  525  * Return the IO ports mapped into a thread.
  526  */
  527 
  528 kern_return_t
  529 i386_io_port_list(thread, list, list_count)
  530         thread_t        thread;
  531         device_t        **list;
  532         unsigned int    *list_count;
  533 {
  534         register pcb_t  pcb;
  535         register iopb_tss_t io_tss;
  536         unsigned int    count, alloc_count;
  537         device_t        *devices;
  538         vm_size_t       size_needed, size;
  539         vm_offset_t     addr;
  540         int             i;
  541 
  542         if (thread == THREAD_NULL)
  543             return KERN_INVALID_ARGUMENT;
  544 
  545         pcb = thread->top_act->mact.pcb;
  546 
  547         alloc_count = 16;               /* a guess */
  548 
  549         do {
  550             size_needed = alloc_count * sizeof(ipc_port_t);
  551             if (size_needed <= size)
  552                 break;
  553 
  554             if (size != 0)
  555                 kfree(addr, size);
  556 
  557             assert(size_needed > 0);
  558             size = size_needed;
  559 
  560             addr = kalloc(size);
  561             if (addr == 0)
  562                 return KERN_RESOURCE_SHORTAGE;
  563 
  564             devices = (device_t *)addr;
  565             count = 0;
  566 
  567             simple_lock(&iopb_lock);
  568             simple_lock(&pcb->lock);
  569             io_tss = pcb->ims.io_tss;
  570             if (io_tss != 0) {
  571                 register io_use_t iu;
  572 
  573                 queue_iterate(&io_tss->io_port_list, iu, io_use_t, tsq) {
  574                     if (++count < alloc_count) {
  575                         *devices = iu->ps->device;
  576                         device_reference(*devices);
  577                         devices++;
  578                     }
  579                 }
  580             }
  581             simple_unlock(&pcb->lock);
  582             simple_unlock(&iopb_lock);
  583         } while (count > alloc_count);
  584 
  585         if (count == 0) {
  586             /*
  587              * No IO ports
  588              */
  589             *list = 0;
  590             *list_count = 0;
  591 
  592             if (size != 0)
  593                 kfree(addr, size);
  594         }
  595         else {
  596             /*
  597              * If we allocated too much, must copy.
  598              */
  599             size_needed = count * sizeof(ipc_port_t);
  600             if (size_needed < size) {
  601                 vm_offset_t     new_addr;
  602 
  603                 new_addr = kalloc(size_needed);
  604                 if (new_addr == 0) {
  605                     for (i = 0; i < count; i++)
  606                         device_deallocate(devices[i]);
  607                     kfree(addr, size);
  608                     return KERN_RESOURCE_SHORTAGE;
  609                 }
  610 
  611                 bcopy((char *)addr, (char *)new_addr, size_needed);
  612                 kfree(addr, size);
  613                 devices = (device_t *)new_addr;
  614             }
  615 
  616             for (i = 0; i < count; i++)
  617                 ((ipc_port_t *)devices)[i] =
  618                         convert_device_to_port(devices[i]);
  619         }
  620         *list = devices;
  621         *list_count = count;
  622 
  623         return KERN_SUCCESS;
  624 }
  625 
  626 /*
  627  * Check whether an IO device is mapped to a particular thread.
  628  * Used to support the 'iopl' device automatic mapping.
  629  */
  630 boolean_t
  631 iopb_check_mapping(
  632         thread_t        thread,
  633         device_t        device)
  634 {
  635         pcb_t           pcb;
  636         io_port_t       io_port;
  637         io_use_t        iu;
  638 
  639         pcb = thread->top_act->mact.pcb;
  640 
  641         simple_lock(&iopb_lock);
  642 
  643         /* Find the io port for the device */
  644 
  645         io_port = device_to_io_port_lookup(device);
  646         if (io_port == 0) {
  647             simple_unlock(&iopb_lock);
  648             return FALSE;
  649         }
  650 
  651         /* Look up the mapping in the device`s mapping list. */
  652 
  653         queue_iterate(&io_port->io_use_list, iu, io_use_t, psq) {
  654             if (iu->ts == pcb->ims.io_tss) {
  655                 /*
  656                  * Device is mapped.
  657                  */
  658                 simple_unlock(&iopb_lock);
  659                 return TRUE;
  660             }
  661         }
  662         simple_unlock(&iopb_lock);
  663         return FALSE;
  664 }
  665 #endif

Cache object: 7470ee5a2cf8bf36233c75f02a129902


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.