2 * ITS emulation for a GICv3-based system
4 * Copyright Linaro.org 2021
7 * Shashi Mallela <shashi.mallela@linaro.org>
9 * This work is licensed under the terms of the GNU GPL, version 2 or (at your
10 * option) any later version. See the COPYING file in the top-level directory.
14 #include "qemu/osdep.h"
16 #include "hw/qdev-properties.h"
17 #include "hw/intc/arm_gicv3_its_common.h"
18 #include "gicv3_internal.h"
19 #include "qom/object.h"
20 #include "qapi/error.h"
22 typedef struct GICv3ITSClass GICv3ITSClass
;
23 /* This is reusing the GICv3ITSState typedef from ARM_GICV3_ITS_COMMON */
24 DECLARE_OBJ_CHECKERS(GICv3ITSState
, GICv3ITSClass
,
25 ARM_GICV3_ITS
, TYPE_ARM_GICV3_ITS
)
27 struct GICv3ITSClass
{
28 GICv3ITSCommonClass parent_class
;
29 void (*parent_reset
)(DeviceState
*dev
);
32 static uint64_t baser_base_addr(uint64_t value
, uint32_t page_sz
)
37 case GITS_PAGE_SIZE_4K
:
38 case GITS_PAGE_SIZE_16K
:
39 result
= FIELD_EX64(value
, GITS_BASER
, PHYADDR
) << 12;
42 case GITS_PAGE_SIZE_64K
:
43 result
= FIELD_EX64(value
, GITS_BASER
, PHYADDRL_64K
) << 16;
44 result
|= FIELD_EX64(value
, GITS_BASER
, PHYADDRH_64K
) << 48;
54 * This function extracts the ITS Device and Collection table specific
55 * parameters (like base_addr, size etc) from GITS_BASER register.
56 * It is called during ITS enable and also during post_load migration
58 static void extract_table_params(GICv3ITSState
*s
)
60 uint16_t num_pages
= 0;
66 for (int i
= 0; i
< 8; i
++) {
73 page_sz_type
= FIELD_EX64(value
, GITS_BASER
, PAGESIZE
);
75 switch (page_sz_type
) {
77 page_sz
= GITS_PAGE_SIZE_4K
;
81 page_sz
= GITS_PAGE_SIZE_16K
;
86 page_sz
= GITS_PAGE_SIZE_64K
;
90 g_assert_not_reached();
93 num_pages
= FIELD_EX64(value
, GITS_BASER
, SIZE
) + 1;
95 type
= FIELD_EX64(value
, GITS_BASER
, TYPE
);
99 case GITS_BASER_TYPE_DEVICE
:
100 memset(&s
->dt
, 0 , sizeof(s
->dt
));
101 s
->dt
.valid
= FIELD_EX64(value
, GITS_BASER
, VALID
);
107 s
->dt
.page_sz
= page_sz
;
108 s
->dt
.indirect
= FIELD_EX64(value
, GITS_BASER
, INDIRECT
);
109 s
->dt
.entry_sz
= FIELD_EX64(value
, GITS_BASER
, ENTRYSIZE
);
111 if (!s
->dt
.indirect
) {
112 s
->dt
.max_entries
= (num_pages
* page_sz
) / s
->dt
.entry_sz
;
114 s
->dt
.max_entries
= (((num_pages
* page_sz
) /
115 L1TABLE_ENTRY_SIZE
) *
116 (page_sz
/ s
->dt
.entry_sz
));
119 s
->dt
.maxids
.max_devids
= (1UL << (FIELD_EX64(s
->typer
, GITS_TYPER
,
122 s
->dt
.base_addr
= baser_base_addr(value
, page_sz
);
126 case GITS_BASER_TYPE_COLLECTION
:
127 memset(&s
->ct
, 0 , sizeof(s
->ct
));
128 s
->ct
.valid
= FIELD_EX64(value
, GITS_BASER
, VALID
);
131 * GITS_TYPER.HCC is 0 for this implementation
132 * hence writes are discarded if ct.valid is 0
138 s
->ct
.page_sz
= page_sz
;
139 s
->ct
.indirect
= FIELD_EX64(value
, GITS_BASER
, INDIRECT
);
140 s
->ct
.entry_sz
= FIELD_EX64(value
, GITS_BASER
, ENTRYSIZE
);
142 if (!s
->ct
.indirect
) {
143 s
->ct
.max_entries
= (num_pages
* page_sz
) / s
->ct
.entry_sz
;
145 s
->ct
.max_entries
= (((num_pages
* page_sz
) /
146 L1TABLE_ENTRY_SIZE
) *
147 (page_sz
/ s
->ct
.entry_sz
));
150 if (FIELD_EX64(s
->typer
, GITS_TYPER
, CIL
)) {
151 s
->ct
.maxids
.max_collids
= (1UL << (FIELD_EX64(s
->typer
,
152 GITS_TYPER
, CIDBITS
) + 1));
154 /* 16-bit CollectionId supported when CIL == 0 */
155 s
->ct
.maxids
.max_collids
= (1UL << 16);
158 s
->ct
.base_addr
= baser_base_addr(value
, page_sz
);
168 static void extract_cmdq_params(GICv3ITSState
*s
)
170 uint16_t num_pages
= 0;
171 uint64_t value
= s
->cbaser
;
173 num_pages
= FIELD_EX64(value
, GITS_CBASER
, SIZE
) + 1;
175 memset(&s
->cq
, 0 , sizeof(s
->cq
));
176 s
->cq
.valid
= FIELD_EX64(value
, GITS_CBASER
, VALID
);
179 s
->cq
.max_entries
= (num_pages
* GITS_PAGE_SIZE_4K
) /
180 GITS_CMDQ_ENTRY_SIZE
;
181 s
->cq
.base_addr
= FIELD_EX64(value
, GITS_CBASER
, PHYADDR
);
182 s
->cq
.base_addr
<<= R_GITS_CBASER_PHYADDR_SHIFT
;
186 static MemTxResult
gicv3_its_translation_write(void *opaque
, hwaddr offset
,
187 uint64_t data
, unsigned size
,
193 static bool its_writel(GICv3ITSState
*s
, hwaddr offset
,
194 uint64_t value
, MemTxAttrs attrs
)
201 s
->ctlr
|= (value
& ~(s
->ctlr
));
203 if (s
->ctlr
& ITS_CTLR_ENABLED
) {
204 extract_table_params(s
);
205 extract_cmdq_params(s
);
211 * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
214 if (!(s
->ctlr
& ITS_CTLR_ENABLED
)) {
215 s
->cbaser
= deposit64(s
->cbaser
, 0, 32, value
);
217 s
->cwriter
= s
->creadr
;
220 case GITS_CBASER
+ 4:
222 * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
225 if (!(s
->ctlr
& ITS_CTLR_ENABLED
)) {
226 s
->cbaser
= deposit64(s
->cbaser
, 32, 32, value
);
228 s
->cwriter
= s
->creadr
;
232 s
->cwriter
= deposit64(s
->cwriter
, 0, 32,
233 (value
& ~R_GITS_CWRITER_RETRY_MASK
));
235 case GITS_CWRITER
+ 4:
236 s
->cwriter
= deposit64(s
->cwriter
, 32, 32, value
);
239 if (s
->gicv3
->gicd_ctlr
& GICD_CTLR_DS
) {
240 s
->creadr
= deposit64(s
->creadr
, 0, 32,
241 (value
& ~R_GITS_CREADR_STALLED_MASK
));
243 /* RO register, ignore the write */
244 qemu_log_mask(LOG_GUEST_ERROR
,
245 "%s: invalid guest write to RO register at offset "
246 TARGET_FMT_plx
"\n", __func__
, offset
);
249 case GITS_CREADR
+ 4:
250 if (s
->gicv3
->gicd_ctlr
& GICD_CTLR_DS
) {
251 s
->creadr
= deposit64(s
->creadr
, 32, 32, value
);
253 /* RO register, ignore the write */
254 qemu_log_mask(LOG_GUEST_ERROR
,
255 "%s: invalid guest write to RO register at offset "
256 TARGET_FMT_plx
"\n", __func__
, offset
);
259 case GITS_BASER
... GITS_BASER
+ 0x3f:
261 * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
264 if (!(s
->ctlr
& ITS_CTLR_ENABLED
)) {
265 index
= (offset
- GITS_BASER
) / 8;
269 value
&= ~GITS_BASER_RO_MASK
;
270 s
->baser
[index
] &= GITS_BASER_RO_MASK
| MAKE_64BIT_MASK(0, 32);
271 s
->baser
[index
] |= value
;
273 value
&= ~GITS_BASER_RO_MASK
;
274 s
->baser
[index
] &= GITS_BASER_RO_MASK
| MAKE_64BIT_MASK(32, 32);
275 s
->baser
[index
] |= value
;
280 case GITS_IDREGS
... GITS_IDREGS
+ 0x2f:
281 /* RO registers, ignore the write */
282 qemu_log_mask(LOG_GUEST_ERROR
,
283 "%s: invalid guest write to RO register at offset "
284 TARGET_FMT_plx
"\n", __func__
, offset
);
293 static bool its_readl(GICv3ITSState
*s
, hwaddr offset
,
294 uint64_t *data
, MemTxAttrs attrs
)
304 *data
= gicv3_iidr();
306 case GITS_IDREGS
... GITS_IDREGS
+ 0x2f:
308 *data
= gicv3_idreg(offset
- GITS_IDREGS
);
311 *data
= extract64(s
->typer
, 0, 32);
314 *data
= extract64(s
->typer
, 32, 32);
317 *data
= extract64(s
->cbaser
, 0, 32);
319 case GITS_CBASER
+ 4:
320 *data
= extract64(s
->cbaser
, 32, 32);
323 *data
= extract64(s
->creadr
, 0, 32);
325 case GITS_CREADR
+ 4:
326 *data
= extract64(s
->creadr
, 32, 32);
329 *data
= extract64(s
->cwriter
, 0, 32);
331 case GITS_CWRITER
+ 4:
332 *data
= extract64(s
->cwriter
, 32, 32);
334 case GITS_BASER
... GITS_BASER
+ 0x3f:
335 index
= (offset
- GITS_BASER
) / 8;
337 *data
= extract64(s
->baser
[index
], 32, 32);
339 *data
= extract64(s
->baser
[index
], 0, 32);
349 static bool its_writell(GICv3ITSState
*s
, hwaddr offset
,
350 uint64_t value
, MemTxAttrs attrs
)
356 case GITS_BASER
... GITS_BASER
+ 0x3f:
358 * IMPDEF choice:- GITS_BASERn register becomes RO if ITS is
361 if (!(s
->ctlr
& ITS_CTLR_ENABLED
)) {
362 index
= (offset
- GITS_BASER
) / 8;
363 s
->baser
[index
] &= GITS_BASER_RO_MASK
;
364 s
->baser
[index
] |= (value
& ~GITS_BASER_RO_MASK
);
369 * IMPDEF choice:- GITS_CBASER register becomes RO if ITS is
372 if (!(s
->ctlr
& ITS_CTLR_ENABLED
)) {
375 s
->cwriter
= s
->creadr
;
379 s
->cwriter
= value
& ~R_GITS_CWRITER_RETRY_MASK
;
382 if (s
->gicv3
->gicd_ctlr
& GICD_CTLR_DS
) {
383 s
->creadr
= value
& ~R_GITS_CREADR_STALLED_MASK
;
385 /* RO register, ignore the write */
386 qemu_log_mask(LOG_GUEST_ERROR
,
387 "%s: invalid guest write to RO register at offset "
388 TARGET_FMT_plx
"\n", __func__
, offset
);
392 /* RO registers, ignore the write */
393 qemu_log_mask(LOG_GUEST_ERROR
,
394 "%s: invalid guest write to RO register at offset "
395 TARGET_FMT_plx
"\n", __func__
, offset
);
404 static bool its_readll(GICv3ITSState
*s
, hwaddr offset
,
405 uint64_t *data
, MemTxAttrs attrs
)
414 case GITS_BASER
... GITS_BASER
+ 0x3f:
415 index
= (offset
- GITS_BASER
) / 8;
416 *data
= s
->baser
[index
];
434 static MemTxResult
gicv3_its_read(void *opaque
, hwaddr offset
, uint64_t *data
,
435 unsigned size
, MemTxAttrs attrs
)
437 GICv3ITSState
*s
= (GICv3ITSState
*)opaque
;
442 result
= its_readl(s
, offset
, data
, attrs
);
445 result
= its_readll(s
, offset
, data
, attrs
);
453 qemu_log_mask(LOG_GUEST_ERROR
,
454 "%s: invalid guest read at offset " TARGET_FMT_plx
455 "size %u\n", __func__
, offset
, size
);
457 * The spec requires that reserved registers are RAZ/WI;
458 * so use false returns from leaf functions as a way to
459 * trigger the guest-error logging but don't return it to
460 * the caller, or we'll cause a spurious guest data abort.
467 static MemTxResult
gicv3_its_write(void *opaque
, hwaddr offset
, uint64_t data
,
468 unsigned size
, MemTxAttrs attrs
)
470 GICv3ITSState
*s
= (GICv3ITSState
*)opaque
;
475 result
= its_writel(s
, offset
, data
, attrs
);
478 result
= its_writell(s
, offset
, data
, attrs
);
486 qemu_log_mask(LOG_GUEST_ERROR
,
487 "%s: invalid guest write at offset " TARGET_FMT_plx
488 "size %u\n", __func__
, offset
, size
);
490 * The spec requires that reserved registers are RAZ/WI;
491 * so use false returns from leaf functions as a way to
492 * trigger the guest-error logging but don't return it to
493 * the caller, or we'll cause a spurious guest data abort.
499 static const MemoryRegionOps gicv3_its_control_ops
= {
500 .read_with_attrs
= gicv3_its_read
,
501 .write_with_attrs
= gicv3_its_write
,
502 .valid
.min_access_size
= 4,
503 .valid
.max_access_size
= 8,
504 .impl
.min_access_size
= 4,
505 .impl
.max_access_size
= 8,
506 .endianness
= DEVICE_NATIVE_ENDIAN
,
509 static const MemoryRegionOps gicv3_its_translation_ops
= {
510 .write_with_attrs
= gicv3_its_translation_write
,
511 .valid
.min_access_size
= 2,
512 .valid
.max_access_size
= 4,
513 .impl
.min_access_size
= 2,
514 .impl
.max_access_size
= 4,
515 .endianness
= DEVICE_NATIVE_ENDIAN
,
518 static void gicv3_arm_its_realize(DeviceState
*dev
, Error
**errp
)
520 GICv3ITSState
*s
= ARM_GICV3_ITS_COMMON(dev
);
523 for (i
= 0; i
< s
->gicv3
->num_cpu
; i
++) {
524 if (!(s
->gicv3
->cpu
[i
].gicr_typer
& GICR_TYPER_PLPIS
)) {
525 error_setg(errp
, "Physical LPI not supported by CPU %d", i
);
530 gicv3_its_init_mmio(s
, &gicv3_its_control_ops
, &gicv3_its_translation_ops
);
532 address_space_init(&s
->gicv3
->dma_as
, s
->gicv3
->dma
,
535 /* set the ITS default features supported */
536 s
->typer
= FIELD_DP64(s
->typer
, GITS_TYPER
, PHYSICAL
,
538 s
->typer
= FIELD_DP64(s
->typer
, GITS_TYPER
, ITT_ENTRY_SIZE
,
539 ITS_ITT_ENTRY_SIZE
- 1);
540 s
->typer
= FIELD_DP64(s
->typer
, GITS_TYPER
, IDBITS
, ITS_IDBITS
);
541 s
->typer
= FIELD_DP64(s
->typer
, GITS_TYPER
, DEVBITS
, ITS_DEVBITS
);
542 s
->typer
= FIELD_DP64(s
->typer
, GITS_TYPER
, CIL
, 1);
543 s
->typer
= FIELD_DP64(s
->typer
, GITS_TYPER
, CIDBITS
, ITS_CIDBITS
);
546 static void gicv3_its_reset(DeviceState
*dev
)
548 GICv3ITSState
*s
= ARM_GICV3_ITS_COMMON(dev
);
549 GICv3ITSClass
*c
= ARM_GICV3_ITS_GET_CLASS(s
);
551 c
->parent_reset(dev
);
553 /* Quiescent bit reset to 1 */
554 s
->ctlr
= FIELD_DP32(s
->ctlr
, GITS_CTLR
, QUIESCENT
, 1);
557 * setting GITS_BASER0.Type = 0b001 (Device)
558 * GITS_BASER1.Type = 0b100 (Collection Table)
559 * GITS_BASER<n>.Type,where n = 3 to 7 are 0b00 (Unimplemented)
560 * GITS_BASER<0,1>.Page_Size = 64KB
561 * and default translation table entry size to 16 bytes
563 s
->baser
[0] = FIELD_DP64(s
->baser
[0], GITS_BASER
, TYPE
,
564 GITS_BASER_TYPE_DEVICE
);
565 s
->baser
[0] = FIELD_DP64(s
->baser
[0], GITS_BASER
, PAGESIZE
,
566 GITS_BASER_PAGESIZE_64K
);
567 s
->baser
[0] = FIELD_DP64(s
->baser
[0], GITS_BASER
, ENTRYSIZE
,
570 s
->baser
[1] = FIELD_DP64(s
->baser
[1], GITS_BASER
, TYPE
,
571 GITS_BASER_TYPE_COLLECTION
);
572 s
->baser
[1] = FIELD_DP64(s
->baser
[1], GITS_BASER
, PAGESIZE
,
573 GITS_BASER_PAGESIZE_64K
);
574 s
->baser
[1] = FIELD_DP64(s
->baser
[1], GITS_BASER
, ENTRYSIZE
,
578 static void gicv3_its_post_load(GICv3ITSState
*s
)
580 if (s
->ctlr
& ITS_CTLR_ENABLED
) {
581 extract_table_params(s
);
582 extract_cmdq_params(s
);
586 static Property gicv3_its_props
[] = {
587 DEFINE_PROP_LINK("parent-gicv3", GICv3ITSState
, gicv3
, "arm-gicv3",
589 DEFINE_PROP_END_OF_LIST(),
592 static void gicv3_its_class_init(ObjectClass
*klass
, void *data
)
594 DeviceClass
*dc
= DEVICE_CLASS(klass
);
595 GICv3ITSClass
*ic
= ARM_GICV3_ITS_CLASS(klass
);
596 GICv3ITSCommonClass
*icc
= ARM_GICV3_ITS_COMMON_CLASS(klass
);
598 dc
->realize
= gicv3_arm_its_realize
;
599 device_class_set_props(dc
, gicv3_its_props
);
600 device_class_set_parent_reset(dc
, gicv3_its_reset
, &ic
->parent_reset
);
601 icc
->post_load
= gicv3_its_post_load
;
604 static const TypeInfo gicv3_its_info
= {
605 .name
= TYPE_ARM_GICV3_ITS
,
606 .parent
= TYPE_ARM_GICV3_ITS_COMMON
,
607 .instance_size
= sizeof(GICv3ITSState
),
608 .class_init
= gicv3_its_class_init
,
609 .class_size
= sizeof(GICv3ITSClass
),
612 static void gicv3_its_register_types(void)
614 type_register_static(&gicv3_its_info
);
617 type_init(gicv3_its_register_types
)