Re: [Xen-devel] [PATCH v4 2/5] xen/arm: vgic-v2: Don't ignore a write in ITARGETSR if one field is 0
On Thu, 2015-10-22 at 17:51 +0100, Julien Grall wrote: > On 22/10/15 17:07, Ian Campbell wrote: > > > diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c > > > index 665afeb..6b7eab3 100644 > > > --- a/xen/arch/arm/vgic-v2.c > > > +++ b/xen/arch/arm/vgic-v2.c > > > @@ -50,6 +50,94 @@ void vgic_v2_setup_hw(paddr_t dbase, paddr_t > > > cbase, > > > paddr_t vbase) > > > vgic_v2_hw.vbase = vbase; > > > } > > > > > > +#define NR_TARGET_PER_REG 4U > > > +#define NR_BIT_PER_TARGET 8U > > > > NR_TARGETS_ and NR_BITS_... > > > > "REG" there is a bit generic, given this only works for registers with > > 8 > > -bit fields, _ITARGETSR instead? > > Well this is within the vgic-v2.c and only one register contains target. > So I found pointless to add ITARGETSR to the name. It's the use of the generic "REG" when there is only one relevant register (which could be named) which I found confusing, since the current name implies it has wider relevance than it actually does. > > This is really a part of the for() iteration expression, but oddly > > place > > here. > > If you turn the "((1 << NR_BIT_PER_TARGET) - 1)" thing into a #define > > or > > constant, then you may find that extracting the relevant byte from the > > unshifted itargetsr using (itargetsr >> (i*NR_BITS_PER_TARGET) and then > > applying the mask is clean enough to use here instead. > > I placed this shift here because I didn't want to use ... >> (i * > NR_BIT_..) which require a multiplication rather than a shift in the > resulting code. FWIW given a constant NR_BITS which is a power of two I think i*NR_BITS would end up a shift with any reasonable compiler. > > > + * guest). > > > + */ > > > +if ( !new_target || (new_target > d->max_vcpus) ) > > > +{ > > > +printk(XENLOG_G_DEBUG > > > > gdprintk? > > I would prefer to keep this printk in non-debug to help us catching any > OS potentially using this trick. > > Based on that I would even use XENLOG_G_WARNING because this is not > really compliant to the spec and we are meant to fix it. Assuming I remember correctly that XENLOG_G_WARNING is ratelimited in default configurations, then OK. > > Regards, > ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v4 2/5] xen/arm: vgic-v2: Don't ignore a write in ITARGETSR if one field is 0
Hi Ian, On 23/10/15 10:30, Ian Campbell wrote: > On Thu, 2015-10-22 at 17:51 +0100, Julien Grall wrote: >> On 22/10/15 17:07, Ian Campbell wrote: diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c index 665afeb..6b7eab3 100644 --- a/xen/arch/arm/vgic-v2.c +++ b/xen/arch/arm/vgic-v2.c @@ -50,6 +50,94 @@ void vgic_v2_setup_hw(paddr_t dbase, paddr_t cbase, paddr_t vbase) vgic_v2_hw.vbase = vbase; } +#define NR_TARGET_PER_REG 4U +#define NR_BIT_PER_TARGET 8U >>> >>> NR_TARGETS_ and NR_BITS_... >>> >>> "REG" there is a bit generic, given this only works for registers with >>> 8 >>> -bit fields, _ITARGETSR instead? >> >> Well this is within the vgic-v2.c and only one register contains target. >> So I found pointless to add ITARGETSR to the name. > > It's the use of the generic "REG" when there is only one relevant register > (which could be named) which I found confusing, since the current name > implies it has wider relevance than it actually does. Ok. I guess you'd like to rename NR_BITS_PER_TARGET? If so, do you have any suggestion? >>> This is really a part of the for() iteration expression, but oddly >>> place >>> here. >>> If you turn the "((1 << NR_BIT_PER_TARGET) - 1)" thing into a #define >>> or >>> constant, then you may find that extracting the relevant byte from the >>> unshifted itargetsr using (itargetsr >> (i*NR_BITS_PER_TARGET) and then >>> applying the mask is clean enough to use here instead. >> >> I placed this shift here because I didn't want to use ... >> (i * >> NR_BIT_..) which require a multiplication rather than a shift in the >> resulting code. > > FWIW given a constant NR_BITS which is a power of two I think i*NR_BITS > would end up a shift with any reasonable compiler. I will give a look. > + * guest). + */ +if ( !new_target || (new_target > d->max_vcpus) ) +{ +printk(XENLOG_G_DEBUG >>> >>> gdprintk? >> >> I would prefer to keep this printk in non-debug to help us catching any >> OS potentially using this trick. >> >> Based on that I would even use XENLOG_G_WARNING because this is not >> really compliant to the spec and we are meant to fix it. > > Assuming I remember correctly that XENLOG_G_WARNING is ratelimited in > default configurations, then OK. Correct, any XENLOG_G_* is rate-limited by default. Regards, -- Julien Grall ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v4 2/5] xen/arm: vgic-v2: Don't ignore a write in ITARGETSR if one field is 0
On Fri, 2015-10-23 at 10:37 +0100, Julien Grall wrote: > Hi Ian, > > On 23/10/15 10:30, Ian Campbell wrote: > > On Thu, 2015-10-22 at 17:51 +0100, Julien Grall wrote: > > > On 22/10/15 17:07, Ian Campbell wrote: > > > > > diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c > > > > > index 665afeb..6b7eab3 100644 > > > > > --- a/xen/arch/arm/vgic-v2.c > > > > > +++ b/xen/arch/arm/vgic-v2.c > > > > > @@ -50,6 +50,94 @@ void vgic_v2_setup_hw(paddr_t dbase, paddr_t > > > > > cbase, > > > > > paddr_t vbase) > > > > > vgic_v2_hw.vbase = vbase; > > > > > } > > > > > > > > > > +#define NR_TARGET_PER_REG 4U > > > > > +#define NR_BIT_PER_TARGET 8U > > > > > > > > NR_TARGETS_ and NR_BITS_... > > > > > > > > "REG" there is a bit generic, given this only works for registers > > > > with > > > > 8 > > > > -bit fields, _ITARGETSR instead? > > > > > > Well this is within the vgic-v2.c and only one register contains > > > target. > > > So I found pointless to add ITARGETSR to the name. > > > > It's the use of the generic "REG" when there is only one relevant > > register > > (which could be named) which I found confusing, since the current name > > implies it has wider relevance than it actually does. > > Ok. I guess you'd like to rename NR_BITS_PER_TARGET? If so, do you have > any suggestion? NR_BITS_PER_TARGET is OK here, since 8 is always correct for that in the gic v2 irrespective of whether it is used with any register. NR_TARGET_PER_REG was the thing I thought we were discussing above. I think that one should be NR_TARGETS_PER_ITARGETSR. Alternatively const unsigned long nr_targets_per_reg = 32/NR_BITS_PER_TARGET; in the context of the vgic_store_itargetsr function (and others which use it) would be ok too. Or maybe 32=>(sizeof(...)*8). And maybe in that context an even terser name would be ok too. Ian. ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel
Re: [Xen-devel] [PATCH v4 2/5] xen/arm: vgic-v2: Don't ignore a write in ITARGETSR if one field is 0
On Mon, 2015-10-12 at 15:22 +0100, Julien Grall wrote: > The current implementation ignores the whole write if one of the field is > 0. Although, based on the spec (4.3.12 IHI 0048B.b), 0 is a valid value > when: > - The interrupt is not wired in the distributor. From the Xen > point of view, it means that the corresponding bit is not set in > d->arch.vgic.allocated_irqs. > - The user wants to disable the IRQ forwarding in the distributor. > I.e the IRQ stays pending in the distributor and never received by > the guest. > > Implementing the later will require more work in Xen because we always > assume the interrupt is forwarded to vCPU. So for now, ignore any field > where the value is 0. > > The emulation of the write access of ITARGETSR has been reworked and > moved to a new function because it would have been difficult to > implement properly the behavior with the current code. > > The new implementation is breaking the register in 4 distinct bytes. For > each byte, it will check the validity of the target list, find the new > target, migrate the interrupt and store the value if necessary. > > In the new implementation there is nearly no distinction of the access > size to avoid having too many different path which is harder to test. > > Signed-off-by: Julien Grall> > --- > This change used to be embedded in "xen/arm: vgic: Optimize the way > to store the target vCPU in the rank". It has been moved out to > avoid having too much functional changes in a single patch. > > I'm not sure if this patch should be backported to Xen 4.6. Without > it any guest writing 0 in one the field won't be able to migrate > other interrupts. Although, in all the use case I've seen, the guest > is read ITARGETSR first and write-back the value with the > corresponding byte changed. > > Changes in v4: > - Patch added > --- > xen/arch/arm/vgic-v2.c | 141 ++- > -- > 1 file changed, 98 insertions(+), 43 deletions(-) > > diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c > index 665afeb..6b7eab3 100644 > --- a/xen/arch/arm/vgic-v2.c > +++ b/xen/arch/arm/vgic-v2.c > @@ -50,6 +50,94 @@ void vgic_v2_setup_hw(paddr_t dbase, paddr_t cbase, > paddr_t vbase) > vgic_v2_hw.vbase = vbase; > } > > +#define NR_TARGET_PER_REG 4U > +#define NR_BIT_PER_TARGET 8U NR_TARGETS_ and NR_BITS_... "REG" there is a bit generic, given this only works for registers with 8 -bit fields, _ITARGETSR instead? > +/* > + * Store a ITARGETSR register. This function only deals with ITARGETSR8 > + * and onwards. > + * > + * Note the offset will be aligned to the appropriate boundary. > + */ > +static void vgic_store_itargetsr(struct domain *d, struct vgic_irq_rank > *rank, > + unsigned int offset, uint32_t > itargetsr) > +{ > +unsigned int i; > +unsigned int regidx = REG_RANK_INDEX(8, offset, DABT_WORD); > +unsigned int virq; > + > +ASSERT(spin_is_locked(>lock)); > + > +/* > + * The ITARGETSR0-7, used for SGIs/PPIs, are implemented RO in the > + * emulation and should never call this function. > + * > + * They all live in the first rank. > + */ > +BUILD_BUG_ON(NR_INTERRUPT_PER_RANK != 32); > +ASSERT(rank->index >= 1); > + > +offset &= INTERRUPT_RANK_MASK; > +offset &= ~(NR_TARGET_PER_REG - 1); > + > +virq = rank->index * NR_INTERRUPT_PER_RANK + offset; > + > +for ( i = 0; i < NR_TARGET_PER_REG; i++, offset++, virq++ ) > +{ > +unsigned int new_target, old_target; > +uint8_t new_mask, old_mask; > + > +new_mask = itargetsr & ((1 << NR_BIT_PER_TARGET) - 1); > +old_mask = vgic_byte_read(rank->v2.itargets[regidx], i); > + > +itargetsr >>= NR_BIT_PER_TARGET; This is really a part of the for() iteration expression, but oddly place here. If you turn the "((1 << NR_BIT_PER_TARGET) - 1)" thing into a #define or constant, then you may find that extracting the relevant byte from the unshifted itargetsr using (itargetsr >> (i*NR_BITS_PER_TARGET) and then applying the mask is clean enough to use here instead. I don't think you rely on the shifting of itargetsr apart from when calculating new_mask. > +/* > + * SPIs are using the 1-N model (see 1.4.3 in ARM IHI 0048B). > + * While the interrupt could be set pending to all the vCPUs in > + * target list, it's not guarantee by the spec. "guaranteed" > + * For simplicity, always route the vIRQ to the first interrupt > + * in the target list > + */ > +new_target = ffs(new_mask); > +old_target = ffs(old_mask); > + > +/* The current target should always be valid */ > +ASSERT(old_target && (old_target <= d->max_vcpus)); > + > +/* > + * Ignore the write request for this interrupt if the new target > + * is invalid. >
Re: [Xen-devel] [PATCH v4 2/5] xen/arm: vgic-v2: Don't ignore a write in ITARGETSR if one field is 0
On 22/10/15 17:07, Ian Campbell wrote: >> diff --git a/xen/arch/arm/vgic-v2.c b/xen/arch/arm/vgic-v2.c >> index 665afeb..6b7eab3 100644 >> --- a/xen/arch/arm/vgic-v2.c >> +++ b/xen/arch/arm/vgic-v2.c >> @@ -50,6 +50,94 @@ void vgic_v2_setup_hw(paddr_t dbase, paddr_t cbase, >> paddr_t vbase) >> vgic_v2_hw.vbase = vbase; >> } >> >> +#define NR_TARGET_PER_REG 4U >> +#define NR_BIT_PER_TARGET 8U > > NR_TARGETS_ and NR_BITS_... > > "REG" there is a bit generic, given this only works for registers with 8 > -bit fields, _ITARGETSR instead? Well this is within the vgic-v2.c and only one register contains target. So I found pointless to add ITARGETSR to the name. > >> +/* >> + * Store a ITARGETSR register. This function only deals with ITARGETSR8 >> + * and onwards. >> + * >> + * Note the offset will be aligned to the appropriate boundary. >> + */ >> +static void vgic_store_itargetsr(struct domain *d, struct vgic_irq_rank >> *rank, >> + unsigned int offset, uint32_t >> itargetsr) >> +{ >> +unsigned int i; >> +unsigned int regidx = REG_RANK_INDEX(8, offset, DABT_WORD); >> +unsigned int virq; >> + >> +ASSERT(spin_is_locked(>lock)); >> + >> +/* >> + * The ITARGETSR0-7, used for SGIs/PPIs, are implemented RO in the >> + * emulation and should never call this function. >> + * >> + * They all live in the first rank. >> + */ >> +BUILD_BUG_ON(NR_INTERRUPT_PER_RANK != 32); >> +ASSERT(rank->index >= 1); >> + >> +offset &= INTERRUPT_RANK_MASK; >> +offset &= ~(NR_TARGET_PER_REG - 1); >> + >> +virq = rank->index * NR_INTERRUPT_PER_RANK + offset; >> + >> +for ( i = 0; i < NR_TARGET_PER_REG; i++, offset++, virq++ ) >> +{ >> +unsigned int new_target, old_target; >> +uint8_t new_mask, old_mask; >> + >> +new_mask = itargetsr & ((1 << NR_BIT_PER_TARGET) - 1); >> +old_mask = vgic_byte_read(rank->v2.itargets[regidx], i); >> + >> +itargetsr >>= NR_BIT_PER_TARGET; > > This is really a part of the for() iteration expression, but oddly place > here. > If you turn the "((1 << NR_BIT_PER_TARGET) - 1)" thing into a #define or > constant, then you may find that extracting the relevant byte from the > unshifted itargetsr using (itargetsr >> (i*NR_BITS_PER_TARGET) and then > applying the mask is clean enough to use here instead. I placed this shift here because I didn't want to use ... >> (i * NR_BIT_..) which require a multiplication rather than a shift in the resulting code. Furthermore, I found the for loop more complicate to read with itargetsr >>= inside. Anyway, I prefer the latter solution so I will use it in the next version. > > I don't think you rely on the shifting of itargetsr apart from when > calculating new_mask. Correct. >> +/* >> + * SPIs are using the 1-N model (see 1.4.3 in ARM IHI 0048B). >> + * While the interrupt could be set pending to all the vCPUs in >> + * target list, it's not guarantee by the spec. > > "guaranteed" > >> + * For simplicity, always route the vIRQ to the first interrupt >> + * in the target list >> + */ >> +new_target = ffs(new_mask); >> +old_target = ffs(old_mask); >> + >> +/* The current target should always be valid */ >> +ASSERT(old_target && (old_target <= d->max_vcpus)); >> + >> +/* >> + * Ignore the write request for this interrupt if the new target >> + * is invalid. >> + * XXX: From the spec, if the target list is not valid, the >> + * interrupt should be ignored (i.e not forwarding to the > > "forwarded". > >> + * guest). >> + */ >> +if ( !new_target || (new_target > d->max_vcpus) ) >> +{ >> +printk(XENLOG_G_DEBUG > > gdprintk? I would prefer to keep this printk in non-debug to help us catching any OS potentially using this trick. Based on that I would even use XENLOG_G_WARNING because this is not really compliant to the spec and we are meant to fix it. Regards, -- Julien Grall ___ Xen-devel mailing list Xen-devel@lists.xen.org http://lists.xen.org/xen-devel