* arch/arm64/src/common/arm64_mte.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
#include "arm64_arch.h"
#include "arm64_mmu.h"
* Pre-processor Definitions
****************************************************************************/
#define GCR_EL1_VAL 0x10001
#define MTE_TAG_SHIFT 56
#define MTE_MM_AILGN 16
* Private Functions
****************************************************************************/
static int mte_is_support(void)
{
int supported;
__asm__ volatile (
"mrs %0, ID_AA64PFR1_EL1\n"
"ubfx %0, %0, #8, #3\n"
: "=r" (supported)
:
: "memory"
);
return supported != 0;
}
* Public Functions
****************************************************************************/
uint8_t up_memtag_get_tag(const void *addr)
{
return 0xf0 | (uint8_t)(((uint64_t)addr) >> MTE_TAG_SHIFT);
}
uint8_t up_memtag_get_random_tag(const void *addr)
{
asm("irg %0, %0" : "=r" (addr));
return up_memtag_get_tag(addr);
}
void *up_memtag_set_tag(const void *addr, uint8_t tag)
{
return (FAR void *)
((((uint64_t)addr) & ~((uint64_t)0xff << MTE_TAG_SHIFT)) |
((uint64_t)tag << MTE_TAG_SHIFT));
}
bool up_memtag_bypass(bool bypass)
{
uint64_t val = read_sysreg(sctlr_el1);
bool state = !(val & SCTLR_TCF1_BIT);
if (bypass)
{
val &= ~SCTLR_TCF1_BIT;
}
else
{
val |= SCTLR_TCF1_BIT;
}
write_sysreg(val, sctlr_el1);
return state;
}
void up_memtag_tag_mem(const void *addr, size_t size)
{
size_t i;
DEBUGASSERT((uintptr_t)addr % MTE_MM_AILGN == 0);
DEBUGASSERT(size % MTE_MM_AILGN == 0);
for (i = 0; i < size; i += MTE_MM_AILGN)
{
asm("stg %0, [%0]" : : "r"(addr + i));
}
}
void arm64_mte_init(void)
{
uint64_t val;
if (!mte_is_support())
{
return;
}
* up. Inconsistent MAIR_EL1 between CPUs sharing the same TLB may
* lead to the wrong memory type being used for a brief window during
* CPU power-up.
*
* CnP is not a boot feature so MTE gets enabled before CnP, but let's
* make sure that is the case.
*/
assert(!(read_sysreg(ttbr0_el1) & TTBR_CNP_BIT));
assert(!(read_sysreg(ttbr1_el1) & TTBR_CNP_BIT));
val = read_sysreg(tcr_el1);
val |= TCR_TCMA1;
write_sysreg(val, tcr_el1);
val = read_sysreg(sctlr_el1);
val |= SCTLR_ATA_BIT | SCTLR_TCF1_BIT;
write_sysreg(val, sctlr_el1);
write_sysreg(GCR_EL1_VAL, gcr_el1);
* RGSR_EL1.SEED must be non-zero for IRG to produce
* pseudorandom numbers. As RGSR_EL1 is UNKNOWN out of reset, we
* must initialize it.
*/
val = (read_sysreg(CNTVCT_EL0) & RGSR_EL1_SEED_MASK) <<
RGSR_EL1_SEED_SHIFT;
if (0 == val)
{
val = 1 << RGSR_EL1_SEED_SHIFT;
}
write_sysreg(val, rgsr_el1);
write_sysreg(0, tfsr_el1);
write_sysreg(0, tfsre0_el1);
}