On Thu, 2021-04-29 at 17:46 -0400, shashi.mall...@linaro.org wrote: On Fri, 2021-04-16 at 19:54 +0100, Peter Maydell wrote: > On Thu, 1 Apr 2021 at 03:41, Shashi Mallela < > shashi.mall...@linaro.org> wrote: > > Defined descriptors for ITS device table,collection table and ITS > > command queue entities.Implemented register read/write functions, > > extract ITS table parameters and command queue parameters,extended > > gicv3 common to capture qemu address space(which host the ITS table > > platform memories required for subsequent ITS processing) and > > initialize the same in its device. > > > > Signed-off-by: Shashi Mallela <shashi.mall...@linaro.org> > > --- > > hw/intc/arm_gicv3_its.c | 313 > > +++++++++++++++++++++++++ > > hw/intc/arm_gicv3_its_common.c | 42 ++++ > > hw/intc/gicv3_internal.h | 33 ++- > > include/hw/intc/arm_gicv3_common.h | 4 + > > include/hw/intc/arm_gicv3_its_common.h | 28 +++ > > 5 files changed, 414 insertions(+), 6 deletions(-) > > > > diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c > > index 209120d102..81373f049d 100644 > > --- a/hw/intc/arm_gicv3_its.c > > +++ b/hw/intc/arm_gicv3_its.c > > @@ -28,6 +28,131 @@ struct GICv3ITSClass { > > void (*parent_reset)(DeviceState *dev); > > }; > > > > +static bool extract_table_params(GICv3ITSState *s, int index) > > +{ > > + uint16_t num_pages = 0; > > + uint8_t page_sz_type; > > + uint8_t type; > > + uint32_t page_sz = 0; > > + uint64_t value = s->baser[index]; > > + > > + num_pages = FIELD_EX64(value, GITS_BASER, SIZE); > > + page_sz_type = FIELD_EX64(value, GITS_BASER, PAGESIZE); > > + > > + if (page_sz_type == 0) { > > + page_sz = GITS_ITT_PAGE_SIZE_0; > > + } else if (page_sz_type == 0) { > > + page_sz = GITS_ITT_PAGE_SIZE_1; > > + } else if (page_sz_type == 2) { > > + page_sz = GITS_ITT_PAGE_SIZE_2; > > + } else { > > + return false; > > The spec says that page_sz+type = 0b11 should be treated as 0b10. > So we could log this as a guest error if you like but otherwise > should handle it the same way we do 0b10. > > > + } > > if (x == CONST1) { > } else if (x == CONST2) { > } else { > } > > is usually clearer written with switch(). (There are other instances > of this pattern below.) > > > + > > + type = FIELD_EX64(value, GITS_BASER, TYPE); > > + > > + if (type == GITS_ITT_TYPE_DEVICE) { > > + s->dt.valid = FIELD_EX64(value, GITS_BASER, VALID); > > + > > + if (s->dt.valid) { > > + s->dt.indirect = FIELD_EX64(value, GITS_BASER, > > INDIRECT); > > + s->dt.entry_sz = FIELD_EX64(value, GITS_BASER, > > ENTRYSIZE); > > + > > + if (!s->dt.indirect) { > > + s->dt.max_entries = ((num_pages + 1) * page_sz) / > > + s- > > >dt.entry_sz; > > + } else { > > + s->dt.max_entries = ((((num_pages + 1) * page_sz) > > / > > + L1TABLE_ENTRY_SIZE) * > > + (page_sz / s->dt.entry_sz)); > > + } > > + > > + s->dt.max_devids = (1UL << (FIELD_EX64(s->typer, > > GITS_TYPER, > > + DEVBITS) + > > 1)); > > + > > + if ((page_sz == GITS_ITT_PAGE_SIZE_0) || > > + (page_sz == GITS_ITT_PAGE_SIZE_1)) { > > + s->dt.base_addr = FIELD_EX64(value, GITS_BASER, > > PHYADDR); > > + s->dt.base_addr <<= R_GITS_BASER_PHYADDR_SHIFT; > > + } else if (page_sz == GITS_ITT_PAGE_SIZE_2) { > > + s->dt.base_addr = FIELD_EX64(value, GITS_BASER, > > PHYADDRL_64K) << > > + R_GITS_BASER_PHYADDRL_64K_SHIFT; > > + s->dt.base_addr |= ((value >> > > R_GITS_BASER_PHYADDR_SHIFT) & > > + R_GITS_BASER_PHYADDRH_64K_M > > ASK) << > > + R_GITS_BASER_PHYADDRH_64K_S > > HIFT; > > + } > > + } > > + } else if (type == GITS_ITT_TYPE_COLLECTION) { > > + s->ct.valid = FIELD_EX64(value, GITS_BASER, VALID); > > + > > + /* > > + * GITS_TYPER.HCC is 0 for this implementation > > + * hence writes are discarded if ct.valid is 0 > > + */ > > + if (s->ct.valid) { > > + s->ct.indirect = FIELD_EX64(value, GITS_BASER, > > INDIRECT); > > + s->ct.entry_sz = FIELD_EX64(value, GITS_BASER, > > ENTRYSIZE); > > + > > + if (!s->ct.indirect) { > > + s->ct.max_entries = ((num_pages + 1) * page_sz) / > > + s->ct.entry_sz; > > + } else { > > + s->ct.max_entries = ((((num_pages + 1) * page_sz) > > / > > + L1TABLE_ENTRY_SIZE) * > > + (page_sz / s->ct.entry_sz)); > > + } > > + > > + if (FIELD_EX64(s->typer, GITS_TYPER, CIL)) { > > + s->ct.max_collids = (1UL << (FIELD_EX64(s->typer, > > GITS_TYPER, > > + CIDBITS) > > + 1)); > > + } else { > > + /* 16-bit CollectionId supported when CIL == 0 */ > > + s->ct.max_collids = (1UL << 16); > > + } > > + > > + if ((page_sz == GITS_ITT_PAGE_SIZE_0) || > > + (page_sz == GITS_ITT_PAGE_SIZE_1)) { > > + s->ct.base_addr = FIELD_EX64(value, GITS_BASER, > > PHYADDR); > > + s->ct.base_addr <<= R_GITS_BASER_PHYADDR_SHIFT; > > + } else if (page_sz == GITS_ITT_PAGE_SIZE_2) { > > + s->ct.base_addr = FIELD_EX64(value, GITS_BASER, > > PHYADDRL_64K) << > > + R_GITS_BASER_PHYADDRL_64K_SHIF > > T; > > + s->ct.base_addr |= ((value >> > > R_GITS_BASER_PHYADDR_SHIFT) & > > + R_GITS_BASER_PHYADDRH_64K_MAS > > K) << > > + R_GITS_BASER_PHYADDRH_64K_SHI > > FT; > > + } > > + } > > + } else { > > + /* unsupported ITS table type */ > > + qemu_log_mask(LOG_GUEST_ERROR, "%s: Unsupported ITS table > > type %d", > > + __func__, type); > > This should never happen, because the TYPE field in a GITS_BASER > register > is read-only. The model should insure that the guest can never write > to > these bits. Then you can just assert() that the field is valid, if > you like. > > > + return false; > > + } > > + return true; > > +} > > + > > +static bool extract_cmdq_params(GICv3ITSState *s) > > +{ > > + uint16_t num_pages = 0; > > + uint64_t value = s->cbaser; > > + > > + num_pages = FIELD_EX64(value, GITS_CBASER, SIZE); > > + > > + s->cq.valid = FIELD_EX64(value, GITS_CBASER, VALID); > > + > > + if (!num_pages || !s->cq.valid) { > > Why do you think num_pages == 0 is not valid ? > Have rectified this > > + return false; > > + } > > + > > + if (s->cq.valid) { > > + s->cq.max_entries = ((num_pages + 1) * > > GITS_ITT_PAGE_SIZE_0) / > > + GITS_CMDQ_ENTRY_SI > > ZE; > > + s->cq.base_addr = FIELD_EX64(value, GITS_CBASER, PHYADDR); > > + s->cq.base_addr <<= R_GITS_CBASER_PHYADDR_SHIFT; > > + } > > + return true; > > +} > > + > > static MemTxResult its_trans_writew(GICv3ITSState *s, hwaddr > > offset, > > uint64_t value, MemTxAttrs attrs) > > { > > @@ -126,7 +251,75 @@ static MemTxResult its_writel(GICv3ITSState > > *s, hwaddr offset, > > uint64_t value, MemTxAttrs > > attrs)> { > > MemTxResult result = MEMTX_OK; > > + int index; > > + uint64_t temp = 0; > > > > + switch (offset) { > > + case GITS_CTLR: > > + s->ctlr |= (value & ~(s->ctlr)); > > + break; > > + case GITS_CBASER: > > + /* GITS_CBASER register becomes RO if ITS is already > > enabled */ > > The spec says writes are UNPREDICTABLE, not RO. We can make an > impdef choice to interpret that as RO for our convenience, but > the comment should note that it is our IMPDEF choice. > > > + if (!(s->ctlr & ITS_CTLR_ENABLED)) { > > + s->cbaser = deposit64(s->cbaser, 0, 32, value); > > + s->creadr = 0; > > + } > > + break; > > + case GITS_CBASER + 4: > > + /* GITS_CBASER register becomes RO if ITS is already > > enabled */ > > + if (!(s->ctlr & ITS_CTLR_ENABLED)) { > > + s->cbaser = deposit64(s->cbaser, 32, 32, value); > > + if (!extract_cmdq_params(s)) { > > You should postpone trying to parse the CBASER fields until > the guest enables the ITS by writing to GITS_CTLR.Enabled. > Because CBASER is a 64-bit register that can be written as two > 32-bit halves, the guest might choose to write the two halves > in either order, and you won't have a full valid CBASER. > If you wait until the ITS is enabled then you know the guest > should have written the register values completely then. > Similarly with BASER. > > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "%s: error extracting GITS_CBASER > > parameters " > > + TARGET_FMT_plx "\n", __func__, offset); > > + s->cbaser = 0; > > Clearing CBASER if the guest writes an invalid value to it > doesn't seem right. Since you have these expanded-out structs, > you can just treat any bogus values as if the guest had written > VALID=0, and leave the actual guest-written value in s->cbaser. > (In fact I think the only case when extract_cmdq_params() > can reasonably return false is exactly when VALID=0, so in > that case you might as well drop the bool return type from it > completely.) > > > + result = MEMTX_ERROR; > > I don't recommend using MEMTX_ERROR here for this kind of > "the guest wrote a value to a valid register but there happened > to be something wrong with the value it wrote". The intention > with the arm_gicv3_dist.c code structure that you've copied > here for the ITS was simply to use MEMTX_ERROR to capture "this > register doesn't exist for this size" to be able to have a > single LOG_GUEST_ERROR message for that at the top level > function. > > For more complicated stuff like this you should just report a > suitable specific LOG_GUEST_ERROR directly in extract_cmdq_params() > and return MEMTX_OK. (The code you have for BASER will actually > report > three different log messages for a single guest mistake -- once > inside > extract_table_params(), once in the code in this function that calls > extract_table_params(), and then once in gicv3_its_read(). One is > sufficient.) > > > + } else { > > + s->creadr = 0; > > + } > > + } > > + break; > > + case GITS_CWRITER: > > + s->cwriter = deposit64(s->cwriter, 0, 32, value); > > + break; > > + case GITS_CWRITER + 4: > > + s->cwriter = deposit64(s->cwriter, 32, 32, value); > > + break; > > + case GITS_BASER ... GITS_BASER + 0x3f: > > + /* GITS_BASERn registers become RO if ITS is already > > enabled */ > > + if (!(s->ctlr & ITS_CTLR_ENABLED)) { > > + index = (offset - GITS_BASER) / 8; > > + > > + if (offset & 7) { > > + temp = s->baser[index]; > > + temp = deposit64(temp, 32, 32, (value & > > ~GITS_BASER_VAL_MASK)); > > + s->baser[index] |= temp; > > + > > + if (!extract_table_params(s, index)) { > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "%s: error extracting GITS_BASER > > parameters " > > + TARGET_FMT_plx "\n", __func__, offset); > > + s->baser[index] = 0; > > + result = MEMTX_ERROR; > > + } > > + } else { > > + s->baser[index] = deposit64(s->baser[index], 0, > > 32, value); > > + } > > + } > > Pretty much all the remarks I made earlier about CBASER apply here > too. > > Also, 'unimplemented' BASER registers are supposed to be RES0, and > I don't think we actually implement more than either 2 or 3, right? > we implement only 2 BASER registers one for device table and one for collection table > > > + break; > > + case GITS_IIDR: > > + case GITS_TYPER: > > + case GITS_CREADR: > > + /* RO registers, ignore the write */ > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "%s: invalid guest write to RO register at offset " > > + TARGET_FMT_plx "\n", __func__, offset); > > + break; > > I wouldn't personally bother explicitly reporting write-to-RO- > register > here: if you just let the default case handle it then the log in > the caller will do a LOG_GUEST_ERROR for you. > > > + default: > > + result = MEMTX_ERROR; > > + break; > > + } > > return result; > > } > > > > @@ -142,7 +382,52 @@ static MemTxResult its_writell(GICv3ITSState > > *s, hwaddr offset, > > uint64_t value, MemTxAttrs attrs) > > { > > MemTxResult result = MEMTX_OK; > > + int index; > > > > + switch (offset) { > > + case GITS_BASER ... GITS_BASER + 0x3f: > > + /* GITS_BASERn registers become RO if ITS is already > > enabled */ > > + if (!(s->ctlr & ITS_CTLR_ENABLED)) { > > + index = (offset - GITS_BASER) / 8; > > + s->baser[index] |= (value & ~GITS_BASER_VAL_MASK); > > + if (!extract_table_params(s, index)) { > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "%s: error extracting GITS_BASER > > parameters " > > + TARGET_FMT_plx "\n", __func__, offset); > > + s->baser[index] = 0; > > + result = MEMTX_ERROR; > > + } > > + } > > + break; > > + case GITS_CBASER: > > + /* GITS_CBASER register becomes RO if ITS is already > > enabled */ > > + if (!(s->ctlr & ITS_CTLR_ENABLED)) { > > + s->cbaser = value; > > + if (!extract_cmdq_params(s)) { > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "%s: error extracting GITS_CBASER > > parameters " > > + TARGET_FMT_plx "\n", __func__, offset); > > + s->cbaser = 0; > > + result = MEMTX_ERROR; > > + } else { > > + s->creadr = 0; > > + } > > + } > > + break; > > + case GITS_CWRITER: > > + s->cwriter = value; > > + break; > > + case GITS_TYPER: > > + case GITS_CREADR: > > + /* RO register, ignore the write */ > > + qemu_log_mask(LOG_GUEST_ERROR, > > + "%s: invalid guest write to RO register at > > offset " > > + TARGET_FMT_plx "\n", __func__, offset); > > + break; > > + default: > > + result = MEMTX_ERROR; > > + break; > > + } > > Comments on the 32-bit write function apply here too. > > > return result; > > } > > @@ -250,6 +557,9 @@ static void gicv3_arm_its_realize(DeviceState > > *dev, Error **errp) > > GICv3ITSState *s = ARM_GICV3_ITS_COMMON(dev); > > > > gicv3_its_init_mmio(s, &gicv3_its_control_ops, > > &gicv3_its_translation_ops); > > + > > + address_space_init(&s->gicv3->sysmem_as, s->gicv3->sysmem, > > + "gicv3-its-sysmem"); > > Indent here seems wrong -- the second line should be lined up with > the first, so the '"' is below the '&'. I think I noticed some of > this > in patch 1 as well, so worth going through and checking that. > > > } > > > > static void gicv3_its_reset(DeviceState *dev) > > @@ -259,6 +569,9 @@ static void gicv3_its_reset(DeviceState *dev) > > > > if (s->gicv3->cpu->gicr_typer & GICR_TYPER_PLPIS) { > > c->parent_reset(dev); > > + memset(&s->dt, 0, sizeof(s->dt)); > > + memset(&s->ct, 0, sizeof(s->ct)); > > + memset(&s->cq, 0, sizeof(s->cq)); > > Would be cleaner to first set the baser/cbaser registers to their > reset values and then just call the function that calculates these > struct fields based on the register values. > > > /* set the ITS default features supported */ > > s->typer = FIELD_DP64(s->typer, GITS_TYPER, PHYSICAL, > > diff --git a/hw/intc/arm_gicv3_its_common.c > > b/hw/intc/arm_gicv3_its_common.c > > index 80cc9ec6d8..9c5c71f350 100644 > > --- a/hw/intc/arm_gicv3_its_common.c > > +++ b/hw/intc/arm_gicv3_its_common.c > > @@ -48,6 +48,42 @@ static int gicv3_its_post_load(void *opaque, int > > version_id) > > return 0; > > } > > > > +static const VMStateDescription vmstate_its_dtdesc = { > > + .name = "arm_gicv3_its_dtdesc", > > + .fields = (VMStateField[]) { > > + VMSTATE_BOOL(valid, DevTableDesc), > > + VMSTATE_BOOL(indirect, DevTableDesc), > > + VMSTATE_UINT16(entry_sz, DevTableDesc), > > + VMSTATE_UINT32(max_entries, DevTableDesc), > > + VMSTATE_UINT32(max_devids, DevTableDesc), > > + VMSTATE_UINT64(base_addr, DevTableDesc), > > + VMSTATE_END_OF_LIST(), > > + }, > > +}; > > + > > +static const VMStateDescription vmstate_its_ctdesc = { > > + .name = "arm_gicv3_its_ctdesc", > > + .fields = (VMStateField[]) { > > + VMSTATE_BOOL(valid, CollTableDesc), > > + VMSTATE_BOOL(indirect, CollTableDesc), > > + VMSTATE_UINT16(entry_sz, CollTableDesc), > > + VMSTATE_UINT32(max_entries, CollTableDesc), > > + VMSTATE_UINT32(max_collids, CollTableDesc), > > + VMSTATE_UINT64(base_addr, CollTableDesc), > > + VMSTATE_END_OF_LIST(), > > + }, > > +}; > > + > > +static const VMStateDescription vmstate_its_cqdesc = { > > + .name = "arm_gicv3_its_cqdesc", > > + .fields = (VMStateField[]) { > > + VMSTATE_BOOL(valid, CmdQDesc), > > + VMSTATE_UINT32(max_entries, CmdQDesc), > > + VMSTATE_UINT64(base_addr, CmdQDesc), > > + VMSTATE_END_OF_LIST(), > > + }, > > +}; > > Do these really need migrating, or are they just expanded out values > that can be recalculated from the BASER and CBASER register values? > If so then it would be simpler to recalculate in a migration post- > load > function. > have removed all the migration specific variables and implemented > migration post-load to recalculate the required values > > > + > > static const VMStateDescription vmstate_its = { > > .name = "arm_gicv3_its", > > .version_id = 1, > > @@ -56,6 +92,12 @@ static const VMStateDescription vmstate_its = { > > .post_load = gicv3_its_post_load, > > .priority = MIG_PRI_GICV3_ITS, > > .fields = (VMStateField[]) { > > + VMSTATE_STRUCT(dt, GICv3ITSState, 0, vmstate_its_dtdesc, > > + DevTableDesc), > > + VMSTATE_STRUCT(ct, GICv3ITSState, 0, vmstate_its_ctdesc, > > + CollTableDesc), > > + VMSTATE_STRUCT(cq, GICv3ITSState, 0, vmstate_its_cqdesc, > > + CmdQDesc), > > As noted previously, you can't just add fields to a > VMStateDescription; > retaining migration compatibility requires more than that. > > > VMSTATE_UINT32(ctlr, GICv3ITSState), > > VMSTATE_UINT32(translater, GICv3ITSState), > > VMSTATE_UINT32(iidr, GICv3ITSState), > > diff --git a/hw/intc/gicv3_internal.h b/hw/intc/gicv3_internal.h > > index 96cfe2dff9..b7701e8ca5 100644 > > --- a/hw/intc/gicv3_internal.h > > +++ b/hw/intc/gicv3_internal.h > > @@ -246,13 +246,14 @@ FIELD(GITS_BASER, INNERCACHE, 59, 3) > > FIELD(GITS_BASER, INDIRECT, 62, 1) > > FIELD(GITS_BASER, VALID, 63, 1) > > > > -#define GITS_BASER_PAGESIZE_4K 0 > > -#define GITS_BASER_PAGESIZE_16K 1 > > -#define GITS_BASER_PAGESIZE_64K 2 > > - > > -#define GITS_ITT_TYPE_DEVICE 1ULL > > -#define GITS_ITT_TYPE_COLLECTION 4ULL > > You just added these in the previous patch, don't move them > in this one. Have patch 1 put them in the right place in the file > to start with. > > > +FIELD(GITS_CBASER, SIZE, 0, 8) > > +FIELD(GITS_CBASER, SHAREABILITY, 10, 2) > > +FIELD(GITS_CBASER, PHYADDR, 12, 40) > > +FIELD(GITS_CBASER, OUTERCACHE, 53, 3) > > +FIELD(GITS_CBASER, INNERCACHE, 59, 3) > > +FIELD(GITS_CBASER, VALID, 63, 1) > > > > +FIELD(GITS_CTLR, ENABLED, 0, 1) > > FIELD(GITS_CTLR, QUIESCENT, 31, 1) > > > > FIELD(GITS_TYPER, PHYSICAL, 0, 1) > > @@ -264,6 +265,26 @@ FIELD(GITS_TYPER, PTA, 19, 1) > > FIELD(GITS_TYPER, CIDBITS, 32, 4) > > FIELD(GITS_TYPER, CIL, 36, 1) > > > > +#define ITS_CTLR_ENABLED (1U) /* ITS Enabled */ > > + > > +#define > > GITS_BASER_VAL_MASK (R_GITS_BASER_ENTRYSIZE_MASK | > > \ > > + R_GITS_BASER_TYPE_MA > > SK) > > + > > +#define GITS_BASER_PAGESIZE_4K 0 > > +#define GITS_BASER_PAGESIZE_16K 1 > > +#define GITS_BASER_PAGESIZE_64K 2 > > + > > +#define GITS_ITT_TYPE_DEVICE 1ULL > > +#define GITS_ITT_TYPE_COLLECTION 4ULL > > + > > +#define GITS_ITT_PAGE_SIZE_0 0x1000 > > +#define GITS_ITT_PAGE_SIZE_1 0x4000 > > +#define GITS_ITT_PAGE_SIZE_2 0x10000 > > + > > +#define L1TABLE_ENTRY_SIZE 8 > > + > > +#define GITS_CMDQ_ENTRY_SIZE 32 > > + > > /** > > * Default features advertised by this version of ITS > > */ > > diff --git a/include/hw/intc/arm_gicv3_common.h > > b/include/hw/intc/arm_gicv3_common.h > > index 91491a2f66..b0f2414fa3 100644 > > --- a/include/hw/intc/arm_gicv3_common.h > > +++ b/include/hw/intc/arm_gicv3_common.h > > @@ -226,12 +226,16 @@ struct GICv3State { > > int dev_fd; /* kvm device fd if backed by kvm vgic support */ > > Error *migration_blocker; > > > > + MemoryRegion *sysmem; > > + AddressSpace sysmem_as; > > I think these would be better named "dma" and "dma_as", because > from the ITS' point of view that's what they are. There's no inherent > requirement that they be connected to the system address space in > particular. > > > + > > /* Distributor */ > > > > /* for a GIC with the security extensions the NS banked > > version of this > > * register is just an alias of bit 1 of the S banked version. > > */ > > uint32_t gicd_ctlr; > > + uint32_t gicd_typer; > > What's this for ? You shouldn't need to be adding new distributor > state fields. > removed > > > uint32_t gicd_statusr[2]; > > GIC_DECLARE_BITMAP(group); /* GICD_IGROUPR */ > > GIC_DECLARE_BITMAP(grpmod); /* GICD_IGRPMODR */ > > diff --git a/include/hw/intc/arm_gicv3_its_common.h > > b/include/hw/intc/arm_gicv3_its_common.h > > index 08bc5652ed..b7eca57221 100644 > > --- a/include/hw/intc/arm_gicv3_its_common.h > > +++ b/include/hw/intc/arm_gicv3_its_common.h > > @@ -43,6 +43,30 @@ > > > > #define GITS_PIDR2 0xFFE8 > > > > +typedef struct { > > + bool valid; > > + bool indirect; > > + uint16_t entry_sz; > > + uint32_t max_entries; > > + uint32_t max_devids; > > + uint64_t base_addr; > > +} DevTableDesc; > > + > > +typedef struct { > > + bool valid; > > + bool indirect; > > + uint16_t entry_sz; > > + uint32_t max_entries; > > + uint32_t max_collids; > > + uint64_t base_addr; > > +} CollTableDesc; > > + > > +typedef struct { > > + bool valid; > > + uint32_t max_entries; > > + uint64_t base_addr; > > +} CmdQDesc; > > + > > struct GICv3ITSState { > > SysBusDevice parent_obj; > > > > @@ -66,6 +90,10 @@ struct GICv3ITSState { > > uint64_t creadr; > > uint64_t baser[8]; > > > > + DevTableDesc dt; > > + CollTableDesc ct; > > + CmdQDesc cq; > > + > > Error *migration_blocker; > > }; > > > > -- > > 2.27.0 > > thanks > -- PMM