|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [RFC PATCH v2 14/22] xen/arm: its: Add emulation of ITS control registers
Hello Vijay, On 19/03/2015 14:38, vijay.kilari@xxxxxxxxx wrote: This variable is not exported so static. Although, I'm not convinced this variable is useful. See my comments later. This function is not exported so static.Also, it looks like to me that the vcpu is not necessary. Please use struct domain *d. Why do you need to have a specific case for the hardware domain? All the vITS code should be domain agnostic except the initialization function. That would make the code a lot simpler. I would prefer if you introduce a new field in domain->arch to store the number of ITS for the domain. You should not assume that the guest as only one vITS. BUG_ON(vits != NULL);Although I would document this BUG_ON to explain that its_to_vits should never fail because MMIOs registered always point to an ITS. Though, an ASSERT maybe better here. This can never happen, you always register 64K range. Missing implementation for GITS_CTLR + return 1; + case GITS_IIDR: + if ( dabt.size != DABT_WORD ) goto bad_width; Missing implementation for GITS_IIDR + return 1; + case GITS_TYPER: + /* GITS_TYPER support word read */ + vits_spin_lock(vits); + val = ((its_get_pta_type() << VITS_GITS_TYPER_PTA_SHIFT) | As said on a previous patch, each ITS may have a different value in PTA. I think it would make the command emulation simpler if we use an hardcoded PTA (PTA = 0 i.e using linear processor numbers seems the simpler). + VITS_GITS_TYPER_HCC | VITS_GITS_DEV_BITS | I will comment the value here..Where does the value of HCC and DEV_BITS come from? Both of them looks wrong to me. + VITS_GITS_ID_BITS | VITS_GITS_ITT_SIZE | Ditto for ID_BITS and ITT_SIZE.Although, it looks like that ITT_SIZE should be the same as the hardware. This is because you let the guest allocation the ITT. I would also rename ITT_SIZE to ITT_ENTRY_SIZE. + VITS_GITS_DISTRIBUTED | VITS_GITS_PLPIS); The bit 3 is marked as implementation defined. So why did you name it DISTRIBUTED? The vits_spin_unlock could be done before setting *r. + return 1; + case GITS_TYPER + 4: I don't like the idea to duplicate the code for GITS_TYPER just for reading the top word. Isn't possible to merge the 2 switch case? Reading the spec again, it's not mandatory support support 32-bit access on 64-bit registers. Given that we don't support GICv3 for 32-bit guest, I would completely drop the 32-bit access on 64-bit guest. + if (dabt.size != DABT_WORD ) goto bad_width; if ( ... + vits_spin_lock(vits); + val = ((its_get_pta_type() << VITS_GITS_TYPER_PTA_SHIFT) | + VITS_GITS_TYPER_HCC | VITS_GITS_DEV_BITS | + VITS_GITS_ID_BITS | VITS_GITS_ITT_SIZE | + VITS_GITS_DISTRIBUTED | VITS_GITS_PLPIS); + *r = (u32)val; + vits_spin_unlock(vits); + return 1; + case 0x0010 ... 0x007c: + case 0xc000 ... 0xffcc: + /* Implementation defined -- read ignored */ + dprintk(XENLOG_ERR, + "vGITS: read unknown 0x000c - 0x007c r%d offset %#08x\n", + dabt.reg, gits_reg); Please don't use XENLOG_ERR in guest code. Also, this printk is not useful and has been dropped in other emulation. + goto read_as_zero; + case GITS_CBASER: + vits_spin_lock(vits); + if ( dabt.size == DABT_DOUBLE_WORD ) + *r = vits->cmd_base && 0xc7ffffffffffffffUL; Why the && and what does mean this constant? if ( ... + vits_spin_lock(vits); + *r = (u32)(vits->cmd_base >> 32); + vits_spin_unlock(vits); + return 1; Same remark as GITS_TYPER for the word read support. Ditt for the word-read Ditto + case 0x0098 ... 0x009c: + case 0x00a0 ... 0x00fc: + case 0x0140 ... 0xbffc: + /* Reserved -- read ignored */ + dprintk(XENLOG_ERR, + "vGITS: read unknown 0x0098-9c or 0x00a0-fc r%d offset %#08x\n", + dabt.reg, gits_reg); No need of printk here. + goto read_as_zero; + case GITS_BASER ... GITS_BASERN: The spec says that registers are RES0 if not implemented.As you use at all baser outside the register emulation, I would implement them RAZ/WI. That would avoid a wrong write implementation. Please check that we access is done via a word-access by introducing a new label read_as_zero_32 (for instance see the vgic v2 emulation). + default: + dprintk(XENLOG_ERR, "vGITS: unhandled read r%d offset %#08x\n", + dabt.reg, gits_reg); printk(XENLOG_G_ERR "%pv: ....", v,...) Also it may be useful to printk which vITS is in use. + return 0; + } + +bad_width: + dprintk(XENLOG_ERR, "vGITS: bad read width %d r%d offset %#08x\n", + dabt.size, dabt.reg, gits_reg); printk(XENLOG_G_ERR "%pv: ...", v,...) Same remark for printing the vITS. + domain_crash_synchronous(); + return 0; + +read_as_zero: + if ( dabt.size != DABT_WORD ) goto bad_width; How do you know that all RAZ access 32-bit access? See implementation defined registers for instance.
I would prefer to introduce multiple label:
read_as_zero_32: /* RAZ 32-bit */
if ( dabt.size != DABT_WORD ) goto bad_width;
read_as_zero: /* Not check necessary */
*r = 0;
And use the correctly label for goto in the emulation. So the code would
be self-documented too.
Same remark as the BUG_ON in vgic_v3_gits_mmio_read.I'm wondering if it would be better to extend the read/write handler to get an opaque pointer in parameter. In this case, it would contain the vits and would avoid the its_to_vits every time. This check is not necessary. Only bit[0] (Enabled) is writable. + vits_spin_unlock(vits); + return 1; + case GITS_IIDR: + /* R0 -- write ignored */ + goto write_ignore; goto write_ignore_32; + case GITS_TYPER: + case GITS_TYPER + 4: + /* R0 -- write ignored */ + goto write_ignore; Please explicitly check the access size. That would avoid to crash the guest when TYPER is write with a 64-bit access. + case 0x0010 ... 0x007c: + case 0xc000 ... 0xffcc: + /* Implementation defined -- write ignored */ + dprintk(XENLOG_ERR, + "vGITS: write to unknown 0x000c - 0x007c r%d offset %#08x\n", + dabt.reg, gits_reg); Please drop the dprintk. + goto write_ignore; + case GITS_CBASER: + if ( dabt.size == DABT_BYTE ) goto bad_width; Please do the check in the invert way. i.e (dabt.size != DABT_WORD) && (dabt.size != DABT_DOUBLE_WORD)Also GITS_CBASER is read-only when GITS_CTLR.Enable is Zero or GITS_CTLR.Quiescent is zero. The mask is difficult to read. And not all the bits are writeable. + val = (*r) | val; + vits->cmd_base = val; + } + vits->cmd_qsize = SZ_4K * ((*r & 0xff) + 1); Please use a define for the mask.Also I would use cmd_qsize to know if the valid is set or not. I.e cmd_qsize = 0 => command queue not valid. You forgot to update GITS_CREADR (i.e setting to 0) when GITS_CBASER is successfully written. + vits_spin_unlock(vits); + return 1; + case GITS_CBASER + 4: 32-bit support is not necessary and make the code more complex for nothing. + /* CBASER support word read */ + if (dabt.size != DABT_WORD ) goto bad_width; + vits_spin_lock(vits); + val = vits->cmd_base & 0xffffffffUL; + val = ((*r & 0xffffffffUL) << 32 ) | val; + vits->cmd_base = val; + /* No Need to update cmd_qsize with higher word write */ + vits_spin_unlock(vits); + return 1; + case GITS_CWRITER: + if ( dabt.size == DABT_BYTE ) goto bad_width; + vits_spin_lock(vits); + if ( dabt.size == DABT_DOUBLE_WORD ) + vits->cmd_write = *r; Only Bits[19:5] are writable. No validation of the value written by the guest? Given your implementation of the command processing, any invalid value will end up to an infinite loop in the hypervisor. Whoops :). + ret = vgic_its_process_cmd(v, vits); + vits_spin_unlock(vits); + return ret; + case GITS_CWRITER + 4: Same remark as GITS_CBASER for the 32-bit support. + if (dabt.size != DABT_WORD ) goto bad_width; + vits_spin_lock(vits); + val = vits->cmd_write & 0xffffffffUL; + val = ((*r & 0xffffffffUL) << 32) | val; + vits->cmd_write = val; + ret = vgic_its_process_cmd(v, vits); + vits_spin_unlock(vits); + return ret; + case GITS_CREADR: + /* R0 -- write ignored */ + goto write_ignore; + case 0x0098 ... 0x009c: + case 0x00a0 ... 0x00fc: + case 0x0140 ... 0xbffc: + /* Reserved -- write ignored */ + dprintk(XENLOG_ERR, + "vGITS: write to unknown 0x98-9c or 0xa0-fc r%d offset %#08x\n", + dabt.reg, gits_reg); Please drop the dprintk + goto write_ignore; + case GITS_BASER ... GITS_BASERN: + /* Nothing to do with this values. Just store and emulate */ As you don't use those values at all, write ignore would be better. cmd_write seems to come out of nowhere... printk(XENLOG_G_ERR "%pv: .....", v, ....); + Print which ITS is in use. + return 0; + } + +bad_width: + dprintk(XENLOG_ERR, "vGITS: bad write width %d r%d offset %#08x\n", + dabt.size, dabt.reg, gits_reg); Ditto + domain_crash_synchronous(); + return 0; + +write_ignore: + if ( dabt.size != DABT_WORD ) goto bad_width; + *r = 0; + return 1; Same remark as read_ignore. You forgot to add the prototype of this function in the header... This code is not really part of the ITS registers emulation... Your patchs series splitting is really confusing. + uint32_t num_its; + int i; + + num_its = its_get_nr_its(); + + d->arch.vits = xzalloc_array(struct vgic_its, num_its); Hmm... why did you use the number of physical ITS rather than the number of vITS used by the guest. It would avoid to waste so much memory for every domain. Regards, -- Julien Grall _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |