diff mbox series

arm64/mm: use correct operators for string comparison in cache.S

Message ID 20181201110144.15970-1-ard.biesheuvel@linaro.org (mailing list archive)
State New, archived
Headers show
Series arm64/mm: use correct operators for string comparison in cache.S | expand

Commit Message

Ard Biesheuvel Dec. 1, 2018, 11:01 a.m. UTC
The GAS directives that are currently being used in dcache_by_line_op
rely on assembler behavior that is not documented, and probably not
guaranteed to produce the correct behavior going forward.

Currently, we end up with some undefined symbols in cache.o:

$ nm arch/arm64/mm/cache.o
	 ...
	 U civac
	 ...
	 U cvac
	 U cvap
	 U cvau

This is due to the fact that the comparisons used to select the
operation type in the dcache_by_line_op macro are comparing symbols
not strings, and even though it seems that GAS is doing the right
thing here (undefined symbols by the same name are equal to each
other), it seems unwise to rely on this.

So let's provide some definitions that are guaranteed to be distinct,
and make them local so they don't pollute the gobal symbol space.

Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
---
 arch/arm64/include/asm/assembler.h | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

Comments

Robin Murphy Dec. 3, 2018, 1:11 p.m. UTC | #1
Hi Ard,

On 01/12/2018 11:01, Ard Biesheuvel wrote:
> The GAS directives that are currently being used in dcache_by_line_op
> rely on assembler behavior that is not documented, and probably not
> guaranteed to produce the correct behavior going forward.
> 
> Currently, we end up with some undefined symbols in cache.o:
> 
> $ nm arch/arm64/mm/cache.o
> 	 ...
> 	 U civac
> 	 ...
> 	 U cvac
> 	 U cvap
> 	 U cvau
> 
> This is due to the fact that the comparisons used to select the
> operation type in the dcache_by_line_op macro are comparing symbols
> not strings, and even though it seems that GAS is doing the right
> thing here (undefined symbols by the same name are equal to each
> other), it seems unwise to rely on this.
> 
> So let's provide some definitions that are guaranteed to be distinct,
> and make them local so they don't pollute the gobal symbol space.

Rather than making the unintended symbol comparisons work properly, can 
we not just implement the string comparisons that were supposed to be? 
Superficially, the diff below seems to still generate the desired output 
(although as always there's probably some subtlety I'm missing).

Robin.

----->8-----

diff --git a/arch/arm64/include/asm/assembler.h 
b/arch/arm64/include/asm/assembler.h
index 6142402c2eb4..2c5f4825fee3 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -383,13 +383,13 @@ alternative_endif
  	sub	\tmp2, \tmp1, #1
  	bic	\kaddr, \kaddr, \tmp2
  9998:
-	.if	(\op == cvau || \op == cvac)
+	.if	("\op" == "cvau" || "\op" == "cvac")
  alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
  	dc	\op, \kaddr
  alternative_else
  	dc	civac, \kaddr
  alternative_endif
-	.elseif	(\op == cvap)
+	.elseif	("\op" == "cvap")
  alternative_if ARM64_HAS_DCPOP
  	sys 3, c7, c12, 1, \kaddr	// dc cvap
  alternative_else

> 
> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> ---
>   arch/arm64/include/asm/assembler.h | 9 +++++++--
>   1 file changed, 7 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
> index 6142402c2eb4..d11c32df85c2 100644
> --- a/arch/arm64/include/asm/assembler.h
> +++ b/arch/arm64/include/asm/assembler.h
> @@ -377,19 +377,24 @@ alternative_endif
>    * 	size:		size of the region
>    * 	Corrupts:	kaddr, size, tmp1, tmp2
>    */
> +	.set	.Lcvau,  0
> +	.set	.Lcvac,  1
> +	.set	.Lcvap,  2
> +	.set	.Lcivac, 3
> +
>   	.macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
>   	dcache_line_size \tmp1, \tmp2
>   	add	\size, \kaddr, \size
>   	sub	\tmp2, \tmp1, #1
>   	bic	\kaddr, \kaddr, \tmp2
>   9998:
> -	.if	(\op == cvau || \op == cvac)
> +	.if	(.L\op == .Lcvau || .L\op == .Lcvac)
>   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
>   	dc	\op, \kaddr
>   alternative_else
>   	dc	civac, \kaddr
>   alternative_endif
> -	.elseif	(\op == cvap)
> +	.elseif	(.L\op == .Lcvap)
>   alternative_if ARM64_HAS_DCPOP
>   	sys 3, c7, c12, 1, \kaddr	// dc cvap
>   alternative_else
>
Ard Biesheuvel Dec. 3, 2018, 1:22 p.m. UTC | #2
On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
>
> Hi Ard,
>
> On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > The GAS directives that are currently being used in dcache_by_line_op
> > rely on assembler behavior that is not documented, and probably not
> > guaranteed to produce the correct behavior going forward.
> >
> > Currently, we end up with some undefined symbols in cache.o:
> >
> > $ nm arch/arm64/mm/cache.o
> >        ...
> >        U civac
> >        ...
> >        U cvac
> >        U cvap
> >        U cvau
> >
> > This is due to the fact that the comparisons used to select the
> > operation type in the dcache_by_line_op macro are comparing symbols
> > not strings, and even though it seems that GAS is doing the right
> > thing here (undefined symbols by the same name are equal to each
> > other), it seems unwise to rely on this.
> >
> > So let's provide some definitions that are guaranteed to be distinct,
> > and make them local so they don't pollute the gobal symbol space.
>
> Rather than making the unintended symbol comparisons work properly, can
> we not just implement the string comparisons that were supposed to be?
> Superficially, the diff below seems to still generate the desired output
> (although as always there's probably some subtlety I'm missing).
>
> Robin.
>
> ----->8-----
>
> diff --git a/arch/arm64/include/asm/assembler.h
> b/arch/arm64/include/asm/assembler.h
> index 6142402c2eb4..2c5f4825fee3 100644
> --- a/arch/arm64/include/asm/assembler.h
> +++ b/arch/arm64/include/asm/assembler.h
> @@ -383,13 +383,13 @@ alternative_endif
>         sub     \tmp2, \tmp1, #1
>         bic     \kaddr, \kaddr, \tmp2
>   9998:
> -       .if     (\op == cvau || \op == cvac)
> +       .if     ("\op" == "cvau" || "\op" == "cvac")
>   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
>         dc      \op, \kaddr
>   alternative_else
>         dc      civac, \kaddr
>   alternative_endif
> -       .elseif (\op == cvap)
> +       .elseif ("\op" == "cvap")
>   alternative_if ARM64_HAS_DCPOP
>         sys 3, c7, c12, 1, \kaddr       // dc cvap
>   alternative_else
>

Looking at the GAS info pages, I find

"Operators" are arithmetic functions, like '+' or '%'.
"Arguments" are symbols, numbers or subexpressions.
An "expression" specifies an address or numeric value.

so even if the comparison works as expected, I'm hesitant to rely on
it to work as expected on any version of GAS or any other assembler
claiming to implement the GAS asm dialect.

We could change the logic to .ifc, which is defined to operate on string, i.e.,

    .ifnc \op, civac
    .ifnc \op, cvap
alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
    dc \op, \kaddr
alternative_else
    dc civac, \kaddr
alternative_endif
    .else
alternative_if ARM64_HAS_DCPOP
    sys 3, c7, c12, 1, \kaddr // dc cvap
alternative_else
    dc cvac, \kaddr
alternative_endif
    .endif
    .else
     dc      civac, \kaddr
    .endif

> >
> > Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
> > ---
> >   arch/arm64/include/asm/assembler.h | 9 +++++++--
> >   1 file changed, 7 insertions(+), 2 deletions(-)
> >
> > diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
> > index 6142402c2eb4..d11c32df85c2 100644
> > --- a/arch/arm64/include/asm/assembler.h
> > +++ b/arch/arm64/include/asm/assembler.h
> > @@ -377,19 +377,24 @@ alternative_endif
> >    *  size:           size of the region
> >    *  Corrupts:       kaddr, size, tmp1, tmp2
> >    */
> > +     .set    .Lcvau,  0
> > +     .set    .Lcvac,  1
> > +     .set    .Lcvap,  2
> > +     .set    .Lcivac, 3
> > +
> >       .macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
> >       dcache_line_size \tmp1, \tmp2
> >       add     \size, \kaddr, \size
> >       sub     \tmp2, \tmp1, #1
> >       bic     \kaddr, \kaddr, \tmp2
> >   9998:
> > -     .if     (\op == cvau || \op == cvac)
> > +     .if     (.L\op == .Lcvau || .L\op == .Lcvac)
> >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> >       dc      \op, \kaddr
> >   alternative_else
> >       dc      civac, \kaddr
> >   alternative_endif
> > -     .elseif (\op == cvap)
> > +     .elseif (.L\op == .Lcvap)
> >   alternative_if ARM64_HAS_DCPOP
> >       sys 3, c7, c12, 1, \kaddr       // dc cvap
> >   alternative_else
> >
Will Deacon Dec. 3, 2018, 5:45 p.m. UTC | #3
On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > The GAS directives that are currently being used in dcache_by_line_op
> > > rely on assembler behavior that is not documented, and probably not
> > > guaranteed to produce the correct behavior going forward.
> > >
> > > Currently, we end up with some undefined symbols in cache.o:
> > >
> > > $ nm arch/arm64/mm/cache.o
> > >        ...
> > >        U civac
> > >        ...
> > >        U cvac
> > >        U cvap
> > >        U cvau
> > >
> > > This is due to the fact that the comparisons used to select the
> > > operation type in the dcache_by_line_op macro are comparing symbols
> > > not strings, and even though it seems that GAS is doing the right
> > > thing here (undefined symbols by the same name are equal to each
> > > other), it seems unwise to rely on this.
> > >
> > > So let's provide some definitions that are guaranteed to be distinct,
> > > and make them local so they don't pollute the gobal symbol space.
> >
> > Rather than making the unintended symbol comparisons work properly, can
> > we not just implement the string comparisons that were supposed to be?
> > Superficially, the diff below seems to still generate the desired output
> > (although as always there's probably some subtlety I'm missing).
> >
> > Robin.
> >
> > ----->8-----
> >
> > diff --git a/arch/arm64/include/asm/assembler.h
> > b/arch/arm64/include/asm/assembler.h
> > index 6142402c2eb4..2c5f4825fee3 100644
> > --- a/arch/arm64/include/asm/assembler.h
> > +++ b/arch/arm64/include/asm/assembler.h
> > @@ -383,13 +383,13 @@ alternative_endif
> >         sub     \tmp2, \tmp1, #1
> >         bic     \kaddr, \kaddr, \tmp2
> >   9998:
> > -       .if     (\op == cvau || \op == cvac)
> > +       .if     ("\op" == "cvau" || "\op" == "cvac")
> >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> >         dc      \op, \kaddr
> >   alternative_else
> >         dc      civac, \kaddr
> >   alternative_endif
> > -       .elseif (\op == cvap)
> > +       .elseif ("\op" == "cvap")
> >   alternative_if ARM64_HAS_DCPOP
> >         sys 3, c7, c12, 1, \kaddr       // dc cvap
> >   alternative_else
> >
> 
> Looking at the GAS info pages, I find
> 
> "Operators" are arithmetic functions, like '+' or '%'.
> "Arguments" are symbols, numbers or subexpressions.
> An "expression" specifies an address or numeric value.
> 
> so even if the comparison works as expected, I'm hesitant to rely on
> it to work as expected on any version of GAS or any other assembler
> claiming to implement the GAS asm dialect.
> 
> We could change the logic to .ifc, which is defined to operate on string, i.e.,

That looks better to me, although I'm not sure why you're inverted the logic
here:

>     .ifnc \op, civac
>     .ifnc \op, cvap

What am I missing?

Will
Ard Biesheuvel Dec. 3, 2018, 5:54 p.m. UTC | #4
On Mon, 3 Dec 2018 at 18:44, Will Deacon <will.deacon@arm.com> wrote:
>
> On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > rely on assembler behavior that is not documented, and probably not
> > > > guaranteed to produce the correct behavior going forward.
> > > >
> > > > Currently, we end up with some undefined symbols in cache.o:
> > > >
> > > > $ nm arch/arm64/mm/cache.o
> > > >        ...
> > > >        U civac
> > > >        ...
> > > >        U cvac
> > > >        U cvap
> > > >        U cvau
> > > >
> > > > This is due to the fact that the comparisons used to select the
> > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > not strings, and even though it seems that GAS is doing the right
> > > > thing here (undefined symbols by the same name are equal to each
> > > > other), it seems unwise to rely on this.
> > > >
> > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > and make them local so they don't pollute the gobal symbol space.
> > >
> > > Rather than making the unintended symbol comparisons work properly, can
> > > we not just implement the string comparisons that were supposed to be?
> > > Superficially, the diff below seems to still generate the desired output
> > > (although as always there's probably some subtlety I'm missing).
> > >
> > > Robin.
> > >
> > > ----->8-----
> > >
> > > diff --git a/arch/arm64/include/asm/assembler.h
> > > b/arch/arm64/include/asm/assembler.h
> > > index 6142402c2eb4..2c5f4825fee3 100644
> > > --- a/arch/arm64/include/asm/assembler.h
> > > +++ b/arch/arm64/include/asm/assembler.h
> > > @@ -383,13 +383,13 @@ alternative_endif
> > >         sub     \tmp2, \tmp1, #1
> > >         bic     \kaddr, \kaddr, \tmp2
> > >   9998:
> > > -       .if     (\op == cvau || \op == cvac)
> > > +       .if     ("\op" == "cvau" || "\op" == "cvac")
> > >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > >         dc      \op, \kaddr
> > >   alternative_else
> > >         dc      civac, \kaddr
> > >   alternative_endif
> > > -       .elseif (\op == cvap)
> > > +       .elseif ("\op" == "cvap")
> > >   alternative_if ARM64_HAS_DCPOP
> > >         sys 3, c7, c12, 1, \kaddr       // dc cvap
> > >   alternative_else
> > >
> >
> > Looking at the GAS info pages, I find
> >
> > "Operators" are arithmetic functions, like '+' or '%'.
> > "Arguments" are symbols, numbers or subexpressions.
> > An "expression" specifies an address or numeric value.
> >
> > so even if the comparison works as expected, I'm hesitant to rely on
> > it to work as expected on any version of GAS or any other assembler
> > claiming to implement the GAS asm dialect.
> >
> > We could change the logic to .ifc, which is defined to operate on string, i.e.,
>
> That looks better to me, although I'm not sure why you're inverted the logic
> here:
>
> >     .ifnc \op, civac
> >     .ifnc \op, cvap
>
> What am I missing?
>

.ifc does not permit '\op equals string1 or \op equals string2'
Will Deacon Dec. 3, 2018, 6:11 p.m. UTC | #5
On Mon, Dec 03, 2018 at 06:54:35PM +0100, Ard Biesheuvel wrote:
> On Mon, 3 Dec 2018 at 18:44, Will Deacon <will.deacon@arm.com> wrote:
> >
> > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > > rely on assembler behavior that is not documented, and probably not
> > > > > guaranteed to produce the correct behavior going forward.
> > > > >
> > > > > Currently, we end up with some undefined symbols in cache.o:
> > > > >
> > > > > $ nm arch/arm64/mm/cache.o
> > > > >        ...
> > > > >        U civac
> > > > >        ...
> > > > >        U cvac
> > > > >        U cvap
> > > > >        U cvau
> > > > >
> > > > > This is due to the fact that the comparisons used to select the
> > > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > > not strings, and even though it seems that GAS is doing the right
> > > > > thing here (undefined symbols by the same name are equal to each
> > > > > other), it seems unwise to rely on this.
> > > > >
> > > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > > and make them local so they don't pollute the gobal symbol space.
> > > >
> > > > Rather than making the unintended symbol comparisons work properly, can
> > > > we not just implement the string comparisons that were supposed to be?
> > > > Superficially, the diff below seems to still generate the desired output
> > > > (although as always there's probably some subtlety I'm missing).
> > > >
> > > > Robin.
> > > >
> > > > ----->8-----
> > > >
> > > > diff --git a/arch/arm64/include/asm/assembler.h
> > > > b/arch/arm64/include/asm/assembler.h
> > > > index 6142402c2eb4..2c5f4825fee3 100644
> > > > --- a/arch/arm64/include/asm/assembler.h
> > > > +++ b/arch/arm64/include/asm/assembler.h
> > > > @@ -383,13 +383,13 @@ alternative_endif
> > > >         sub     \tmp2, \tmp1, #1
> > > >         bic     \kaddr, \kaddr, \tmp2
> > > >   9998:
> > > > -       .if     (\op == cvau || \op == cvac)
> > > > +       .if     ("\op" == "cvau" || "\op" == "cvac")
> > > >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > > >         dc      \op, \kaddr
> > > >   alternative_else
> > > >         dc      civac, \kaddr
> > > >   alternative_endif
> > > > -       .elseif (\op == cvap)
> > > > +       .elseif ("\op" == "cvap")
> > > >   alternative_if ARM64_HAS_DCPOP
> > > >         sys 3, c7, c12, 1, \kaddr       // dc cvap
> > > >   alternative_else
> > > >
> > >
> > > Looking at the GAS info pages, I find
> > >
> > > "Operators" are arithmetic functions, like '+' or '%'.
> > > "Arguments" are symbols, numbers or subexpressions.
> > > An "expression" specifies an address or numeric value.
> > >
> > > so even if the comparison works as expected, I'm hesitant to rely on
> > > it to work as expected on any version of GAS or any other assembler
> > > claiming to implement the GAS asm dialect.
> > >
> > > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> >
> > That looks better to me, although I'm not sure why you're inverted the logic
> > here:
> >
> > >     .ifnc \op, civac
> > >     .ifnc \op, cvap
> >
> > What am I missing?
> >
> 
> .ifc does not permit '\op equals string1 or \op equals string2'

Thanks. Then I guess we invert the logic as you suggest, or we duplicate the
alternative code. Looking at this some more, I think what we currently have
is broken because on a system with ARM64_WORKAROUND_CLEAN_CACHE but not
ARM64_HAS_DCPOP, you'll get DC CVAC for __clean_dcache_area_pop, which
would be broken on that CPU.

Will
Ard Biesheuvel Dec. 4, 2018, 12:44 a.m. UTC | #6
On Mon, 3 Dec 2018 at 19:10, Will Deacon <will.deacon@arm.com> wrote:
>
> On Mon, Dec 03, 2018 at 06:54:35PM +0100, Ard Biesheuvel wrote:
> > On Mon, 3 Dec 2018 at 18:44, Will Deacon <will.deacon@arm.com> wrote:
> > >
> > > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > > > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > > > rely on assembler behavior that is not documented, and probably not
> > > > > > guaranteed to produce the correct behavior going forward.
> > > > > >
> > > > > > Currently, we end up with some undefined symbols in cache.o:
> > > > > >
> > > > > > $ nm arch/arm64/mm/cache.o
> > > > > >        ...
> > > > > >        U civac
> > > > > >        ...
> > > > > >        U cvac
> > > > > >        U cvap
> > > > > >        U cvau
> > > > > >
> > > > > > This is due to the fact that the comparisons used to select the
> > > > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > > > not strings, and even though it seems that GAS is doing the right
> > > > > > thing here (undefined symbols by the same name are equal to each
> > > > > > other), it seems unwise to rely on this.
> > > > > >
> > > > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > > > and make them local so they don't pollute the gobal symbol space.
> > > > >
> > > > > Rather than making the unintended symbol comparisons work properly, can
> > > > > we not just implement the string comparisons that were supposed to be?
> > > > > Superficially, the diff below seems to still generate the desired output
> > > > > (although as always there's probably some subtlety I'm missing).
> > > > >
> > > > > Robin.
> > > > >
> > > > > ----->8-----
> > > > >
> > > > > diff --git a/arch/arm64/include/asm/assembler.h
> > > > > b/arch/arm64/include/asm/assembler.h
> > > > > index 6142402c2eb4..2c5f4825fee3 100644
> > > > > --- a/arch/arm64/include/asm/assembler.h
> > > > > +++ b/arch/arm64/include/asm/assembler.h
> > > > > @@ -383,13 +383,13 @@ alternative_endif
> > > > >         sub     \tmp2, \tmp1, #1
> > > > >         bic     \kaddr, \kaddr, \tmp2
> > > > >   9998:
> > > > > -       .if     (\op == cvau || \op == cvac)
> > > > > +       .if     ("\op" == "cvau" || "\op" == "cvac")
> > > > >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > > > >         dc      \op, \kaddr
> > > > >   alternative_else
> > > > >         dc      civac, \kaddr
> > > > >   alternative_endif
> > > > > -       .elseif (\op == cvap)
> > > > > +       .elseif ("\op" == "cvap")
> > > > >   alternative_if ARM64_HAS_DCPOP
> > > > >         sys 3, c7, c12, 1, \kaddr       // dc cvap
> > > > >   alternative_else
> > > > >
> > > >
> > > > Looking at the GAS info pages, I find
> > > >
> > > > "Operators" are arithmetic functions, like '+' or '%'.
> > > > "Arguments" are symbols, numbers or subexpressions.
> > > > An "expression" specifies an address or numeric value.
> > > >
> > > > so even if the comparison works as expected, I'm hesitant to rely on
> > > > it to work as expected on any version of GAS or any other assembler
> > > > claiming to implement the GAS asm dialect.
> > > >
> > > > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> > >
> > > That looks better to me, although I'm not sure why you're inverted the logic
> > > here:
> > >
> > > >     .ifnc \op, civac
> > > >     .ifnc \op, cvap
> > >
> > > What am I missing?
> > >
> >
> > .ifc does not permit '\op equals string1 or \op equals string2'
>
> Thanks. Then I guess we invert the logic as you suggest, or we duplicate the
> alternative code. Looking at this some more, I think what we currently have
> is broken because on a system with ARM64_WORKAROUND_CLEAN_CACHE but not
> ARM64_HAS_DCPOP, you'll get DC CVAC for __clean_dcache_area_pop, which
> would be broken on that CPU.
>

Can we just fallback to civac instead? Or do we need to add logic to
combine the two feature flags?
Dave Martin Dec. 6, 2018, 11:20 a.m. UTC | #7
On Mon, Dec 03, 2018 at 05:45:06PM +0000, Will Deacon wrote:
> On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > rely on assembler behavior that is not documented, and probably not
> > > > guaranteed to produce the correct behavior going forward.
> > > >
> > > > Currently, we end up with some undefined symbols in cache.o:
> > > >
> > > > $ nm arch/arm64/mm/cache.o
> > > >        ...
> > > >        U civac
> > > >        ...
> > > >        U cvac
> > > >        U cvap
> > > >        U cvau
> > > >
> > > > This is due to the fact that the comparisons used to select the
> > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > not strings, and even though it seems that GAS is doing the right
> > > > thing here (undefined symbols by the same name are equal to each
> > > > other), it seems unwise to rely on this.
> > > >
> > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > and make them local so they don't pollute the gobal symbol space.
> > >
> > > Rather than making the unintended symbol comparisons work properly, can
> > > we not just implement the string comparisons that were supposed to be?
> > > Superficially, the diff below seems to still generate the desired output
> > > (although as always there's probably some subtlety I'm missing).
> > >
> > > Robin.
> > >
> > > ----->8-----
> > >
> > > diff --git a/arch/arm64/include/asm/assembler.h
> > > b/arch/arm64/include/asm/assembler.h
> > > index 6142402c2eb4..2c5f4825fee3 100644
> > > --- a/arch/arm64/include/asm/assembler.h
> > > +++ b/arch/arm64/include/asm/assembler.h
> > > @@ -383,13 +383,13 @@ alternative_endif
> > >         sub     \tmp2, \tmp1, #1
> > >         bic     \kaddr, \kaddr, \tmp2
> > >   9998:
> > > -       .if     (\op == cvau || \op == cvac)
> > > +       .if     ("\op" == "cvau" || "\op" == "cvac")
> > >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > >         dc      \op, \kaddr
> > >   alternative_else
> > >         dc      civac, \kaddr
> > >   alternative_endif
> > > -       .elseif (\op == cvap)
> > > +       .elseif ("\op" == "cvap")

(Whatever this looks like, it's still comparing symbols someone probably
already pointed that out.  Oh, and the () are redundant.  This isn't C,
but, meh.)

> > >   alternative_if ARM64_HAS_DCPOP
> > >         sys 3, c7, c12, 1, \kaddr       // dc cvap
> > >   alternative_else
> > >
> > 
> > Looking at the GAS info pages, I find
> > 
> > "Operators" are arithmetic functions, like '+' or '%'.
> > "Arguments" are symbols, numbers or subexpressions.
> > An "expression" specifies an address or numeric value.
> > 
> > so even if the comparison works as expected, I'm hesitant to rely on
> > it to work as expected on any version of GAS or any other assembler
> > claiming to implement the GAS asm dialect.
> > 
> > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> 
> That looks better to me, although I'm not sure why you're inverted the logic
> here:
> 
> >     .ifnc \op, civac
> >     .ifnc \op, cvap
> 
> What am I missing?

I vote for the .ifc approach.

Note, the current works-by-accident approach using == has the odd side-
effect of spitting out undefined symbol references in the .o file.  It
seems that isn't breaking the link, but I wonder whether there are any
side-effects we're not aware of.

If we don't like the inverted logic, there is always

	.set .L__foo_\@, 0
	.ifc \op, civac
	.set .L__foo_\@, 1
	.endif
	.ifc \op, cvap
	.set .L__foo_\@, 1
	.endif

	.if .L__foo_\@
	// ...
	.endif

which is ugly.  Either way, the logic could be wrapped as a helper:

	.macro if_string_is_either str, cmp1, cmp2, insn:vararg
		.ifnc "\str","\cmp1"
		.ifnc "\str","\cmp2"
		.exitm
		.endif
		.endif

		\insn
	.endm

Cheers
---Dave
Ard Biesheuvel Dec. 6, 2018, 11:47 a.m. UTC | #8
On Thu, 6 Dec 2018 at 12:20, Dave Martin <Dave.Martin@arm.com> wrote:
>
> On Mon, Dec 03, 2018 at 05:45:06PM +0000, Will Deacon wrote:
> > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > > rely on assembler behavior that is not documented, and probably not
> > > > > guaranteed to produce the correct behavior going forward.
> > > > >
> > > > > Currently, we end up with some undefined symbols in cache.o:
> > > > >
> > > > > $ nm arch/arm64/mm/cache.o
> > > > >        ...
> > > > >        U civac
> > > > >        ...
> > > > >        U cvac
> > > > >        U cvap
> > > > >        U cvau
> > > > >
> > > > > This is due to the fact that the comparisons used to select the
> > > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > > not strings, and even though it seems that GAS is doing the right
> > > > > thing here (undefined symbols by the same name are equal to each
> > > > > other), it seems unwise to rely on this.
> > > > >
> > > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > > and make them local so they don't pollute the gobal symbol space.
> > > >
> > > > Rather than making the unintended symbol comparisons work properly, can
> > > > we not just implement the string comparisons that were supposed to be?
> > > > Superficially, the diff below seems to still generate the desired output
> > > > (although as always there's probably some subtlety I'm missing).
> > > >
> > > > Robin.
> > > >
> > > > ----->8-----
> > > >
> > > > diff --git a/arch/arm64/include/asm/assembler.h
> > > > b/arch/arm64/include/asm/assembler.h
> > > > index 6142402c2eb4..2c5f4825fee3 100644
> > > > --- a/arch/arm64/include/asm/assembler.h
> > > > +++ b/arch/arm64/include/asm/assembler.h
> > > > @@ -383,13 +383,13 @@ alternative_endif
> > > >         sub     \tmp2, \tmp1, #1
> > > >         bic     \kaddr, \kaddr, \tmp2
> > > >   9998:
> > > > -       .if     (\op == cvau || \op == cvac)
> > > > +       .if     ("\op" == "cvau" || "\op" == "cvac")
> > > >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > > >         dc      \op, \kaddr
> > > >   alternative_else
> > > >         dc      civac, \kaddr
> > > >   alternative_endif
> > > > -       .elseif (\op == cvap)
> > > > +       .elseif ("\op" == "cvap")
>
> (Whatever this looks like, it's still comparing symbols someone probably
> already pointed that out.  Oh, and the () are redundant.  This isn't C,
> but, meh.)
>
> > > >   alternative_if ARM64_HAS_DCPOP
> > > >         sys 3, c7, c12, 1, \kaddr       // dc cvap
> > > >   alternative_else
> > > >
> > >
> > > Looking at the GAS info pages, I find
> > >
> > > "Operators" are arithmetic functions, like '+' or '%'.
> > > "Arguments" are symbols, numbers or subexpressions.
> > > An "expression" specifies an address or numeric value.
> > >
> > > so even if the comparison works as expected, I'm hesitant to rely on
> > > it to work as expected on any version of GAS or any other assembler
> > > claiming to implement the GAS asm dialect.
> > >
> > > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> >
> > That looks better to me, although I'm not sure why you're inverted the logic
> > here:
> >
> > >     .ifnc \op, civac
> > >     .ifnc \op, cvap
> >
> > What am I missing?
>
> I vote for the .ifc approach.
>
> Note, the current works-by-accident approach using == has the odd side-
> effect of spitting out undefined symbol references in the .o file.  It
> seems that isn't breaking the link, but I wonder whether there are any
> side-effects we're not aware of.
>

Did you read the commit log at all? :-)

> If we don't like the inverted logic, there is always
>
>         .set .L__foo_\@, 0
>         .ifc \op, civac
>         .set .L__foo_\@, 1
>         .endif
>         .ifc \op, cvap
>         .set .L__foo_\@, 1
>         .endif
>
>         .if .L__foo_\@
>         // ...
>         .endif
>
> which is ugly.  Either way, the logic could be wrapped as a helper:
>
>         .macro if_string_is_either str, cmp1, cmp2, insn:vararg
>                 .ifnc "\str","\cmp1"
>                 .ifnc "\str","\cmp2"
>                 .exitm
>                 .endif
>                 .endif
>
>                 \insn
>         .endm
>

Yeah, I don't think this is an improvement over using inverted logic.
Will Deacon Dec. 6, 2018, 11:51 a.m. UTC | #9
On Tue, Dec 04, 2018 at 01:44:01AM +0100, Ard Biesheuvel wrote:
> On Mon, 3 Dec 2018 at 19:10, Will Deacon <will.deacon@arm.com> wrote:
> >
> > On Mon, Dec 03, 2018 at 06:54:35PM +0100, Ard Biesheuvel wrote:
> > > On Mon, 3 Dec 2018 at 18:44, Will Deacon <will.deacon@arm.com> wrote:
> > > >
> > > > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > > > > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > > > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > > > > rely on assembler behavior that is not documented, and probably not
> > > > > > > guaranteed to produce the correct behavior going forward.
> > > > > > >
> > > > > > > Currently, we end up with some undefined symbols in cache.o:
> > > > > > >
> > > > > > > $ nm arch/arm64/mm/cache.o
> > > > > > >        ...
> > > > > > >        U civac
> > > > > > >        ...
> > > > > > >        U cvac
> > > > > > >        U cvap
> > > > > > >        U cvau
> > > > > > >
> > > > > > > This is due to the fact that the comparisons used to select the
> > > > > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > > > > not strings, and even though it seems that GAS is doing the right
> > > > > > > thing here (undefined symbols by the same name are equal to each
> > > > > > > other), it seems unwise to rely on this.
> > > > > > >
> > > > > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > > > > and make them local so they don't pollute the gobal symbol space.
> > > > > >
> > > > > > Rather than making the unintended symbol comparisons work properly, can
> > > > > > we not just implement the string comparisons that were supposed to be?
> > > > > > Superficially, the diff below seems to still generate the desired output
> > > > > > (although as always there's probably some subtlety I'm missing).
> > > > > >
> > > > > > Robin.
> > > > > >
> > > > > > ----->8-----
> > > > > >
> > > > > > diff --git a/arch/arm64/include/asm/assembler.h
> > > > > > b/arch/arm64/include/asm/assembler.h
> > > > > > index 6142402c2eb4..2c5f4825fee3 100644
> > > > > > --- a/arch/arm64/include/asm/assembler.h
> > > > > > +++ b/arch/arm64/include/asm/assembler.h
> > > > > > @@ -383,13 +383,13 @@ alternative_endif
> > > > > >         sub     \tmp2, \tmp1, #1
> > > > > >         bic     \kaddr, \kaddr, \tmp2
> > > > > >   9998:
> > > > > > -       .if     (\op == cvau || \op == cvac)
> > > > > > +       .if     ("\op" == "cvau" || "\op" == "cvac")
> > > > > >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > > > > >         dc      \op, \kaddr
> > > > > >   alternative_else
> > > > > >         dc      civac, \kaddr
> > > > > >   alternative_endif
> > > > > > -       .elseif (\op == cvap)
> > > > > > +       .elseif ("\op" == "cvap")
> > > > > >   alternative_if ARM64_HAS_DCPOP
> > > > > >         sys 3, c7, c12, 1, \kaddr       // dc cvap
> > > > > >   alternative_else
> > > > > >
> > > > >
> > > > > Looking at the GAS info pages, I find
> > > > >
> > > > > "Operators" are arithmetic functions, like '+' or '%'.
> > > > > "Arguments" are symbols, numbers or subexpressions.
> > > > > An "expression" specifies an address or numeric value.
> > > > >
> > > > > so even if the comparison works as expected, I'm hesitant to rely on
> > > > > it to work as expected on any version of GAS or any other assembler
> > > > > claiming to implement the GAS asm dialect.
> > > > >
> > > > > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> > > >
> > > > That looks better to me, although I'm not sure why you're inverted the logic
> > > > here:
> > > >
> > > > >     .ifnc \op, civac
> > > > >     .ifnc \op, cvap
> > > >
> > > > What am I missing?
> > > >
> > >
> > > .ifc does not permit '\op equals string1 or \op equals string2'
> >
> > Thanks. Then I guess we invert the logic as you suggest, or we duplicate the
> > alternative code. Looking at this some more, I think what we currently have
> > is broken because on a system with ARM64_WORKAROUND_CLEAN_CACHE but not
> > ARM64_HAS_DCPOP, you'll get DC CVAC for __clean_dcache_area_pop, which
> > would be broken on that CPU.
> >
> 
> Can we just fallback to civac instead? Or do we need to add logic to
> combine the two feature flags?

I guess this could introduce a performance regression for CPUs without
either DCPOP or ARM64_WORKAROUND_CLEAN_CACHE, since we're effectively
forcing a hefty cache miss on a subsequent access to the persisted data.

So I'd prefer not to make the CIVAC unconditional unless we have to.

Will
Ard Biesheuvel Dec. 6, 2018, 11:59 a.m. UTC | #10
On Thu, 6 Dec 2018 at 12:51, Will Deacon <will.deacon@arm.com> wrote:
>
> On Tue, Dec 04, 2018 at 01:44:01AM +0100, Ard Biesheuvel wrote:
> > On Mon, 3 Dec 2018 at 19:10, Will Deacon <will.deacon@arm.com> wrote:
> > >
> > > On Mon, Dec 03, 2018 at 06:54:35PM +0100, Ard Biesheuvel wrote:
> > > > On Mon, 3 Dec 2018 at 18:44, Will Deacon <will.deacon@arm.com> wrote:
> > > > >
> > > > > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:
> > > > > > On Mon, 3 Dec 2018 at 14:11, Robin Murphy <robin.murphy@arm.com> wrote:
> > > > > > > On 01/12/2018 11:01, Ard Biesheuvel wrote:
> > > > > > > > The GAS directives that are currently being used in dcache_by_line_op
> > > > > > > > rely on assembler behavior that is not documented, and probably not
> > > > > > > > guaranteed to produce the correct behavior going forward.
> > > > > > > >
> > > > > > > > Currently, we end up with some undefined symbols in cache.o:
> > > > > > > >
> > > > > > > > $ nm arch/arm64/mm/cache.o
> > > > > > > >        ...
> > > > > > > >        U civac
> > > > > > > >        ...
> > > > > > > >        U cvac
> > > > > > > >        U cvap
> > > > > > > >        U cvau
> > > > > > > >
> > > > > > > > This is due to the fact that the comparisons used to select the
> > > > > > > > operation type in the dcache_by_line_op macro are comparing symbols
> > > > > > > > not strings, and even though it seems that GAS is doing the right
> > > > > > > > thing here (undefined symbols by the same name are equal to each
> > > > > > > > other), it seems unwise to rely on this.
> > > > > > > >
> > > > > > > > So let's provide some definitions that are guaranteed to be distinct,
> > > > > > > > and make them local so they don't pollute the gobal symbol space.
> > > > > > >
> > > > > > > Rather than making the unintended symbol comparisons work properly, can
> > > > > > > we not just implement the string comparisons that were supposed to be?
> > > > > > > Superficially, the diff below seems to still generate the desired output
> > > > > > > (although as always there's probably some subtlety I'm missing).
> > > > > > >
> > > > > > > Robin.
> > > > > > >
> > > > > > > ----->8-----
> > > > > > >
> > > > > > > diff --git a/arch/arm64/include/asm/assembler.h
> > > > > > > b/arch/arm64/include/asm/assembler.h
> > > > > > > index 6142402c2eb4..2c5f4825fee3 100644
> > > > > > > --- a/arch/arm64/include/asm/assembler.h
> > > > > > > +++ b/arch/arm64/include/asm/assembler.h
> > > > > > > @@ -383,13 +383,13 @@ alternative_endif
> > > > > > >         sub     \tmp2, \tmp1, #1
> > > > > > >         bic     \kaddr, \kaddr, \tmp2
> > > > > > >   9998:
> > > > > > > -       .if     (\op == cvau || \op == cvac)
> > > > > > > +       .if     ("\op" == "cvau" || "\op" == "cvac")
> > > > > > >   alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
> > > > > > >         dc      \op, \kaddr
> > > > > > >   alternative_else
> > > > > > >         dc      civac, \kaddr
> > > > > > >   alternative_endif
> > > > > > > -       .elseif (\op == cvap)
> > > > > > > +       .elseif ("\op" == "cvap")
> > > > > > >   alternative_if ARM64_HAS_DCPOP
> > > > > > >         sys 3, c7, c12, 1, \kaddr       // dc cvap
> > > > > > >   alternative_else
> > > > > > >
> > > > > >
> > > > > > Looking at the GAS info pages, I find
> > > > > >
> > > > > > "Operators" are arithmetic functions, like '+' or '%'.
> > > > > > "Arguments" are symbols, numbers or subexpressions.
> > > > > > An "expression" specifies an address or numeric value.
> > > > > >
> > > > > > so even if the comparison works as expected, I'm hesitant to rely on
> > > > > > it to work as expected on any version of GAS or any other assembler
> > > > > > claiming to implement the GAS asm dialect.
> > > > > >
> > > > > > We could change the logic to .ifc, which is defined to operate on string, i.e.,
> > > > >
> > > > > That looks better to me, although I'm not sure why you're inverted the logic
> > > > > here:
> > > > >
> > > > > >     .ifnc \op, civac
> > > > > >     .ifnc \op, cvap
> > > > >
> > > > > What am I missing?
> > > > >
> > > >
> > > > .ifc does not permit '\op equals string1 or \op equals string2'
> > >
> > > Thanks. Then I guess we invert the logic as you suggest, or we duplicate the
> > > alternative code. Looking at this some more, I think what we currently have
> > > is broken because on a system with ARM64_WORKAROUND_CLEAN_CACHE but not
> > > ARM64_HAS_DCPOP, you'll get DC CVAC for __clean_dcache_area_pop, which
> > > would be broken on that CPU.
> > >
> >
> > Can we just fallback to civac instead? Or do we need to add logic to
> > combine the two feature flags?
>
> I guess this could introduce a performance regression for CPUs without
> either DCPOP or ARM64_WORKAROUND_CLEAN_CACHE, since we're effectively
> forcing a hefty cache miss on a subsequent access to the persisted data.
>
> So I'd prefer not to make the CIVAC unconditional unless we have to.
>

