root / hw / armv7m_nvic.c @ 1de7afc9
History | View | Annotate | Download (18 kB)
1 |
/*
|
---|---|
2 |
* ARM Nested Vectored Interrupt Controller
|
3 |
*
|
4 |
* Copyright (c) 2006-2007 CodeSourcery.
|
5 |
* Written by Paul Brook
|
6 |
*
|
7 |
* This code is licensed 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 "sysbus.h" |
14 |
#include "qemu/timer.h" |
15 |
#include "arm-misc.h" |
16 |
#include "exec/address-spaces.h" |
17 |
#include "arm_gic_internal.h" |
18 |
|
19 |
typedef struct { |
20 |
GICState gic; |
21 |
struct {
|
22 |
uint32_t control; |
23 |
uint32_t reload; |
24 |
int64_t tick; |
25 |
QEMUTimer *timer; |
26 |
} systick; |
27 |
MemoryRegion sysregmem; |
28 |
MemoryRegion gic_iomem_alias; |
29 |
MemoryRegion container; |
30 |
uint32_t num_irq; |
31 |
} nvic_state; |
32 |
|
33 |
#define TYPE_NVIC "armv7m_nvic" |
34 |
/**
|
35 |
* NVICClass:
|
36 |
* @parent_reset: the parent class' reset handler.
|
37 |
*
|
38 |
* A model of the v7M NVIC and System Controller
|
39 |
*/
|
40 |
typedef struct NVICClass { |
41 |
/*< private >*/
|
42 |
ARMGICClass parent_class; |
43 |
/*< public >*/
|
44 |
int (*parent_init)(SysBusDevice *dev);
|
45 |
void (*parent_reset)(DeviceState *dev);
|
46 |
} NVICClass; |
47 |
|
48 |
#define NVIC_CLASS(klass) \
|
49 |
OBJECT_CLASS_CHECK(NVICClass, (klass), TYPE_NVIC) |
50 |
#define NVIC_GET_CLASS(obj) \
|
51 |
OBJECT_GET_CLASS(NVICClass, (obj), TYPE_NVIC) |
52 |
#define NVIC(obj) \
|
53 |
OBJECT_CHECK(nvic_state, (obj), TYPE_NVIC) |
54 |
|
55 |
static const uint8_t nvic_id[] = { |
56 |
0x00, 0xb0, 0x1b, 0x00, 0x0d, 0xe0, 0x05, 0xb1 |
57 |
}; |
58 |
|
59 |
/* qemu timers run at 1GHz. We want something closer to 1MHz. */
|
60 |
#define SYSTICK_SCALE 1000ULL |
61 |
|
62 |
#define SYSTICK_ENABLE (1 << 0) |
63 |
#define SYSTICK_TICKINT (1 << 1) |
64 |
#define SYSTICK_CLKSOURCE (1 << 2) |
65 |
#define SYSTICK_COUNTFLAG (1 << 16) |
66 |
|
67 |
int system_clock_scale;
|
68 |
|
69 |
/* Conversion factor from qemu timer to SysTick frequencies. */
|
70 |
static inline int64_t systick_scale(nvic_state *s) |
71 |
{ |
72 |
if (s->systick.control & SYSTICK_CLKSOURCE)
|
73 |
return system_clock_scale;
|
74 |
else
|
75 |
return 1000; |
76 |
} |
77 |
|
78 |
static void systick_reload(nvic_state *s, int reset) |
79 |
{ |
80 |
if (reset)
|
81 |
s->systick.tick = qemu_get_clock_ns(vm_clock); |
82 |
s->systick.tick += (s->systick.reload + 1) * systick_scale(s);
|
83 |
qemu_mod_timer(s->systick.timer, s->systick.tick); |
84 |
} |
85 |
|
86 |
static void systick_timer_tick(void * opaque) |
87 |
{ |
88 |
nvic_state *s = (nvic_state *)opaque; |
89 |
s->systick.control |= SYSTICK_COUNTFLAG; |
90 |
if (s->systick.control & SYSTICK_TICKINT) {
|
91 |
/* Trigger the interrupt. */
|
92 |
armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); |
93 |
} |
94 |
if (s->systick.reload == 0) { |
95 |
s->systick.control &= ~SYSTICK_ENABLE; |
96 |
} else {
|
97 |
systick_reload(s, 0);
|
98 |
} |
99 |
} |
100 |
|
101 |
static void systick_reset(nvic_state *s) |
102 |
{ |
103 |
s->systick.control = 0;
|
104 |
s->systick.reload = 0;
|
105 |
s->systick.tick = 0;
|
106 |
qemu_del_timer(s->systick.timer); |
107 |
} |
108 |
|
109 |
/* The external routines use the hardware vector numbering, ie. the first
|
110 |
IRQ is #16. The internal GIC routines use #32 as the first IRQ. */
|
111 |
void armv7m_nvic_set_pending(void *opaque, int irq) |
112 |
{ |
113 |
nvic_state *s = (nvic_state *)opaque; |
114 |
if (irq >= 16) |
115 |
irq += 16;
|
116 |
gic_set_pending_private(&s->gic, 0, irq);
|
117 |
} |
118 |
|
119 |
/* Make pending IRQ active. */
|
120 |
int armv7m_nvic_acknowledge_irq(void *opaque) |
121 |
{ |
122 |
nvic_state *s = (nvic_state *)opaque; |
123 |
uint32_t irq; |
124 |
|
125 |
irq = gic_acknowledge_irq(&s->gic, 0);
|
126 |
if (irq == 1023) |
127 |
hw_error("Interrupt but no vector\n");
|
128 |
if (irq >= 32) |
129 |
irq -= 16;
|
130 |
return irq;
|
131 |
} |
132 |
|
133 |
void armv7m_nvic_complete_irq(void *opaque, int irq) |
134 |
{ |
135 |
nvic_state *s = (nvic_state *)opaque; |
136 |
if (irq >= 16) |
137 |
irq += 16;
|
138 |
gic_complete_irq(&s->gic, 0, irq);
|
139 |
} |
140 |
|
141 |
static uint32_t nvic_readl(nvic_state *s, uint32_t offset)
|
142 |
{ |
143 |
uint32_t val; |
144 |
int irq;
|
145 |
|
146 |
switch (offset) {
|
147 |
case 4: /* Interrupt Control Type. */ |
148 |
return (s->num_irq / 32) - 1; |
149 |
case 0x10: /* SysTick Control and Status. */ |
150 |
val = s->systick.control; |
151 |
s->systick.control &= ~SYSTICK_COUNTFLAG; |
152 |
return val;
|
153 |
case 0x14: /* SysTick Reload Value. */ |
154 |
return s->systick.reload;
|
155 |
case 0x18: /* SysTick Current Value. */ |
156 |
{ |
157 |
int64_t t; |
158 |
if ((s->systick.control & SYSTICK_ENABLE) == 0) |
159 |
return 0; |
160 |
t = qemu_get_clock_ns(vm_clock); |
161 |
if (t >= s->systick.tick)
|
162 |
return 0; |
163 |
val = ((s->systick.tick - (t + 1)) / systick_scale(s)) + 1; |
164 |
/* The interrupt in triggered when the timer reaches zero.
|
165 |
However the counter is not reloaded until the next clock
|
166 |
tick. This is a hack to return zero during the first tick. */
|
167 |
if (val > s->systick.reload)
|
168 |
val = 0;
|
169 |
return val;
|
170 |
} |
171 |
case 0x1c: /* SysTick Calibration Value. */ |
172 |
return 10000; |
173 |
case 0xd00: /* CPUID Base. */ |
174 |
return cpu_single_env->cp15.c0_cpuid;
|
175 |
case 0xd04: /* Interrypt Control State. */ |
176 |
/* VECTACTIVE */
|
177 |
val = s->gic.running_irq[0];
|
178 |
if (val == 1023) { |
179 |
val = 0;
|
180 |
} else if (val >= 32) { |
181 |
val -= 16;
|
182 |
} |
183 |
/* RETTOBASE */
|
184 |
if (s->gic.running_irq[0] == 1023 |
185 |
|| s->gic.last_active[s->gic.running_irq[0]][0] == 1023) { |
186 |
val |= (1 << 11); |
187 |
} |
188 |
/* VECTPENDING */
|
189 |
if (s->gic.current_pending[0] != 1023) |
190 |
val |= (s->gic.current_pending[0] << 12); |
191 |
/* ISRPENDING */
|
192 |
for (irq = 32; irq < s->num_irq; irq++) { |
193 |
if (s->gic.irq_state[irq].pending) {
|
194 |
val |= (1 << 22); |
195 |
break;
|
196 |
} |
197 |
} |
198 |
/* PENDSTSET */
|
199 |
if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending)
|
200 |
val |= (1 << 26); |
201 |
/* PENDSVSET */
|
202 |
if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending)
|
203 |
val |= (1 << 28); |
204 |
/* NMIPENDSET */
|
205 |
if (s->gic.irq_state[ARMV7M_EXCP_NMI].pending)
|
206 |
val |= (1 << 31); |
207 |
return val;
|
208 |
case 0xd08: /* Vector Table Offset. */ |
209 |
return cpu_single_env->v7m.vecbase;
|
210 |
case 0xd0c: /* Application Interrupt/Reset Control. */ |
211 |
return 0xfa05000; |
212 |
case 0xd10: /* System Control. */ |
213 |
/* TODO: Implement SLEEPONEXIT. */
|
214 |
return 0; |
215 |
case 0xd14: /* Configuration Control. */ |
216 |
/* TODO: Implement Configuration Control bits. */
|
217 |
return 0; |
218 |
case 0xd24: /* System Handler Status. */ |
219 |
val = 0;
|
220 |
if (s->gic.irq_state[ARMV7M_EXCP_MEM].active) val |= (1 << 0); |
221 |
if (s->gic.irq_state[ARMV7M_EXCP_BUS].active) val |= (1 << 1); |
222 |
if (s->gic.irq_state[ARMV7M_EXCP_USAGE].active) val |= (1 << 3); |
223 |
if (s->gic.irq_state[ARMV7M_EXCP_SVC].active) val |= (1 << 7); |
224 |
if (s->gic.irq_state[ARMV7M_EXCP_DEBUG].active) val |= (1 << 8); |
225 |
if (s->gic.irq_state[ARMV7M_EXCP_PENDSV].active) val |= (1 << 10); |
226 |
if (s->gic.irq_state[ARMV7M_EXCP_SYSTICK].active) val |= (1 << 11); |
227 |
if (s->gic.irq_state[ARMV7M_EXCP_USAGE].pending) val |= (1 << 12); |
228 |
if (s->gic.irq_state[ARMV7M_EXCP_MEM].pending) val |= (1 << 13); |
229 |
if (s->gic.irq_state[ARMV7M_EXCP_BUS].pending) val |= (1 << 14); |
230 |
if (s->gic.irq_state[ARMV7M_EXCP_SVC].pending) val |= (1 << 15); |
231 |
if (s->gic.irq_state[ARMV7M_EXCP_MEM].enabled) val |= (1 << 16); |
232 |
if (s->gic.irq_state[ARMV7M_EXCP_BUS].enabled) val |= (1 << 17); |
233 |
if (s->gic.irq_state[ARMV7M_EXCP_USAGE].enabled) val |= (1 << 18); |
234 |
return val;
|
235 |
case 0xd28: /* Configurable Fault Status. */ |
236 |
/* TODO: Implement Fault Status. */
|
237 |
qemu_log_mask(LOG_UNIMP, "Configurable Fault Status unimplemented\n");
|
238 |
return 0; |
239 |
case 0xd2c: /* Hard Fault Status. */ |
240 |
case 0xd30: /* Debug Fault Status. */ |
241 |
case 0xd34: /* Mem Manage Address. */ |
242 |
case 0xd38: /* Bus Fault Address. */ |
243 |
case 0xd3c: /* Aux Fault Status. */ |
244 |
/* TODO: Implement fault status registers. */
|
245 |
qemu_log_mask(LOG_UNIMP, "Fault status registers unimplemented\n");
|
246 |
return 0; |
247 |
case 0xd40: /* PFR0. */ |
248 |
return 0x00000030; |
249 |
case 0xd44: /* PRF1. */ |
250 |
return 0x00000200; |
251 |
case 0xd48: /* DFR0. */ |
252 |
return 0x00100000; |
253 |
case 0xd4c: /* AFR0. */ |
254 |
return 0x00000000; |
255 |
case 0xd50: /* MMFR0. */ |
256 |
return 0x00000030; |
257 |
case 0xd54: /* MMFR1. */ |
258 |
return 0x00000000; |
259 |
case 0xd58: /* MMFR2. */ |
260 |
return 0x00000000; |
261 |
case 0xd5c: /* MMFR3. */ |
262 |
return 0x00000000; |
263 |
case 0xd60: /* ISAR0. */ |
264 |
return 0x01141110; |
265 |
case 0xd64: /* ISAR1. */ |
266 |
return 0x02111000; |
267 |
case 0xd68: /* ISAR2. */ |
268 |
return 0x21112231; |
269 |
case 0xd6c: /* ISAR3. */ |
270 |
return 0x01111110; |
271 |
case 0xd70: /* ISAR4. */ |
272 |
return 0x01310102; |
273 |
/* TODO: Implement debug registers. */
|
274 |
default:
|
275 |
qemu_log_mask(LOG_GUEST_ERROR, "NVIC: Bad read offset 0x%x\n", offset);
|
276 |
return 0; |
277 |
} |
278 |
} |
279 |
|
280 |
static void nvic_writel(nvic_state *s, uint32_t offset, uint32_t value) |
281 |
{ |
282 |
uint32_t oldval; |
283 |
switch (offset) {
|
284 |
case 0x10: /* SysTick Control and Status. */ |
285 |
oldval = s->systick.control; |
286 |
s->systick.control &= 0xfffffff8;
|
287 |
s->systick.control |= value & 7;
|
288 |
if ((oldval ^ value) & SYSTICK_ENABLE) {
|
289 |
int64_t now = qemu_get_clock_ns(vm_clock); |
290 |
if (value & SYSTICK_ENABLE) {
|
291 |
if (s->systick.tick) {
|
292 |
s->systick.tick += now; |
293 |
qemu_mod_timer(s->systick.timer, s->systick.tick); |
294 |
} else {
|
295 |
systick_reload(s, 1);
|
296 |
} |
297 |
} else {
|
298 |
qemu_del_timer(s->systick.timer); |
299 |
s->systick.tick -= now; |
300 |
if (s->systick.tick < 0) |
301 |
s->systick.tick = 0;
|
302 |
} |
303 |
} else if ((oldval ^ value) & SYSTICK_CLKSOURCE) { |
304 |
/* This is a hack. Force the timer to be reloaded
|
305 |
when the reference clock is changed. */
|
306 |
systick_reload(s, 1);
|
307 |
} |
308 |
break;
|
309 |
case 0x14: /* SysTick Reload Value. */ |
310 |
s->systick.reload = value; |
311 |
break;
|
312 |
case 0x18: /* SysTick Current Value. Writes reload the timer. */ |
313 |
systick_reload(s, 1);
|
314 |
s->systick.control &= ~SYSTICK_COUNTFLAG; |
315 |
break;
|
316 |
case 0xd04: /* Interrupt Control State. */ |
317 |
if (value & (1 << 31)) { |
318 |
armv7m_nvic_set_pending(s, ARMV7M_EXCP_NMI); |
319 |
} |
320 |
if (value & (1 << 28)) { |
321 |
armv7m_nvic_set_pending(s, ARMV7M_EXCP_PENDSV); |
322 |
} else if (value & (1 << 27)) { |
323 |
s->gic.irq_state[ARMV7M_EXCP_PENDSV].pending = 0;
|
324 |
gic_update(&s->gic); |
325 |
} |
326 |
if (value & (1 << 26)) { |
327 |
armv7m_nvic_set_pending(s, ARMV7M_EXCP_SYSTICK); |
328 |
} else if (value & (1 << 25)) { |
329 |
s->gic.irq_state[ARMV7M_EXCP_SYSTICK].pending = 0;
|
330 |
gic_update(&s->gic); |
331 |
} |
332 |
break;
|
333 |
case 0xd08: /* Vector Table Offset. */ |
334 |
cpu_single_env->v7m.vecbase = value & 0xffffff80;
|
335 |
break;
|
336 |
case 0xd0c: /* Application Interrupt/Reset Control. */ |
337 |
if ((value >> 16) == 0x05fa) { |
338 |
if (value & 2) { |
339 |
qemu_log_mask(LOG_UNIMP, "VECTCLRACTIVE unimplemented\n");
|
340 |
} |
341 |
if (value & 5) { |
342 |
qemu_log_mask(LOG_UNIMP, "AIRCR system reset unimplemented\n");
|
343 |
} |
344 |
} |
345 |
break;
|
346 |
case 0xd10: /* System Control. */ |
347 |
case 0xd14: /* Configuration Control. */ |
348 |
/* TODO: Implement control registers. */
|
349 |
qemu_log_mask(LOG_UNIMP, "NVIC: SCR and CCR unimplemented\n");
|
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 |
qemu_log_mask(LOG_UNIMP, |
365 |
"NVIC: fault status registers unimplemented\n");
|
366 |
break;
|
367 |
case 0xf00: /* Software Triggered Interrupt Register */ |
368 |
if ((value & 0x1ff) < s->num_irq) { |
369 |
gic_set_pending_private(&s->gic, 0, value & 0x1ff); |
370 |
} |
371 |
break;
|
372 |
default:
|
373 |
qemu_log_mask(LOG_GUEST_ERROR, |
374 |
"NVIC: Bad write offset 0x%x\n", offset);
|
375 |
} |
376 |
} |
377 |
|
378 |
static uint64_t nvic_sysreg_read(void *opaque, hwaddr addr, |
379 |
unsigned size)
|
380 |
{ |
381 |
nvic_state *s = (nvic_state *)opaque; |
382 |
uint32_t offset = addr; |
383 |
int i;
|
384 |
uint32_t val; |
385 |
|
386 |
switch (offset) {
|
387 |
case 0xd18 ... 0xd23: /* System Handler Priority. */ |
388 |
val = 0;
|
389 |
for (i = 0; i < size; i++) { |
390 |
val |= s->gic.priority1[(offset - 0xd14) + i][0] << (i * 8); |
391 |
} |
392 |
return val;
|
393 |
case 0xfe0 ... 0xfff: /* ID. */ |
394 |
if (offset & 3) { |
395 |
return 0; |
396 |
} |
397 |
return nvic_id[(offset - 0xfe0) >> 2]; |
398 |
} |
399 |
if (size == 4) { |
400 |
return nvic_readl(s, offset);
|
401 |
} |
402 |
qemu_log_mask(LOG_GUEST_ERROR, |
403 |
"NVIC: Bad read of size %d at offset 0x%x\n", size, offset);
|
404 |
return 0; |
405 |
} |
406 |
|
407 |
static void nvic_sysreg_write(void *opaque, hwaddr addr, |
408 |
uint64_t value, unsigned size)
|
409 |
{ |
410 |
nvic_state *s = (nvic_state *)opaque; |
411 |
uint32_t offset = addr; |
412 |
int i;
|
413 |
|
414 |
switch (offset) {
|
415 |
case 0xd18 ... 0xd23: /* System Handler Priority. */ |
416 |
for (i = 0; i < size; i++) { |
417 |
s->gic.priority1[(offset - 0xd14) + i][0] = |
418 |
(value >> (i * 8)) & 0xff; |
419 |
} |
420 |
gic_update(&s->gic); |
421 |
return;
|
422 |
} |
423 |
if (size == 4) { |
424 |
nvic_writel(s, offset, value); |
425 |
return;
|
426 |
} |
427 |
qemu_log_mask(LOG_GUEST_ERROR, |
428 |
"NVIC: Bad write of size %d at offset 0x%x\n", size, offset);
|
429 |
} |
430 |
|
431 |
static const MemoryRegionOps nvic_sysreg_ops = { |
432 |
.read = nvic_sysreg_read, |
433 |
.write = nvic_sysreg_write, |
434 |
.endianness = DEVICE_NATIVE_ENDIAN, |
435 |
}; |
436 |
|
437 |
static const VMStateDescription vmstate_nvic = { |
438 |
.name = "armv7m_nvic",
|
439 |
.version_id = 1,
|
440 |
.minimum_version_id = 1,
|
441 |
.minimum_version_id_old = 1,
|
442 |
.fields = (VMStateField[]) { |
443 |
VMSTATE_UINT32(systick.control, nvic_state), |
444 |
VMSTATE_UINT32(systick.reload, nvic_state), |
445 |
VMSTATE_INT64(systick.tick, nvic_state), |
446 |
VMSTATE_TIMER(systick.timer, nvic_state), |
447 |
VMSTATE_END_OF_LIST() |
448 |
} |
449 |
}; |
450 |
|
451 |
static void armv7m_nvic_reset(DeviceState *dev) |
452 |
{ |
453 |
nvic_state *s = NVIC(dev); |
454 |
NVICClass *nc = NVIC_GET_CLASS(s); |
455 |
nc->parent_reset(dev); |
456 |
/* Common GIC reset resets to disabled; the NVIC doesn't have
|
457 |
* per-CPU interfaces so mark our non-existent CPU interface
|
458 |
* as enabled by default, and with a priority mask which allows
|
459 |
* all interrupts through.
|
460 |
*/
|
461 |
s->gic.cpu_enabled[0] = 1; |
462 |
s->gic.priority_mask[0] = 0x100; |
463 |
/* The NVIC as a whole is always enabled. */
|
464 |
s->gic.enabled = 1;
|
465 |
systick_reset(s); |
466 |
} |
467 |
|
468 |
static int armv7m_nvic_init(SysBusDevice *dev) |
469 |
{ |
470 |
nvic_state *s = NVIC(dev); |
471 |
NVICClass *nc = NVIC_GET_CLASS(s); |
472 |
|
473 |
/* The NVIC always has only one CPU */
|
474 |
s->gic.num_cpu = 1;
|
475 |
/* Tell the common code we're an NVIC */
|
476 |
s->gic.revision = 0xffffffff;
|
477 |
s->num_irq = s->gic.num_irq; |
478 |
nc->parent_init(dev); |
479 |
gic_init_irqs_and_distributor(&s->gic, s->num_irq); |
480 |
/* The NVIC and system controller register area looks like this:
|
481 |
* 0..0xff : system control registers, including systick
|
482 |
* 0x100..0xcff : GIC-like registers
|
483 |
* 0xd00..0xfff : system control registers
|
484 |
* We use overlaying to put the GIC like registers
|
485 |
* over the top of the system control register region.
|
486 |
*/
|
487 |
memory_region_init(&s->container, "nvic", 0x1000); |
488 |
/* The system register region goes at the bottom of the priority
|
489 |
* stack as it covers the whole page.
|
490 |
*/
|
491 |
memory_region_init_io(&s->sysregmem, &nvic_sysreg_ops, s, |
492 |
"nvic_sysregs", 0x1000); |
493 |
memory_region_add_subregion(&s->container, 0, &s->sysregmem);
|
494 |
/* Alias the GIC region so we can get only the section of it
|
495 |
* we need, and layer it on top of the system register region.
|
496 |
*/
|
497 |
memory_region_init_alias(&s->gic_iomem_alias, "nvic-gic", &s->gic.iomem,
|
498 |
0x100, 0xc00); |
499 |
memory_region_add_subregion_overlap(&s->container, 0x100,
|
500 |
&s->gic_iomem_alias, 1);
|
501 |
/* Map the whole thing into system memory at the location required
|
502 |
* by the v7M architecture.
|
503 |
*/
|
504 |
memory_region_add_subregion(get_system_memory(), 0xe000e000, &s->container);
|
505 |
s->systick.timer = qemu_new_timer_ns(vm_clock, systick_timer_tick, s); |
506 |
return 0; |
507 |
} |
508 |
|
509 |
static void armv7m_nvic_instance_init(Object *obj) |
510 |
{ |
511 |
/* We have a different default value for the num-irq property
|
512 |
* than our superclass. This function runs after qdev init
|
513 |
* has set the defaults from the Property array and before
|
514 |
* any user-specified property setting, so just modify the
|
515 |
* value in the GICState struct.
|
516 |
*/
|
517 |
GICState *s = ARM_GIC_COMMON(obj); |
518 |
/* The ARM v7m may have anything from 0 to 496 external interrupt
|
519 |
* IRQ lines. We default to 64. Other boards may differ and should
|
520 |
* set the num-irq property appropriately.
|
521 |
*/
|
522 |
s->num_irq = 64;
|
523 |
} |
524 |
|
525 |
static void armv7m_nvic_class_init(ObjectClass *klass, void *data) |
526 |
{ |
527 |
NVICClass *nc = NVIC_CLASS(klass); |
528 |
DeviceClass *dc = DEVICE_CLASS(klass); |
529 |
SysBusDeviceClass *sdc = SYS_BUS_DEVICE_CLASS(klass); |
530 |
|
531 |
nc->parent_reset = dc->reset; |
532 |
nc->parent_init = sdc->init; |
533 |
sdc->init = armv7m_nvic_init; |
534 |
dc->vmsd = &vmstate_nvic; |
535 |
dc->reset = armv7m_nvic_reset; |
536 |
} |
537 |
|
538 |
static TypeInfo armv7m_nvic_info = {
|
539 |
.name = TYPE_NVIC, |
540 |
.parent = TYPE_ARM_GIC_COMMON, |
541 |
.instance_init = armv7m_nvic_instance_init, |
542 |
.instance_size = sizeof(nvic_state),
|
543 |
.class_init = armv7m_nvic_class_init, |
544 |
.class_size = sizeof(NVICClass),
|
545 |
}; |
546 |
|
547 |
static void armv7m_nvic_register_types(void) |
548 |
{ |
549 |
type_register_static(&armv7m_nvic_info); |
550 |
} |
551 |
|
552 |
type_init(armv7m_nvic_register_types) |