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