OK

I have some patches that extend alternative patching via callbacks for
this. I will send them out shortly.
Dave Martin Dec. 6, 2018, 12:02 p.m. UTC | #11
On Thu, Dec 06, 2018 at 12:47:16PM +0100, Ard Biesheuvel wrote:
> On Thu, 6 Dec 2018 at 12:20, Dave Martin <Dave.Martin@arm.com> wrote:
> >
> > On Mon, Dec 03, 2018 at 05:45:06PM +0000, Will Deacon wrote:
> > > On Mon, Dec 03, 2018 at 02:22:14PM +0100, Ard Biesheuvel wrote:

[...]

> > > That looks better to me, although I'm not sure why you're inverted the logic
> > > here:
> > >
> > > >     .ifnc \op, civac
> > > >     .ifnc \op, cvap
> > >
> > > What am I missing?
> >
> > I vote for the .ifc approach.
> >
> > Note, the current works-by-accident approach using == has the odd side-
> > effect of spitting out undefined symbol references in the .o file.  It
> > seems that isn't breaking the link, but I wonder whether there are any
> > side-effects we're not aware of.
> >
> 
> Did you read the commit log at all? :-)

Due to a combination of a mutt snafu and laziness, no.  (However did you
guess? ;)

> > If we don't like the inverted logic, there is always
> >
> >         .set .L__foo_\@, 0
> >         .ifc \op, civac
> >         .set .L__foo_\@, 1
> >         .endif
> >         .ifc \op, cvap
> >         .set .L__foo_\@, 1
> >         .endif
> >
> >         .if .L__foo_\@
> >         // ...
> >         .endif
> >
> > which is ugly.  Either way, the logic could be wrapped as a helper:
> >
> >         .macro if_string_is_either str, cmp1, cmp2, insn:vararg
> >                 .ifnc "\str","\cmp1"
> >                 .ifnc "\str","\cmp2"
> >                 .exitm
> >                 .endif
> >                 .endif
> >
> >                 \insn
> >         .endm
> >
> 
> Yeah, I don't think this is an improvement over using inverted logic.

As a single instance, no.  But if this issue comes up in multiple places
it could be worth wrapping it up.

Cheers
---Dave
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/assembler.h b/arch/arm64/include/asm/assembler.h
index 6142402c2eb4..d11c32df85c2 100644
--- a/arch/arm64/include/asm/assembler.h
+++ b/arch/arm64/include/asm/assembler.h
@@ -377,19 +377,24 @@  alternative_endif
  * 	size:		size of the region
  * 	Corrupts:	kaddr, size, tmp1, tmp2
  */
+	.set	.Lcvau,  0
+	.set	.Lcvac,  1
+	.set	.Lcvap,  2
+	.set	.Lcivac, 3
+
 	.macro dcache_by_line_op op, domain, kaddr, size, tmp1, tmp2
 	dcache_line_size \tmp1, \tmp2
 	add	\size, \kaddr, \size
 	sub	\tmp2, \tmp1, #1
 	bic	\kaddr, \kaddr, \tmp2
 9998:
-	.if	(\op == cvau || \op == cvac)
+	.if	(.L\op == .Lcvau || .L\op == .Lcvac)
 alternative_if_not ARM64_WORKAROUND_CLEAN_CACHE
 	dc	\op, \kaddr
 alternative_else
 	dc	civac, \kaddr
 alternative_endif
-	.elseif	(\op == cvap)
+	.elseif	(.L\op == .Lcvap)
 alternative_if ARM64_HAS_DCPOP
 	sys 3, c7, c12, 1, \kaddr	// dc cvap
 alternative_else