diff mbox series

arm64: clear_page() shouldn't use DC ZVA when DCZID_EL0.DZP == 1

Message ID 20211026034844.1393437-1-reijiw@google.com (mailing list archive)
State New, archived
Headers show
Series arm64: clear_page() shouldn't use DC ZVA when DCZID_EL0.DZP == 1 | expand

Commit Message

Reiji Watanabe Oct. 26, 2021, 3:48 a.m. UTC
Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
should make sure that DCZID_EL0.DZP, which indicates whether or not use
of DC ZVA instruction is prohibited, is zero when using the instruction.
Use stp as memset does instead when DCZID_EL0.DZP == 1.

Signed-off-by: Reiji Watanabe <reijiw@google.com>
---
 arch/arm64/lib/clear_page.S | 11 +++++++++++
 1 file changed, 11 insertions(+)

Comments

Catalin Marinas Oct. 26, 2021, 9:06 a.m. UTC | #1
On Mon, Oct 25, 2021 at 08:48:44PM -0700, Reiji Watanabe wrote:
> Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> should make sure that DCZID_EL0.DZP, which indicates whether or not use
> of DC ZVA instruction is prohibited, is zero when using the instruction.
> Use stp as memset does instead when DCZID_EL0.DZP == 1.

For correctness, this is fine, but have you come across a system that
has DZP == 1 (or hypervisor setting HCR_EL2.TDZ)?
Robin Murphy Oct. 26, 2021, 11:22 a.m. UTC | #2
On 2021-10-26 04:48, Reiji Watanabe wrote:
> Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> should make sure that DCZID_EL0.DZP, which indicates whether or not use
> of DC ZVA instruction is prohibited, is zero when using the instruction.
> Use stp as memset does instead when DCZID_EL0.DZP == 1.
> 
> Signed-off-by: Reiji Watanabe <reijiw@google.com>
> ---
>   arch/arm64/lib/clear_page.S | 11 +++++++++++
>   1 file changed, 11 insertions(+)
> 
> diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
> index b84b179edba3..7ce1bfa4081c 100644
> --- a/arch/arm64/lib/clear_page.S
> +++ b/arch/arm64/lib/clear_page.S
> @@ -16,6 +16,7 @@
>    */
>   SYM_FUNC_START_PI(clear_page)
>   	mrs	x1, dczid_el0
> +	tbnz	x1, #4, 2f	/* Branch if DC GVA is prohibited */
>   	and	w1, w1, #0xf
>   	mov	x2, #4
>   	lsl	x1, x2, x1
> @@ -25,5 +26,15 @@ SYM_FUNC_START_PI(clear_page)
>   	tst	x0, #(PAGE_SIZE - 1)
>   	b.ne	1b
>   	ret
> +
> +2:	mov	x1, #(PAGE_SIZE)
> +	sub	x0, x0, #16	/* Pre-bias. */

Out of curiosity, what's this for? It's not like we need to worry about 
PAGE_SIZE or page addresses being misaligned. I don't really see why 
we'd need a different condition from the DC ZVA loop.

Robin.

> +3:	stp	xzr, xzr, [x0, #16]
> +	stp	xzr, xzr, [x0, #32]
> +	stp	xzr, xzr, [x0, #48]
> +	stp	xzr, xzr, [x0, #64]!
> +	subs	x1, x1, #64
> +	b.gt	3b
> +	ret
>   SYM_FUNC_END_PI(clear_page)
>   EXPORT_SYMBOL(clear_page)
>
Mark Rutland Oct. 26, 2021, 12:23 p.m. UTC | #3
On Tue, Oct 26, 2021 at 12:22:20PM +0100, Robin Murphy wrote:
> On 2021-10-26 04:48, Reiji Watanabe wrote:
> > Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> > should make sure that DCZID_EL0.DZP, which indicates whether or not use
> > of DC ZVA instruction is prohibited, is zero when using the instruction.
> > Use stp as memset does instead when DCZID_EL0.DZP == 1.
> > 
> > Signed-off-by: Reiji Watanabe <reijiw@google.com>
> > ---
> >   arch/arm64/lib/clear_page.S | 11 +++++++++++
> >   1 file changed, 11 insertions(+)
> > 
> > diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
> > index b84b179edba3..7ce1bfa4081c 100644
> > --- a/arch/arm64/lib/clear_page.S
> > +++ b/arch/arm64/lib/clear_page.S
> > @@ -16,6 +16,7 @@
> >    */
> >   SYM_FUNC_START_PI(clear_page)
> >   	mrs	x1, dczid_el0
> > +	tbnz	x1, #4, 2f	/* Branch if DC GVA is prohibited */

DCZID_EL0.DZP (AKA DCZID_EL0[4]) says whether all of DC {ZVA,GVA,GZVA}
are prohibited. This loop uses DZ ZVA, not GC GVA, so it'd be nice to
s/GVA/ZVA/ here.

Howver, `DC GVA` and `DC GZVA` are both used in mte_set_mem_tag_range(),
which'll need a similar update...

> >   	and	w1, w1, #0xf
> >   	mov	x2, #4
> >   	lsl	x1, x2, x1
> > @@ -25,5 +26,15 @@ SYM_FUNC_START_PI(clear_page)
> >   	tst	x0, #(PAGE_SIZE - 1)
> >   	b.ne	1b
> >   	ret
> > +
> > +2:	mov	x1, #(PAGE_SIZE)
> > +	sub	x0, x0, #16	/* Pre-bias. */
> 
> Out of curiosity, what's this for? It's not like we need to worry about
> PAGE_SIZE or page addresses being misaligned. I don't really see why we'd
> need a different condition from the DC ZVA loop.

I believe this was copied from arch/arm64/lib/memset.S, in the
`.Lnot_short` case, where we have:

| .Lnot_short:
|         sub     dst, dst, #16/* Pre-bias.  */
|         sub     count, count, #64
| 1:
|         stp     A_l, A_l, [dst, #16]
|         stp     A_l, A_l, [dst, #32]
|         stp     A_l, A_l, [dst, #48]
|         stp     A_l, A_l, [dst, #64]!
|         subs    count, count, #64
|         b.ge    1b

> Robin.
> 
> > +3:	stp	xzr, xzr, [x0, #16]
> > +	stp	xzr, xzr, [x0, #32]
> > +	stp	xzr, xzr, [x0, #48]
> > +	stp	xzr, xzr, [x0, #64]!
> > +	subs	x1, x1, #64
> > +	b.gt	3b
> > +	ret

FWIW, I'd also prefer consistency with the existing loop, i.e.

2:	stp	xzr, xzr, [x0, #0]
	stp	xzr, xzr, [x0, #16]
	stp	xzr, xzr, [x0, #32]
	stp	xzr, xzr, [x0, #48]
	add	x0, x0, #64
	tst	x0, #(PAGE_SIZE - 1)
	b.ne	2b
	ret

Thanks,
Mark.

> >   SYM_FUNC_END_PI(clear_page)
> >   EXPORT_SYMBOL(clear_page)
> > 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
Reiji Watanabe Oct. 27, 2021, 1:35 a.m. UTC | #4
On Tue, Oct 26, 2021 at 2:06 AM Catalin Marinas <catalin.marinas@arm.com> wrote:
>
> On Mon, Oct 25, 2021 at 08:48:44PM -0700, Reiji Watanabe wrote:
> > Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> > should make sure that DCZID_EL0.DZP, which indicates whether or not use
> > of DC ZVA instruction is prohibited, is zero when using the instruction.
> > Use stp as memset does instead when DCZID_EL0.DZP == 1.
>
> For correctness, this is fine, but have you come across a system that
> has DZP == 1 (or hypervisor setting HCR_EL2.TDZ)?

We are thinking of setting HCR_EL2.TDZ considering live migration
support between two systems with different DCZID_EL0.BS.

Thanks,
Reiji
Reiji Watanabe Oct. 27, 2021, 6:44 a.m. UTC | #5
On Tue, Oct 26, 2021 at 5:23 AM Mark Rutland <mark.rutland@arm.com> wrote:
>
> On Tue, Oct 26, 2021 at 12:22:20PM +0100, Robin Murphy wrote:
> > On 2021-10-26 04:48, Reiji Watanabe wrote:
> > > Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> > > should make sure that DCZID_EL0.DZP, which indicates whether or not use
> > > of DC ZVA instruction is prohibited, is zero when using the instruction.
> > > Use stp as memset does instead when DCZID_EL0.DZP == 1.
> > >
> > > Signed-off-by: Reiji Watanabe <reijiw@google.com>
> > > ---
> > >   arch/arm64/lib/clear_page.S | 11 +++++++++++
> > >   1 file changed, 11 insertions(+)
> > >
> > > diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
> > > index b84b179edba3..7ce1bfa4081c 100644
> > > --- a/arch/arm64/lib/clear_page.S
> > > +++ b/arch/arm64/lib/clear_page.S
> > > @@ -16,6 +16,7 @@
> > >    */
> > >   SYM_FUNC_START_PI(clear_page)
> > >     mrs     x1, dczid_el0
> > > +   tbnz    x1, #4, 2f      /* Branch if DC GVA is prohibited */
>
> DCZID_EL0.DZP (AKA DCZID_EL0[4]) says whether all of DC {ZVA,GVA,GZVA}
> are prohibited. This loop uses DZ ZVA, not GC GVA, so it'd be nice to
> s/GVA/ZVA/ here.

Thank you for catching it ! I will fix that.

> Howver, `DC GVA` and `DC GZVA` are both used in mte_set_mem_tag_range(),
> which'll need a similar update...

Yes, I'm aware of that and mte_zero_clear_page_tags() needs to get
updated as well.  But, Since I'm not familiar with MTE (and I don't
have any plans to use MTE yet), I didn't work on them (I'm not sure
how I can test them).
I might try to fix them separately later as well when I have time
(not so soon most likely though).


> > >     and     w1, w1, #0xf
> > >     mov     x2, #4
> > >     lsl     x1, x2, x1
> > > @@ -25,5 +26,15 @@ SYM_FUNC_START_PI(clear_page)
> > >     tst     x0, #(PAGE_SIZE - 1)
> > >     b.ne    1b
> > >     ret
> > > +
> > > +2: mov     x1, #(PAGE_SIZE)
> > > +   sub     x0, x0, #16     /* Pre-bias. */
> >
> > Out of curiosity, what's this for? It's not like we need to worry about
> > PAGE_SIZE or page addresses being misaligned. I don't really see why we'd
> > need a different condition from the DC ZVA loop.
>
> I believe this was copied from arch/arm64/lib/memset.S, in the
> `.Lnot_short` case, where we have:

Yes, I used the same code as memset.  I couldn't come up with any
other implementation that could get same performance with fewer
number of instructions in the loop than that.


> | .Lnot_short:
> |         sub     dst, dst, #16/* Pre-bias.  */
> |         sub     count, count, #64
> | 1:
> |         stp     A_l, A_l, [dst, #16]
> |         stp     A_l, A_l, [dst, #32]
> |         stp     A_l, A_l, [dst, #48]
> |         stp     A_l, A_l, [dst, #64]!
> |         subs    count, count, #64
> |         b.ge    1b
>
> > Robin.
> >
> > > +3: stp     xzr, xzr, [x0, #16]
> > > +   stp     xzr, xzr, [x0, #32]
> > > +   stp     xzr, xzr, [x0, #48]
> > > +   stp     xzr, xzr, [x0, #64]!
> > > +   subs    x1, x1, #64
> > > +   b.gt    3b
> > > +   ret
>
> FWIW, I'd also prefer consistency with the existing loop, i.e.
>
> 2:      stp     xzr, xzr, [x0, #0]
>         stp     xzr, xzr, [x0, #16]
>         stp     xzr, xzr, [x0, #32]
>         stp     xzr, xzr, [x0, #48]
>         add     x0, x0, #64
>         tst     x0, #(PAGE_SIZE - 1)
>         b.ne    2b
>         ret

Thank you for the suggestion.  Yes, I agree that it would be better
in terms of consistency with the existing loop.
I will fix this as you suggested in the v2 patch.

Thanks,
Reiji
Mark Rutland Oct. 27, 2021, 11:09 a.m. UTC | #6
On Tue, Oct 26, 2021 at 11:44:51PM -0700, Reiji Watanabe wrote:
> On Tue, Oct 26, 2021 at 5:23 AM Mark Rutland <mark.rutland@arm.com> wrote:
> > On Tue, Oct 26, 2021 at 12:22:20PM +0100, Robin Murphy wrote:
> > > On 2021-10-26 04:48, Reiji Watanabe wrote:
> > > > Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> > > > should make sure that DCZID_EL0.DZP, which indicates whether or not use
> > > > of DC ZVA instruction is prohibited, is zero when using the instruction.
> > > > Use stp as memset does instead when DCZID_EL0.DZP == 1.
> > > >
> > > > Signed-off-by: Reiji Watanabe <reijiw@google.com>
> > > > ---
> > > >   arch/arm64/lib/clear_page.S | 11 +++++++++++
> > > >   1 file changed, 11 insertions(+)
> > > >
> > > > diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
> > > > index b84b179edba3..7ce1bfa4081c 100644
> > > > --- a/arch/arm64/lib/clear_page.S
> > > > +++ b/arch/arm64/lib/clear_page.S
> > > > @@ -16,6 +16,7 @@
> > > >    */
> > > >   SYM_FUNC_START_PI(clear_page)
> > > >     mrs     x1, dczid_el0
> > > > +   tbnz    x1, #4, 2f      /* Branch if DC GVA is prohibited */
> >
> > DCZID_EL0.DZP (AKA DCZID_EL0[4]) says whether all of DC {ZVA,GVA,GZVA}
> > are prohibited. This loop uses DZ ZVA, not GC GVA, so it'd be nice to
> > s/GVA/ZVA/ here.
> 
> Thank you for catching it ! I will fix that.
> 
> > Howver, `DC GVA` and `DC GZVA` are both used in mte_set_mem_tag_range(),
> > which'll need a similar update...
> 
> Yes, I'm aware of that and mte_zero_clear_page_tags() needs to get
> updated as well.  But, Since I'm not familiar with MTE (and I don't
> have any plans to use MTE yet), I didn't work on them (I'm not sure
> how I can test them).
> I might try to fix them separately later as well when I have time
> (not so soon most likely though).

My view is that we should either:

* Document that we require DCZID_EL0.DZP==0, as is implicitly the case
  today.

* Fix *all* usage of DC {ZVA,GVZ,GZVA} to work with DCZID_EL0.DZP==1.

... otherwise we're just hiding the problem rather than fixing it.

QEMU TCG mode has MTE support, so it should be possible to test using
that in a configuration such as:

 -machine virt,virtualization=on,mte=on -cpu max

... then you can hack the EL2 stub code in head.S to initialize
HCR_EL2.TDZ=1 before dropping to EL1 (and reporting that the kernel
started at EL1).

Thanks,
Mark.
Reiji Watanabe Oct. 28, 2021, 1:49 a.m. UTC | #7
On Wed, Oct 27, 2021 at 4:09 AM Mark Rutland <mark.rutland@arm.com> wrote:
>
> On Tue, Oct 26, 2021 at 11:44:51PM -0700, Reiji Watanabe wrote:
> > On Tue, Oct 26, 2021 at 5:23 AM Mark Rutland <mark.rutland@arm.com> wrote:
> > > On Tue, Oct 26, 2021 at 12:22:20PM +0100, Robin Murphy wrote:
> > > > On 2021-10-26 04:48, Reiji Watanabe wrote:
> > > > > Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> > > > > should make sure that DCZID_EL0.DZP, which indicates whether or not use
> > > > > of DC ZVA instruction is prohibited, is zero when using the instruction.
> > > > > Use stp as memset does instead when DCZID_EL0.DZP == 1.
> > > > >
> > > > > Signed-off-by: Reiji Watanabe <reijiw@google.com>
> > > > > ---
> > > > >   arch/arm64/lib/clear_page.S | 11 +++++++++++
> > > > >   1 file changed, 11 insertions(+)
> > > > >
> > > > > diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
> > > > > index b84b179edba3..7ce1bfa4081c 100644
> > > > > --- a/arch/arm64/lib/clear_page.S
> > > > > +++ b/arch/arm64/lib/clear_page.S
> > > > > @@ -16,6 +16,7 @@
> > > > >    */
> > > > >   SYM_FUNC_START_PI(clear_page)
> > > > >     mrs     x1, dczid_el0
> > > > > +   tbnz    x1, #4, 2f      /* Branch if DC GVA is prohibited */
> > >
> > > DCZID_EL0.DZP (AKA DCZID_EL0[4]) says whether all of DC {ZVA,GVA,GZVA}
> > > are prohibited. This loop uses DZ ZVA, not GC GVA, so it'd be nice to
> > > s/GVA/ZVA/ here.
> >
> > Thank you for catching it ! I will fix that.
> >
> > > Howver, `DC GVA` and `DC GZVA` are both used in mte_set_mem_tag_range(),
> > > which'll need a similar update...
> >
> > Yes, I'm aware of that and mte_zero_clear_page_tags() needs to get
> > updated as well.  But, Since I'm not familiar with MTE (and I don't
> > have any plans to use MTE yet), I didn't work on them (I'm not sure
> > how I can test them).
> > I might try to fix them separately later as well when I have time
> > (not so soon most likely though).
>
> My view is that we should either:
>
> * Document that we require DCZID_EL0.DZP==0, as is implicitly the case
>   today.
>
> * Fix *all* usage of DC {ZVA,GVZ,GZVA} to work with DCZID_EL0.DZP==1.
>
> ... otherwise we're just hiding the problem rather than fixing it.
>
> QEMU TCG mode has MTE support, so it should be possible to test using
> that in a configuration such as:
>
>  -machine virt,virtualization=on,mte=on -cpu max
>
> ... then you can hack the EL2 stub code in head.S to initialize
> HCR_EL2.TDZ=1 before dropping to EL1 (and reporting that the kernel
> started at EL1).

Understood.
I will work on the MTE fixes and include them into the v2 patch.
Thank you so much for all the comments and information.

Regards,
Reiji
Will Deacon Oct. 28, 2021, 7:46 a.m. UTC | #8
On Wed, Oct 27, 2021 at 12:09:47PM +0100, Mark Rutland wrote:
> On Tue, Oct 26, 2021 at 11:44:51PM -0700, Reiji Watanabe wrote:
> > On Tue, Oct 26, 2021 at 5:23 AM Mark Rutland <mark.rutland@arm.com> wrote:
> > > On Tue, Oct 26, 2021 at 12:22:20PM +0100, Robin Murphy wrote:
> > > > On 2021-10-26 04:48, Reiji Watanabe wrote:
> > > > > Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> > > > > should make sure that DCZID_EL0.DZP, which indicates whether or not use
> > > > > of DC ZVA instruction is prohibited, is zero when using the instruction.
> > > > > Use stp as memset does instead when DCZID_EL0.DZP == 1.
> > > > >
> > > > > Signed-off-by: Reiji Watanabe <reijiw@google.com>
> > > > > ---
> > > > >   arch/arm64/lib/clear_page.S | 11 +++++++++++
> > > > >   1 file changed, 11 insertions(+)
> > > > >
> > > > > diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
> > > > > index b84b179edba3..7ce1bfa4081c 100644
> > > > > --- a/arch/arm64/lib/clear_page.S
> > > > > +++ b/arch/arm64/lib/clear_page.S
> > > > > @@ -16,6 +16,7 @@
> > > > >    */
> > > > >   SYM_FUNC_START_PI(clear_page)
> > > > >     mrs     x1, dczid_el0
> > > > > +   tbnz    x1, #4, 2f      /* Branch if DC GVA is prohibited */
> > >
> > > DCZID_EL0.DZP (AKA DCZID_EL0[4]) says whether all of DC {ZVA,GVA,GZVA}
> > > are prohibited. This loop uses DZ ZVA, not GC GVA, so it'd be nice to
> > > s/GVA/ZVA/ here.
> > 
> > Thank you for catching it ! I will fix that.
> > 
> > > Howver, `DC GVA` and `DC GZVA` are both used in mte_set_mem_tag_range(),
> > > which'll need a similar update...
> > 
> > Yes, I'm aware of that and mte_zero_clear_page_tags() needs to get
> > updated as well.  But, Since I'm not familiar with MTE (and I don't
> > have any plans to use MTE yet), I didn't work on them (I'm not sure
> > how I can test them).
> > I might try to fix them separately later as well when I have time
> > (not so soon most likely though).
> 
> My view is that we should either:
> 
> * Document that we require DCZID_EL0.DZP==0, as is implicitly the case
>   today.

I disagree with that. There's nothing wrong in trapping this stuff, as long
as you go ahead and emulate it, which is exactly why we aren't checking it at
the moment as EL2 should be prepared to handle the trap. The Arm ARM talks
about the instructions being "prohibited" but that doesn't mean anything --
the reality is that they trap to EL2.

We could document *that* though?

Will
Mark Rutland Oct. 28, 2021, 9:03 a.m. UTC | #9
On Thu, Oct 28, 2021 at 08:46:10AM +0100, Will Deacon wrote:
> On Wed, Oct 27, 2021 at 12:09:47PM +0100, Mark Rutland wrote:
> > On Tue, Oct 26, 2021 at 11:44:51PM -0700, Reiji Watanabe wrote:
> > > On Tue, Oct 26, 2021 at 5:23 AM Mark Rutland <mark.rutland@arm.com> wrote:
> > > > On Tue, Oct 26, 2021 at 12:22:20PM +0100, Robin Murphy wrote:
> > > > > On 2021-10-26 04:48, Reiji Watanabe wrote:
> > > > > > Currently, clear_page() uses DC ZVA instruction unconditionally.  But it
> > > > > > should make sure that DCZID_EL0.DZP, which indicates whether or not use
> > > > > > of DC ZVA instruction is prohibited, is zero when using the instruction.
> > > > > > Use stp as memset does instead when DCZID_EL0.DZP == 1.
> > > > > >
> > > > > > Signed-off-by: Reiji Watanabe <reijiw@google.com>
> > > > > > ---
> > > > > >   arch/arm64/lib/clear_page.S | 11 +++++++++++
> > > > > >   1 file changed, 11 insertions(+)
> > > > > >
> > > > > > diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
> > > > > > index b84b179edba3..7ce1bfa4081c 100644
> > > > > > --- a/arch/arm64/lib/clear_page.S
> > > > > > +++ b/arch/arm64/lib/clear_page.S
> > > > > > @@ -16,6 +16,7 @@
> > > > > >    */
> > > > > >   SYM_FUNC_START_PI(clear_page)
> > > > > >     mrs     x1, dczid_el0
> > > > > > +   tbnz    x1, #4, 2f      /* Branch if DC GVA is prohibited */
> > > >
> > > > DCZID_EL0.DZP (AKA DCZID_EL0[4]) says whether all of DC {ZVA,GVA,GZVA}
> > > > are prohibited. This loop uses DZ ZVA, not GC GVA, so it'd be nice to
> > > > s/GVA/ZVA/ here.
> > > 
> > > Thank you for catching it ! I will fix that.
> > > 
> > > > Howver, `DC GVA` and `DC GZVA` are both used in mte_set_mem_tag_range(),
> > > > which'll need a similar update...
> > > 
> > > Yes, I'm aware of that and mte_zero_clear_page_tags() needs to get
> > > updated as well.  But, Since I'm not familiar with MTE (and I don't
> > > have any plans to use MTE yet), I didn't work on them (I'm not sure
> > > how I can test them).
> > > I might try to fix them separately later as well when I have time
> > > (not so soon most likely though).
> > 
> > My view is that we should either:
> > 
> > * Document that we require DCZID_EL0.DZP==0, as is implicitly the case
> >   today.
> 
> I disagree with that. There's nothing wrong in trapping this stuff, as long
> as you go ahead and emulate it, which is exactly why we aren't checking it at
> the moment as EL2 should be prepared to handle the trap. The Arm ARM talks
> about the instructions being "prohibited" but that doesn't mean anything --
> the reality is that they trap to EL2.

TBH, I think trapping DC ZVA rather than forcing it to be UNDEF was an
architectural mistake.

I think the intent of the "prohibited" wording (and exposure of
DCZID_EL0.DZP to EL0 and EL1) is clearly that SW should *avoid* DC ZVA and
friends when DCZID_EL0.DZP is set (and libc and the Arm optimized
routines have *always* checked that), and performance would be abysmal
with emulated DC ZVA, so at minimum we want to avoid hitting emulation
in the common case.

> We could document *that* though?

I guess; though it makes me uneasy since the architecture clearly pushes
people to read CTR_EL0.DZP, and heavily implies that there's no need to
emulate, so I don't think we have much of a leg to stand on from an
architecture PoV.

If we need to support this, my preference would be to support
DCZID_EL0.DZP==1 by avoiding the trapped instructions entirely.

I realise the problem as ever is "what does userspace do?".

Thanks,
Mark.
diff mbox series

Patch

diff --git a/arch/arm64/lib/clear_page.S b/arch/arm64/lib/clear_page.S
index b84b179edba3..7ce1bfa4081c 100644
--- a/arch/arm64/lib/clear_page.S
+++ b/arch/arm64/lib/clear_page.S
@@ -16,6 +16,7 @@ 
  */
 SYM_FUNC_START_PI(clear_page)
 	mrs	x1, dczid_el0
+	tbnz	x1, #4, 2f	/* Branch if DC GVA is prohibited */
 	and	w1, w1, #0xf
 	mov	x2, #4
 	lsl	x1, x2, x1
@@ -25,5 +26,15 @@  SYM_FUNC_START_PI(clear_page)
 	tst	x0, #(PAGE_SIZE - 1)
 	b.ne	1b
 	ret
+
+2:	mov	x1, #(PAGE_SIZE)
+	sub	x0, x0, #16	/* Pre-bias. */
+3:	stp	xzr, xzr, [x0, #16]
+	stp	xzr, xzr, [x0, #32]
+	stp	xzr, xzr, [x0, #48]
+	stp	xzr, xzr, [x0, #64]!
+	subs	x1, x1, #64
+	b.gt	3b
+	ret
 SYM_FUNC_END_PI(clear_page)
 EXPORT_SYMBOL(clear_page)