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

qemu/0.9.1/hw/armv7m_nvic.c

    1: /*
    2:  * ARM Nested Vectored Interrupt Controller
    3:  *
    4:  * Copyright (c) 2006-2007 CodeSourcery.
    5:  * Written by Paul Brook
    6:  *
    7:  * This code is licenced under the GPL.
    8:  *
    9:  * The ARMv7M System controller is fairly tightly tied in with the
   10:  * NVIC.  Much of that is also implemented here.
   11:  */
   12: 
   13: #include "hw.h"
   14: #include "qemu-timer.h"
   15: #include "arm-misc.h"
   16: 
   17: /* 32 internal lines (16 used for system exceptions) plus 64 external
   18:    interrupt lines.  */
   19: #define GIC_NIRQ 96
   20: #define NCPU 1
   21: #define NVIC 1
   22: 
   23: /* Only a single "CPU" interface is present.  */
   24: static inline int
   25: gic_get_current_cpu(void)
   26: {
   27:     return 0;
   28: }
   29: 
   30: static uint32_t nvic_readl(void *opaque, uint32_t offset);
   31: static void nvic_writel(void *opaque, uint32_t offset, uint32_t value);
   32: 
   33: #include "arm_gic.c"
   34: 
   35: typedef struct {
   36:     struct {
   37:         uint32_t control;
   38:         uint32_t reload;
   39:         int64_t tick;
   40:         QEMUTimer *timer;
   41:     } systick;
   42:     gic_state *gic;
   43: } nvic_state;
   44: 
   45: /* qemu timers run at 1GHz.   We want something closer to 1MHz.  */
   46: #define SYSTICK_SCALE 1000ULL
   47: 
   48: #define SYSTICK_ENABLE    (1 << 0)
   49: #define SYSTICK_TICKINT   (1 << 1)
   50: #define SYSTICK_CLKSOURCE (1 << 2)
   51: #define SYSTICK_COUNTFLAG (1 << 16)
   52: 
   53: /* Multiplication factor to convert from system clock ticks to qemu timer
   54:    ticks.  */
   55: int system_clock_scale;
   56: 
   57: /* Conversion factor from qemu timer to SysTick frequencies.  */
   58: static inline int64_t systick_scale(nvic_state *s)
   59: {
   60:     if (s->systick.control & SYSTICK_CLKSOURCE)
   61:         return system_clock_scale;
   62:     else
   63:         return 1000;
   64: }
   65: 
   66: static void systick_reload(nvic_state *s, int reset)
   67: {
   68:     if (reset)
   69:         s->systick.tick = qemu_get_clock(vm_clock);
   70:     s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
   71:     qemu_mod_timer(s->systick.timer, s->systick.tick);
   72: }
   73: 
   74: static void systick_timer_tick(void * opaque)
   75: {
   76:     nvic_state *s = (nvic_state *)opaque;
   77:     s->systick.control |= SYSTICK_COUNTFLAG;
   78:     if (s->systick.control & SYSTICK_TICKINT) {
   79:         /* Trigger the interrupt.  */
   80:         armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
   81:     }
   82:     if (s->systick.reload == 0) {
   83:         s->systick.control &= ~SYSTICK_ENABLE;
   84:     } else {
   85:         systick_reload(s, 0);
   86:     }
   87: }
   88: 
   89: /* The external routines use the hardware vector numbering, ie. the first
   90:    IRQ is #16.  The internal GIC routines use #32 as the first IRQ.  */
   91: void armv7m_nvic_set_pending(void *opaque, int irq)
   92: {
   93:     nvic_state *s = (nvic_state *)opaque;
   94:     if (irq >= 16)
   95:         irq += 16;
   96:     gic_set_pending_private(s->gic, 0, irq);
   97: }
   98: 
   99: /* Make pending IRQ active.  */
  100: int armv7m_nvic_acknowledge_irq(void *opaque)
  101: {
  102:     nvic_state *s = (nvic_state *)opaque;
  103:     uint32_t irq;
  104: 
  105:     irq = gic_acknowledge_irq(s->gic, 0);
  106:     if (irq == 1023)
  107:         cpu_abort(cpu_single_env, "Interrupt but no vector\n");
  108:     if (irq >= 32)
  109:         irq -= 16;
  110:     return irq;
  111: }
  112: 
  113: void armv7m_nvic_complete_irq(void *opaque, int irq)
  114: {
  115:     nvic_state *s = (nvic_state *)opaque;
  116:     if (irq >= 16)
  117:         irq += 16;
  118:     gic_complete_irq(s->gic, 0, irq);
  119: }
  120: 
  121: static uint32_t nvic_readl(void *opaque, uint32_t offset)
  122: {
  123:     nvic_state *s = (nvic_state *)opaque;
  124:     uint32_t val;
  125:     int irq;
  126: 
  127:     switch (offset) {
  128:     case 4: /* Interrupt Control Type.  */
  129:         return (GIC_NIRQ / 32) - 1;
  130:     case 0x10: /* SysTick Control and Status.  */
  131:         val = s->systick.control;
  132:         s->systick.control &= ~SYSTICK_COUNTFLAG;
  133:         return val;
  134:     case 0x14: /* SysTick Reload Value.  */
  135:         return s->systick.reload;
  136:     case 0x18: /* SysTick Current Value.  */
  137:         {
  138:             int64_t t;
  139:             if ((s->systick.control & SYSTICK_ENABLE) == 0)
  140:                 return 0;
  141:             t = qemu_get_clock(vm_clock);
  142:             if (t >= s->systick.tick)
  143:                 return 0;
  144:             val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
  145:             /* The interrupt in triggered when the timer reaches zero.
  146:                However the counter is not reloaded until the next clock
  147:                tick.  This is a hack to return zero during the first tick.  */
  148:             if (val > s->systick.reload)
  149:                 val = 0;
  150:             return val;
  151:         }
  152:     case 0x1c: /* SysTick Calibration Value.  */
  153:         return 10000;
  154:     case 0xd00: /* CPUID Base.  */
  155:         return cpu_single_env->cp15.c0_cpuid;
  156:     case 0xd04: /* Interrypt Control State.  */
  157:         /* VECTACTIVE */
  158:         val = s->gic->running_irq[0];
  159:         if (val == 1023) {
  160:             val = 0;
  161:         } else if (val >= 32) {
  162:             val -= 16;
  163:         }
  164:         /* RETTOBASE */
  165:         if (s->gic->running_irq[0] == 1023
  166:                 || s->gic->last_active[s->gic->running_irq[0]][0] == 1023) {
  167:             val |= (1 << 11);
  168:         }
  169:         /* VECTPENDING */
  170:         if (s->gic->current_pending[0] != 1023)
  171:             val |= (s->gic->current_pending[0] << 12);
  172:         /* ISRPENDING */
  173:         for (irq = 32; irq < GIC_NIRQ; irq++) {
  174:             if (s->gic->irq_state[irq].pending) {
  175:                 val |= (1 << 22);
  176:                 break;
  177:             }
  178:         }
  179:         /* PENDSTSET */
  180:         if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending)
  181:             val |= (1 << 26);
  182:         /* PENDSVSET */
  183:         if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending)
  184:             val |= (1 << 28);
  185:         /* NMIPENDSET */
  186:         if (s->gic->irq_state[ARMV7M_EXCP_NMI].pending)
  187:             val |= (1 << 31);
  188:         return val;
  189:     case 0xd08: /* Vector Table Offset.  */
  190:         return cpu_single_env->v7m.vecbase;
  191:     case 0xd0c: /* Application Interrupt/Reset Control.  */
  192:         return 0xfa05000;
  193:     case 0xd10: /* System Control.  */
  194:         /* TODO: Implement SLEEPONEXIT.  */
  195:         return 0;
  196:     case 0xd14: /* Configuration Control.  */
  197:         /* TODO: Implement Configuration Control bits.  */
  198:         return 0;
  199:     case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
  200:         irq = offset - 0xd14;
  201:         val = 0;
  202:         val = s->gic->priority1[irq++][0];
  203:         val = s->gic->priority1[irq++][0] << 8;
  204:         val = s->gic->priority1[irq++][0] << 16;
  205:         val = s->gic->priority1[irq][0] << 24;
  206:         return val;
  207:     case 0xd24: /* System Handler Status.  */
  208:         val = 0;
  209:         if (s->gic->irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
  210:         if (s->gic->irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
  211:         if (s->gic->irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
  212:         if (s->gic->irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
  213:         if (s->gic->irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
  214:         if (s->gic->irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
  215:         if (s->gic->irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
  216:         if (s->gic->irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
  217:         if (s->gic->irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
  218:         if (s->gic->irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
  219:         if (s->gic->irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
  220:         if (s->gic->irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
  221:         if (s->gic->irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
  222:         if (s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
  223:         return val;
  224:     case 0xd28: /* Configurable Fault Status.  */
  225:         /* TODO: Implement Fault Status.  */
  226:         cpu_abort(cpu_single_env,
  227:                   "Not implemented: Configurable Fault Status.");
  228:         return 0;
  229:     case 0xd2c: /* Hard Fault Status.  */
  230:     case 0xd30: /* Debug Fault Status.  */
  231:     case 0xd34: /* Mem Manage Address.  */
  232:     case 0xd38: /* Bus Fault Address.  */
  233:     case 0xd3c: /* Aux Fault Status.  */
  234:         /* TODO: Implement fault status registers.  */
  235:         goto bad_reg;
  236:     case 0xd40: /* PFR0.  */
  237:         return 0x00000030;
  238:     case 0xd44: /* PRF1.  */
  239:         return 0x00000200;
  240:     case 0xd48: /* DFR0.  */
  241:         return 0x00100000;
  242:     case 0xd4c: /* AFR0.  */
  243:         return 0x00000000;
  244:     case 0xd50: /* MMFR0.  */
  245:         return 0x00000030;
  246:     case 0xd54: /* MMFR1.  */
  247:         return 0x00000000;
  248:     case 0xd58: /* MMFR2.  */
  249:         return 0x00000000;
  250:     case 0xd5c: /* MMFR3.  */
  251:         return 0x00000000;
  252:     case 0xd60: /* ISAR0.  */
  253:         return 0x01141110;
  254:     case 0xd64: /* ISAR1.  */
  255:         return 0x02111000;
  256:     case 0xd68: /* ISAR2.  */
  257:         return 0x21112231;
  258:     case 0xd6c: /* ISAR3.  */
  259:         return 0x01111110;
  260:     case 0xd70: /* ISAR4.  */
  261:         return 0x01310102;
  262:     /* TODO: Implement debug registers.  */
  263:     default:
  264:     bad_reg:
  265:         cpu_abort(cpu_single_env, "NVIC: Bad read offset 0x%x\n", offset);
  266:     }
  267: }
  268: 
  269: static void nvic_writel(void *opaque, uint32_t offset, uint32_t value)
  270: {
  271:     nvic_state *s = (nvic_state *)opaque;
  272:     uint32_t oldval;
  273:     switch (offset) {
  274:     case 0x10: /* SysTick Control and Status.  */
  275:         oldval = s->systick.control;
  276:         s->systick.control &= 0xfffffff8;
  277:         s->systick.control |= value & 7;
  278:         if ((oldval ^ value) & SYSTICK_ENABLE) {
  279:             int64_t now = qemu_get_clock(vm_clock);
  280:             if (value & SYSTICK_ENABLE) {
  281:                 if (s->systick.tick) {
  282:                     s->systick.tick += now;
  283:                     qemu_mod_timer(s->systick.timer, s->systick.tick);
  284:                 } else {
  285:                     systick_reload(s, 1);
  286:                 }
  287:             } else {
  288:                 qemu_del_timer(s->systick.timer);
  289:                 s->systick.tick -= now;
  290:                 if (s->systick.tick < 0)
  291:                   s->systick.tick = 0;
  292:             }
  293:         } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
  294:             /* This is a hack. Force the timer to be reloaded
  295:                when the reference clock is changed.  */
  296:             systick_reload(s, 1);
  297:         }
  298:         break;
  299:     case 0x14: /* SysTick Reload Value.  */
  300:         s->systick.reload = value;
  301:         break;
  302:     case 0x18: /* SysTick Current Value.  Writes reload the timer.  */
  303:         systick_reload(s, 1);
  304:         s->systick.control &= ~SYSTICK_COUNTFLAG;
  305:         break;
  306:     case 0xd04: /* Interrupt Control State.  */
  307:         if (value & (1 << 31)) {
  308:             armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
  309:         }
  310:         if (value & (1 << 28)) {
  311:             armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
  312:         } else if (value & (1 << 27)) {
  313:             s->gic->irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
  314:             gic_update(s->gic);
  315:         }
  316:         if (value & (1 << 26)) {
  317:             armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
  318:         } else if (value & (1 << 25)) {
  319:             s->gic->irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
  320:             gic_update(s->gic);
  321:         }
  322:         break;
  323:     case 0xd08: /* Vector Table Offset.  */
  324:         cpu_single_env->v7m.vecbase = value & 0xffffff80;
  325:         break;
  326:     case 0xd0c: /* Application Interrupt/Reset Control.  */
  327:         if ((value >> 16) == 0x05fa) {
  328:             if (value & 2) {
  329:                 cpu_abort(cpu_single_env, "VECTCLRACTIVE not implemented");
  330:             }
  331:             if (value & 5) {
  332:                 cpu_abort(cpu_single_env, "System reset");
  333:             }
  334:         }
  335:         break;
  336:     case 0xd10: /* System Control.  */
  337:     case 0xd14: /* Configuration Control.  */
  338:         /* TODO: Implement control registers.  */
  339:         goto bad_reg;
  340:     case 0xd18: case 0xd1c: case 0xd20: /* System Handler Priority.  */
  341:         {
  342:             int irq;
  343:             irq = offset - 0xd14;
  344:             s->gic->priority1[irq++][0] = value & 0xff;
  345:             s->gic->priority1[irq++][0] = (value >> 8) & 0xff;
  346:             s->gic->priority1[irq++][0] = (value >> 16) & 0xff;
  347:             s->gic->priority1[irq][0] = (value >> 24) & 0xff;
  348:             gic_update(s->gic);
  349:         }
  350:         break;
  351:     case 0xd24: /* System Handler Control.  */
  352:         /* TODO: Real hardware allows you to set/clear the active bits
  353:            under some circumstances.  We don't implement this.  */
  354:         s->gic->irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
  355:         s->gic->irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
  356:         s->gic->irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
  357:         break;
  358:     case 0xd28: /* Configurable Fault Status.  */
  359:     case 0xd2c: /* Hard Fault Status.  */
  360:     case 0xd30: /* Debug Fault Status.  */
  361:     case 0xd34: /* Mem Manage Address.  */
  362:     case 0xd38: /* Bus Fault Address.  */
  363:     case 0xd3c: /* Aux Fault Status.  */
  364:         goto bad_reg;
  365:     default:
  366:     bad_reg:
  367:         cpu_abort(cpu_single_env, "NVIC: Bad write offset 0x%x\n", offset);
  368:     }
  369: }
  370: 
  371: qemu_irq *armv7m_nvic_init(CPUState *env)
  372: {
  373:     nvic_state *s;
  374:     qemu_irq *parent;
  375: 
  376:     parent = arm_pic_init_cpu(env);
  377:     s = (nvic_state *)qemu_mallocz(sizeof(nvic_state));
  378:     s->gic = gic_init(0xe000e000, &parent[ARM_PIC_CPU_IRQ]);
  379:     s->gic->nvic = s;
  380:     s->systick.timer = qemu_new_timer(vm_clock, systick_timer_tick, s);
  381:     if (env->v7m.nvic)
  382:         cpu_abort(env, "CPU can only have one NVIC\n");
  383:     env->v7m.nvic = s;
  384:     return s->gic->in;
  385: }
Syntax (Markdown)