Re: [PATCH v5 04/22] target/arm: Add helper_mte_check{1,2,3}

2019-12-03 Thread Richard Henderson
Oh, to finish up on the replies...

On 12/3/19 1:42 PM, Peter Maydell wrote:
>> +ptr_tag = allocation_tag_from_addr(dirty_ptr);
>> +if (ptr_tag == 0) {
>> +ARMVAParameters p = aa64_va_parameters(env, dirty_ptr, stage1, 
>> true);
>> +if (p.tcma) {
>> +return clean_ptr;
>> +}
>> +}
> 
> I don't think this logic gets the "regime has two address ranges"
> case correct. For a two-address-range translation regime (where
> TCR_ELx has TCMA0 and TCMA1 bits, rather than just a single TCMA bit),
> then the 'select' argument to this function needs to be involved,
> because we should do a tag-unchecked access if:
>  * addr[59:55]==0b0 (ie select == 0 and ptr_tag == 0)
>and TCR_ELx.TCMA0 is set
>  * addr[59:55]==0b1 (ie select == 1 and ptr_tag == 0xf)
>and TCR_ELx.TCMA1 is set
> (the pseudocode for this is in AArch64.AccessTagIsChecked(),
> and the TCR_EL1.TCMA[01] bit definitions agree; the text in
> D6.8.1 appears to be confused.)

It used to be correct.

That was the lovely bit about physical vs logical tags.  Add 1 bit bit 55, let
the carry ripple up, so that the physical tag check for TCMA was always against 
0.

That seems to be broken now in the final spec.

>> +el = arm_current_el(env);
>> +regime_el = (el ? el : 1);   /* TODO: ARMv8.1-VHE EL2&0 regime */
> 
> We could write this as "regime_el(env, stage1)" if that function
> wasn't local to helper.c, right ?

Yes.

>> +/* noreturn; fall through to assert anyway */
> 
> hopefully this fallthrough comment syntax doesn't confuse any
> of our compilers/static analyzers...

It shouldn't...

>> +/* Tag check fail causes asynchronous flag set.  */
>> +env->cp15.tfsr_el[regime_el] |= 1 << select;
> 
> Won't this incorrectly accumulate tagfails for EL0 into
> TFSR_EL1 rather than TFSRE0_EL1 ? I think you want "[el]".

Yep.

>> +/* Case 3: Reserved. */
>> +qemu_log_mask(LOG_GUEST_ERROR,
>> +  "Tag check failure with SCTLR_EL%d.TCF "
>> +  "set to reserved value %d\n", regime_el, tcf);
> 
> Technically this message is going to be wrong for the
> case of el==0 (where it's SCTLR_EL1.TCF0, not .TCF, that's
> been mis-set).

Yep.


r~



Re: [PATCH v5 04/22] target/arm: Add helper_mte_check{1,2,3}

2019-12-03 Thread Peter Maydell
On Tue, 3 Dec 2019 at 16:06, Richard Henderson
 wrote:
> On 12/3/19 1:42 PM, Peter Maydell wrote:
> > This reads a bit oddly, because (in the final version of the spec)
> > physical and logical tags are identical (AArch64.PhysicalTag()
> > just returns bits [59:56] of the vaddr).
>
> I missed that change between draft and final.
>
> Wow, that's really annoying.  If they were going to drop physical vs logical
> tags, why did they keep the language?

It leaves space for a potential future architecture making
the mapping something other than 1:1.

> Is this really intentional?

Yes.

thanks
-- PMM



Re: [PATCH v5 04/22] target/arm: Add helper_mte_check{1,2,3}

2019-12-03 Thread Richard Henderson
On 12/3/19 1:42 PM, Peter Maydell wrote:
>> +static int allocation_tag_from_addr(uint64_t ptr)
>> +{
>> +ptr += 1ULL << 55;  /* carry ptr[55] into ptr[59:56].  */
>> +return extract64(ptr, 56, 4);
> 
> What's the carry-bit-55 logic for? The pseudocode
> AArch64.AllocationTagFromAddress just returns bits [59:56].

This was the old physical tag extraction.

>> +static uint64_t do_mte_check(CPUARMState *env, uint64_t dirty_ptr,
>> + uint64_t clean_ptr, uint32_t select,
>> + uintptr_t ra)
>> +{
>> +ARMMMUIdx stage1 = arm_stage1_mmu_idx(env);
>> +int ptr_tag, mem_tag;
>> +
>> +/*
>> + * If TCMA is enabled, then physical tag 0 is unchecked.
>> + * Note the rules in D6.8.1 are written with logical tags, where
>> + * the corresponding physical tag rule is simpler: equal to 0.
>> + * We will need the physical tag below anyway.
>> + */
> 
> This reads a bit oddly, because (in the final version of the spec)
> physical and logical tags are identical (AArch64.PhysicalTag()
> just returns bits [59:56] of the vaddr).

I missed that change between draft and final.

Wow, that's really annoying.  If they were going to drop physical vs logical
tags, why did they keep the language?

Frankly, it made a *lot* of sense as a way to handle addresses in TTBR1, which
now have asymmetric special cases.  In particular, ADDG will, as I read it now,
with allocation tag access disabled, munge a TTBR1 address to <59:56> = 0.
Which is fine so long as access is disabled, but when re-enabled (e.g. via
PSTATE.TCO) the address will no longer pass the TCMA test.

Is this really intentional?


r~



Re: [PATCH v5 04/22] target/arm: Add helper_mte_check{1,2,3}

2019-12-03 Thread Peter Maydell
On Fri, 11 Oct 2019 at 14:49, Richard Henderson
 wrote:
>
> Implements the rules of "PE generation of Checked and Unchecked
> accesses" which aren't already implied by TB_FLAGS_MTE_ACTIVE.
> Implements the rules of "PE handling of Tag Check Failure".
>
> Does not implement tag physical address space, so all operations
> reduce to unchecked so far.
>
> Signed-off-by: Richard Henderson 
> ---
> v2: Fix TFSR update.
> v3: Split helper_mte_check per {1,2} IAs; take tbi data from translate.
> v5: Split helper_mte_check3, the only one that needs a runtime check for tbi.
> ---
>  target/arm/helper-a64.h|   4 +
>  target/arm/mte_helper.c| 167 +
>  target/arm/translate-a64.c |  15 +++-
>  target/arm/Makefile.objs   |   1 +
>  4 files changed, 186 insertions(+), 1 deletion(-)
>  create mode 100644 target/arm/mte_helper.c
>
> diff --git a/target/arm/helper-a64.h b/target/arm/helper-a64.h
> index a915c1247f..a82e21f15a 100644
> --- a/target/arm/helper-a64.h
> +++ b/target/arm/helper-a64.h
> @@ -102,3 +102,7 @@ DEF_HELPER_FLAGS_3(autda, TCG_CALL_NO_WG, i64, env, i64, 
> i64)
>  DEF_HELPER_FLAGS_3(autdb, TCG_CALL_NO_WG, i64, env, i64, i64)
>  DEF_HELPER_FLAGS_2(xpaci, TCG_CALL_NO_RWG_SE, i64, env, i64)
>  DEF_HELPER_FLAGS_2(xpacd, TCG_CALL_NO_RWG_SE, i64, env, i64)
> +
> +DEF_HELPER_FLAGS_2(mte_check1, TCG_CALL_NO_WG, i64, env, i64)
> +DEF_HELPER_FLAGS_2(mte_check2, TCG_CALL_NO_WG, i64, env, i64)
> +DEF_HELPER_FLAGS_3(mte_check3, TCG_CALL_NO_WG, i64, env, i64, i32)
> diff --git a/target/arm/mte_helper.c b/target/arm/mte_helper.c
> new file mode 100644
> index 00..bbb90cbe86
> --- /dev/null
> +++ b/target/arm/mte_helper.c
> @@ -0,0 +1,167 @@
> +/*
> + * ARM v8.5-MemTag Operations
> + *
> + * Copyright (c) 2019 Linaro, Ltd.
> + *
> + * This library is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * This library is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with this library; if not, see 
> .
> + */
> +
> +#include "qemu/osdep.h"
> +#include "cpu.h"
> +#include "internals.h"
> +#include "exec/exec-all.h"
> +#include "exec/cpu_ldst.h"
> +#include "exec/helper-proto.h"
> +
> +
> +static int get_allocation_tag(CPUARMState *env, uint64_t ptr, uintptr_t ra)
> +{
> +/* Tag storage not implemented.  */
> +return -1;
> +}
> +
> +static int allocation_tag_from_addr(uint64_t ptr)
> +{
> +ptr += 1ULL << 55;  /* carry ptr[55] into ptr[59:56].  */
> +return extract64(ptr, 56, 4);

What's the carry-bit-55 logic for? The pseudocode
AArch64.AllocationTagFromAddress just returns bits [59:56].

> +}
> +
> +/*
> + * Perform a checked access for MTE.
> + * On arrival, TBI is known to enabled, as is allocation_tag_access_enabled.

"to be"

> + */
> +static uint64_t do_mte_check(CPUARMState *env, uint64_t dirty_ptr,
> + uint64_t clean_ptr, uint32_t select,
> + uintptr_t ra)
> +{
> +ARMMMUIdx stage1 = arm_stage1_mmu_idx(env);
> +int ptr_tag, mem_tag;
> +
> +/*
> + * If TCMA is enabled, then physical tag 0 is unchecked.
> + * Note the rules in D6.8.1 are written with logical tags, where
> + * the corresponding physical tag rule is simpler: equal to 0.
> + * We will need the physical tag below anyway.
> + */

This reads a bit oddly, because (in the final version of the spec)
physical and logical tags are identical (AArch64.PhysicalTag()
just returns bits [59:56] of the vaddr).

> +ptr_tag = allocation_tag_from_addr(dirty_ptr);
> +if (ptr_tag == 0) {
> +ARMVAParameters p = aa64_va_parameters(env, dirty_ptr, stage1, true);
> +if (p.tcma) {
> +return clean_ptr;
> +}
> +}

I don't think this logic gets the "regime has two address ranges"
case correct. For a two-address-range translation regime (where
TCR_ELx has TCMA0 and TCMA1 bits, rather than just a single TCMA bit),
then the 'select' argument to this function needs to be involved,
because we should do a tag-unchecked access if:
 * addr[59:55]==0b0 (ie select == 0 and ptr_tag == 0)
   and TCR_ELx.TCMA0 is set
 * addr[59:55]==0b1 (ie select == 1 and ptr_tag == 0xf)
   and TCR_ELx.TCMA1 is set
(the pseudocode for this is in AArch64.AccessTagIsChecked(),
and the TCR_EL1.TCMA[01] bit definitions agree; the text in
D6.8.1 appears to be confused.)

> +
> +/*
> + * If an access is made to an address that does not provide tag
> + * storage, the result is