|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH 12/24] ARM: vGICv3: introduce basic ITS emulation bits
Hi Andre, On 28/09/16 19:24, Andre Przywara wrote: Create a new file to hold the emulation code for the ITS widget. For now we emulate the memory mapped ITS registers and provide a stub to introduce the ITS command handling framework (but without actually emulating any commands at this time). The ITS is a complex piece so I think it would be good to describe more in the commit message how this will work. Also a documentation in the tree would be very good to help understanding the code. CWRITER and CREADR are registers so they need to be described in term of number of bits. Also, while the top word of CREADR/CWRITER is RES0. I would much prefer to see uint64_t rather than uint32_t as this is the real size of the register. + spinlock_t its_lock; /* protects the collection and device tables */ + uint64_t baser0, baser1; Please describe what contains baser0 and baser1. If I understand correctly the code, baser0 will be store Device information whilst baser1 the collection. + uint16_t *coll_table; What is the layout of the device table? + int max_collections; unsigned int + uint64_t *dev_table; What is the layout of the device table? + int max_devices; unsigned int. + bool enabled; +}; + +/* An Interrupt Translation Table Entry: this is indexed by a Coding style: /* * Foo Please make this function inline. + int word, int shift, int size) unsigned for all those parameters. It is probably better to use BIT_ULL (see my explanation on previous patches). +} + +#define its_cmd_get_command(cmd) its_cmd_mask_field(cmd, 0, 0, 8) +#define its_cmd_get_deviceid(cmd) its_cmd_mask_field(cmd, 0, 32, 32) +#define its_cmd_get_size(cmd) its_cmd_mask_field(cmd, 1, 0, 5) +#define its_cmd_get_id(cmd) its_cmd_mask_field(cmd, 1, 0, 32) +#define its_cmd_get_physical_id(cmd) its_cmd_mask_field(cmd, 1, 32, 32) +#define its_cmd_get_collection(cmd) its_cmd_mask_field(cmd, 2, 0, 16) +#define its_cmd_get_target_addr(cmd) its_cmd_mask_field(cmd, 2, 16, 32) +#define its_cmd_get_validbit(cmd) its_cmd_mask_field(cmd, 2, 63, 1) + +#define ITS_CMD_BUFFER_SIZE(baser) ((((baser) & 0xff) + 1) << 12) + +static int vgic_its_handle_cmds(struct domain *d, struct virt_its *its, + uint32_t writer) uint64_t here. You return an error value but the caller does not check it. Should not the caller do a different action when the return -1? If not, it should be documented. + + spin_lock(&its->vcmd_lock); I am quite concerned about this locking. Coding style: switch ( ... ) The indentation is wrong. + default: + gdprintk(XENLOG_G_WARNING, "ITS: unhandled ITS command %ld\n", gdprintk will happen XENLOG_GUEST, so you can use XENLOG_WARNING here. Also s/%ld/%lu/ + its_cmd_get_command(cmdptr)); Should not we report the error to the default, or crash it? We tend to do the latter on Xen for constrained unpredictable behavior. + break; + } + + its->creadr += ITS_CMD_SIZE; + if ( its->creadr == ITS_CMD_BUFFER_SIZE(its->cbaser) ) + its->creadr = 0; + } + its->cwriter = writer; I think its->cwriter should be updated before the loop. So another vCPU could read the correct CWRITER whilst this vCPU is executing the commands. + + spin_unlock(&its->vcmd_lock); + + return 0; +} + +/***************************** + * ITS registers read access * + *****************************/ + +/* The physical address is encoded slightly differently depending on Coding style: /* * foo Please document what is bit 9. Please use a define for BIT(31). Also, technically the ITS is not quiescent when command are executed (GITS_CTLR could be read from another vCPU). + break; + case VREG32(GITS_IIDR): + if ( info->dabt.size != DABT_WORD ) goto bad_width; + *r = vgic_reg32_extract(GITS_IIDR_VALUE, info); + break; + case VREG64(GITS_TYPER): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + *r = vgic_reg64_extract(0x1eff1, info); Please document the value and add defines. Vijay's mentioned about the number of device IDs, but the number of collection likely needs to be dynamic as it depends on the number of vCPUs. + break; + case VREG64(GITS_CBASER): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + *r = vgic_reg64_extract(its->cbaser, info); + break; + case VREG64(GITS_CWRITER): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + *r = vgic_reg64_extract(its->cwriter, info); + break; + case VREG64(GITS_CREADR): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + *r = vgic_reg64_extract(its->creadr, info); + break; + case VREG64(GITS_BASER0): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + *r = vgic_reg64_extract(its->baser0, info); + break; + case VREG64(GITS_BASER1): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + *r = vgic_reg64_extract(its->baser1, info); + break; + case VRANGE64(GITS_BASER2, GITS_BASER7): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + *r = vgic_reg64_extract(0, info); Please introduce a label read_as_zero_64 at the end and do the implementation of RAZ there. It will acts as a documentation too (see an example in vgic-v3.c). Also, vgic_reg64_extract(0, info) will ... always return 0. So you can optimize it ;). + break; + case VREG32(GICD_PIDR2): This feels odd to use GICD_PIDR2 here. Please define GITS_PIDR2 to avoid any confusion. + if ( info->dabt.size != DABT_WORD ) goto bad_width; + *r = vgic_reg32_extract(GICV3_GICD_PIDR2, info); Ditto. + break; Please add all the registers even implementation defined and reserved one. Ignoring registers without any warning is usually a bad idea as it makes very difficult to debug it. You can look at vgic-v3.c for an example. + } + + return 1; + +bad_width: Please print an error here (see vgic-v3.c). + domain_crash_synchronous(); + + return 0; +} + +/****************************** + * ITS registers write access * + ******************************/ + +static int its_baser_table_size(uint64_t baser) unsigned int for the return and the function would probably benefit to be inlined. unsigned int. + + switch ( (baser >> 8) & 3 ) Please define 8 and 3.
It looks like to me that the switch could be turned into an array:
unsigned page_size[] = {SZ_4K, SZ_16K, SZ_64K, SZ_64K};
This woudl make the code simpler.
+ + return page_size * ((baser & GENMASK(7, 0)) + 1); +} + +static int its_baser_nr_entries(uint64_t baser) unsigned int for the return and the function would probably benefit to be inlined. unsigned int for the type. Also please use a define for 48. ctlr could be defined in the case... here. I tend to prefer to restrict the scope whenever it is possible. + ctlr = its->enabled ? GITS_CTLR_ENABLE : 0; + if ( info->dabt.size != DABT_WORD ) goto bad_width; + vgic_reg32_update(&ctlr, r, info); + its->enabled = ctlr & GITS_CTLR_ENABLE; + /* TODO: trigger something ... */ The indentation is wrong. + return 1; + case VREG32(GITS_IIDR): + goto write_ignore_32; + case VREG32(GITS_TYPER): + goto write_ignore_32; + case VREG64(GITS_CBASER): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access. + + /* Changing base registers with the ITS enabled is UNPREDICTABLE. */ + if ( its->enabled ) + return 1; + There may have concurrent access to GITS_BASER, so you want to have some lock here. + reg = its->cbaser; + vgic_reg64_update(®, r, info); + /* TODO: sanitise! */ Please fix this todo as soon as possible. + its->cbaser = reg; Also, I am not sure to understand why you need a temporary variable. Whilst you could directly update its->cbaser: vgic_regs64_update(&its->cbaser, r, info);Also, from the spec (8.19.2 in ARM IHI 0069C), GITS_CREADR (i.e its->creadr) should be reset to 0. + + if ( reg & BIT(63) ) Please define bit 63. Please use vgic_reg64_check_access. + reg = its->cwriter; + vgic_reg64_update(®, r, info); vgic_its_handle_cmds expect CWRITER to the bit 0 (Retry) masked and bit [32:20], [4:1] should be RES0 (i.e masked). + vgic_its_handle_cmds(d, its, reg); Should not you check the return value? + return 1; + case VREG64(GITS_CREADR): + goto write_ignore_64; + case VREG64(GITS_BASER0): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + + /* Changing base registers with the ITS enabled is UNPREDICTABLE. */ + if ( its->enabled ) + return 1; + + reg = its->baser0; + vgic_reg64_update(®, r, info); + + reg &= ~GITS_BASER_RO_MASK; + reg |= (sizeof(uint64_t) - 1) << GITS_BASER_ENTRY_SIZE_SHIFT; Where does this sizeof(uint64_t) come from? + reg |= GITS_BASER_TYPE_DEVICE << GITS_BASER_TYPE_SHIFT; + /* TODO: sanitise! */ + /* TODO: locking(?) */ Yes, some locking is needed. I am not sure to understand why we need to memset and what the value corresponds to. Why don't you update baser0 directly (with vgic_reg64_update)? + return 1; + case VREG64(GITS_BASER1): + if ( info->dabt.size < DABT_WORD ) goto bad_width; Please use vgic_reg64_check_access + + /* Changing base registers with the ITS enabled is UNPREDICTABLE. */ + if ( its->enabled ) + return 1; + + reg = its->baser1; + vgic_reg64_update(®, r, info); + reg &= ~GITS_BASER_RO_MASK; + reg |= (sizeof(uint16_t) - 1) << GITS_BASER_ENTRY_SIZE_SHIFT; + reg |= GITS_BASER_TYPE_COLLECTION << GITS_BASER_TYPE_SHIFT; + /* TODO: sanitise! */ + + /* TODO: sort out locking */ I am expecting this to be fixed in the next version. I am not sure to understand why we need to memset and what the value corresponds to. Why don't you update baser1 directly (with vgic_reg64_update)? + return 1; + case VRANGE64(GITS_BASER2, GITS_BASER7): + goto write_ignore_64; From the ITS register map, we would have to emulate more register (at least reserved, implementation defined and RAZ). + default: + gdprintk(XENLOG_G_WARNING, "ITS: unhandled ITS register 0x%lx\n", + info->gpa & 0xffff); + return 0; + } + + return 1; + +write_ignore_64: + if ( ! vgic_reg64_check_access(info->dabt) ) goto bad_width; + return 1; + +write_ignore_32: + if ( info->dabt.size != DABT_WORD ) goto bad_width; + return 1; + +bad_width: + printk(XENLOG_G_ERR "%pv vGICR: bad read width %d r%d offset %#08lx\n", + v, info->dabt.size, info->dabt.reg, info->gpa & 0xffff); + + domain_crash_synchronous(); + + return 0; +} + The Makefile already includes the vi This will break compilation with randconfig as the ITS is selectable. Please make sure that every patch built one by one. A good approach would be allowing the selection of the ITS at the end of this series. Those values should not be defined in gic_v3_defs.h but a vgic headers. My rationale is, those value are implementation defined (e.g depends on the emulation). This function should be defined in vgic.h and not gic_v3_defs.h #endif /* __ASM_ARM_GIC_V3_DEFS_H__ */ /* Regards, -- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx https://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |