|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [XEN v4] xen/arm: vGICv3: Emulate properly 32-bit access on GICR_PENDBASER
On Thu, 27 Oct 2022 16:40:01 +0100
Ayan Kumar Halder <ayankuma@xxxxxxx> wrote:
Hi Ayan,
> On 27/10/2022 10:44, Andre Przywara wrote:
> > On Wed, 26 Oct 2022 19:30:04 +0100
> > Ayan Kumar Halder <ayankuma@xxxxxxx> wrote:
> >
> > Hi,
>
> Hi Andre,
>
> I need a clarification.
>
> >
> >> If a guest is running in 32 bit mode and it tries to access
> >> "GICR_PENDBASER + 4" mmio reg, it will be trapped to Xen.
> >> vreg_reg64_extract()
> >> will return the value stored "v->arch.vgic.rdist_pendbase + 4".
> >> This will be stored in a 64bit cpu register.
> >> So now we have the top 32 bits of GICR_PENDBASER (a 64 bit MMIO register)
> >> stored
> >> in the lower 32 bits of the 64bit cpu register.
> >>
> >> This 64bit cpu register is then modified bitwise with a mask (ie
> >> GICR_PENDBASER_PTZ, it clears the 62nd bit). But the PTZ (which is bit 30
> >> in the
> >> 64 bit cpu register) is not cleared as expected by the specification.
> >>
> >> The correct thing to do here is to store the value of
> >> "v->arch.vgic.rdist_pendbase" in a temporary 64 bit variable. This
> >> variable is
> >> then modified bitwise with GICR_PENDBASER_PTZ mask. It is then passed to
> >> vreg_reg64_extract() which will extract 32 bits from the given offset.
> >>
> >> Also, we have removed spin_lock_irqsave()/spin_unlock_irqrestore() to
> >> protect
> >> v->arch.vgic.rdist_pendbase. The reason being v->arch.vgic.rdist_pendbase
> >> is
> >> now being read/written in an atomic manner (using
> >> read_atomic()/write_atomic()).
> >>
> >> Signed-off-by: Ayan Kumar Halder <ayankuma@xxxxxxx>
> >> Release-acked-by: Henry Wang <Henry.Wang@xxxxxxx>
> >> ---
> >>
> >> Changes from:-
> >>
> >> v1 - 1. Extracted this fix from "[RFC PATCH v1 05/12] Arm: GICv3: Emulate
> >> GICR_PENDBASER and GICR_PROPBASER on AArch32" into a separate patch with an
> >> appropriate commit message.
> >>
> >> v2 - 1. Removed spin_lock_irqsave(). Used read_atomic() to read
> >> v->arch.vgic.rdist_pendbase in an atomic context.
> >> 2. Rectified the commit message to state that the cpu register is 64 bit.
> >> (because currently, GICv3 is supported on Arm64 only). Reworded to make it
> >> clear.
> >>
> >> v3 - 1. Added read_atomic()/write_atomic() for access to
> >> v->arch.vgic.rdist_pendbase
> >> in __vgic_v3_rdistr_rd_mmio_write().
> >>
> >> xen/arch/arm/vgic-v3.c | 19 ++++++-------------
> >> 1 file changed, 6 insertions(+), 13 deletions(-)
> >>
> >> diff --git a/xen/arch/arm/vgic-v3.c b/xen/arch/arm/vgic-v3.c
> >> index 0c23f6df9d..1adbdc0e54 100644
> >> --- a/xen/arch/arm/vgic-v3.c
> >> +++ b/xen/arch/arm/vgic-v3.c
> >> @@ -249,16 +249,15 @@ static int __vgic_v3_rdistr_rd_mmio_read(struct vcpu
> >> *v, mmio_info_t *info,
> >>
> >> case VREG64(GICR_PENDBASER):
> >> {
> >> - unsigned long flags;
> >> + uint64_t val;
> >>
> >> if ( !v->domain->arch.vgic.has_its )
> >> goto read_as_zero_64;
> >> if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
> >>
> >> - spin_lock_irqsave(&v->arch.vgic.lock, flags);
> >> - *r = vreg_reg64_extract(v->arch.vgic.rdist_pendbase, info);
> >> - *r &= ~GICR_PENDBASER_PTZ; /* WO, reads as 0 */
> >> - spin_unlock_irqrestore(&v->arch.vgic.lock, flags);
> >> + val = read_atomic(&v->arch.vgic.rdist_pendbase);
> >> + val &= ~GICR_PENDBASER_PTZ; /* WO, reads as 0 */
> >> + *r = vreg_reg64_extract(val, info);
> > That part looks fine now.
> >
> >> return 1;
> >> }
> >>
> >> @@ -566,25 +565,19 @@ static int __vgic_v3_rdistr_rd_mmio_write(struct
> >> vcpu *v, mmio_info_t *info,
> >>
> >> case VREG64(GICR_PENDBASER):
> >> {
> >> - unsigned long flags;
> >> -
> >> if ( !v->domain->arch.vgic.has_its )
> >> goto write_ignore_64;
> >> if ( !vgic_reg64_check_access(dabt) ) goto bad_width;
> >>
> >> - spin_lock_irqsave(&v->arch.vgic.lock, flags);
> >> -
> > I don't think you can drop the lock here easily. If it would be just for
> > the LPIs enabled check, that'd be fine, because you can never turn LPIs off
> > again (but that would deserve an explicit comment then).
> >
> > But down below you do a read-modify-write operation of rdist_pendbase, and
> > need to make sure no one else is attempting that at the same time.
> >
> > Cheers,
> > Andre
> >
> >> /* Writing PENDBASER with LPIs enabled is UNPREDICTABLE. */
> >> if ( !(v->arch.vgic.flags & VGIC_V3_LPIS_ENABLED) )
> >> {
> >> - reg = v->arch.vgic.rdist_pendbase;
> >> + reg = read_atomic(&v->arch.vgic.rdist_pendbase);
> >> vreg_reg64_update(®, r, info);
> >> reg = sanitize_pendbaser(reg);
> >> - v->arch.vgic.rdist_pendbase = reg;
> >> + write_atomic(&v->arch.vgic.rdist_pendbase, reg);
> >> }
> >>
> >> - spin_unlock_irqrestore(&v->arch.vgic.lock, false);
>
> Shouldn't this be "spin_unlock_irqrestore(&v->arch.vgic.lock, flags)" ?
Ouch, indeed, looks like a typo!
There is a some type check in spin_lock_irqsave() and local_irq_restore(),
but not in spin_unlock_irqrestore(), so we missed that.
Cheers,
Andre
>
> - Ayan
>
> >> -
> >> return 1;
> >> }
> >>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |