]> Git Repo - qemu.git/blame - hw/misc/tz-mpc.c
exec.c: Rename cpu_physical_memory_write_rom_internal()
[qemu.git] / hw / misc / tz-mpc.c
CommitLineData
344f4b15
PM
1/*
2 * ARM AHB5 TrustZone Memory Protection Controller emulation
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/tz-mpc.h"
19
20/* Our IOMMU has two IOMMU indexes, one for secure transactions and one for
21 * non-secure transactions.
22 */
23enum {
24 IOMMU_IDX_S,
25 IOMMU_IDX_NS,
26 IOMMU_NUM_INDEXES,
27};
28
29/* Config registers */
30REG32(CTRL, 0x00)
cdb60998
PM
31 FIELD(CTRL, SEC_RESP, 4, 1)
32 FIELD(CTRL, AUTOINC, 8, 1)
33 FIELD(CTRL, LOCKDOWN, 31, 1)
344f4b15
PM
34REG32(BLK_MAX, 0x10)
35REG32(BLK_CFG, 0x14)
36REG32(BLK_IDX, 0x18)
37REG32(BLK_LUT, 0x1c)
38REG32(INT_STAT, 0x20)
cdb60998 39 FIELD(INT_STAT, IRQ, 0, 1)
344f4b15 40REG32(INT_CLEAR, 0x24)
cdb60998 41 FIELD(INT_CLEAR, IRQ, 0, 1)
344f4b15 42REG32(INT_EN, 0x28)
cdb60998 43 FIELD(INT_EN, IRQ, 0, 1)
344f4b15
PM
44REG32(INT_INFO1, 0x2c)
45REG32(INT_INFO2, 0x30)
57c49a6e
PM
46 FIELD(INT_INFO2, HMASTER, 0, 16)
47 FIELD(INT_INFO2, HNONSEC, 16, 1)
48 FIELD(INT_INFO2, CFG_NS, 17, 1)
344f4b15 49REG32(INT_SET, 0x34)
cdb60998 50 FIELD(INT_SET, IRQ, 0, 1)
344f4b15
PM
51REG32(PIDR4, 0xfd0)
52REG32(PIDR5, 0xfd4)
53REG32(PIDR6, 0xfd8)
54REG32(PIDR7, 0xfdc)
55REG32(PIDR0, 0xfe0)
56REG32(PIDR1, 0xfe4)
57REG32(PIDR2, 0xfe8)
58REG32(PIDR3, 0xfec)
59REG32(CIDR0, 0xff0)
60REG32(CIDR1, 0xff4)
61REG32(CIDR2, 0xff8)
62REG32(CIDR3, 0xffc)
63
64static const uint8_t tz_mpc_idregs[] = {
65 0x04, 0x00, 0x00, 0x00,
66 0x60, 0xb8, 0x1b, 0x00,
67 0x0d, 0xf0, 0x05, 0xb1,
68};
69
cdb60998
PM
70static void tz_mpc_irq_update(TZMPC *s)
71{
72 qemu_set_irq(s->irq, s->int_stat && s->int_en);
73}
74
dd29d068
PM
75static void tz_mpc_iommu_notify(TZMPC *s, uint32_t lutidx,
76 uint32_t oldlut, uint32_t newlut)
77{
78 /* Called when the LUT word at lutidx has changed from oldlut to newlut;
79 * must call the IOMMU notifiers for the changed blocks.
80 */
81 IOMMUTLBEntry entry = {
82 .addr_mask = s->blocksize - 1,
83 };
84 hwaddr addr = lutidx * s->blocksize * 32;
85 int i;
86
87 for (i = 0; i < 32; i++, addr += s->blocksize) {
88 bool block_is_ns;
89
90 if (!((oldlut ^ newlut) & (1 << i))) {
91 continue;
92 }
93 /* This changes the mappings for both the S and the NS space,
94 * so we need to do four notifies: an UNMAP then a MAP for each.
95 */
96 block_is_ns = newlut & (1 << i);
97
98 trace_tz_mpc_iommu_notify(addr);
99 entry.iova = addr;
100 entry.translated_addr = addr;
101
102 entry.perm = IOMMU_NONE;
103 memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry);
104 memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry);
105
106 entry.perm = IOMMU_RW;
107 if (block_is_ns) {
108 entry.target_as = &s->blocked_io_as;
109 } else {
110 entry.target_as = &s->downstream_as;
111 }
112 memory_region_notify_iommu(&s->upstream, IOMMU_IDX_S, entry);
113 if (block_is_ns) {
114 entry.target_as = &s->downstream_as;
115 } else {
116 entry.target_as = &s->blocked_io_as;
117 }
118 memory_region_notify_iommu(&s->upstream, IOMMU_IDX_NS, entry);
119 }
120}
121
cdb60998
PM
122static void tz_mpc_autoinc_idx(TZMPC *s, unsigned access_size)
123{
124 /* Auto-increment BLK_IDX if necessary */
125 if (access_size == 4 && (s->ctrl & R_CTRL_AUTOINC_MASK)) {
126 s->blk_idx++;
127 s->blk_idx %= s->blk_max;
128 }
129}
130
344f4b15
PM
131static MemTxResult tz_mpc_reg_read(void *opaque, hwaddr addr,
132 uint64_t *pdata,
133 unsigned size, MemTxAttrs attrs)
134{
cdb60998 135 TZMPC *s = TZ_MPC(opaque);
344f4b15
PM
136 uint64_t r;
137 uint32_t offset = addr & ~0x3;
138
139 if (!attrs.secure && offset < A_PIDR4) {
140 /* NS accesses can only see the ID registers */
141 qemu_log_mask(LOG_GUEST_ERROR,
142 "TZ MPC register read: NS access to offset 0x%x\n",
143 offset);
144 r = 0;
145 goto read_out;
146 }
147
148 switch (offset) {
cdb60998
PM
149 case A_CTRL:
150 r = s->ctrl;
151 break;
152 case A_BLK_MAX:
153 r = s->blk_max;
154 break;
155 case A_BLK_CFG:
156 /* We are never in "init in progress state", so this just indicates
157 * the block size. s->blocksize == (1 << BLK_CFG + 5), so
158 * BLK_CFG == ctz32(s->blocksize) - 5
159 */
160 r = ctz32(s->blocksize) - 5;
161 break;
162 case A_BLK_IDX:
163 r = s->blk_idx;
164 break;
165 case A_BLK_LUT:
166 r = s->blk_lut[s->blk_idx];
167 tz_mpc_autoinc_idx(s, size);
168 break;
169 case A_INT_STAT:
170 r = s->int_stat;
171 break;
172 case A_INT_EN:
173 r = s->int_en;
174 break;
175 case A_INT_INFO1:
176 r = s->int_info1;
177 break;
178 case A_INT_INFO2:
179 r = s->int_info2;
180 break;
344f4b15
PM
181 case A_PIDR4:
182 case A_PIDR5:
183 case A_PIDR6:
184 case A_PIDR7:
185 case A_PIDR0:
186 case A_PIDR1:
187 case A_PIDR2:
188 case A_PIDR3:
189 case A_CIDR0:
190 case A_CIDR1:
191 case A_CIDR2:
192 case A_CIDR3:
193 r = tz_mpc_idregs[(offset - A_PIDR4) / 4];
194 break;
195 case A_INT_CLEAR:
196 case A_INT_SET:
197 qemu_log_mask(LOG_GUEST_ERROR,
198 "TZ MPC register read: write-only offset 0x%x\n",
199 offset);
200 r = 0;
201 break;
202 default:
203 qemu_log_mask(LOG_GUEST_ERROR,
204 "TZ MPC register read: bad offset 0x%x\n", offset);
205 r = 0;
206 break;
207 }
208
209 if (size != 4) {
210 /* None of our registers are read-sensitive (except BLK_LUT,
211 * which can special case the "size not 4" case), so just
212 * pull the right bytes out of the word read result.
213 */
214 r = extract32(r, (addr & 3) * 8, size * 8);
215 }
216
217read_out:
218 trace_tz_mpc_reg_read(addr, r, size);
219 *pdata = r;
220 return MEMTX_OK;
221}
222
223static MemTxResult tz_mpc_reg_write(void *opaque, hwaddr addr,
224 uint64_t value,
225 unsigned size, MemTxAttrs attrs)
226{
cdb60998 227 TZMPC *s = TZ_MPC(opaque);
344f4b15
PM
228 uint32_t offset = addr & ~0x3;
229
230 trace_tz_mpc_reg_write(addr, value, size);
231
232 if (!attrs.secure && offset < A_PIDR4) {
233 /* NS accesses can only see the ID registers */
234 qemu_log_mask(LOG_GUEST_ERROR,
235 "TZ MPC register write: NS access to offset 0x%x\n",
236 offset);
237 return MEMTX_OK;
238 }
239
240 if (size != 4) {
241 /* Expand the byte or halfword write to a full word size.
242 * In most cases we can do this with zeroes; the exceptions
243 * are CTRL, BLK_IDX and BLK_LUT.
244 */
245 uint32_t oldval;
246
247 switch (offset) {
cdb60998
PM
248 case A_CTRL:
249 oldval = s->ctrl;
250 break;
251 case A_BLK_IDX:
252 oldval = s->blk_idx;
253 break;
254 case A_BLK_LUT:
255 oldval = s->blk_lut[s->blk_idx];
256 break;
344f4b15
PM
257 default:
258 oldval = 0;
259 break;
260 }
261 value = deposit32(oldval, (addr & 3) * 8, size * 8, value);
262 }
263
cdb60998
PM
264 if ((s->ctrl & R_CTRL_LOCKDOWN_MASK) &&
265 (offset == A_CTRL || offset == A_BLK_LUT || offset == A_INT_EN)) {
266 /* Lockdown mode makes these three registers read-only, and
267 * the only way out of it is to reset the device.
268 */
269 qemu_log_mask(LOG_GUEST_ERROR, "TZ MPC register write to offset 0x%x "
270 "while MPC is in lockdown mode\n", offset);
271 return MEMTX_OK;
272 }
273
344f4b15 274 switch (offset) {
cdb60998
PM
275 case A_CTRL:
276 /* We don't implement the 'data gating' feature so all other bits
277 * are reserved and we make them RAZ/WI.
278 */
279 s->ctrl = value & (R_CTRL_SEC_RESP_MASK |
280 R_CTRL_AUTOINC_MASK |
281 R_CTRL_LOCKDOWN_MASK);
282 break;
283 case A_BLK_IDX:
284 s->blk_idx = value % s->blk_max;
285 break;
286 case A_BLK_LUT:
dd29d068 287 tz_mpc_iommu_notify(s, s->blk_idx, s->blk_lut[s->blk_idx], value);
cdb60998
PM
288 s->blk_lut[s->blk_idx] = value;
289 tz_mpc_autoinc_idx(s, size);
290 break;
291 case A_INT_CLEAR:
292 if (value & R_INT_CLEAR_IRQ_MASK) {
293 s->int_stat = 0;
294 tz_mpc_irq_update(s);
295 }
296 break;
297 case A_INT_EN:
298 s->int_en = value & R_INT_EN_IRQ_MASK;
299 tz_mpc_irq_update(s);
300 break;
301 case A_INT_SET:
302 if (value & R_INT_SET_IRQ_MASK) {
303 s->int_stat = R_INT_STAT_IRQ_MASK;
304 tz_mpc_irq_update(s);
305 }
306 break;
344f4b15
PM
307 case A_PIDR4:
308 case A_PIDR5:
309 case A_PIDR6:
310 case A_PIDR7:
311 case A_PIDR0:
312 case A_PIDR1:
313 case A_PIDR2:
314 case A_PIDR3:
315 case A_CIDR0:
316 case A_CIDR1:
317 case A_CIDR2:
318 case A_CIDR3:
319 qemu_log_mask(LOG_GUEST_ERROR,
320 "TZ MPC register write: read-only offset 0x%x\n", offset);
321 break;
322 default:
323 qemu_log_mask(LOG_GUEST_ERROR,
324 "TZ MPC register write: bad offset 0x%x\n", offset);
325 break;
326 }
327
328 return MEMTX_OK;
329}
330
331static const MemoryRegionOps tz_mpc_reg_ops = {
332 .read_with_attrs = tz_mpc_reg_read,
333 .write_with_attrs = tz_mpc_reg_write,
334 .endianness = DEVICE_LITTLE_ENDIAN,
335 .valid.min_access_size = 1,
336 .valid.max_access_size = 4,
337 .impl.min_access_size = 1,
338 .impl.max_access_size = 4,
339};
340
57c49a6e
PM
341static inline bool tz_mpc_cfg_ns(TZMPC *s, hwaddr addr)
342{
343 /* Return the cfg_ns bit from the LUT for the specified address */
344 hwaddr blknum = addr / s->blocksize;
345 hwaddr blkword = blknum / 32;
346 uint32_t blkbit = 1U << (blknum % 32);
347
348 /* This would imply the address was larger than the size we
349 * defined this memory region to be, so it can't happen.
350 */
351 assert(blkword < s->blk_max);
352 return s->blk_lut[blkword] & blkbit;
353}
354
355static MemTxResult tz_mpc_handle_block(TZMPC *s, hwaddr addr, MemTxAttrs attrs)
356{
357 /* Handle a blocked transaction: raise IRQ, capture info, etc */
358 if (!s->int_stat) {
359 /* First blocked transfer: capture information into INT_INFO1 and
360 * INT_INFO2. Subsequent transfers are still blocked but don't
361 * capture information until the guest clears the interrupt.
362 */
363
364 s->int_info1 = addr;
365 s->int_info2 = 0;
366 s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HMASTER,
367 attrs.requester_id & 0xffff);
368 s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, HNONSEC,
369 ~attrs.secure);
370 s->int_info2 = FIELD_DP32(s->int_info2, INT_INFO2, CFG_NS,
371 tz_mpc_cfg_ns(s, addr));
372 s->int_stat |= R_INT_STAT_IRQ_MASK;
373 tz_mpc_irq_update(s);
374 }
375
376 /* Generate bus error if desired; otherwise RAZ/WI */
377 return (s->ctrl & R_CTRL_SEC_RESP_MASK) ? MEMTX_ERROR : MEMTX_OK;
378}
379
344f4b15
PM
380/* Accesses only reach these read and write functions if the MPC is
381 * blocking them; non-blocked accesses go directly to the downstream
382 * memory region without passing through this code.
383 */
384static MemTxResult tz_mpc_mem_blocked_read(void *opaque, hwaddr addr,
385 uint64_t *pdata,
386 unsigned size, MemTxAttrs attrs)
387{
57c49a6e
PM
388 TZMPC *s = TZ_MPC(opaque);
389
344f4b15
PM
390 trace_tz_mpc_mem_blocked_read(addr, size, attrs.secure);
391
392 *pdata = 0;
57c49a6e 393 return tz_mpc_handle_block(s, addr, attrs);
344f4b15
PM
394}
395
396static MemTxResult tz_mpc_mem_blocked_write(void *opaque, hwaddr addr,
397 uint64_t value,
398 unsigned size, MemTxAttrs attrs)
399{
57c49a6e
PM
400 TZMPC *s = TZ_MPC(opaque);
401
344f4b15
PM
402 trace_tz_mpc_mem_blocked_write(addr, value, size, attrs.secure);
403
57c49a6e 404 return tz_mpc_handle_block(s, addr, attrs);
344f4b15
PM
405}
406
407static const MemoryRegionOps tz_mpc_mem_blocked_ops = {
408 .read_with_attrs = tz_mpc_mem_blocked_read,
409 .write_with_attrs = tz_mpc_mem_blocked_write,
410 .endianness = DEVICE_LITTLE_ENDIAN,
411 .valid.min_access_size = 1,
412 .valid.max_access_size = 8,
413 .impl.min_access_size = 1,
414 .impl.max_access_size = 8,
415};
416
417static IOMMUTLBEntry tz_mpc_translate(IOMMUMemoryRegion *iommu,
418 hwaddr addr, IOMMUAccessFlags flags,
419 int iommu_idx)
420{
421 TZMPC *s = TZ_MPC(container_of(iommu, TZMPC, upstream));
422 bool ok;
423
424 IOMMUTLBEntry ret = {
425 .iova = addr & ~(s->blocksize - 1),
426 .translated_addr = addr & ~(s->blocksize - 1),
427 .addr_mask = s->blocksize - 1,
428 .perm = IOMMU_RW,
429 };
430
431 /* Look at the per-block configuration for this address, and
432 * return a TLB entry directing the transaction at either
433 * downstream_as or blocked_io_as, as appropriate.
dd29d068
PM
434 * If the LUT cfg_ns bit is 1, only non-secure transactions
435 * may pass. If the bit is 0, only secure transactions may pass.
344f4b15 436 */
dd29d068 437 ok = tz_mpc_cfg_ns(s, addr) == (iommu_idx == IOMMU_IDX_NS);
344f4b15
PM
438
439 trace_tz_mpc_translate(addr, flags,
440 iommu_idx == IOMMU_IDX_S ? "S" : "NS",
441 ok ? "pass" : "block");
442
443 ret.target_as = ok ? &s->downstream_as : &s->blocked_io_as;
444 return ret;
445}
446
447static int tz_mpc_attrs_to_index(IOMMUMemoryRegion *iommu, MemTxAttrs attrs)
448{
449 /* We treat unspecified attributes like secure. Transactions with
450 * unspecified attributes come from places like
451 * cpu_physical_memory_write_rom() for initial image load, and we want
452 * those to pass through the from-reset "everything is secure" config.
453 * All the real during-emulation transactions from the CPU will
454 * specify attributes.
455 */
456 return (attrs.unspecified || attrs.secure) ? IOMMU_IDX_S : IOMMU_IDX_NS;
457}
458
459static int tz_mpc_num_indexes(IOMMUMemoryRegion *iommu)
460{
461 return IOMMU_NUM_INDEXES;
462}
463
464static void tz_mpc_reset(DeviceState *dev)
465{
cdb60998
PM
466 TZMPC *s = TZ_MPC(dev);
467
468 s->ctrl = 0x00000100;
469 s->blk_idx = 0;
470 s->int_stat = 0;
471 s->int_en = 1;
472 s->int_info1 = 0;
473 s->int_info2 = 0;
474
475 memset(s->blk_lut, 0, s->blk_max * sizeof(uint32_t));
344f4b15
PM
476}
477
478static void tz_mpc_init(Object *obj)
479{
480 DeviceState *dev = DEVICE(obj);
481 TZMPC *s = TZ_MPC(obj);
482
483 qdev_init_gpio_out_named(dev, &s->irq, "irq", 1);
484}
485
486static void tz_mpc_realize(DeviceState *dev, Error **errp)
487{
488 Object *obj = OBJECT(dev);
489 SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
490 TZMPC *s = TZ_MPC(dev);
491 uint64_t size;
492
493 /* We can't create the upstream end of the port until realize,
494 * as we don't know the size of the MR used as the downstream until then.
495 * We insist on having a downstream, to avoid complicating the code
496 * with handling the "don't know how big this is" case. It's easy
497 * enough for the user to create an unimplemented_device as downstream
498 * if they have nothing else to plug into this.
499 */
500 if (!s->downstream) {
501 error_setg(errp, "MPC 'downstream' link not set");
502 return;
503 }
504
505 size = memory_region_size(s->downstream);
506
507 memory_region_init_iommu(&s->upstream, sizeof(s->upstream),
508 TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
509 obj, "tz-mpc-upstream", size);
510
511 /* In real hardware the block size is configurable. In QEMU we could
512 * make it configurable but will need it to be at least as big as the
513 * target page size so we can execute out of the resulting MRs. Guest
514 * software is supposed to check the block size using the BLK_CFG
515 * register, so make it fixed at the page size.
516 */
517 s->blocksize = memory_region_iommu_get_min_page_size(&s->upstream);
518 if (size % s->blocksize != 0) {
519 error_setg(errp,
520 "MPC 'downstream' size %" PRId64
521 " is not a multiple of %" HWADDR_PRIx " bytes",
522 size, s->blocksize);
523 object_unref(OBJECT(&s->upstream));
524 return;
525 }
526
527 /* BLK_MAX is the max value of BLK_IDX, which indexes an array of 32-bit
528 * words, each bit of which indicates one block.
529 */
530 s->blk_max = DIV_ROUND_UP(size / s->blocksize, 32);
531
532 memory_region_init_io(&s->regmr, obj, &tz_mpc_reg_ops,
533 s, "tz-mpc-regs", 0x1000);
534 sysbus_init_mmio(sbd, &s->regmr);
535
536 sysbus_init_mmio(sbd, MEMORY_REGION(&s->upstream));
537
538 /* This memory region is not exposed to users of this device as a
539 * sysbus MMIO region, but is instead used internally as something
540 * that our IOMMU translate function might direct accesses to.
541 */
542 memory_region_init_io(&s->blocked_io, obj, &tz_mpc_mem_blocked_ops,
543 s, "tz-mpc-blocked-io", size);
544
545 address_space_init(&s->downstream_as, s->downstream,
546 "tz-mpc-downstream");
547 address_space_init(&s->blocked_io_as, &s->blocked_io,
548 "tz-mpc-blocked-io");
cdb60998 549
218fe5ce 550 s->blk_lut = g_new0(uint32_t, s->blk_max);
cdb60998
PM
551}
552
553static int tz_mpc_post_load(void *opaque, int version_id)
554{
555 TZMPC *s = TZ_MPC(opaque);
556
557 /* Check the incoming data doesn't point blk_idx off the end of blk_lut. */
558 if (s->blk_idx >= s->blk_max) {
559 return -1;
560 }
561 return 0;
344f4b15
PM
562}
563
564static const VMStateDescription tz_mpc_vmstate = {
565 .name = "tz-mpc",
566 .version_id = 1,
567 .minimum_version_id = 1,
cdb60998 568 .post_load = tz_mpc_post_load,
344f4b15 569 .fields = (VMStateField[]) {
cdb60998
PM
570 VMSTATE_UINT32(ctrl, TZMPC),
571 VMSTATE_UINT32(blk_idx, TZMPC),
572 VMSTATE_UINT32(int_stat, TZMPC),
573 VMSTATE_UINT32(int_en, TZMPC),
574 VMSTATE_UINT32(int_info1, TZMPC),
575 VMSTATE_UINT32(int_info2, TZMPC),
576 VMSTATE_VARRAY_UINT32(blk_lut, TZMPC, blk_max,
577 0, vmstate_info_uint32, uint32_t),
344f4b15
PM
578 VMSTATE_END_OF_LIST()
579 }
580};
581
582static Property tz_mpc_properties[] = {
583 DEFINE_PROP_LINK("downstream", TZMPC, downstream,
584 TYPE_MEMORY_REGION, MemoryRegion *),
585 DEFINE_PROP_END_OF_LIST(),
586};
587
588static void tz_mpc_class_init(ObjectClass *klass, void *data)
589{
590 DeviceClass *dc = DEVICE_CLASS(klass);
591
592 dc->realize = tz_mpc_realize;
593 dc->vmsd = &tz_mpc_vmstate;
594 dc->reset = tz_mpc_reset;
595 dc->props = tz_mpc_properties;
596}
597
598static const TypeInfo tz_mpc_info = {
599 .name = TYPE_TZ_MPC,
600 .parent = TYPE_SYS_BUS_DEVICE,
601 .instance_size = sizeof(TZMPC),
602 .instance_init = tz_mpc_init,
603 .class_init = tz_mpc_class_init,
604};
605
606static void tz_mpc_iommu_memory_region_class_init(ObjectClass *klass,
607 void *data)
608{
609 IOMMUMemoryRegionClass *imrc = IOMMU_MEMORY_REGION_CLASS(klass);
610
611 imrc->translate = tz_mpc_translate;
612 imrc->attrs_to_index = tz_mpc_attrs_to_index;
613 imrc->num_indexes = tz_mpc_num_indexes;
614}
615
616static const TypeInfo tz_mpc_iommu_memory_region_info = {
617 .name = TYPE_TZ_MPC_IOMMU_MEMORY_REGION,
618 .parent = TYPE_IOMMU_MEMORY_REGION,
619 .class_init = tz_mpc_iommu_memory_region_class_init,
620};
621
622static void tz_mpc_register_types(void)
623{
624 type_register_static(&tz_mpc_info);
625 type_register_static(&tz_mpc_iommu_memory_region_info);
626}
627
628type_init(tz_mpc_register_types);
This page took 0.118878 seconds and 4 git commands to generate.