armv7m: Implement reading and writing of PRIGROUP
[qemu/ar7.git] / hw / intc / armv7m_nvic.c
blobce22001b6c57e6cf788d370db0bf292db0bf2fff
1 /*
2 * ARM Nested Vectored Interrupt Controller
4 * Copyright (c) 2006-2007 CodeSourcery.
5 * Written by Paul Brook
7 * This code is licensed under the GPL.
9 * The ARMv7M System controller is fairly tightly tied in with the
10 * NVIC. Much of that is also implemented here.
13 #include "qemu/osdep.h"
14 #include "qapi/error.h"
15 #include "qemu-common.h"
16 #include "cpu.h"
17 #include "hw/sysbus.h"
18 #include "qemu/timer.h"
19 #include "hw/arm/arm.h"
20 #include "exec/address-spaces.h"
21 #include "gic_internal.h"
22 #include "qemu/log.h"
24 typedef struct NVICState {
25 GICState gic;
26 ARMCPU *cpu;
28 uint32_t prigroup;
30 struct {
31 uint32_t control;
32 uint32_t reload;
33 int64_t tick;
34 QEMUTimer *timer;
35 } systick;
36 MemoryRegion sysregmem;
37 MemoryRegion gic_iomem_alias;
38 MemoryRegion container;
39 uint32_t num_irq;
40 qemu_irq sysresetreq;
41 } NVICState;
43 #define TYPE_NVIC "armv7m_nvic"
44 /**
45 * NVICClass:
46 * @parent_reset: the parent class' reset handler.
48 * A model of the v7M NVIC and System Controller
50 typedef struct NVICClass {
51 /*< private >*/
52 ARMGICClass parent_class;
53 /*< public >*/
54 DeviceRealize parent_realize;
55 void (*parent_reset)(DeviceState *dev);
56 } NVICClass;
58 #define NVIC_CLASS(klass) \
59 OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC)
60 #define NVIC_GET_CLASS(obj) \
61 OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC)
62 #define NVIC(obj) \
63 OBJECT_CHECK(NVICState, (obj), TYPE_NVIC)
65 static const uint8_t nvic_id[] = {
66 0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1
69 /* qemu timers run at 1GHz. We want something closer to 1MHz. */
70 #define SYSTICK_SCALE 1000ULL
72 #define SYSTICK_ENABLE (1 << 0)
73 #define SYSTICK_TICKINT (1 << 1)
74 #define SYSTICK_CLKSOURCE (1 << 2)
75 #define SYSTICK_COUNTFLAG (1 << 16)
77 int system_clock_scale;
79 /* Conversion factor from qemu timer to SysTick frequencies. */
80 static inline int64_t systick_scale(NVICState *s)
82 if (s->systick.control & SYSTICK_CLKSOURCE)
83 return system_clock_scale;
84 else
85 return 1000;
88 static void systick_reload(NVICState *s, int reset)
90 /* The Cortex-M3 Devices Generic User Guide says that "When the
91 * ENABLE bit is set to 1, the counter loads the RELOAD value from the
92 * SYST RVR register and then counts down". So, we need to check the
93 * ENABLE bit before reloading the value.
95 if ((s->systick.control & SYSTICK_ENABLE) == 0) {
96 return;
99 if (reset)
100 s->systick.tick = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
101 s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
102 timer_mod(s->systick.timer, s->systick.tick);
105 static void systick_timer_tick(void * opaque)
107 NVICState *s = (NVICState *)opaque;
108 s->systick.control |= SYSTICK_COUNTFLAG;
109 if (s->systick.control & SYSTICK_TICKINT) {
110 /* Trigger the interrupt. */
111 armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
113 if (s->systick.reload == 0) {
114 s->systick.control &= ~SYSTICK_ENABLE;
115 } else {
116 systick_reload(s, 0);
120 static void systick_reset(NVICState *s)
122 s->systick.control = 0;
123 s->systick.reload = 0;
124 s->systick.tick = 0;
125 timer_del(s->systick.timer);
128 /* The external routines use the hardware vector numbering, ie. the first
129 IRQ is #16. The internal GIC routines use #32 as the first IRQ. */
130 void armv7m_nvic_set_pending(void *opaque, int irq)
132 NVICState *s = (NVICState *)opaque;
133 if (irq >= 16)
134 irq += 16;
135 gic_set_pending_private(&s->gic, 0, irq);
138 /* Make pending IRQ active. */
139 int armv7m_nvic_acknowledge_irq(void *opaque)
141 NVICState *s = (NVICState *)opaque;
142 uint32_t irq;
144 irq = gic_acknowledge_irq(&s->gic, 0, MEMTXATTRS_UNSPECIFIED);
145 if (irq == 1023)
146 hw_error("Interrupt but no vector\n");
147 if (irq >= 32)
148 irq -= 16;
149 return irq;
152 void armv7m_nvic_complete_irq(void *opaque, int irq)
154 NVICState *s = (NVICState *)opaque;
155 if (irq >= 16)
156 irq += 16;
157 gic_complete_irq(&s->gic, 0, irq, MEMTXATTRS_UNSPECIFIED);
160 static uint32_t nvic_readl(NVICState *s, uint32_t offset)
162 ARMCPU *cpu = s->cpu;
163 uint32_t val;
164 int irq;
166 switch (offset) {
167 case 4: /* Interrupt Control Type. */
168 return (s->num_irq / 32) - 1;
169 case 0x10: /* SysTick Control and Status. */
170 val = s->systick.control;
171 s->systick.control &= ~SYSTICK_COUNTFLAG;
172 return val;
173 case 0x14: /* SysTick Reload Value. */
174 return s->systick.reload;
175 case 0x18: /* SysTick Current Value. */
177 int64_t t;
178 if ((s->systick.control & SYSTICK_ENABLE) == 0)
179 return 0;
180 t = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
181 if (t >= s->systick.tick)
182 return 0;
183 val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1;
184 /* The interrupt in triggered when the timer reaches zero.
185 However the counter is not reloaded until the next clock
186 tick. This is a hack to return zero during the first tick. */
187 if (val > s->systick.reload)
188 val = 0;
189 return val;
191 case 0x1c: /* SysTick Calibration Value. */
192 return 10000;
193 case 0xd00: /* CPUID Base. */
194 return cpu->midr;
195 case 0xd04: /* Interrupt Control State. */
196 /* VECTACTIVE */
197 val = cpu->env.v7m.exception;
198 if (val == 1023) {
199 val = 0;
200 } else if (val >= 32) {
201 val -= 16;
203 /* VECTPENDING */
204 if (s->gic.current_pending[0] != 1023)
205 val |= (s->gic.current_pending[0] << 12);
206 /* ISRPENDING and RETTOBASE */
207 for (irq = 32; irq < s->num_irq; irq++) {
208 if (s->gic.irq_state[irq].pending) {
209 val |= (1 << 22);
210 break;
212 if (irq != cpu->env.v7m.exception && s->gic.irq_state[irq].active) {
213 val |= (1 << 11);
216 /* PENDSTSET */
217 if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
218 val |= (1 << 26);
219 /* PENDSVSET */
220 if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
221 val |= (1 << 28);
222 /* NMIPENDSET */
223 if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
224 val |= (1 << 31);
225 return val;
226 case 0xd08: /* Vector Table Offset. */
227 return cpu->env.v7m.vecbase;
228 case 0xd0c: /* Application Interrupt/Reset Control. */
229 return 0xfa050000 | (s->prigroup << 8);
230 case 0xd10: /* System Control. */
231 /* TODO: Implement SLEEPONEXIT. */
232 return 0;
233 case 0xd14: /* Configuration Control. */
234 return cpu->env.v7m.ccr;
235 case 0xd24: /* System Handler Status. */
236 val = 0;
237 if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0);
238 if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1);
239 if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3);
240 if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7);
241 if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8);
242 if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10);
243 if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11);
244 if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12);
245 if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13);
246 if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14);
247 if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15);
248 if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16);
249 if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17);
250 if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18);
251 return val;
252 case 0xd28: /* Configurable Fault Status. */
253 return cpu->env.v7m.cfsr;
254 case 0xd2c: /* Hard Fault Status. */
255 return cpu->env.v7m.hfsr;
256 case 0xd30: /* Debug Fault Status. */
257 return cpu->env.v7m.dfsr;
258 case 0xd34: /* MMFAR MemManage Fault Address */
259 return cpu->env.v7m.mmfar;
260 case 0xd38: /* Bus Fault Address. */
261 return cpu->env.v7m.bfar;
262 case 0xd3c: /* Aux Fault Status. */
263 /* TODO: Implement fault status registers. */
264 qemu_log_mask(LOG_UNIMP,
265 "Aux Fault status registers unimplemented\n");
266 return 0;
267 case 0xd40: /* PFR0. */
268 return 0x00000030;
269 case 0xd44: /* PRF1. */
270 return 0x00000200;
271 case 0xd48: /* DFR0. */
272 return 0x00100000;
273 case 0xd4c: /* AFR0. */
274 return 0x00000000;
275 case 0xd50: /* MMFR0. */
276 return 0x00000030;
277 case 0xd54: /* MMFR1. */
278 return 0x00000000;
279 case 0xd58: /* MMFR2. */
280 return 0x00000000;
281 case 0xd5c: /* MMFR3. */
282 return 0x00000000;
283 case 0xd60: /* ISAR0. */
284 return 0x01141110;
285 case 0xd64: /* ISAR1. */
286 return 0x02111000;
287 case 0xd68: /* ISAR2. */
288 return 0x21112231;
289 case 0xd6c: /* ISAR3. */
290 return 0x01111110;
291 case 0xd70: /* ISAR4. */
292 return 0x01310102;
293 /* TODO: Implement debug registers. */
294 default:
295 qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
296 return 0;
300 static void nvic_writel(NVICState *s, uint32_t offset, uint32_t value)
302 ARMCPU *cpu = s->cpu;
303 uint32_t oldval;
304 switch (offset) {
305 case 0x10: /* SysTick Control and Status. */
306 oldval = s->systick.control;
307 s->systick.control &= 0xfffffff8;
308 s->systick.control |= value & 7;
309 if ((oldval ^ value) & SYSTICK_ENABLE) {
310 int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
311 if (value & SYSTICK_ENABLE) {
312 if (s->systick.tick) {
313 s->systick.tick += now;
314 timer_mod(s->systick.timer, s->systick.tick);
315 } else {
316 systick_reload(s, 1);
318 } else {
319 timer_del(s->systick.timer);
320 s->systick.tick -= now;
321 if (s->systick.tick < 0)
322 s->systick.tick = 0;
324 } else if ((oldval ^ value) & SYSTICK_CLKSOURCE) {
325 /* This is a hack. Force the timer to be reloaded
326 when the reference clock is changed. */
327 systick_reload(s, 1);
329 break;
330 case 0x14: /* SysTick Reload Value. */
331 s->systick.reload = value;
332 break;
333 case 0x18: /* SysTick Current Value. Writes reload the timer. */
334 systick_reload(s, 1);
335 s->systick.control &= ~SYSTICK_COUNTFLAG;
336 break;
337 case 0xd04: /* Interrupt Control State. */
338 if (value & (1 << 31)) {
339 armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI);
341 if (value & (1 << 28)) {
342 armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV);
343 } else if (value & (1 << 27)) {
344 s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
345 gic_update(&s->gic);
347 if (value & (1 << 26)) {
348 armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK);
349 } else if (value & (1 << 25)) {
350 s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
351 gic_update(&s->gic);
353 break;
354 case 0xd08: /* Vector Table Offset. */
355 cpu->env.v7m.vecbase = value & 0xffffff80;
356 break;
357 case 0xd0c: /* Application Interrupt/Reset Control. */
358 if ((value >> 16) == 0x05fa) {
359 if (value & 4) {
360 qemu_irq_pulse(s->sysresetreq);
362 if (value & 2) {
363 qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
365 if (value & 1) {
366 qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
368 s->prigroup = extract32(value, 8, 3);
370 break;
371 case 0xd10: /* System Control. */
372 /* TODO: Implement control registers. */
373 qemu_log_mask(LOG_UNIMP, "NVIC: SCR unimplemented\n");
374 break;
375 case 0xd14: /* Configuration Control. */
376 /* Enforce RAZ/WI on reserved and must-RAZ/WI bits */
377 value &= (R_V7M_CCR_STKALIGN_MASK |
378 R_V7M_CCR_BFHFNMIGN_MASK |
379 R_V7M_CCR_DIV_0_TRP_MASK |
380 R_V7M_CCR_UNALIGN_TRP_MASK |
381 R_V7M_CCR_USERSETMPEND_MASK |
382 R_V7M_CCR_NONBASETHRDENA_MASK);
384 cpu->env.v7m.ccr = value;
385 break;
386 case 0xd24: /* System Handler Control. */
387 /* TODO: Real hardware allows you to set/clear the active bits
388 under some circumstances. We don't implement this. */
389 s->gic.irq_state[ARMV7M_EXCP_MEM].enabled = (value & (1 << 16)) != 0;
390 s->gic.irq_state[ARMV7M_EXCP_BUS].enabled = (value & (1 << 17)) != 0;
391 s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled = (value & (1 << 18)) != 0;
392 break;
393 case 0xd28: /* Configurable Fault Status. */
394 cpu->env.v7m.cfsr &= ~value; /* W1C */
395 break;
396 case 0xd2c: /* Hard Fault Status. */
397 cpu->env.v7m.hfsr &= ~value; /* W1C */
398 break;
399 case 0xd30: /* Debug Fault Status. */
400 cpu->env.v7m.dfsr &= ~value; /* W1C */
401 break;
402 case 0xd34: /* Mem Manage Address. */
403 cpu->env.v7m.mmfar = value;
404 return;
405 case 0xd38: /* Bus Fault Address. */
406 cpu->env.v7m.bfar = value;
407 return;
408 case 0xd3c: /* Aux Fault Status. */
409 qemu_log_mask(LOG_UNIMP,
410 "NVIC: Aux fault status registers unimplemented\n");
411 break;
412 case 0xf00: /* Software Triggered Interrupt Register */
413 /* user mode can only write to STIR if CCR.USERSETMPEND permits it */
414 if ((value & 0x1ff) < s->num_irq &&
415 (arm_current_el(&cpu->env) ||
416 (cpu->env.v7m.ccr & R_V7M_CCR_USERSETMPEND_MASK))) {
417 gic_set_pending_private(&s->gic, 0, value & 0x1ff);
419 break;
420 default:
421 qemu_log_mask(LOG_GUEST_ERROR,
422 "NVIC: Bad write offset 0x%x\n", offset);
426 static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr,
427 unsigned size)
429 NVICState *s = (NVICState *)opaque;
430 uint32_t offset = addr;
431 int i;
432 uint32_t val;
434 switch (offset) {
435 case 0xd18 ... 0xd23: /* System Handler Priority. */
436 val = 0;
437 for (i = 0; i < size; i++) {
438 val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8);
440 return val;
441 case 0xfe0 ... 0xfff: /* ID. */
442 if (offset & 3) {
443 return 0;
445 return nvic_id[(offset - 0xfe0) >> 2];
447 if (size == 4) {
448 return nvic_readl(s, offset);
450 qemu_log_mask(LOG_GUEST_ERROR,
451 "NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
452 return 0;
455 static void nvic_sysreg_write(void *opaque, hwaddr addr,
456 uint64_t value, unsigned size)
458 NVICState *s = (NVICState *)opaque;
459 uint32_t offset = addr;
460 int i;
462 switch (offset) {
463 case 0xd18 ... 0xd23: /* System Handler Priority. */
464 for (i = 0; i < size; i++) {
465 s->gic.priority1[(offset - 0xd14) + i][0] =
466 (value >> (i * 8)) & 0xff;
468 gic_update(&s->gic);
469 return;
471 if (size == 4) {
472 nvic_writel(s, offset, value);
473 return;
475 qemu_log_mask(LOG_GUEST_ERROR,
476 "NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
479 static const MemoryRegionOps nvic_sysreg_ops = {
480 .read = nvic_sysreg_read,
481 .write = nvic_sysreg_write,
482 .endianness = DEVICE_NATIVE_ENDIAN,
485 static const VMStateDescription vmstate_nvic = {
486 .name = "armv7m_nvic",
487 .version_id = 2,
488 .minimum_version_id = 2,
489 .fields = (VMStateField[]) {
490 VMSTATE_UINT32(systick.control, NVICState),
491 VMSTATE_UINT32(systick.reload, NVICState),
492 VMSTATE_INT64(systick.tick, NVICState),
493 VMSTATE_TIMER_PTR(systick.timer, NVICState),
494 VMSTATE_UINT32(prigroup, NVICState),
495 VMSTATE_END_OF_LIST()
499 static void armv7m_nvic_reset(DeviceState *dev)
501 NVICState *s = NVIC(dev);
502 NVICClass *nc = NVIC_GET_CLASS(s);
503 nc->parent_reset(dev);
504 /* Common GIC reset resets to disabled; the NVIC doesn't have
505 * per-CPU interfaces so mark our non-existent CPU interface
506 * as enabled by default, and with a priority mask which allows
507 * all interrupts through.
509 s->gic.cpu_ctlr[0] = GICC_CTLR_EN_GRP0;
510 s->gic.priority_mask[0] = 0x100;
511 /* The NVIC as a whole is always enabled. */
512 s->gic.ctlr = 1;
513 systick_reset(s);
516 static void armv7m_nvic_realize(DeviceState *dev, Error **errp)
518 NVICState *s = NVIC(dev);
519 NVICClass *nc = NVIC_GET_CLASS(s);
520 Error *local_err = NULL;
522 s->cpu = ARM_CPU(qemu_get_cpu(0));
523 assert(s->cpu);
524 /* The NVIC always has only one CPU */
525 s->gic.num_cpu = 1;
526 /* Tell the common code we're an NVIC */
527 s->gic.revision = 0xffffffff;
528 s->num_irq = s->gic.num_irq;
529 nc->parent_realize(dev, &local_err);
530 if (local_err) {
531 error_propagate(errp, local_err);
532 return;
534 gic_init_irqs_and_distributor(&s->gic);
535 /* The NVIC and system controller register area looks like this:
536 * 0..0xff : system control registers, including systick
537 * 0x100..0xcff : GIC-like registers
538 * 0xd00..0xfff : system control registers
539 * We use overlaying to put the GIC like registers
540 * over the top of the system control register region.
542 memory_region_init(&s->container, OBJECT(s), "nvic", 0x1000);
543 /* The system register region goes at the bottom of the priority
544 * stack as it covers the whole page.
546 memory_region_init_io(&s->sysregmem, OBJECT(s), &nvic_sysreg_ops, s,
547 "nvic_sysregs", 0x1000);
548 memory_region_add_subregion(&s->container, 0, &s->sysregmem);
549 /* Alias the GIC region so we can get only the section of it
550 * we need, and layer it on top of the system register region.
552 memory_region_init_alias(&s->gic_iomem_alias, OBJECT(s),
553 "nvic-gic", &s->gic.iomem,
554 0x100, 0xc00);
555 memory_region_add_subregion_overlap(&s->container, 0x100,
556 &s->gic_iomem_alias, 1);
557 /* Map the whole thing into system memory at the location required
558 * by the v7M architecture.
560 memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
561 s->systick.timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, systick_timer_tick, s);
564 static void armv7m_nvic_instance_init(Object *obj)
566 /* We have a different default value for the num-irq property
567 * than our superclass. This function runs after qdev init
568 * has set the defaults from the Property array and before
569 * any user-specified property setting, so just modify the
570 * value in the GICState struct.
572 GICState *s = ARM_GIC_COMMON(obj);
573 DeviceState *dev = DEVICE(obj);
574 NVICState *nvic = NVIC(obj);
575 /* The ARM v7m may have anything from 0 to 496 external interrupt
576 * IRQ lines. We default to 64. Other boards may differ and should
577 * set the num-irq property appropriately.
579 s->num_irq = 64;
580 qdev_init_gpio_out_named(dev, &nvic->sysresetreq, "SYSRESETREQ", 1);
583 static void armv7m_nvic_class_init(ObjectClass *klass, void *data)
585 NVICClass *nc = NVIC_CLASS(klass);
586 DeviceClass *dc = DEVICE_CLASS(klass);
588 nc->parent_reset = dc->reset;
589 nc->parent_realize = dc->realize;
590 dc->vmsd = &vmstate_nvic;
591 dc->reset = armv7m_nvic_reset;
592 dc->realize = armv7m_nvic_realize;
595 static const TypeInfo armv7m_nvic_info = {
596 .name = TYPE_NVIC,
597 .parent = TYPE_ARM_GIC_COMMON,
598 .instance_init = armv7m_nvic_instance_init,
599 .instance_size = sizeof(NVICState),
600 .class_init = armv7m_nvic_class_init,
601 .class_size = sizeof(NVICClass),
604 static void armv7m_nvic_register_types(void)
606 type_register_static(&armv7m_nvic_info);
609 type_init(armv7m_nvic_register_types)