1 | /* |
2 | * Arm IoT Kit security controller |
3 | * |
4 | * Copyright (c) 2018 Linaro Limited |
5 | * Written by Peter Maydell |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License version 2 or |
9 | * (at your option) any later version. |
10 | */ |
11 | |
12 | #include "qemu/osdep.h" |
13 | #include "qemu/log.h" |
14 | #include "qemu/module.h" |
15 | #include "qapi/error.h" |
16 | #include "trace.h" |
17 | #include "hw/sysbus.h" |
18 | #include "migration/vmstate.h" |
19 | #include "hw/registerfields.h" |
20 | #include "hw/irq.h" |
21 | #include "hw/misc/iotkit-secctl.h" |
22 | |
23 | /* Registers in the secure privilege control block */ |
24 | REG32(SECRESPCFG, 0x10) |
25 | REG32(NSCCFG, 0x14) |
26 | REG32(SECMPCINTSTATUS, 0x1c) |
27 | REG32(SECPPCINTSTAT, 0x20) |
28 | REG32(SECPPCINTCLR, 0x24) |
29 | REG32(SECPPCINTEN, 0x28) |
30 | REG32(SECMSCINTSTAT, 0x30) |
31 | REG32(SECMSCINTCLR, 0x34) |
32 | REG32(SECMSCINTEN, 0x38) |
33 | REG32(BRGINTSTAT, 0x40) |
34 | REG32(BRGINTCLR, 0x44) |
35 | REG32(BRGINTEN, 0x48) |
36 | REG32(AHBNSPPC0, 0x50) |
37 | REG32(AHBNSPPCEXP0, 0x60) |
38 | REG32(AHBNSPPCEXP1, 0x64) |
39 | REG32(AHBNSPPCEXP2, 0x68) |
40 | REG32(AHBNSPPCEXP3, 0x6c) |
41 | REG32(APBNSPPC0, 0x70) |
42 | REG32(APBNSPPC1, 0x74) |
43 | REG32(APBNSPPCEXP0, 0x80) |
44 | REG32(APBNSPPCEXP1, 0x84) |
45 | REG32(APBNSPPCEXP2, 0x88) |
46 | REG32(APBNSPPCEXP3, 0x8c) |
47 | REG32(AHBSPPPC0, 0x90) |
48 | REG32(AHBSPPPCEXP0, 0xa0) |
49 | REG32(AHBSPPPCEXP1, 0xa4) |
50 | REG32(AHBSPPPCEXP2, 0xa8) |
51 | REG32(AHBSPPPCEXP3, 0xac) |
52 | REG32(APBSPPPC0, 0xb0) |
53 | REG32(APBSPPPC1, 0xb4) |
54 | REG32(APBSPPPCEXP0, 0xc0) |
55 | REG32(APBSPPPCEXP1, 0xc4) |
56 | REG32(APBSPPPCEXP2, 0xc8) |
57 | REG32(APBSPPPCEXP3, 0xcc) |
58 | REG32(NSMSCEXP, 0xd0) |
59 | REG32(PID4, 0xfd0) |
60 | REG32(PID5, 0xfd4) |
61 | REG32(PID6, 0xfd8) |
62 | REG32(PID7, 0xfdc) |
63 | REG32(PID0, 0xfe0) |
64 | REG32(PID1, 0xfe4) |
65 | REG32(PID2, 0xfe8) |
66 | REG32(PID3, 0xfec) |
67 | REG32(CID0, 0xff0) |
68 | REG32(CID1, 0xff4) |
69 | REG32(CID2, 0xff8) |
70 | REG32(CID3, 0xffc) |
71 | |
72 | /* Registers in the non-secure privilege control block */ |
73 | REG32(AHBNSPPPC0, 0x90) |
74 | REG32(AHBNSPPPCEXP0, 0xa0) |
75 | REG32(AHBNSPPPCEXP1, 0xa4) |
76 | REG32(AHBNSPPPCEXP2, 0xa8) |
77 | REG32(AHBNSPPPCEXP3, 0xac) |
78 | REG32(APBNSPPPC0, 0xb0) |
79 | REG32(APBNSPPPC1, 0xb4) |
80 | REG32(APBNSPPPCEXP0, 0xc0) |
81 | REG32(APBNSPPPCEXP1, 0xc4) |
82 | REG32(APBNSPPPCEXP2, 0xc8) |
83 | REG32(APBNSPPPCEXP3, 0xcc) |
84 | /* PID and CID registers are also present in the NS block */ |
85 | |
86 | static const uint8_t iotkit_secctl_s_idregs[] = { |
87 | 0x04, 0x00, 0x00, 0x00, |
88 | 0x52, 0xb8, 0x0b, 0x00, |
89 | 0x0d, 0xf0, 0x05, 0xb1, |
90 | }; |
91 | |
92 | static const uint8_t iotkit_secctl_ns_idregs[] = { |
93 | 0x04, 0x00, 0x00, 0x00, |
94 | 0x53, 0xb8, 0x0b, 0x00, |
95 | 0x0d, 0xf0, 0x05, 0xb1, |
96 | }; |
97 | |
98 | /* The register sets for the various PPCs (AHB internal, APB internal, |
99 | * AHB expansion, APB expansion) are all set up so that they are |
100 | * in 16-aligned blocks so offsets 0xN0, 0xN4, 0xN8, 0xNC are PPCs |
101 | * 0, 1, 2, 3 of that type, so we can convert a register address offset |
102 | * into an an index into a PPC array easily. |
103 | */ |
104 | static inline int offset_to_ppc_idx(uint32_t offset) |
105 | { |
106 | return extract32(offset, 2, 2); |
107 | } |
108 | |
109 | typedef void PerPPCFunction(IoTKitSecCtlPPC *ppc); |
110 | |
111 | static void foreach_ppc(IoTKitSecCtl *s, PerPPCFunction *fn) |
112 | { |
113 | int i; |
114 | |
115 | for (i = 0; i < IOTS_NUM_APB_PPC; i++) { |
116 | fn(&s->apb[i]); |
117 | } |
118 | for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) { |
119 | fn(&s->apbexp[i]); |
120 | } |
121 | for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) { |
122 | fn(&s->ahbexp[i]); |
123 | } |
124 | } |
125 | |
126 | static MemTxResult iotkit_secctl_s_read(void *opaque, hwaddr addr, |
127 | uint64_t *pdata, |
128 | unsigned size, MemTxAttrs attrs) |
129 | { |
130 | uint64_t r; |
131 | uint32_t offset = addr & ~0x3; |
132 | IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); |
133 | |
134 | switch (offset) { |
135 | case A_AHBNSPPC0: |
136 | case A_AHBSPPPC0: |
137 | r = 0; |
138 | break; |
139 | case A_SECRESPCFG: |
140 | r = s->secrespcfg; |
141 | break; |
142 | case A_NSCCFG: |
143 | r = s->nsccfg; |
144 | break; |
145 | case A_SECMPCINTSTATUS: |
146 | r = s->mpcintstatus; |
147 | break; |
148 | case A_SECPPCINTSTAT: |
149 | r = s->secppcintstat; |
150 | break; |
151 | case A_SECPPCINTEN: |
152 | r = s->secppcinten; |
153 | break; |
154 | case A_BRGINTSTAT: |
155 | /* QEMU's bus fabric can never report errors as it doesn't buffer |
156 | * writes, so we never report bridge interrupts. |
157 | */ |
158 | r = 0; |
159 | break; |
160 | case A_BRGINTEN: |
161 | r = s->brginten; |
162 | break; |
163 | case A_AHBNSPPCEXP0: |
164 | case A_AHBNSPPCEXP1: |
165 | case A_AHBNSPPCEXP2: |
166 | case A_AHBNSPPCEXP3: |
167 | r = s->ahbexp[offset_to_ppc_idx(offset)].ns; |
168 | break; |
169 | case A_APBNSPPC0: |
170 | case A_APBNSPPC1: |
171 | r = s->apb[offset_to_ppc_idx(offset)].ns; |
172 | break; |
173 | case A_APBNSPPCEXP0: |
174 | case A_APBNSPPCEXP1: |
175 | case A_APBNSPPCEXP2: |
176 | case A_APBNSPPCEXP3: |
177 | r = s->apbexp[offset_to_ppc_idx(offset)].ns; |
178 | break; |
179 | case A_AHBSPPPCEXP0: |
180 | case A_AHBSPPPCEXP1: |
181 | case A_AHBSPPPCEXP2: |
182 | case A_AHBSPPPCEXP3: |
183 | r = s->apbexp[offset_to_ppc_idx(offset)].sp; |
184 | break; |
185 | case A_APBSPPPC0: |
186 | case A_APBSPPPC1: |
187 | r = s->apb[offset_to_ppc_idx(offset)].sp; |
188 | break; |
189 | case A_APBSPPPCEXP0: |
190 | case A_APBSPPPCEXP1: |
191 | case A_APBSPPPCEXP2: |
192 | case A_APBSPPPCEXP3: |
193 | r = s->apbexp[offset_to_ppc_idx(offset)].sp; |
194 | break; |
195 | case A_SECMSCINTSTAT: |
196 | r = s->secmscintstat; |
197 | break; |
198 | case A_SECMSCINTEN: |
199 | r = s->secmscinten; |
200 | break; |
201 | case A_NSMSCEXP: |
202 | r = s->nsmscexp; |
203 | break; |
204 | case A_PID4: |
205 | case A_PID5: |
206 | case A_PID6: |
207 | case A_PID7: |
208 | case A_PID0: |
209 | case A_PID1: |
210 | case A_PID2: |
211 | case A_PID3: |
212 | case A_CID0: |
213 | case A_CID1: |
214 | case A_CID2: |
215 | case A_CID3: |
216 | r = iotkit_secctl_s_idregs[(offset - A_PID4) / 4]; |
217 | break; |
218 | case A_SECPPCINTCLR: |
219 | case A_SECMSCINTCLR: |
220 | case A_BRGINTCLR: |
221 | qemu_log_mask(LOG_GUEST_ERROR, |
222 | "IotKit SecCtl S block read: write-only offset 0x%x\n" , |
223 | offset); |
224 | r = 0; |
225 | break; |
226 | default: |
227 | qemu_log_mask(LOG_GUEST_ERROR, |
228 | "IotKit SecCtl S block read: bad offset 0x%x\n" , offset); |
229 | r = 0; |
230 | break; |
231 | } |
232 | |
233 | if (size != 4) { |
234 | /* None of our registers are access-sensitive, so just pull the right |
235 | * byte out of the word read result. |
236 | */ |
237 | r = extract32(r, (addr & 3) * 8, size * 8); |
238 | } |
239 | |
240 | trace_iotkit_secctl_s_read(offset, r, size); |
241 | *pdata = r; |
242 | return MEMTX_OK; |
243 | } |
244 | |
245 | static void iotkit_secctl_update_ppc_ap(IoTKitSecCtlPPC *ppc) |
246 | { |
247 | int i; |
248 | |
249 | for (i = 0; i < ppc->numports; i++) { |
250 | bool v; |
251 | |
252 | if (extract32(ppc->ns, i, 1)) { |
253 | v = extract32(ppc->nsp, i, 1); |
254 | } else { |
255 | v = extract32(ppc->sp, i, 1); |
256 | } |
257 | qemu_set_irq(ppc->ap[i], v); |
258 | } |
259 | } |
260 | |
261 | static void iotkit_secctl_ppc_ns_write(IoTKitSecCtlPPC *ppc, uint32_t value) |
262 | { |
263 | int i; |
264 | |
265 | ppc->ns = value & MAKE_64BIT_MASK(0, ppc->numports); |
266 | for (i = 0; i < ppc->numports; i++) { |
267 | qemu_set_irq(ppc->nonsec[i], extract32(ppc->ns, i, 1)); |
268 | } |
269 | iotkit_secctl_update_ppc_ap(ppc); |
270 | } |
271 | |
272 | static void iotkit_secctl_ppc_sp_write(IoTKitSecCtlPPC *ppc, uint32_t value) |
273 | { |
274 | ppc->sp = value & MAKE_64BIT_MASK(0, ppc->numports); |
275 | iotkit_secctl_update_ppc_ap(ppc); |
276 | } |
277 | |
278 | static void iotkit_secctl_ppc_nsp_write(IoTKitSecCtlPPC *ppc, uint32_t value) |
279 | { |
280 | ppc->nsp = value & MAKE_64BIT_MASK(0, ppc->numports); |
281 | iotkit_secctl_update_ppc_ap(ppc); |
282 | } |
283 | |
284 | static void iotkit_secctl_ppc_update_irq_clear(IoTKitSecCtlPPC *ppc) |
285 | { |
286 | uint32_t value = ppc->parent->secppcintstat; |
287 | |
288 | qemu_set_irq(ppc->irq_clear, extract32(value, ppc->irq_bit_offset, 1)); |
289 | } |
290 | |
291 | static void iotkit_secctl_ppc_update_irq_enable(IoTKitSecCtlPPC *ppc) |
292 | { |
293 | uint32_t value = ppc->parent->secppcinten; |
294 | |
295 | qemu_set_irq(ppc->irq_enable, extract32(value, ppc->irq_bit_offset, 1)); |
296 | } |
297 | |
298 | static void iotkit_secctl_update_mscexp_irqs(qemu_irq *msc_irqs, uint32_t value) |
299 | { |
300 | int i; |
301 | |
302 | for (i = 0; i < IOTS_NUM_EXP_MSC; i++) { |
303 | qemu_set_irq(msc_irqs[i], extract32(value, i + 16, 1)); |
304 | } |
305 | } |
306 | |
307 | static void iotkit_secctl_update_msc_irq(IoTKitSecCtl *s) |
308 | { |
309 | /* Update the combined MSC IRQ, based on S_MSCEXP_STATUS and S_MSCEXP_EN */ |
310 | bool level = s->secmscintstat & s->secmscinten; |
311 | |
312 | qemu_set_irq(s->msc_irq, level); |
313 | } |
314 | |
315 | static MemTxResult iotkit_secctl_s_write(void *opaque, hwaddr addr, |
316 | uint64_t value, |
317 | unsigned size, MemTxAttrs attrs) |
318 | { |
319 | IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); |
320 | uint32_t offset = addr; |
321 | IoTKitSecCtlPPC *ppc; |
322 | |
323 | trace_iotkit_secctl_s_write(offset, value, size); |
324 | |
325 | if (size != 4) { |
326 | /* Byte and halfword writes are ignored */ |
327 | qemu_log_mask(LOG_GUEST_ERROR, |
328 | "IotKit SecCtl S block write: bad size, ignored\n" ); |
329 | return MEMTX_OK; |
330 | } |
331 | |
332 | switch (offset) { |
333 | case A_NSCCFG: |
334 | s->nsccfg = value & 3; |
335 | qemu_set_irq(s->nsc_cfg_irq, s->nsccfg); |
336 | break; |
337 | case A_SECRESPCFG: |
338 | value &= 1; |
339 | s->secrespcfg = value; |
340 | qemu_set_irq(s->sec_resp_cfg, s->secrespcfg); |
341 | break; |
342 | case A_SECPPCINTCLR: |
343 | value &= 0x00f000f3; |
344 | foreach_ppc(s, iotkit_secctl_ppc_update_irq_clear); |
345 | break; |
346 | case A_SECPPCINTEN: |
347 | s->secppcinten = value & 0x00f000f3; |
348 | foreach_ppc(s, iotkit_secctl_ppc_update_irq_enable); |
349 | break; |
350 | case A_BRGINTCLR: |
351 | break; |
352 | case A_BRGINTEN: |
353 | s->brginten = value & 0xffff0000; |
354 | break; |
355 | case A_AHBNSPPCEXP0: |
356 | case A_AHBNSPPCEXP1: |
357 | case A_AHBNSPPCEXP2: |
358 | case A_AHBNSPPCEXP3: |
359 | ppc = &s->ahbexp[offset_to_ppc_idx(offset)]; |
360 | iotkit_secctl_ppc_ns_write(ppc, value); |
361 | break; |
362 | case A_APBNSPPC0: |
363 | case A_APBNSPPC1: |
364 | ppc = &s->apb[offset_to_ppc_idx(offset)]; |
365 | iotkit_secctl_ppc_ns_write(ppc, value); |
366 | break; |
367 | case A_APBNSPPCEXP0: |
368 | case A_APBNSPPCEXP1: |
369 | case A_APBNSPPCEXP2: |
370 | case A_APBNSPPCEXP3: |
371 | ppc = &s->apbexp[offset_to_ppc_idx(offset)]; |
372 | iotkit_secctl_ppc_ns_write(ppc, value); |
373 | break; |
374 | case A_AHBSPPPCEXP0: |
375 | case A_AHBSPPPCEXP1: |
376 | case A_AHBSPPPCEXP2: |
377 | case A_AHBSPPPCEXP3: |
378 | ppc = &s->ahbexp[offset_to_ppc_idx(offset)]; |
379 | iotkit_secctl_ppc_sp_write(ppc, value); |
380 | break; |
381 | case A_APBSPPPC0: |
382 | case A_APBSPPPC1: |
383 | ppc = &s->apb[offset_to_ppc_idx(offset)]; |
384 | iotkit_secctl_ppc_sp_write(ppc, value); |
385 | break; |
386 | case A_APBSPPPCEXP0: |
387 | case A_APBSPPPCEXP1: |
388 | case A_APBSPPPCEXP2: |
389 | case A_APBSPPPCEXP3: |
390 | ppc = &s->apbexp[offset_to_ppc_idx(offset)]; |
391 | iotkit_secctl_ppc_sp_write(ppc, value); |
392 | break; |
393 | case A_SECMSCINTCLR: |
394 | iotkit_secctl_update_mscexp_irqs(s->mscexp_clear, value); |
395 | break; |
396 | case A_SECMSCINTEN: |
397 | s->secmscinten = value; |
398 | iotkit_secctl_update_msc_irq(s); |
399 | break; |
400 | case A_NSMSCEXP: |
401 | s->nsmscexp = value; |
402 | iotkit_secctl_update_mscexp_irqs(s->mscexp_ns, value); |
403 | break; |
404 | case A_SECMPCINTSTATUS: |
405 | case A_SECPPCINTSTAT: |
406 | case A_SECMSCINTSTAT: |
407 | case A_BRGINTSTAT: |
408 | case A_AHBNSPPC0: |
409 | case A_AHBSPPPC0: |
410 | case A_PID4: |
411 | case A_PID5: |
412 | case A_PID6: |
413 | case A_PID7: |
414 | case A_PID0: |
415 | case A_PID1: |
416 | case A_PID2: |
417 | case A_PID3: |
418 | case A_CID0: |
419 | case A_CID1: |
420 | case A_CID2: |
421 | case A_CID3: |
422 | qemu_log_mask(LOG_GUEST_ERROR, |
423 | "IoTKit SecCtl S block write: " |
424 | "read-only offset 0x%x\n" , offset); |
425 | break; |
426 | default: |
427 | qemu_log_mask(LOG_GUEST_ERROR, |
428 | "IotKit SecCtl S block write: bad offset 0x%x\n" , |
429 | offset); |
430 | break; |
431 | } |
432 | |
433 | return MEMTX_OK; |
434 | } |
435 | |
436 | static MemTxResult iotkit_secctl_ns_read(void *opaque, hwaddr addr, |
437 | uint64_t *pdata, |
438 | unsigned size, MemTxAttrs attrs) |
439 | { |
440 | IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); |
441 | uint64_t r; |
442 | uint32_t offset = addr & ~0x3; |
443 | |
444 | switch (offset) { |
445 | case A_AHBNSPPPC0: |
446 | r = 0; |
447 | break; |
448 | case A_AHBNSPPPCEXP0: |
449 | case A_AHBNSPPPCEXP1: |
450 | case A_AHBNSPPPCEXP2: |
451 | case A_AHBNSPPPCEXP3: |
452 | r = s->ahbexp[offset_to_ppc_idx(offset)].nsp; |
453 | break; |
454 | case A_APBNSPPPC0: |
455 | case A_APBNSPPPC1: |
456 | r = s->apb[offset_to_ppc_idx(offset)].nsp; |
457 | break; |
458 | case A_APBNSPPPCEXP0: |
459 | case A_APBNSPPPCEXP1: |
460 | case A_APBNSPPPCEXP2: |
461 | case A_APBNSPPPCEXP3: |
462 | r = s->apbexp[offset_to_ppc_idx(offset)].nsp; |
463 | break; |
464 | case A_PID4: |
465 | case A_PID5: |
466 | case A_PID6: |
467 | case A_PID7: |
468 | case A_PID0: |
469 | case A_PID1: |
470 | case A_PID2: |
471 | case A_PID3: |
472 | case A_CID0: |
473 | case A_CID1: |
474 | case A_CID2: |
475 | case A_CID3: |
476 | r = iotkit_secctl_ns_idregs[(offset - A_PID4) / 4]; |
477 | break; |
478 | default: |
479 | qemu_log_mask(LOG_GUEST_ERROR, |
480 | "IotKit SecCtl NS block write: bad offset 0x%x\n" , |
481 | offset); |
482 | r = 0; |
483 | break; |
484 | } |
485 | |
486 | if (size != 4) { |
487 | /* None of our registers are access-sensitive, so just pull the right |
488 | * byte out of the word read result. |
489 | */ |
490 | r = extract32(r, (addr & 3) * 8, size * 8); |
491 | } |
492 | |
493 | trace_iotkit_secctl_ns_read(offset, r, size); |
494 | *pdata = r; |
495 | return MEMTX_OK; |
496 | } |
497 | |
498 | static MemTxResult iotkit_secctl_ns_write(void *opaque, hwaddr addr, |
499 | uint64_t value, |
500 | unsigned size, MemTxAttrs attrs) |
501 | { |
502 | IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); |
503 | uint32_t offset = addr; |
504 | IoTKitSecCtlPPC *ppc; |
505 | |
506 | trace_iotkit_secctl_ns_write(offset, value, size); |
507 | |
508 | if (size != 4) { |
509 | /* Byte and halfword writes are ignored */ |
510 | qemu_log_mask(LOG_GUEST_ERROR, |
511 | "IotKit SecCtl NS block write: bad size, ignored\n" ); |
512 | return MEMTX_OK; |
513 | } |
514 | |
515 | switch (offset) { |
516 | case A_AHBNSPPPCEXP0: |
517 | case A_AHBNSPPPCEXP1: |
518 | case A_AHBNSPPPCEXP2: |
519 | case A_AHBNSPPPCEXP3: |
520 | ppc = &s->ahbexp[offset_to_ppc_idx(offset)]; |
521 | iotkit_secctl_ppc_nsp_write(ppc, value); |
522 | break; |
523 | case A_APBNSPPPC0: |
524 | case A_APBNSPPPC1: |
525 | ppc = &s->apb[offset_to_ppc_idx(offset)]; |
526 | iotkit_secctl_ppc_nsp_write(ppc, value); |
527 | break; |
528 | case A_APBNSPPPCEXP0: |
529 | case A_APBNSPPPCEXP1: |
530 | case A_APBNSPPPCEXP2: |
531 | case A_APBNSPPPCEXP3: |
532 | ppc = &s->apbexp[offset_to_ppc_idx(offset)]; |
533 | iotkit_secctl_ppc_nsp_write(ppc, value); |
534 | break; |
535 | case A_AHBNSPPPC0: |
536 | case A_PID4: |
537 | case A_PID5: |
538 | case A_PID6: |
539 | case A_PID7: |
540 | case A_PID0: |
541 | case A_PID1: |
542 | case A_PID2: |
543 | case A_PID3: |
544 | case A_CID0: |
545 | case A_CID1: |
546 | case A_CID2: |
547 | case A_CID3: |
548 | qemu_log_mask(LOG_GUEST_ERROR, |
549 | "IoTKit SecCtl NS block write: " |
550 | "read-only offset 0x%x\n" , offset); |
551 | break; |
552 | default: |
553 | qemu_log_mask(LOG_GUEST_ERROR, |
554 | "IotKit SecCtl NS block write: bad offset 0x%x\n" , |
555 | offset); |
556 | break; |
557 | } |
558 | |
559 | return MEMTX_OK; |
560 | } |
561 | |
562 | static const MemoryRegionOps iotkit_secctl_s_ops = { |
563 | .read_with_attrs = iotkit_secctl_s_read, |
564 | .write_with_attrs = iotkit_secctl_s_write, |
565 | .endianness = DEVICE_LITTLE_ENDIAN, |
566 | .valid.min_access_size = 1, |
567 | .valid.max_access_size = 4, |
568 | .impl.min_access_size = 1, |
569 | .impl.max_access_size = 4, |
570 | }; |
571 | |
572 | static const MemoryRegionOps iotkit_secctl_ns_ops = { |
573 | .read_with_attrs = iotkit_secctl_ns_read, |
574 | .write_with_attrs = iotkit_secctl_ns_write, |
575 | .endianness = DEVICE_LITTLE_ENDIAN, |
576 | .valid.min_access_size = 1, |
577 | .valid.max_access_size = 4, |
578 | .impl.min_access_size = 1, |
579 | .impl.max_access_size = 4, |
580 | }; |
581 | |
582 | static void iotkit_secctl_reset_ppc(IoTKitSecCtlPPC *ppc) |
583 | { |
584 | ppc->ns = 0; |
585 | ppc->sp = 0; |
586 | ppc->nsp = 0; |
587 | } |
588 | |
589 | static void iotkit_secctl_reset(DeviceState *dev) |
590 | { |
591 | IoTKitSecCtl *s = IOTKIT_SECCTL(dev); |
592 | |
593 | s->secppcintstat = 0; |
594 | s->secppcinten = 0; |
595 | s->secrespcfg = 0; |
596 | s->nsccfg = 0; |
597 | s->brginten = 0; |
598 | |
599 | foreach_ppc(s, iotkit_secctl_reset_ppc); |
600 | } |
601 | |
602 | static void iotkit_secctl_mpc_status(void *opaque, int n, int level) |
603 | { |
604 | IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); |
605 | |
606 | s->mpcintstatus = deposit32(s->mpcintstatus, n, 1, !!level); |
607 | } |
608 | |
609 | static void iotkit_secctl_mpcexp_status(void *opaque, int n, int level) |
610 | { |
611 | IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); |
612 | |
613 | s->mpcintstatus = deposit32(s->mpcintstatus, n + 16, 1, !!level); |
614 | } |
615 | |
616 | static void iotkit_secctl_mscexp_status(void *opaque, int n, int level) |
617 | { |
618 | IoTKitSecCtl *s = IOTKIT_SECCTL(opaque); |
619 | |
620 | s->secmscintstat = deposit32(s->secmscintstat, n + 16, 1, !!level); |
621 | iotkit_secctl_update_msc_irq(s); |
622 | } |
623 | |
624 | static void iotkit_secctl_ppc_irqstatus(void *opaque, int n, int level) |
625 | { |
626 | IoTKitSecCtlPPC *ppc = opaque; |
627 | IoTKitSecCtl *s = IOTKIT_SECCTL(ppc->parent); |
628 | int irqbit = ppc->irq_bit_offset + n; |
629 | |
630 | s->secppcintstat = deposit32(s->secppcintstat, irqbit, 1, level); |
631 | } |
632 | |
633 | static void iotkit_secctl_init_ppc(IoTKitSecCtl *s, |
634 | IoTKitSecCtlPPC *ppc, |
635 | const char *name, |
636 | int numports, |
637 | int irq_bit_offset) |
638 | { |
639 | char *gpioname; |
640 | DeviceState *dev = DEVICE(s); |
641 | |
642 | ppc->numports = numports; |
643 | ppc->irq_bit_offset = irq_bit_offset; |
644 | ppc->parent = s; |
645 | |
646 | gpioname = g_strdup_printf("%s_nonsec" , name); |
647 | qdev_init_gpio_out_named(dev, ppc->nonsec, gpioname, numports); |
648 | g_free(gpioname); |
649 | gpioname = g_strdup_printf("%s_ap" , name); |
650 | qdev_init_gpio_out_named(dev, ppc->ap, gpioname, numports); |
651 | g_free(gpioname); |
652 | gpioname = g_strdup_printf("%s_irq_enable" , name); |
653 | qdev_init_gpio_out_named(dev, &ppc->irq_enable, gpioname, 1); |
654 | g_free(gpioname); |
655 | gpioname = g_strdup_printf("%s_irq_clear" , name); |
656 | qdev_init_gpio_out_named(dev, &ppc->irq_clear, gpioname, 1); |
657 | g_free(gpioname); |
658 | gpioname = g_strdup_printf("%s_irq_status" , name); |
659 | qdev_init_gpio_in_named_with_opaque(dev, iotkit_secctl_ppc_irqstatus, |
660 | ppc, gpioname, 1); |
661 | g_free(gpioname); |
662 | } |
663 | |
664 | static void iotkit_secctl_init(Object *obj) |
665 | { |
666 | IoTKitSecCtl *s = IOTKIT_SECCTL(obj); |
667 | SysBusDevice *sbd = SYS_BUS_DEVICE(obj); |
668 | DeviceState *dev = DEVICE(obj); |
669 | int i; |
670 | |
671 | iotkit_secctl_init_ppc(s, &s->apb[0], "apb_ppc0" , |
672 | IOTS_APB_PPC0_NUM_PORTS, 0); |
673 | iotkit_secctl_init_ppc(s, &s->apb[1], "apb_ppc1" , |
674 | IOTS_APB_PPC1_NUM_PORTS, 1); |
675 | |
676 | for (i = 0; i < IOTS_NUM_APB_EXP_PPC; i++) { |
677 | IoTKitSecCtlPPC *ppc = &s->apbexp[i]; |
678 | char *ppcname = g_strdup_printf("apb_ppcexp%d" , i); |
679 | iotkit_secctl_init_ppc(s, ppc, ppcname, IOTS_PPC_NUM_PORTS, 4 + i); |
680 | g_free(ppcname); |
681 | } |
682 | for (i = 0; i < IOTS_NUM_AHB_EXP_PPC; i++) { |
683 | IoTKitSecCtlPPC *ppc = &s->ahbexp[i]; |
684 | char *ppcname = g_strdup_printf("ahb_ppcexp%d" , i); |
685 | iotkit_secctl_init_ppc(s, ppc, ppcname, IOTS_PPC_NUM_PORTS, 20 + i); |
686 | g_free(ppcname); |
687 | } |
688 | |
689 | qdev_init_gpio_out_named(dev, &s->sec_resp_cfg, "sec_resp_cfg" , 1); |
690 | qdev_init_gpio_out_named(dev, &s->nsc_cfg_irq, "nsc_cfg" , 1); |
691 | |
692 | qdev_init_gpio_in_named(dev, iotkit_secctl_mpc_status, "mpc_status" , |
693 | IOTS_NUM_MPC); |
694 | qdev_init_gpio_in_named(dev, iotkit_secctl_mpcexp_status, |
695 | "mpcexp_status" , IOTS_NUM_EXP_MPC); |
696 | |
697 | qdev_init_gpio_in_named(dev, iotkit_secctl_mscexp_status, |
698 | "mscexp_status" , IOTS_NUM_EXP_MSC); |
699 | qdev_init_gpio_out_named(dev, s->mscexp_clear, "mscexp_clear" , |
700 | IOTS_NUM_EXP_MSC); |
701 | qdev_init_gpio_out_named(dev, s->mscexp_ns, "mscexp_ns" , |
702 | IOTS_NUM_EXP_MSC); |
703 | qdev_init_gpio_out_named(dev, &s->msc_irq, "msc_irq" , 1); |
704 | |
705 | memory_region_init_io(&s->s_regs, obj, &iotkit_secctl_s_ops, |
706 | s, "iotkit-secctl-s-regs" , 0x1000); |
707 | memory_region_init_io(&s->ns_regs, obj, &iotkit_secctl_ns_ops, |
708 | s, "iotkit-secctl-ns-regs" , 0x1000); |
709 | sysbus_init_mmio(sbd, &s->s_regs); |
710 | sysbus_init_mmio(sbd, &s->ns_regs); |
711 | } |
712 | |
713 | static const VMStateDescription iotkit_secctl_ppc_vmstate = { |
714 | .name = "iotkit-secctl-ppc" , |
715 | .version_id = 1, |
716 | .minimum_version_id = 1, |
717 | .fields = (VMStateField[]) { |
718 | VMSTATE_UINT32(ns, IoTKitSecCtlPPC), |
719 | VMSTATE_UINT32(sp, IoTKitSecCtlPPC), |
720 | VMSTATE_UINT32(nsp, IoTKitSecCtlPPC), |
721 | VMSTATE_END_OF_LIST() |
722 | } |
723 | }; |
724 | |
725 | static const VMStateDescription iotkit_secctl_mpcintstatus_vmstate = { |
726 | .name = "iotkit-secctl-mpcintstatus" , |
727 | .version_id = 1, |
728 | .minimum_version_id = 1, |
729 | .fields = (VMStateField[]) { |
730 | VMSTATE_UINT32(mpcintstatus, IoTKitSecCtl), |
731 | VMSTATE_END_OF_LIST() |
732 | } |
733 | }; |
734 | |
735 | static bool needed_always(void *opaque) |
736 | { |
737 | return true; |
738 | } |
739 | |
740 | static const VMStateDescription iotkit_secctl_msc_vmstate = { |
741 | .name = "iotkit-secctl/msc" , |
742 | .version_id = 1, |
743 | .minimum_version_id = 1, |
744 | .needed = needed_always, |
745 | .fields = (VMStateField[]) { |
746 | VMSTATE_UINT32(secmscintstat, IoTKitSecCtl), |
747 | VMSTATE_UINT32(secmscinten, IoTKitSecCtl), |
748 | VMSTATE_UINT32(nsmscexp, IoTKitSecCtl), |
749 | VMSTATE_END_OF_LIST() |
750 | } |
751 | }; |
752 | |
753 | static const VMStateDescription iotkit_secctl_vmstate = { |
754 | .name = "iotkit-secctl" , |
755 | .version_id = 1, |
756 | .minimum_version_id = 1, |
757 | .fields = (VMStateField[]) { |
758 | VMSTATE_UINT32(secppcintstat, IoTKitSecCtl), |
759 | VMSTATE_UINT32(secppcinten, IoTKitSecCtl), |
760 | VMSTATE_UINT32(secrespcfg, IoTKitSecCtl), |
761 | VMSTATE_UINT32(nsccfg, IoTKitSecCtl), |
762 | VMSTATE_UINT32(brginten, IoTKitSecCtl), |
763 | VMSTATE_STRUCT_ARRAY(apb, IoTKitSecCtl, IOTS_NUM_APB_PPC, 1, |
764 | iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC), |
765 | VMSTATE_STRUCT_ARRAY(apbexp, IoTKitSecCtl, IOTS_NUM_APB_EXP_PPC, 1, |
766 | iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC), |
767 | VMSTATE_STRUCT_ARRAY(ahbexp, IoTKitSecCtl, IOTS_NUM_AHB_EXP_PPC, 1, |
768 | iotkit_secctl_ppc_vmstate, IoTKitSecCtlPPC), |
769 | VMSTATE_END_OF_LIST() |
770 | }, |
771 | .subsections = (const VMStateDescription*[]) { |
772 | &iotkit_secctl_mpcintstatus_vmstate, |
773 | &iotkit_secctl_msc_vmstate, |
774 | NULL |
775 | }, |
776 | }; |
777 | |
778 | static void iotkit_secctl_class_init(ObjectClass *klass, void *data) |
779 | { |
780 | DeviceClass *dc = DEVICE_CLASS(klass); |
781 | |
782 | dc->vmsd = &iotkit_secctl_vmstate; |
783 | dc->reset = iotkit_secctl_reset; |
784 | } |
785 | |
786 | static const TypeInfo iotkit_secctl_info = { |
787 | .name = TYPE_IOTKIT_SECCTL, |
788 | .parent = TYPE_SYS_BUS_DEVICE, |
789 | .instance_size = sizeof(IoTKitSecCtl), |
790 | .instance_init = iotkit_secctl_init, |
791 | .class_init = iotkit_secctl_class_init, |
792 | }; |
793 | |
794 | static void iotkit_secctl_register_types(void) |
795 | { |
796 | type_register_static(&iotkit_secctl_info); |
797 | } |
798 | |
799 | type_init(iotkit_secctl_register_types); |
800 | |