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

Cache object: b309850261997f2d2ec72f63c8750f95


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