(linenum→info "unix/slp.c:2238")

qemu/0.9.1/hw/i8259.c

    1: /*
    2:  * QEMU 8259 interrupt controller emulation
    3:  *
    4:  * Copyright (c) 2003-2004 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: #include "hw.h"
   25: #include "pc.h"
   26: #include "isa.h"
   27: #include "console.h"
   28: 
   29: /* debug PIC */
   30: //#define DEBUG_PIC
   31: 
   32: //#define DEBUG_IRQ_LATENCY
   33: //#define DEBUG_IRQ_COUNT
   34: 
   35: typedef struct PicState {
   36:     uint8_t last_irr; /* edge detection */
   37:     uint8_t irr; /* interrupt request register */
   38:     uint8_t imr; /* interrupt mask register */
   39:     uint8_t isr; /* interrupt service register */
   40:     uint8_t priority_add; /* highest irq priority */
   41:     uint8_t irq_base;
   42:     uint8_t read_reg_select;
   43:     uint8_t poll;
   44:     uint8_t special_mask;
   45:     uint8_t init_state;
   46:     uint8_t auto_eoi;
   47:     uint8_t rotate_on_auto_eoi;
   48:     uint8_t special_fully_nested_mode;
   49:     uint8_t init4; /* true if 4 byte init */
   50:     uint8_t single_mode; /* true if slave pic is not initialized */
   51:     uint8_t elcr; /* PIIX edge/trigger selection*/
   52:     uint8_t elcr_mask;
   53:     PicState2 *pics_state;
   54: } PicState;
   55: 
   56: struct PicState2 {
   57:     /* 0 is master pic, 1 is slave pic */
   58:     /* XXX: better separation between the two pics */
   59:     PicState pics[2];
   60:     qemu_irq parent_irq;
   61:     void *irq_request_opaque;
   62:     /* IOAPIC callback support */
   63:     SetIRQFunc *alt_irq_func;
   64:     void *alt_irq_opaque;
   65: };
   66: 
   67: #if defined(DEBUG_PIC) || defined (DEBUG_IRQ_COUNT)
   68: static int irq_level[16];
   69: #endif
   70: #ifdef DEBUG_IRQ_COUNT
   71: static uint64_t irq_count[16];
   72: #endif
   73: 
   74: /* set irq level. If an edge is detected, then the IRR is set to 1 */
   75: static inline void pic_set_irq1(PicState *s, int irq, int level)
   76: {
   77:     int mask;
   78:     mask = 1 << irq;
   79:     if (s->elcr & mask) {
   80:         /* level triggered */
   81:         if (level) {
   82:             s->irr |= mask;
   83:             s->last_irr |= mask;
   84:         } else {
   85:             s->irr &= ~mask;
   86:             s->last_irr &= ~mask;
   87:         }
   88:     } else {
   89:         /* edge triggered */
   90:         if (level) {
   91:             if ((s->last_irr & mask) == 0)
   92:                 s->irr |= mask;
   93:             s->last_irr |= mask;
   94:         } else {
   95:             s->last_irr &= ~mask;
   96:         }
   97:     }
   98: }
   99: 
  100: /* return the highest priority found in mask (highest = smallest
  101:    number). Return 8 if no irq */
  102: static inline int get_priority(PicState *s, int mask)
  103: {
  104:     int priority;
  105:     if (mask == 0)
  106:         return 8;
  107:     priority = 0;
  108:     while ((mask & (1 << ((priority + s->priority_add) & 7))) == 0)
  109:         priority++;
  110:     return priority;
  111: }
  112: 
  113: /* return the pic wanted interrupt. return -1 if none */
  114: static int pic_get_irq(PicState *s)
  115: {
  116:     int mask, cur_priority, priority;
  117: 
  118:     mask = s->irr & ~s->imr;
  119:     priority = get_priority(s, mask);
  120:     if (priority == 8)
  121:         return -1;
  122:     /* compute current priority. If special fully nested mode on the
  123:        master, the IRQ coming from the slave is not taken into account
  124:        for the priority computation. */
  125:     mask = s->isr;
  126:     if (s->special_fully_nested_mode && s == &s->pics_state->pics[0])
  127:         mask &= ~(1 << 2);
  128:     cur_priority = get_priority(s, mask);
  129:     if (priority < cur_priority) {
  130:         /* higher priority found: an irq should be generated */
  131:         return (priority + s->priority_add) & 7;
  132:     } else {
  133:         return -1;
  134:     }
  135: }
  136: 
  137: /* raise irq to CPU if necessary. must be called every time the active
  138:    irq may change */
  139: /* XXX: should not export it, but it is needed for an APIC kludge */
  140: void pic_update_irq(PicState2 *s)
  141: {
  142:     int irq2, irq;
  143: 
  144:     /* first look at slave pic */
  145:     irq2 = pic_get_irq(&s->pics[1]);
  146:     if (irq2 >= 0) {
  147:         /* if irq request by slave pic, signal master PIC */
  148:         pic_set_irq1(&s->pics[0], 2, 1);
  149:         pic_set_irq1(&s->pics[0], 2, 0);
  150:     }
  151:     /* look at requested irq */
  152:     irq = pic_get_irq(&s->pics[0]);
  153:     if (irq >= 0) {
  154: #if defined(DEBUG_PIC)
  155:         {
  156:             int i;
  157:             for(i = 0; i < 2; i++) {
  158:                 printf("pic%d: imr=%x irr=%x padd=%d\n",
  159:                        i, s->pics[i].imr, s->pics[i].irr,
  160:                        s->pics[i].priority_add);
  161: 
  162:             }
  163:         }
  164:         printf("pic: cpu_interrupt\n");
  165: #endif
  166:         qemu_irq_raise(s->parent_irq);
  167:     }
  168: 
  169: /* all targets should do this rather than acking the IRQ in the cpu */
  170: #if defined(TARGET_MIPS) || defined(TARGET_PPC)
  171:     else {
  172:         qemu_irq_lower(s->parent_irq);
  173:     }
  174: #endif
  175: }
  176: 
  177: #ifdef DEBUG_IRQ_LATENCY
  178: int64_t irq_time[16];
  179: #endif
  180: 
  181: static void i8259_set_irq(void *opaque, int irq, int level)
  182: {
  183:     PicState2 *s = opaque;
  184: 
  185: #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
  186:     if (level != irq_level[irq]) {
  187: #if defined(DEBUG_PIC)
  188:         printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
  189: #endif
  190:         irq_level[irq] = level;
  191: #ifdef DEBUG_IRQ_COUNT
  192:         if (level == 1)
  193:             irq_count[irq]++;
  194: #endif
  195:     }
  196: #endif
  197: #ifdef DEBUG_IRQ_LATENCY
  198:     if (level) {
  199:         irq_time[irq] = qemu_get_clock(vm_clock);
  200:     }
  201: #endif
  202:     pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
  203:     /* used for IOAPIC irqs */
  204:     if (s->alt_irq_func)
  205:         s->alt_irq_func(s->alt_irq_opaque, irq, level);
  206:     pic_update_irq(s);
  207: }
  208: 
  209: /* acknowledge interrupt 'irq' */
  210: static inline void pic_intack(PicState *s, int irq)
  211: {
  212:     if (s->auto_eoi) {
  213:         if (s->rotate_on_auto_eoi)
  214:             s->priority_add = (irq + 1) & 7;
  215:     } else {
  216:         s->isr |= (1 << irq);
  217:     }
  218:     /* We don't clear a level sensitive interrupt here */
  219:     if (!(s->elcr & (1 << irq)))
  220:         s->irr &= ~(1 << irq);
  221: }
  222: 
  223: int pic_read_irq(PicState2 *s)
  224: {
  225:     int irq, irq2, intno;
  226: 
  227:     irq = pic_get_irq(&s->pics[0]);
  228:     if (irq >= 0) {
  229:         pic_intack(&s->pics[0], irq);
  230:         if (irq == 2) {
  231:             irq2 = pic_get_irq(&s->pics[1]);
  232:             if (irq2 >= 0) {
  233:                 pic_intack(&s->pics[1], irq2);
  234:             } else {
  235:                 /* spurious IRQ on slave controller */
  236:                 irq2 = 7;
  237:             }
  238:             intno = s->pics[1].irq_base + irq2;
  239:             irq = irq2 + 8;
  240:         } else {
  241:             intno = s->pics[0].irq_base + irq;
  242:         }
  243:     } else {
  244:         /* spurious IRQ on host controller */
  245:         irq = 7;
  246:         intno = s->pics[0].irq_base + irq;
  247:     }
  248:     pic_update_irq(s);
  249: 
  250: #ifdef DEBUG_IRQ_LATENCY
  251:     printf("IRQ%d latency=%0.3fus\n",
  252:            irq,
  253:            (double)(qemu_get_clock(vm_clock) - irq_time[irq]) * 1000000.0 / ticks_per_sec);
  254: #endif
  255: #if defined(DEBUG_PIC)
  256:     printf("pic_interrupt: irq=%d\n", irq);
  257: #endif
  258:     return intno;
  259: }
  260: 
  261: static void pic_reset(void *opaque)
  262: {
  263:     PicState *s = opaque;
  264: 
  265:     s->last_irr = 0;
  266:     s->irr = 0;
  267:     s->imr = 0;
  268:     s->isr = 0;
  269:     s->priority_add = 0;
  270:     s->irq_base = 0;
  271:     s->read_reg_select = 0;
  272:     s->poll = 0;
  273:     s->special_mask = 0;
  274:     s->init_state = 0;
  275:     s->auto_eoi = 0;
  276:     s->rotate_on_auto_eoi = 0;
  277:     s->special_fully_nested_mode = 0;
  278:     s->init4 = 0;
  279:     s->single_mode = 0;
  280:     /* Note: ELCR is not reset */
  281: }
  282: 
  283: static void pic_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  284: {
  285:     PicState *s = opaque;
  286:     int priority, cmd, irq;
  287: 
  288: #ifdef DEBUG_PIC
  289:     printf("pic_write: addr=0x%02x val=0x%02x\n", addr, val);
  290: #endif
  291:     addr &= 1;
  292:     if (addr == 0) {
  293:         if (val & 0x10) {
  294:             /* init */
  295:             pic_reset(s);
  296:             /* deassert a pending interrupt */
  297:             qemu_irq_lower(s->pics_state->parent_irq);
  298:             s->init_state = 1;
  299:             s->init4 = val & 1;
  300:             s->single_mode = val & 2;
  301:             if (val & 0x08)
  302:                 hw_error("level sensitive irq not supported");
  303:         } else if (val & 0x08) {
  304:             if (val & 0x04)
  305:                 s->poll = 1;
  306:             if (val & 0x02)
  307:                 s->read_reg_select = val & 1;
  308:             if (val & 0x40)
  309:                 s->special_mask = (val >> 5) & 1;
  310:         } else {
  311:             cmd = val >> 5;
  312:             switch(cmd) {
  313:             case 0:
  314:             case 4:
  315:                 s->rotate_on_auto_eoi = cmd >> 2;
  316:                 break;
  317:             case 1: /* end of interrupt */
  318:             case 5:
  319:                 priority = get_priority(s, s->isr);
  320:                 if (priority != 8) {
  321:                     irq = (priority + s->priority_add) & 7;
  322:                     s->isr &= ~(1 << irq);
  323:                     if (cmd == 5)
  324:                         s->priority_add = (irq + 1) & 7;
  325:                     pic_update_irq(s->pics_state);
  326:                 }
  327:                 break;
  328:             case 3:
  329:                 irq = val & 7;
  330:                 s->isr &= ~(1 << irq);
  331:                 pic_update_irq(s->pics_state);
  332:                 break;
  333:             case 6:
  334:                 s->priority_add = (val + 1) & 7;
  335:                 pic_update_irq(s->pics_state);
  336:                 break;
  337:             case 7:
  338:                 irq = val & 7;
  339:                 s->isr &= ~(1 << irq);
  340:                 s->priority_add = (irq + 1) & 7;
  341:                 pic_update_irq(s->pics_state);
  342:                 break;
  343:             default:
  344:                 /* no operation */
  345:                 break;
  346:             }
  347:         }
  348:     } else {
  349:         switch(s->init_state) {
  350:         case 0:
  351:             /* normal mode */
  352:             s->imr = val;
  353:             pic_update_irq(s->pics_state);
  354:             break;
  355:         case 1:
  356:             s->irq_base = val & 0xf8;
  357:             s->init_state = s->single_mode ? (s->init4 ? 3 : 0) : 2;
  358:             break;
  359:         case 2:
  360:             if (s->init4) {
  361:                 s->init_state = 3;
  362:             } else {
  363:                 s->init_state = 0;
  364:             }
  365:             break;
  366:         case 3:
  367:             s->special_fully_nested_mode = (val >> 4) & 1;
  368:             s->auto_eoi = (val >> 1) & 1;
  369:             s->init_state = 0;
  370:             break;
  371:         }
  372:     }
  373: }
  374: 
  375: static uint32_t pic_poll_read (PicState *s, uint32_t addr1)
  376: {
  377:     int ret;
  378: 
  379:     ret = pic_get_irq(s);
  380:     if (ret >= 0) {
  381:         if (addr1 >> 7) {
  382:             s->pics_state->pics[0].isr &= ~(1 << 2);
  383:             s->pics_state->pics[0].irr &= ~(1 << 2);
  384:         }
  385:         s->irr &= ~(1 << ret);
  386:         s->isr &= ~(1 << ret);
  387:         if (addr1 >> 7 || ret != 2)
  388:             pic_update_irq(s->pics_state);
  389:     } else {
  390:         ret = 0x07;
  391:         pic_update_irq(s->pics_state);
  392:     }
  393: 
  394:     return ret;
  395: }
  396: 
  397: static uint32_t pic_ioport_read(void *opaque, uint32_t addr1)
  398: {
  399:     PicState *s = opaque;
  400:     unsigned int addr;
  401:     int ret;
  402: 
  403:     addr = addr1;
  404:     addr &= 1;
  405:     if (s->poll) {
  406:         ret = pic_poll_read(s, addr1);
  407:         s->poll = 0;
  408:     } else {
  409:         if (addr == 0) {
  410:             if (s->read_reg_select)
  411:                 ret = s->isr;
  412:             else
  413:                 ret = s->irr;
  414:         } else {
  415:             ret = s->imr;
  416:         }
  417:     }
  418: #ifdef DEBUG_PIC
  419:     printf("pic_read: addr=0x%02x val=0x%02x\n", addr1, ret);
  420: #endif
  421:     return ret;
  422: }
  423: 
  424: /* memory mapped interrupt status */
  425: /* XXX: may be the same than pic_read_irq() */
  426: uint32_t pic_intack_read(PicState2 *s)
  427: {
  428:     int ret;
  429: 
  430:     ret = pic_poll_read(&s->pics[0], 0x00);
  431:     if (ret == 2)
  432:         ret = pic_poll_read(&s->pics[1], 0x80) + 8;
  433:     /* Prepare for ISR read */
  434:     s->pics[0].read_reg_select = 1;
  435: 
  436:     return ret;
  437: }
  438: 
  439: static void elcr_ioport_write(void *opaque, uint32_t addr, uint32_t val)
  440: {
  441:     PicState *s = opaque;
  442:     s->elcr = val & s->elcr_mask;
  443: }
  444: 
  445: static uint32_t elcr_ioport_read(void *opaque, uint32_t addr1)
  446: {
  447:     PicState *s = opaque;
  448:     return s->elcr;
  449: }
  450: 
  451: static void pic_save(QEMUFile *f, void *opaque)
  452: {
  453:     PicState *s = opaque;
  454: 
  455:     qemu_put_8s(f, &s->last_irr);
  456:     qemu_put_8s(f, &s->irr);
  457:     qemu_put_8s(f, &s->imr);
  458:     qemu_put_8s(f, &s->isr);
  459:     qemu_put_8s(f, &s->priority_add);
  460:     qemu_put_8s(f, &s->irq_base);
  461:     qemu_put_8s(f, &s->read_reg_select);
  462:     qemu_put_8s(f, &s->poll);
  463:     qemu_put_8s(f, &s->special_mask);
  464:     qemu_put_8s(f, &s->init_state);
  465:     qemu_put_8s(f, &s->auto_eoi);
  466:     qemu_put_8s(f, &s->rotate_on_auto_eoi);
  467:     qemu_put_8s(f, &s->special_fully_nested_mode);
  468:     qemu_put_8s(f, &s->init4);
  469:     qemu_put_8s(f, &s->single_mode);
  470:     qemu_put_8s(f, &s->elcr);
  471: }
  472: 
  473: static int pic_load(QEMUFile *f, void *opaque, int version_id)
  474: {
  475:     PicState *s = opaque;
  476: 
  477:     if (version_id != 1)
  478:         return -EINVAL;
  479: 
  480:     qemu_get_8s(f, &s->last_irr);
  481:     qemu_get_8s(f, &s->irr);
  482:     qemu_get_8s(f, &s->imr);
  483:     qemu_get_8s(f, &s->isr);
  484:     qemu_get_8s(f, &s->priority_add);
  485:     qemu_get_8s(f, &s->irq_base);
  486:     qemu_get_8s(f, &s->read_reg_select);
  487:     qemu_get_8s(f, &s->poll);
  488:     qemu_get_8s(f, &s->special_mask);
  489:     qemu_get_8s(f, &s->init_state);
  490:     qemu_get_8s(f, &s->auto_eoi);
  491:     qemu_get_8s(f, &s->rotate_on_auto_eoi);
  492:     qemu_get_8s(f, &s->special_fully_nested_mode);
  493:     qemu_get_8s(f, &s->init4);
  494:     qemu_get_8s(f, &s->single_mode);
  495:     qemu_get_8s(f, &s->elcr);
  496:     return 0;
  497: }
  498: 
  499: /* XXX: add generic master/slave system */
  500: static void pic_init1(int io_addr, int elcr_addr, PicState *s)
  501: {
  502:     register_ioport_write(io_addr, 2, 1, pic_ioport_write, s);
  503:     register_ioport_read(io_addr, 2, 1, pic_ioport_read, s);
  504:     if (elcr_addr >= 0) {
  505:         register_ioport_write(elcr_addr, 1, 1, elcr_ioport_write, s);
  506:         register_ioport_read(elcr_addr, 1, 1, elcr_ioport_read, s);
  507:     }
  508:     register_savevm("i8259", io_addr, 1, pic_save, pic_load, s);
  509:     qemu_register_reset(pic_reset, s);
  510: }
  511: 
  512: void pic_info(void)
  513: {
  514:     int i;
  515:     PicState *s;
  516: 
  517:     if (!isa_pic)
  518:         return;
  519: 
  520:     for(i=0;i<2;i++) {
  521:         s = &isa_pic->pics[i];
  522:         term_printf("pic%d: irr=%02x imr=%02x isr=%02x hprio=%d irq_base=%02x rr_sel=%d elcr=%02x fnm=%d\n",
  523:                     i, s->irr, s->imr, s->isr, s->priority_add,
  524:                     s->irq_base, s->read_reg_select, s->elcr,
  525:                     s->special_fully_nested_mode);
  526:     }
  527: }
  528: 
  529: void irq_info(void)
  530: {
  531: #ifndef DEBUG_IRQ_COUNT
  532:     term_printf("irq statistic code not compiled.\n");
  533: #else
  534:     int i;
  535:     int64_t count;
  536: 
  537:     term_printf("IRQ statistics:\n");
  538:     for (i = 0; i < 16; i++) {
  539:         count = irq_count[i];
  540:         if (count > 0)
  541:             term_printf("%2d: %" PRId64 "\n", i, count);
  542:     }
  543: #endif
  544: }
  545: 
  546: qemu_irq *i8259_init(qemu_irq parent_irq)
  547: {
  548:     PicState2 *s;
  549: 
  550:     s = qemu_mallocz(sizeof(PicState2));
  551:     if (!s)
  552:         return NULL;
  553:     pic_init1(0x20, 0x4d0, &s->pics[0]);
  554:     pic_init1(0xa0, 0x4d1, &s->pics[1]);
  555:     s->pics[0].elcr_mask = 0xf8;
  556:     s->pics[1].elcr_mask = 0xde;
  557:     s->parent_irq = parent_irq;
  558:     s->pics[0].pics_state = s;
  559:     s->pics[1].pics_state = s;
  560:     isa_pic = s;
  561:     return qemu_allocate_irqs(i8259_set_irq, s, 16);
  562: }
  563: 
  564: void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
  565:                           void *alt_irq_opaque)
  566: {
  567:     s->alt_irq_func = alt_irq_func;
  568:     s->alt_irq_opaque = alt_irq_opaque;
  569: }
1
Syntax (Markdown)