File:  [Qemu by Fabrice Bellard] / qemu / ioport.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:16:56 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

    1: /*
    2:  * QEMU System Emulator
    3:  *
    4:  * Copyright (c) 2003-2008 Fabrice Bellard
    5:  *
    6:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    7:  * of this software and associated documentation files (the "Software"), to deal
    8:  * in the Software without restriction, including without limitation the rights
    9:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   10:  * copies of the Software, and to permit persons to whom the Software is
   11:  * furnished to do so, subject to the following conditions:
   12:  *
   13:  * The above copyright notice and this permission notice shall be included in
   14:  * all copies or substantial portions of the Software.
   15:  *
   16:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   17:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   18:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   19:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   20:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   21:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   22:  * THE SOFTWARE.
   23:  */
   24: /*
   25:  * splitted out ioport related stuffs from vl.c.
   26:  */
   27: 
   28: #include "ioport.h"
   29: #include "trace.h"
   30: #include "memory.h"
   31: 
   32: /***********************************************************/
   33: /* IO Port */
   34: 
   35: //#define DEBUG_UNUSED_IOPORT
   36: //#define DEBUG_IOPORT
   37: 
   38: #ifdef DEBUG_UNUSED_IOPORT
   39: #  define LOG_UNUSED_IOPORT(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
   40: #else
   41: #  define LOG_UNUSED_IOPORT(fmt, ...) do{ } while (0)
   42: #endif
   43: 
   44: #ifdef DEBUG_IOPORT
   45: #  define LOG_IOPORT(...) qemu_log_mask(CPU_LOG_IOPORT, ## __VA_ARGS__)
   46: #else
   47: #  define LOG_IOPORT(...) do { } while (0)
   48: #endif
   49: 
   50: /* XXX: use a two level table to limit memory usage */
   51: 
   52: static void *ioport_opaque[MAX_IOPORTS];
   53: static IOPortReadFunc *ioport_read_table[3][MAX_IOPORTS];
   54: static IOPortWriteFunc *ioport_write_table[3][MAX_IOPORTS];
   55: 
   56: static IOPortReadFunc default_ioport_readb, default_ioport_readw, default_ioport_readl;
   57: static IOPortWriteFunc default_ioport_writeb, default_ioport_writew, default_ioport_writel;
   58: 
   59: static uint32_t ioport_read(int index, uint32_t address)
   60: {
   61:     static IOPortReadFunc * const default_func[3] = {
   62:         default_ioport_readb,
   63:         default_ioport_readw,
   64:         default_ioport_readl
   65:     };
   66:     IOPortReadFunc *func = ioport_read_table[index][address];
   67:     if (!func)
   68:         func = default_func[index];
   69:     return func(ioport_opaque[address], address);
   70: }
   71: 
   72: static void ioport_write(int index, uint32_t address, uint32_t data)
   73: {
   74:     static IOPortWriteFunc * const default_func[3] = {
   75:         default_ioport_writeb,
   76:         default_ioport_writew,
   77:         default_ioport_writel
   78:     };
   79:     IOPortWriteFunc *func = ioport_write_table[index][address];
   80:     if (!func)
   81:         func = default_func[index];
   82:     func(ioport_opaque[address], address, data);
   83: }
   84: 
   85: static uint32_t default_ioport_readb(void *opaque, uint32_t address)
   86: {
   87:     LOG_UNUSED_IOPORT("unused inb: port=0x%04"PRIx32"\n", address);
   88:     return 0xff;
   89: }
   90: 
   91: static void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
   92: {
   93:     LOG_UNUSED_IOPORT("unused outb: port=0x%04"PRIx32" data=0x%02"PRIx32"\n",
   94:                       address, data);
   95: }
   96: 
   97: /* default is to make two byte accesses */
   98: static uint32_t default_ioport_readw(void *opaque, uint32_t address)
   99: {
  100:     uint32_t data;
  101:     data = ioport_read(0, address);
  102:     address = (address + 1) & IOPORTS_MASK;
  103:     data |= ioport_read(0, address) << 8;
  104:     return data;
  105: }
  106: 
  107: static void default_ioport_writew(void *opaque, uint32_t address, uint32_t data)
  108: {
  109:     ioport_write(0, address, data & 0xff);
  110:     address = (address + 1) & IOPORTS_MASK;
  111:     ioport_write(0, address, (data >> 8) & 0xff);
  112: }
  113: 
  114: static uint32_t default_ioport_readl(void *opaque, uint32_t address)
  115: {
  116:     LOG_UNUSED_IOPORT("unused inl: port=0x%04"PRIx32"\n", address);
  117:     return 0xffffffff;
  118: }
  119: 
  120: static void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
  121: {
  122:     LOG_UNUSED_IOPORT("unused outl: port=0x%04"PRIx32" data=0x%02"PRIx32"\n",
  123:                       address, data);
  124: }
  125: 
  126: static int ioport_bsize(int size, int *bsize)
  127: {
  128:     if (size == 1) {
  129:         *bsize = 0;
  130:     } else if (size == 2) {
  131:         *bsize = 1;
  132:     } else if (size == 4) {
  133:         *bsize = 2;
  134:     } else {
  135:         return -1;
  136:     }
  137:     return 0;
  138: }
  139: 
  140: /* size is the word size in byte */
  141: int register_ioport_read(pio_addr_t start, int length, int size,
  142:                          IOPortReadFunc *func, void *opaque)
  143: {
  144:     int i, bsize;
  145: 
  146:     if (ioport_bsize(size, &bsize)) {
  147:         hw_error("register_ioport_read: invalid size");
  148:         return -1;
  149:     }
  150:     for(i = start; i < start + length; ++i) {
  151:         ioport_read_table[bsize][i] = func;
  152:         if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
  153:             hw_error("register_ioport_read: invalid opaque for address 0x%x",
  154:                      i);
  155:         ioport_opaque[i] = opaque;
  156:     }
  157:     return 0;
  158: }
  159: 
  160: /* size is the word size in byte */
  161: int register_ioport_write(pio_addr_t start, int length, int size,
  162:                           IOPortWriteFunc *func, void *opaque)
  163: {
  164:     int i, bsize;
  165: 
  166:     if (ioport_bsize(size, &bsize)) {
  167:         hw_error("register_ioport_write: invalid size");
  168:         return -1;
  169:     }
  170:     for(i = start; i < start + length; ++i) {
  171:         ioport_write_table[bsize][i] = func;
  172:         if (ioport_opaque[i] != NULL && ioport_opaque[i] != opaque)
  173:             hw_error("register_ioport_write: invalid opaque for address 0x%x",
  174:                      i);
  175:         ioport_opaque[i] = opaque;
  176:     }
  177:     return 0;
  178: }
  179: 
  180: static uint32_t ioport_readb_thunk(void *opaque, uint32_t addr)
  181: {
  182:     IORange *ioport = opaque;
  183:     uint64_t data;
  184: 
  185:     ioport->ops->read(ioport, addr - ioport->base, 1, &data);
  186:     return data;
  187: }
  188: 
  189: static uint32_t ioport_readw_thunk(void *opaque, uint32_t addr)
  190: {
  191:     IORange *ioport = opaque;
  192:     uint64_t data;
  193: 
  194:     ioport->ops->read(ioport, addr - ioport->base, 2, &data);
  195:     return data;
  196: }
  197: 
  198: static uint32_t ioport_readl_thunk(void *opaque, uint32_t addr)
  199: {
  200:     IORange *ioport = opaque;
  201:     uint64_t data;
  202: 
  203:     ioport->ops->read(ioport, addr - ioport->base, 4, &data);
  204:     return data;
  205: }
  206: 
  207: static void ioport_writeb_thunk(void *opaque, uint32_t addr, uint32_t data)
  208: {
  209:     IORange *ioport = opaque;
  210: 
  211:     ioport->ops->write(ioport, addr - ioport->base, 1, data);
  212: }
  213: 
  214: static void ioport_writew_thunk(void *opaque, uint32_t addr, uint32_t data)
  215: {
  216:     IORange *ioport = opaque;
  217: 
  218:     ioport->ops->write(ioport, addr - ioport->base, 2, data);
  219: }
  220: 
  221: static void ioport_writel_thunk(void *opaque, uint32_t addr, uint32_t data)
  222: {
  223:     IORange *ioport = opaque;
  224: 
  225:     ioport->ops->write(ioport, addr - ioport->base, 4, data);
  226: }
  227: 
  228: void ioport_register(IORange *ioport)
  229: {
  230:     register_ioport_read(ioport->base, ioport->len, 1,
  231:                          ioport_readb_thunk, ioport);
  232:     register_ioport_read(ioport->base, ioport->len, 2,
  233:                          ioport_readw_thunk, ioport);
  234:     register_ioport_read(ioport->base, ioport->len, 4,
  235:                          ioport_readl_thunk, ioport);
  236:     register_ioport_write(ioport->base, ioport->len, 1,
  237:                           ioport_writeb_thunk, ioport);
  238:     register_ioport_write(ioport->base, ioport->len, 2,
  239:                           ioport_writew_thunk, ioport);
  240:     register_ioport_write(ioport->base, ioport->len, 4,
  241:                           ioport_writel_thunk, ioport);
  242: }
  243: 
  244: void isa_unassign_ioport(pio_addr_t start, int length)
  245: {
  246:     int i;
  247: 
  248:     for(i = start; i < start + length; i++) {
  249:         ioport_read_table[0][i] = NULL;
  250:         ioport_read_table[1][i] = NULL;
  251:         ioport_read_table[2][i] = NULL;
  252: 
  253:         ioport_write_table[0][i] = NULL;
  254:         ioport_write_table[1][i] = NULL;
  255:         ioport_write_table[2][i] = NULL;
  256: 
  257:         ioport_opaque[i] = NULL;
  258:     }
  259: }
  260: 
  261: bool isa_is_ioport_assigned(pio_addr_t start)
  262: {
  263:     return (ioport_read_table[0][start] || ioport_write_table[0][start] ||
  264: 	    ioport_read_table[1][start] || ioport_write_table[1][start] ||
  265: 	    ioport_read_table[2][start] || ioport_write_table[2][start]);
  266: }
  267: 
  268: /***********************************************************/
  269: 
  270: void cpu_outb(pio_addr_t addr, uint8_t val)
  271: {
  272:     LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
  273:     trace_cpu_out(addr, val);
  274:     ioport_write(0, addr, val);
  275: }
  276: 
  277: void cpu_outw(pio_addr_t addr, uint16_t val)
  278: {
  279:     LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
  280:     trace_cpu_out(addr, val);
  281:     ioport_write(1, addr, val);
  282: }
  283: 
  284: void cpu_outl(pio_addr_t addr, uint32_t val)
  285: {
  286:     LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
  287:     trace_cpu_out(addr, val);
  288:     ioport_write(2, addr, val);
  289: }
  290: 
  291: uint8_t cpu_inb(pio_addr_t addr)
  292: {
  293:     uint8_t val;
  294:     val = ioport_read(0, addr);
  295:     trace_cpu_in(addr, val);
  296:     LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
  297:     return val;
  298: }
  299: 
  300: uint16_t cpu_inw(pio_addr_t addr)
  301: {
  302:     uint16_t val;
  303:     val = ioport_read(1, addr);
  304:     trace_cpu_in(addr, val);
  305:     LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
  306:     return val;
  307: }
  308: 
  309: uint32_t cpu_inl(pio_addr_t addr)
  310: {
  311:     uint32_t val;
  312:     val = ioport_read(2, addr);
  313:     trace_cpu_in(addr, val);
  314:     LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
  315:     return val;
  316: }
  317: 
  318: void portio_list_init(PortioList *piolist,
  319:                       const MemoryRegionPortio *callbacks,
  320:                       void *opaque, const char *name)
  321: {
  322:     unsigned n = 0;
  323: 
  324:     while (callbacks[n].size) {
  325:         ++n;
  326:     }
  327: 
  328:     piolist->ports = callbacks;
  329:     piolist->nr = 0;
  330:     piolist->regions = g_new0(MemoryRegion *, n);
  331:     piolist->address_space = NULL;
  332:     piolist->opaque = opaque;
  333:     piolist->name = name;
  334: }
  335: 
  336: void portio_list_destroy(PortioList *piolist)
  337: {
  338:     g_free(piolist->regions);
  339: }
  340: 
  341: static void portio_list_add_1(PortioList *piolist,
  342:                               const MemoryRegionPortio *pio_init,
  343:                               unsigned count, unsigned start,
  344:                               unsigned off_low, unsigned off_high)
  345: {
  346:     MemoryRegionPortio *pio;
  347:     MemoryRegionOps *ops;
  348:     MemoryRegion *region;
  349:     unsigned i;
  350: 
  351:     /* Copy the sub-list and null-terminate it.  */
  352:     pio = g_new(MemoryRegionPortio, count + 1);
  353:     memcpy(pio, pio_init, sizeof(MemoryRegionPortio) * count);
  354:     memset(pio + count, 0, sizeof(MemoryRegionPortio));
  355: 
  356:     /* Adjust the offsets to all be zero-based for the region.  */
  357:     for (i = 0; i < count; ++i) {
  358:         pio[i].offset -= off_low;
  359:     }
  360: 
  361:     ops = g_new0(MemoryRegionOps, 1);
  362:     ops->old_portio = pio;
  363: 
  364:     region = g_new(MemoryRegion, 1);
  365:     memory_region_init_io(region, ops, piolist->opaque, piolist->name,
  366:                           off_high - off_low);
  367:     memory_region_set_offset(region, start + off_low);
  368:     memory_region_add_subregion(piolist->address_space,
  369:                                 start + off_low, region);
  370:     piolist->regions[piolist->nr++] = region;
  371: }
  372: 
  373: void portio_list_add(PortioList *piolist,
  374:                      MemoryRegion *address_space,
  375:                      uint32_t start)
  376: {
  377:     const MemoryRegionPortio *pio, *pio_start = piolist->ports;
  378:     unsigned int off_low, off_high, off_last, count;
  379: 
  380:     piolist->address_space = address_space;
  381: 
  382:     /* Handle the first entry specially.  */
  383:     off_last = off_low = pio_start->offset;
  384:     off_high = off_low + pio_start->len;
  385:     count = 1;
  386: 
  387:     for (pio = pio_start + 1; pio->size != 0; pio++, count++) {
  388:         /* All entries must be sorted by offset.  */
  389:         assert(pio->offset >= off_last);
  390:         off_last = pio->offset;
  391: 
  392:         /* If we see a hole, break the region.  */
  393:         if (off_last > off_high) {
  394:             portio_list_add_1(piolist, pio_start, count, start, off_low,
  395:                               off_high);
  396:             /* ... and start collecting anew.  */
  397:             pio_start = pio;
  398:             off_low = off_last;
  399:             off_high = off_low + pio->len;
  400:             count = 0;
  401:         } else if (off_last + pio->len > off_high) {
  402:             off_high = off_last + pio->len;
  403:         }
  404:     }
  405: 
  406:     /* There will always be an open sub-list.  */
  407:     portio_list_add_1(piolist, pio_start, count, start, off_low, off_high);
  408: }
  409: 
  410: void portio_list_del(PortioList *piolist)
  411: {
  412:     MemoryRegion *mr;
  413:     unsigned i;
  414: 
  415:     for (i = 0; i < piolist->nr; ++i) {
  416:         mr = piolist->regions[i];
  417:         memory_region_del_subregion(piolist->address_space, mr);
  418:         memory_region_destroy(mr);
  419:         g_free((MemoryRegionOps *)mr->ops);
  420:         g_free(mr);
  421:         piolist->regions[i] = NULL;
  422:     }
  423: }

unix.superglobalmegacorp.com