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

Cache object: 50fba82d1d5d9486313f78d9d117253b


[ 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.