tests/tcg/aarch64: Add mte smoke tests
Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20210212184902.1251044-32-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
e32328645e
commit
36cd5fbdbf
@ -35,6 +35,12 @@ endif
|
||||
# bti-2 tests PROT_BTI, so no special compiler support required.
|
||||
AARCH64_TESTS += bti-2
|
||||
|
||||
# MTE Tests
|
||||
ifneq ($(DOCKER_IMAGE)$(CROSS_CC_HAS_ARMV8_MTE),)
|
||||
AARCH64_TESTS += mte-1 mte-2 mte-3 mte-4
|
||||
mte-%: CFLAGS += -march=armv8.5-a+memtag
|
||||
endif
|
||||
|
||||
# Semihosting smoke test for linux-user
|
||||
AARCH64_TESTS += semihosting
|
||||
run-semihosting: semihosting
|
||||
|
28
tests/tcg/aarch64/mte-1.c
Normal file
28
tests/tcg/aarch64/mte-1.c
Normal file
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Memory tagging, basic pass cases.
|
||||
*
|
||||
* Copyright (c) 2021 Linaro Ltd
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "mte.h"
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
int *p0, *p1, *p2;
|
||||
long c;
|
||||
|
||||
enable_mte(PR_MTE_TCF_NONE);
|
||||
p0 = alloc_mte_mem(sizeof(*p0));
|
||||
|
||||
asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(1));
|
||||
assert(p1 != p0);
|
||||
asm("subp %0,%1,%2" : "=r"(c) : "r"(p0), "r"(p1));
|
||||
assert(c == 0);
|
||||
|
||||
asm("stg %0, [%0]" : : "r"(p1));
|
||||
asm("ldg %0, [%1]" : "=r"(p2) : "r"(p0), "0"(p0));
|
||||
assert(p1 == p2);
|
||||
|
||||
return 0;
|
||||
}
|
45
tests/tcg/aarch64/mte-2.c
Normal file
45
tests/tcg/aarch64/mte-2.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Memory tagging, basic fail cases, synchronous signals.
|
||||
*
|
||||
* Copyright (c) 2021 Linaro Ltd
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "mte.h"
|
||||
|
||||
void pass(int sig, siginfo_t *info, void *uc)
|
||||
{
|
||||
assert(info->si_code == SEGV_MTESERR);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
struct sigaction sa;
|
||||
int *p0, *p1, *p2;
|
||||
long excl = 1;
|
||||
|
||||
enable_mte(PR_MTE_TCF_SYNC);
|
||||
p0 = alloc_mte_mem(sizeof(*p0));
|
||||
|
||||
/* Create two differently tagged pointers. */
|
||||
asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl));
|
||||
asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1));
|
||||
assert(excl != 1);
|
||||
asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl));
|
||||
assert(p1 != p2);
|
||||
|
||||
/* Store the tag from the first pointer. */
|
||||
asm("stg %0, [%0]" : : "r"(p1));
|
||||
|
||||
*p1 = 0;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = pass;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
|
||||
*p2 = 0;
|
||||
|
||||
abort();
|
||||
}
|
51
tests/tcg/aarch64/mte-3.c
Normal file
51
tests/tcg/aarch64/mte-3.c
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Memory tagging, basic fail cases, asynchronous signals.
|
||||
*
|
||||
* Copyright (c) 2021 Linaro Ltd
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "mte.h"
|
||||
|
||||
void pass(int sig, siginfo_t *info, void *uc)
|
||||
{
|
||||
assert(info->si_code == SEGV_MTEAERR);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
struct sigaction sa;
|
||||
long *p0, *p1, *p2;
|
||||
long excl = 1;
|
||||
|
||||
enable_mte(PR_MTE_TCF_ASYNC);
|
||||
p0 = alloc_mte_mem(sizeof(*p0));
|
||||
|
||||
/* Create two differently tagged pointers. */
|
||||
asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl));
|
||||
asm("gmi %0,%1,%0" : "+r"(excl) : "r" (p1));
|
||||
assert(excl != 1);
|
||||
asm("irg %0,%1,%2" : "=r"(p2) : "r"(p0), "r"(excl));
|
||||
assert(p1 != p2);
|
||||
|
||||
/* Store the tag from the first pointer. */
|
||||
asm("stg %0, [%0]" : : "r"(p1));
|
||||
|
||||
*p1 = 0;
|
||||
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_sigaction = pass;
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
|
||||
/*
|
||||
* Signal for async error will happen eventually.
|
||||
* For a real kernel this should be after the next IRQ (e.g. timer).
|
||||
* For qemu linux-user, we kick the cpu and exit at the next TB.
|
||||
* In either case, loop until this happens (or killed by timeout).
|
||||
* For extra sauce, yield, producing EXCP_YIELD to cpu_loop().
|
||||
*/
|
||||
asm("str %0, [%0]; yield" : : "r"(p2));
|
||||
while (1);
|
||||
}
|
45
tests/tcg/aarch64/mte-4.c
Normal file
45
tests/tcg/aarch64/mte-4.c
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Memory tagging, re-reading tag checks.
|
||||
*
|
||||
* Copyright (c) 2021 Linaro Ltd
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "mte.h"
|
||||
|
||||
void __attribute__((noinline)) tagset(void *p, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < size; i += 16) {
|
||||
asm("stg %0, [%0]" : : "r"(p + i));
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__((noinline)) tagcheck(void *p, size_t size)
|
||||
{
|
||||
size_t i;
|
||||
void *c;
|
||||
|
||||
for (i = 0; i < size; i += 16) {
|
||||
asm("ldg %0, [%1]" : "=r"(c) : "r"(p + i), "0"(p));
|
||||
assert(c == p);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
size_t size = getpagesize() * 4;
|
||||
long excl = 1;
|
||||
int *p0, *p1;
|
||||
|
||||
enable_mte(PR_MTE_TCF_ASYNC);
|
||||
p0 = alloc_mte_mem(size);
|
||||
|
||||
/* Tag the pointer. */
|
||||
asm("irg %0,%1,%2" : "=r"(p1) : "r"(p0), "r"(excl));
|
||||
|
||||
tagset(p1, size);
|
||||
tagcheck(p1, size);
|
||||
|
||||
return 0;
|
||||
}
|
60
tests/tcg/aarch64/mte.h
Normal file
60
tests/tcg/aarch64/mte.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Linux kernel fallback API definitions for MTE and test helpers.
|
||||
*
|
||||
* Copyright (c) 2021 Linaro Ltd
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
|
||||
#ifndef PR_SET_TAGGED_ADDR_CTRL
|
||||
# define PR_SET_TAGGED_ADDR_CTRL 55
|
||||
#endif
|
||||
#ifndef PR_TAGGED_ADDR_ENABLE
|
||||
# define PR_TAGGED_ADDR_ENABLE (1UL << 0)
|
||||
#endif
|
||||
#ifndef PR_MTE_TCF_SHIFT
|
||||
# define PR_MTE_TCF_SHIFT 1
|
||||
# define PR_MTE_TCF_NONE (0UL << PR_MTE_TCF_SHIFT)
|
||||
# define PR_MTE_TCF_SYNC (1UL << PR_MTE_TCF_SHIFT)
|
||||
# define PR_MTE_TCF_ASYNC (2UL << PR_MTE_TCF_SHIFT)
|
||||
# define PR_MTE_TAG_SHIFT 3
|
||||
#endif
|
||||
|
||||
#ifndef PROT_MTE
|
||||
# define PROT_MTE 0x20
|
||||
#endif
|
||||
|
||||
#ifndef SEGV_MTEAERR
|
||||
# define SEGV_MTEAERR 8
|
||||
# define SEGV_MTESERR 9
|
||||
#endif
|
||||
|
||||
static void enable_mte(int tcf)
|
||||
{
|
||||
int r = prctl(PR_SET_TAGGED_ADDR_CTRL,
|
||||
PR_TAGGED_ADDR_ENABLE | tcf | (0xfffe << PR_MTE_TAG_SHIFT),
|
||||
0, 0, 0);
|
||||
if (r < 0) {
|
||||
perror("PR_SET_TAGGED_ADDR_CTRL");
|
||||
exit(2);
|
||||
}
|
||||
}
|
||||
|
||||
static void *alloc_mte_mem(size_t size)
|
||||
{
|
||||
void *p = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_MTE,
|
||||
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
if (p == MAP_FAILED) {
|
||||
perror("mmap PROT_MTE");
|
||||
exit(2);
|
||||
}
|
||||
return p;
|
||||
}
|
@ -244,6 +244,10 @@ for target in $target_list; do
|
||||
-mbranch-protection=standard -o $TMPE $TMPC; then
|
||||
echo "CROSS_CC_HAS_ARMV8_BTI=y" >> $config_target_mak
|
||||
fi
|
||||
if do_compiler "$target_compiler" $target_compiler_cflags \
|
||||
-march=armv8.5-a+memtag -o $TMPE $TMPC; then
|
||||
echo "CROSS_CC_HAS_ARMV8_MTE=y" >> $config_target_mak
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user