File: | hw/intc/omap_intc.c |
Location: | line 565, column 19 |
Description: | Access to field 'swi' results in a dereference of a null pointer (loaded from variable 'bank') |
1 | /* | |||
2 | * TI OMAP interrupt controller emulation. | |||
3 | * | |||
4 | * Copyright (C) 2006-2008 Andrzej Zaborowski <balrog@zabor.org> | |||
5 | * Copyright (C) 2007-2008 Nokia Corporation | |||
6 | * | |||
7 | * This program is free software; you can redistribute it and/or | |||
8 | * modify it under the terms of the GNU General Public License as | |||
9 | * published by the Free Software Foundation; either version 2 or | |||
10 | * (at your option) version 3 of the License. | |||
11 | * | |||
12 | * This program is distributed in the hope that it will be useful, | |||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
15 | * GNU General Public License for more details. | |||
16 | * | |||
17 | * You should have received a copy of the GNU General Public License along | |||
18 | * with this program; if not, see <http://www.gnu.org/licenses/>. | |||
19 | */ | |||
20 | #include "hw/hw.h" | |||
21 | #include "hw/arm/omap.h" | |||
22 | #include "hw/sysbus.h" | |||
23 | ||||
24 | /* Interrupt Handlers */ | |||
25 | struct omap_intr_handler_bank_s { | |||
26 | uint32_t irqs; | |||
27 | uint32_t inputs; | |||
28 | uint32_t mask; | |||
29 | uint32_t fiq; | |||
30 | uint32_t sens_edge; | |||
31 | uint32_t swi; | |||
32 | unsigned char priority[32]; | |||
33 | }; | |||
34 | ||||
35 | #define TYPE_OMAP_INTC"common-omap-intc" "common-omap-intc" | |||
36 | #define OMAP_INTC(obj)((struct omap_intr_handler_s *)object_dynamic_cast_assert(((Object *)((obj))), ("common-omap-intc"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 36, __func__)) \ | |||
37 | OBJECT_CHECK(struct omap_intr_handler_s, (obj), TYPE_OMAP_INTC)((struct omap_intr_handler_s *)object_dynamic_cast_assert(((Object *)((obj))), ("common-omap-intc"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 37, __func__)) | |||
38 | ||||
39 | struct omap_intr_handler_s { | |||
40 | SysBusDevice parent_obj; | |||
41 | ||||
42 | qemu_irq *pins; | |||
43 | qemu_irq parent_intr[2]; | |||
44 | MemoryRegion mmio; | |||
45 | void *iclk; | |||
46 | void *fclk; | |||
47 | unsigned char nbanks; | |||
48 | int level_only; | |||
49 | uint32_t size; | |||
50 | ||||
51 | uint8_t revision; | |||
52 | ||||
53 | /* state */ | |||
54 | uint32_t new_agr[2]; | |||
55 | int sir_intr[2]; | |||
56 | int autoidle; | |||
57 | uint32_t mask; | |||
58 | struct omap_intr_handler_bank_s bank[3]; | |||
59 | }; | |||
60 | ||||
61 | static void omap_inth_sir_update(struct omap_intr_handler_s *s, int is_fiq) | |||
62 | { | |||
63 | int i, j, sir_intr, p_intr, p, f; | |||
64 | uint32_t level; | |||
65 | sir_intr = 0; | |||
66 | p_intr = 255; | |||
67 | ||||
68 | /* Find the interrupt line with the highest dynamic priority. | |||
69 | * Note: 0 denotes the hightest priority. | |||
70 | * If all interrupts have the same priority, the default order is IRQ_N, | |||
71 | * IRQ_N-1,...,IRQ_0. */ | |||
72 | for (j = 0; j < s->nbanks; ++j) { | |||
73 | level = s->bank[j].irqs & ~s->bank[j].mask & | |||
74 | (is_fiq ? s->bank[j].fiq : ~s->bank[j].fiq); | |||
75 | for (f = ffs(level), i = f - 1, level >>= f - 1; f; i += f, | |||
76 | level >>= f) { | |||
77 | p = s->bank[j].priority[i]; | |||
78 | if (p <= p_intr) { | |||
79 | p_intr = p; | |||
80 | sir_intr = 32 * j + i; | |||
81 | } | |||
82 | f = ffs(level >> 1); | |||
83 | } | |||
84 | } | |||
85 | s->sir_intr[is_fiq] = sir_intr; | |||
86 | } | |||
87 | ||||
88 | static inline void omap_inth_update(struct omap_intr_handler_s *s, int is_fiq) | |||
89 | { | |||
90 | int i; | |||
91 | uint32_t has_intr = 0; | |||
92 | ||||
93 | for (i = 0; i < s->nbanks; ++i) | |||
94 | has_intr |= s->bank[i].irqs & ~s->bank[i].mask & | |||
95 | (is_fiq ? s->bank[i].fiq : ~s->bank[i].fiq); | |||
96 | ||||
97 | if (s->new_agr[is_fiq] & has_intr & s->mask) { | |||
98 | s->new_agr[is_fiq] = 0; | |||
99 | omap_inth_sir_update(s, is_fiq); | |||
100 | qemu_set_irq(s->parent_intr[is_fiq], 1); | |||
101 | } | |||
102 | } | |||
103 | ||||
104 | #define INT_FALLING_EDGE0 0 | |||
105 | #define INT_LOW_LEVEL1 1 | |||
106 | ||||
107 | static void omap_set_intr(void *opaque, int irq, int req) | |||
108 | { | |||
109 | struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; | |||
110 | uint32_t rise; | |||
111 | ||||
112 | struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; | |||
113 | int n = irq & 31; | |||
114 | ||||
115 | if (req) { | |||
116 | rise = ~bank->irqs & (1 << n); | |||
117 | if (~bank->sens_edge & (1 << n)) | |||
118 | rise &= ~bank->inputs; | |||
119 | ||||
120 | bank->inputs |= (1 << n); | |||
121 | if (rise) { | |||
122 | bank->irqs |= rise; | |||
123 | omap_inth_update(ih, 0); | |||
124 | omap_inth_update(ih, 1); | |||
125 | } | |||
126 | } else { | |||
127 | rise = bank->sens_edge & bank->irqs & (1 << n); | |||
128 | bank->irqs &= ~rise; | |||
129 | bank->inputs &= ~(1 << n); | |||
130 | } | |||
131 | } | |||
132 | ||||
133 | /* Simplified version with no edge detection */ | |||
134 | static void omap_set_intr_noedge(void *opaque, int irq, int req) | |||
135 | { | |||
136 | struct omap_intr_handler_s *ih = (struct omap_intr_handler_s *) opaque; | |||
137 | uint32_t rise; | |||
138 | ||||
139 | struct omap_intr_handler_bank_s *bank = &ih->bank[irq >> 5]; | |||
140 | int n = irq & 31; | |||
141 | ||||
142 | if (req) { | |||
143 | rise = ~bank->inputs & (1 << n); | |||
144 | if (rise) { | |||
145 | bank->irqs |= bank->inputs |= rise; | |||
146 | omap_inth_update(ih, 0); | |||
147 | omap_inth_update(ih, 1); | |||
148 | } | |||
149 | } else | |||
150 | bank->irqs = (bank->inputs &= ~(1 << n)) | bank->swi; | |||
151 | } | |||
152 | ||||
153 | static uint64_t omap_inth_read(void *opaque, hwaddr addr, | |||
154 | unsigned size) | |||
155 | { | |||
156 | struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; | |||
157 | int i, offset = addr; | |||
158 | int bank_no = offset >> 8; | |||
159 | int line_no; | |||
160 | struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; | |||
161 | offset &= 0xff; | |||
162 | ||||
163 | switch (offset) { | |||
164 | case 0x00: /* ITR */ | |||
165 | return bank->irqs; | |||
166 | ||||
167 | case 0x04: /* MIR */ | |||
168 | return bank->mask; | |||
169 | ||||
170 | case 0x10: /* SIR_IRQ_CODE */ | |||
171 | case 0x14: /* SIR_FIQ_CODE */ | |||
172 | if (bank_no != 0) | |||
173 | break; | |||
174 | line_no = s->sir_intr[(offset - 0x10) >> 2]; | |||
175 | bank = &s->bank[line_no >> 5]; | |||
176 | i = line_no & 31; | |||
177 | if (((bank->sens_edge >> i) & 1) == INT_FALLING_EDGE0) | |||
178 | bank->irqs &= ~(1 << i); | |||
179 | return line_no; | |||
180 | ||||
181 | case 0x18: /* CONTROL_REG */ | |||
182 | if (bank_no != 0) | |||
183 | break; | |||
184 | return 0; | |||
185 | ||||
186 | case 0x1c: /* ILR0 */ | |||
187 | case 0x20: /* ILR1 */ | |||
188 | case 0x24: /* ILR2 */ | |||
189 | case 0x28: /* ILR3 */ | |||
190 | case 0x2c: /* ILR4 */ | |||
191 | case 0x30: /* ILR5 */ | |||
192 | case 0x34: /* ILR6 */ | |||
193 | case 0x38: /* ILR7 */ | |||
194 | case 0x3c: /* ILR8 */ | |||
195 | case 0x40: /* ILR9 */ | |||
196 | case 0x44: /* ILR10 */ | |||
197 | case 0x48: /* ILR11 */ | |||
198 | case 0x4c: /* ILR12 */ | |||
199 | case 0x50: /* ILR13 */ | |||
200 | case 0x54: /* ILR14 */ | |||
201 | case 0x58: /* ILR15 */ | |||
202 | case 0x5c: /* ILR16 */ | |||
203 | case 0x60: /* ILR17 */ | |||
204 | case 0x64: /* ILR18 */ | |||
205 | case 0x68: /* ILR19 */ | |||
206 | case 0x6c: /* ILR20 */ | |||
207 | case 0x70: /* ILR21 */ | |||
208 | case 0x74: /* ILR22 */ | |||
209 | case 0x78: /* ILR23 */ | |||
210 | case 0x7c: /* ILR24 */ | |||
211 | case 0x80: /* ILR25 */ | |||
212 | case 0x84: /* ILR26 */ | |||
213 | case 0x88: /* ILR27 */ | |||
214 | case 0x8c: /* ILR28 */ | |||
215 | case 0x90: /* ILR29 */ | |||
216 | case 0x94: /* ILR30 */ | |||
217 | case 0x98: /* ILR31 */ | |||
218 | i = (offset - 0x1c) >> 2; | |||
219 | return (bank->priority[i] << 2) | | |||
220 | (((bank->sens_edge >> i) & 1) << 1) | | |||
221 | ((bank->fiq >> i) & 1); | |||
222 | ||||
223 | case 0x9c: /* ISR */ | |||
224 | return 0x00000000; | |||
225 | ||||
226 | } | |||
227 | OMAP_BAD_REG(addr)fprintf(stderr, "%s: Bad register " "%#08" "l" "x" "\n", __FUNCTION__ , addr); | |||
228 | return 0; | |||
229 | } | |||
230 | ||||
231 | static void omap_inth_write(void *opaque, hwaddr addr, | |||
232 | uint64_t value, unsigned size) | |||
233 | { | |||
234 | struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; | |||
235 | int i, offset = addr; | |||
236 | int bank_no = offset >> 8; | |||
237 | struct omap_intr_handler_bank_s *bank = &s->bank[bank_no]; | |||
238 | offset &= 0xff; | |||
239 | ||||
240 | switch (offset) { | |||
241 | case 0x00: /* ITR */ | |||
242 | /* Important: ignore the clearing if the IRQ is level-triggered and | |||
243 | the input bit is 1 */ | |||
244 | bank->irqs &= value | (bank->inputs & bank->sens_edge); | |||
245 | return; | |||
246 | ||||
247 | case 0x04: /* MIR */ | |||
248 | bank->mask = value; | |||
249 | omap_inth_update(s, 0); | |||
250 | omap_inth_update(s, 1); | |||
251 | return; | |||
252 | ||||
253 | case 0x10: /* SIR_IRQ_CODE */ | |||
254 | case 0x14: /* SIR_FIQ_CODE */ | |||
255 | OMAP_RO_REG(addr)fprintf(stderr, "%s: Read-only register " "%#08" "l" "x" "\n" , __FUNCTION__, addr); | |||
256 | break; | |||
257 | ||||
258 | case 0x18: /* CONTROL_REG */ | |||
259 | if (bank_no != 0) | |||
260 | break; | |||
261 | if (value & 2) { | |||
262 | qemu_set_irq(s->parent_intr[1], 0); | |||
263 | s->new_agr[1] = ~0; | |||
264 | omap_inth_update(s, 1); | |||
265 | } | |||
266 | if (value & 1) { | |||
267 | qemu_set_irq(s->parent_intr[0], 0); | |||
268 | s->new_agr[0] = ~0; | |||
269 | omap_inth_update(s, 0); | |||
270 | } | |||
271 | return; | |||
272 | ||||
273 | case 0x1c: /* ILR0 */ | |||
274 | case 0x20: /* ILR1 */ | |||
275 | case 0x24: /* ILR2 */ | |||
276 | case 0x28: /* ILR3 */ | |||
277 | case 0x2c: /* ILR4 */ | |||
278 | case 0x30: /* ILR5 */ | |||
279 | case 0x34: /* ILR6 */ | |||
280 | case 0x38: /* ILR7 */ | |||
281 | case 0x3c: /* ILR8 */ | |||
282 | case 0x40: /* ILR9 */ | |||
283 | case 0x44: /* ILR10 */ | |||
284 | case 0x48: /* ILR11 */ | |||
285 | case 0x4c: /* ILR12 */ | |||
286 | case 0x50: /* ILR13 */ | |||
287 | case 0x54: /* ILR14 */ | |||
288 | case 0x58: /* ILR15 */ | |||
289 | case 0x5c: /* ILR16 */ | |||
290 | case 0x60: /* ILR17 */ | |||
291 | case 0x64: /* ILR18 */ | |||
292 | case 0x68: /* ILR19 */ | |||
293 | case 0x6c: /* ILR20 */ | |||
294 | case 0x70: /* ILR21 */ | |||
295 | case 0x74: /* ILR22 */ | |||
296 | case 0x78: /* ILR23 */ | |||
297 | case 0x7c: /* ILR24 */ | |||
298 | case 0x80: /* ILR25 */ | |||
299 | case 0x84: /* ILR26 */ | |||
300 | case 0x88: /* ILR27 */ | |||
301 | case 0x8c: /* ILR28 */ | |||
302 | case 0x90: /* ILR29 */ | |||
303 | case 0x94: /* ILR30 */ | |||
304 | case 0x98: /* ILR31 */ | |||
305 | i = (offset - 0x1c) >> 2; | |||
306 | bank->priority[i] = (value >> 2) & 0x1f; | |||
307 | bank->sens_edge &= ~(1 << i); | |||
308 | bank->sens_edge |= ((value >> 1) & 1) << i; | |||
309 | bank->fiq &= ~(1 << i); | |||
310 | bank->fiq |= (value & 1) << i; | |||
311 | return; | |||
312 | ||||
313 | case 0x9c: /* ISR */ | |||
314 | for (i = 0; i < 32; i ++) | |||
315 | if (value & (1 << i)) { | |||
316 | omap_set_intr(s, 32 * bank_no + i, 1); | |||
317 | return; | |||
318 | } | |||
319 | return; | |||
320 | } | |||
321 | OMAP_BAD_REG(addr)fprintf(stderr, "%s: Bad register " "%#08" "l" "x" "\n", __FUNCTION__ , addr); | |||
322 | } | |||
323 | ||||
324 | static const MemoryRegionOps omap_inth_mem_ops = { | |||
325 | .read = omap_inth_read, | |||
326 | .write = omap_inth_write, | |||
327 | .endianness = DEVICE_NATIVE_ENDIAN, | |||
328 | .valid = { | |||
329 | .min_access_size = 4, | |||
330 | .max_access_size = 4, | |||
331 | }, | |||
332 | }; | |||
333 | ||||
334 | static void omap_inth_reset(DeviceState *dev) | |||
335 | { | |||
336 | struct omap_intr_handler_s *s = OMAP_INTC(dev)((struct omap_intr_handler_s *)object_dynamic_cast_assert(((Object *)((dev))), ("common-omap-intc"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 336, __func__)); | |||
337 | int i; | |||
338 | ||||
339 | for (i = 0; i < s->nbanks; ++i){ | |||
340 | s->bank[i].irqs = 0x00000000; | |||
341 | s->bank[i].mask = 0xffffffff; | |||
342 | s->bank[i].sens_edge = 0x00000000; | |||
343 | s->bank[i].fiq = 0x00000000; | |||
344 | s->bank[i].inputs = 0x00000000; | |||
345 | s->bank[i].swi = 0x00000000; | |||
346 | memset(s->bank[i].priority, 0, sizeof(s->bank[i].priority)); | |||
347 | ||||
348 | if (s->level_only) | |||
349 | s->bank[i].sens_edge = 0xffffffff; | |||
350 | } | |||
351 | ||||
352 | s->new_agr[0] = ~0; | |||
353 | s->new_agr[1] = ~0; | |||
354 | s->sir_intr[0] = 0; | |||
355 | s->sir_intr[1] = 0; | |||
356 | s->autoidle = 0; | |||
357 | s->mask = ~0; | |||
358 | ||||
359 | qemu_set_irq(s->parent_intr[0], 0); | |||
360 | qemu_set_irq(s->parent_intr[1], 0); | |||
361 | } | |||
362 | ||||
363 | static int omap_intc_init(SysBusDevice *sbd) | |||
364 | { | |||
365 | DeviceState *dev = DEVICE(sbd)((DeviceState *)object_dynamic_cast_assert(((Object *)((sbd)) ), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 365, __func__)); | |||
366 | struct omap_intr_handler_s *s = OMAP_INTC(dev)((struct omap_intr_handler_s *)object_dynamic_cast_assert(((Object *)((dev))), ("common-omap-intc"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 366, __func__)); | |||
367 | ||||
368 | if (!s->iclk) { | |||
369 | hw_error("omap-intc: clk not connected\n"); | |||
370 | } | |||
371 | s->nbanks = 1; | |||
372 | sysbus_init_irq(sbd, &s->parent_intr[0]); | |||
373 | sysbus_init_irq(sbd, &s->parent_intr[1]); | |||
374 | qdev_init_gpio_in(dev, omap_set_intr, s->nbanks * 32); | |||
375 | memory_region_init_io(&s->mmio, OBJECT(s)((Object *)(s)), &omap_inth_mem_ops, s, | |||
376 | "omap-intc", s->size); | |||
377 | sysbus_init_mmio(sbd, &s->mmio); | |||
378 | return 0; | |||
379 | } | |||
380 | ||||
381 | static Property omap_intc_properties[] = { | |||
382 | DEFINE_PROP_UINT32("size", struct omap_intr_handler_s, size, 0x100){ .name = ("size"), .info = &(qdev_prop_uint32), .offset = __builtin_offsetof(struct omap_intr_handler_s, size) + ((uint32_t *)0 - (typeof(((struct omap_intr_handler_s *)0)->size)*)0) , .qtype = QTYPE_QINT, .defval = (uint32_t)0x100, }, | |||
383 | DEFINE_PROP_PTR("clk", struct omap_intr_handler_s, iclk){ .name = ("clk"), .info = &(qdev_prop_ptr), .offset = __builtin_offsetof (struct omap_intr_handler_s, iclk) + ((void**)0 - (typeof(((struct omap_intr_handler_s *)0)->iclk)*)0), }, | |||
384 | DEFINE_PROP_END_OF_LIST(){}, | |||
385 | }; | |||
386 | ||||
387 | static void omap_intc_class_init(ObjectClass *klass, void *data) | |||
388 | { | |||
389 | DeviceClass *dc = DEVICE_CLASS(klass)((DeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 389, __func__)); | |||
390 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass)((SysBusDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 390, __func__)); | |||
391 | ||||
392 | k->init = omap_intc_init; | |||
393 | dc->reset = omap_inth_reset; | |||
394 | dc->props = omap_intc_properties; | |||
395 | /* Reason: pointer property "clk" */ | |||
396 | dc->cannot_instantiate_with_device_add_yet = true1; | |||
397 | } | |||
398 | ||||
399 | static const TypeInfo omap_intc_info = { | |||
400 | .name = "omap-intc", | |||
401 | .parent = TYPE_OMAP_INTC"common-omap-intc", | |||
402 | .class_init = omap_intc_class_init, | |||
403 | }; | |||
404 | ||||
405 | static uint64_t omap2_inth_read(void *opaque, hwaddr addr, | |||
406 | unsigned size) | |||
407 | { | |||
408 | struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; | |||
409 | int offset = addr; | |||
410 | int bank_no, line_no; | |||
411 | struct omap_intr_handler_bank_s *bank = NULL((void*)0); | |||
412 | ||||
413 | if ((offset & 0xf80) == 0x80) { | |||
414 | bank_no = (offset & 0x60) >> 5; | |||
415 | if (bank_no < s->nbanks) { | |||
416 | offset &= ~0x60; | |||
417 | bank = &s->bank[bank_no]; | |||
418 | } else { | |||
419 | OMAP_BAD_REG(addr)fprintf(stderr, "%s: Bad register " "%#08" "l" "x" "\n", __FUNCTION__ , addr); | |||
420 | return 0; | |||
421 | } | |||
422 | } | |||
423 | ||||
424 | switch (offset) { | |||
425 | case 0x00: /* INTC_REVISION */ | |||
426 | return s->revision; | |||
427 | ||||
428 | case 0x10: /* INTC_SYSCONFIG */ | |||
429 | return (s->autoidle >> 2) & 1; | |||
430 | ||||
431 | case 0x14: /* INTC_SYSSTATUS */ | |||
432 | return 1; /* RESETDONE */ | |||
433 | ||||
434 | case 0x40: /* INTC_SIR_IRQ */ | |||
435 | return s->sir_intr[0]; | |||
436 | ||||
437 | case 0x44: /* INTC_SIR_FIQ */ | |||
438 | return s->sir_intr[1]; | |||
439 | ||||
440 | case 0x48: /* INTC_CONTROL */ | |||
441 | return (!s->mask) << 2; /* GLOBALMASK */ | |||
442 | ||||
443 | case 0x4c: /* INTC_PROTECTION */ | |||
444 | return 0; | |||
445 | ||||
446 | case 0x50: /* INTC_IDLE */ | |||
447 | return s->autoidle & 3; | |||
448 | ||||
449 | /* Per-bank registers */ | |||
450 | case 0x80: /* INTC_ITR */ | |||
451 | return bank->inputs; | |||
452 | ||||
453 | case 0x84: /* INTC_MIR */ | |||
454 | return bank->mask; | |||
455 | ||||
456 | case 0x88: /* INTC_MIR_CLEAR */ | |||
457 | case 0x8c: /* INTC_MIR_SET */ | |||
458 | return 0; | |||
459 | ||||
460 | case 0x90: /* INTC_ISR_SET */ | |||
461 | return bank->swi; | |||
462 | ||||
463 | case 0x94: /* INTC_ISR_CLEAR */ | |||
464 | return 0; | |||
465 | ||||
466 | case 0x98: /* INTC_PENDING_IRQ */ | |||
467 | return bank->irqs & ~bank->mask & ~bank->fiq; | |||
468 | ||||
469 | case 0x9c: /* INTC_PENDING_FIQ */ | |||
470 | return bank->irqs & ~bank->mask & bank->fiq; | |||
471 | ||||
472 | /* Per-line registers */ | |||
473 | case 0x100 ... 0x300: /* INTC_ILR */ | |||
474 | bank_no = (offset - 0x100) >> 7; | |||
475 | if (bank_no > s->nbanks) | |||
476 | break; | |||
477 | bank = &s->bank[bank_no]; | |||
478 | line_no = (offset & 0x7f) >> 2; | |||
479 | return (bank->priority[line_no] << 2) | | |||
480 | ((bank->fiq >> line_no) & 1); | |||
481 | } | |||
482 | OMAP_BAD_REG(addr)fprintf(stderr, "%s: Bad register " "%#08" "l" "x" "\n", __FUNCTION__ , addr); | |||
483 | return 0; | |||
484 | } | |||
485 | ||||
486 | static void omap2_inth_write(void *opaque, hwaddr addr, | |||
487 | uint64_t value, unsigned size) | |||
488 | { | |||
489 | struct omap_intr_handler_s *s = (struct omap_intr_handler_s *) opaque; | |||
490 | int offset = addr; | |||
491 | int bank_no, line_no; | |||
492 | struct omap_intr_handler_bank_s *bank = NULL((void*)0); | |||
| ||||
493 | ||||
494 | if ((offset & 0xf80) == 0x80) { | |||
495 | bank_no = (offset & 0x60) >> 5; | |||
496 | if (bank_no < s->nbanks) { | |||
497 | offset &= ~0x60; | |||
498 | bank = &s->bank[bank_no]; | |||
499 | } else { | |||
500 | OMAP_BAD_REG(addr)fprintf(stderr, "%s: Bad register " "%#08" "l" "x" "\n", __FUNCTION__ , addr); | |||
501 | return; | |||
502 | } | |||
503 | } | |||
504 | ||||
505 | switch (offset) { | |||
506 | case 0x10: /* INTC_SYSCONFIG */ | |||
507 | s->autoidle &= 4; | |||
508 | s->autoidle |= (value & 1) << 2; | |||
509 | if (value & 2) { /* SOFTRESET */ | |||
510 | omap_inth_reset(DEVICE(s)((DeviceState *)object_dynamic_cast_assert(((Object *)((s))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 510, __func__))); | |||
511 | } | |||
512 | return; | |||
513 | ||||
514 | case 0x48: /* INTC_CONTROL */ | |||
515 | s->mask = (value & 4) ? 0 : ~0; /* GLOBALMASK */ | |||
516 | if (value & 2) { /* NEWFIQAGR */ | |||
517 | qemu_set_irq(s->parent_intr[1], 0); | |||
518 | s->new_agr[1] = ~0; | |||
519 | omap_inth_update(s, 1); | |||
520 | } | |||
521 | if (value & 1) { /* NEWIRQAGR */ | |||
522 | qemu_set_irq(s->parent_intr[0], 0); | |||
523 | s->new_agr[0] = ~0; | |||
524 | omap_inth_update(s, 0); | |||
525 | } | |||
526 | return; | |||
527 | ||||
528 | case 0x4c: /* INTC_PROTECTION */ | |||
529 | /* TODO: Make a bitmap (or sizeof(char)map) of access privileges | |||
530 | * for every register, see Chapter 3 and 4 for privileged mode. */ | |||
531 | if (value & 1) | |||
532 | fprintf(stderrstderr, "%s: protection mode enable attempt\n", | |||
533 | __FUNCTION__); | |||
534 | return; | |||
535 | ||||
536 | case 0x50: /* INTC_IDLE */ | |||
537 | s->autoidle &= ~3; | |||
538 | s->autoidle |= value & 3; | |||
539 | return; | |||
540 | ||||
541 | /* Per-bank registers */ | |||
542 | case 0x84: /* INTC_MIR */ | |||
543 | bank->mask = value; | |||
544 | omap_inth_update(s, 0); | |||
545 | omap_inth_update(s, 1); | |||
546 | return; | |||
547 | ||||
548 | case 0x88: /* INTC_MIR_CLEAR */ | |||
549 | bank->mask &= ~value; | |||
550 | omap_inth_update(s, 0); | |||
551 | omap_inth_update(s, 1); | |||
552 | return; | |||
553 | ||||
554 | case 0x8c: /* INTC_MIR_SET */ | |||
555 | bank->mask |= value; | |||
556 | return; | |||
557 | ||||
558 | case 0x90: /* INTC_ISR_SET */ | |||
559 | bank->irqs |= bank->swi |= value; | |||
560 | omap_inth_update(s, 0); | |||
561 | omap_inth_update(s, 1); | |||
562 | return; | |||
563 | ||||
564 | case 0x94: /* INTC_ISR_CLEAR */ | |||
565 | bank->swi &= ~value; | |||
| ||||
566 | bank->irqs = bank->swi & bank->inputs; | |||
567 | return; | |||
568 | ||||
569 | /* Per-line registers */ | |||
570 | case 0x100 ... 0x300: /* INTC_ILR */ | |||
571 | bank_no = (offset - 0x100) >> 7; | |||
572 | if (bank_no > s->nbanks) | |||
573 | break; | |||
574 | bank = &s->bank[bank_no]; | |||
575 | line_no = (offset & 0x7f) >> 2; | |||
576 | bank->priority[line_no] = (value >> 2) & 0x3f; | |||
577 | bank->fiq &= ~(1 << line_no); | |||
578 | bank->fiq |= (value & 1) << line_no; | |||
579 | return; | |||
580 | ||||
581 | case 0x00: /* INTC_REVISION */ | |||
582 | case 0x14: /* INTC_SYSSTATUS */ | |||
583 | case 0x40: /* INTC_SIR_IRQ */ | |||
584 | case 0x44: /* INTC_SIR_FIQ */ | |||
585 | case 0x80: /* INTC_ITR */ | |||
586 | case 0x98: /* INTC_PENDING_IRQ */ | |||
587 | case 0x9c: /* INTC_PENDING_FIQ */ | |||
588 | OMAP_RO_REG(addr)fprintf(stderr, "%s: Read-only register " "%#08" "l" "x" "\n" , __FUNCTION__, addr); | |||
589 | return; | |||
590 | } | |||
591 | OMAP_BAD_REG(addr)fprintf(stderr, "%s: Bad register " "%#08" "l" "x" "\n", __FUNCTION__ , addr); | |||
592 | } | |||
593 | ||||
594 | static const MemoryRegionOps omap2_inth_mem_ops = { | |||
595 | .read = omap2_inth_read, | |||
596 | .write = omap2_inth_write, | |||
597 | .endianness = DEVICE_NATIVE_ENDIAN, | |||
598 | .valid = { | |||
599 | .min_access_size = 4, | |||
600 | .max_access_size = 4, | |||
601 | }, | |||
602 | }; | |||
603 | ||||
604 | static int omap2_intc_init(SysBusDevice *sbd) | |||
605 | { | |||
606 | DeviceState *dev = DEVICE(sbd)((DeviceState *)object_dynamic_cast_assert(((Object *)((sbd)) ), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 606, __func__)); | |||
607 | struct omap_intr_handler_s *s = OMAP_INTC(dev)((struct omap_intr_handler_s *)object_dynamic_cast_assert(((Object *)((dev))), ("common-omap-intc"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 607, __func__)); | |||
608 | ||||
609 | if (!s->iclk) { | |||
610 | hw_error("omap2-intc: iclk not connected\n"); | |||
611 | } | |||
612 | if (!s->fclk) { | |||
613 | hw_error("omap2-intc: fclk not connected\n"); | |||
614 | } | |||
615 | s->level_only = 1; | |||
616 | s->nbanks = 3; | |||
617 | sysbus_init_irq(sbd, &s->parent_intr[0]); | |||
618 | sysbus_init_irq(sbd, &s->parent_intr[1]); | |||
619 | qdev_init_gpio_in(dev, omap_set_intr_noedge, s->nbanks * 32); | |||
620 | memory_region_init_io(&s->mmio, OBJECT(s)((Object *)(s)), &omap2_inth_mem_ops, s, | |||
621 | "omap2-intc", 0x1000); | |||
622 | sysbus_init_mmio(sbd, &s->mmio); | |||
623 | return 0; | |||
624 | } | |||
625 | ||||
626 | static Property omap2_intc_properties[] = { | |||
627 | DEFINE_PROP_UINT8("revision", struct omap_intr_handler_s,{ .name = ("revision"), .info = &(qdev_prop_uint8), .offset = __builtin_offsetof(struct omap_intr_handler_s, revision) + ((uint8_t*)0 - (typeof(((struct omap_intr_handler_s *)0)-> revision)*)0), .qtype = QTYPE_QINT, .defval = (uint8_t)0x21, } | |||
628 | revision, 0x21){ .name = ("revision"), .info = &(qdev_prop_uint8), .offset = __builtin_offsetof(struct omap_intr_handler_s, revision) + ((uint8_t*)0 - (typeof(((struct omap_intr_handler_s *)0)-> revision)*)0), .qtype = QTYPE_QINT, .defval = (uint8_t)0x21, }, | |||
629 | DEFINE_PROP_PTR("iclk", struct omap_intr_handler_s, iclk){ .name = ("iclk"), .info = &(qdev_prop_ptr), .offset = __builtin_offsetof (struct omap_intr_handler_s, iclk) + ((void**)0 - (typeof(((struct omap_intr_handler_s *)0)->iclk)*)0), }, | |||
630 | DEFINE_PROP_PTR("fclk", struct omap_intr_handler_s, fclk){ .name = ("fclk"), .info = &(qdev_prop_ptr), .offset = __builtin_offsetof (struct omap_intr_handler_s, fclk) + ((void**)0 - (typeof(((struct omap_intr_handler_s *)0)->fclk)*)0), }, | |||
631 | DEFINE_PROP_END_OF_LIST(){}, | |||
632 | }; | |||
633 | ||||
634 | static void omap2_intc_class_init(ObjectClass *klass, void *data) | |||
635 | { | |||
636 | DeviceClass *dc = DEVICE_CLASS(klass)((DeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 636, __func__)); | |||
637 | SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass)((SysBusDeviceClass *)object_class_dynamic_cast_assert(((ObjectClass *)((klass))), ("sys-bus-device"), "/home/stefan/src/qemu/qemu.org/qemu/hw/intc/omap_intc.c" , 637, __func__)); | |||
638 | ||||
639 | k->init = omap2_intc_init; | |||
640 | dc->reset = omap_inth_reset; | |||
641 | dc->props = omap2_intc_properties; | |||
642 | /* Reason: pointer property "iclk", "fclk" */ | |||
643 | dc->cannot_instantiate_with_device_add_yet = true1; | |||
644 | } | |||
645 | ||||
646 | static const TypeInfo omap2_intc_info = { | |||
647 | .name = "omap2-intc", | |||
648 | .parent = TYPE_OMAP_INTC"common-omap-intc", | |||
649 | .class_init = omap2_intc_class_init, | |||
650 | }; | |||
651 | ||||
652 | static const TypeInfo omap_intc_type_info = { | |||
653 | .name = TYPE_OMAP_INTC"common-omap-intc", | |||
654 | .parent = TYPE_SYS_BUS_DEVICE"sys-bus-device", | |||
655 | .instance_size = sizeof(struct omap_intr_handler_s), | |||
656 | .abstract = true1, | |||
657 | }; | |||
658 | ||||
659 | static void omap_intc_register_types(void) | |||
660 | { | |||
661 | type_register_static(&omap_intc_type_info); | |||
662 | type_register_static(&omap_intc_info); | |||
663 | type_register_static(&omap2_intc_info); | |||
664 | } | |||
665 | ||||
666 | type_init(omap_intc_register_types)static void __attribute__((constructor)) do_qemu_init_omap_intc_register_types (void) { register_module_init(omap_intc_register_types, MODULE_INIT_QOM ); } |