340ca46b68
Add tests to exercise the MTE stubs. The tests will only run if a version of GDB that supports MTE is available in the test environment. Signed-off-by: Gustavo Romero <gustavo.romero@linaro.org> [AJB: re-base and checkpatch fixes] Message-Id: <20240628050850.536447-12-gustavo.romero@linaro.org> Signed-off-by: Alex Bennée <alex.bennee@linaro.org> Message-Id: <20240705084047.857176-41-alex.bennee@linaro.org>
100 lines
2.5 KiB
C
100 lines
2.5 KiB
C
/*
|
|
* To be compiled with -march=armv8.5-a+memtag
|
|
*
|
|
* This test is adapted from a Linux test. Please see:
|
|
*
|
|
* https://www.kernel.org/doc/html/next/arch/arm64/memory-tagging-extension.html#example-of-correct-usage
|
|
*/
|
|
#include <errno.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/auxv.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/prctl.h>
|
|
#include <string.h>
|
|
/*
|
|
* From arch/arm64/include/uapi/asm/hwcap.h
|
|
*/
|
|
#define HWCAP2_MTE (1 << 18)
|
|
|
|
/*
|
|
* From arch/arm64/include/uapi/asm/mman.h
|
|
*/
|
|
#define PROT_MTE 0x20
|
|
|
|
/*
|
|
* Insert a random logical tag into the given pointer.
|
|
*/
|
|
#define insert_random_tag(ptr) ({ \
|
|
uint64_t __val; \
|
|
asm("irg %0, %1" : "=r" (__val) : "r" (ptr)); \
|
|
__val; \
|
|
})
|
|
|
|
/*
|
|
* Set the allocation tag on the destination address.
|
|
*/
|
|
#define set_tag(tagged_addr) do { \
|
|
asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \
|
|
} while (0)
|
|
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
unsigned char *a;
|
|
unsigned long page_sz = sysconf(_SC_PAGESIZE);
|
|
unsigned long hwcap2 = getauxval(AT_HWCAP2);
|
|
|
|
/* check if MTE is present */
|
|
if (!(hwcap2 & HWCAP2_MTE)) {
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/*
|
|
* Enable the tagged address ABI, synchronous or asynchronous MTE
|
|
* tag check faults (based on per-CPU preference) and allow all
|
|
* non-zero tags in the randomly generated set.
|
|
*/
|
|
if (prctl(PR_SET_TAGGED_ADDR_CTRL,
|
|
PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC |
|
|
(0xfffe << PR_MTE_TAG_SHIFT),
|
|
0, 0, 0)) {
|
|
perror("prctl() failed");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
a = mmap(0, page_sz, PROT_READ | PROT_WRITE,
|
|
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
if (a == MAP_FAILED) {
|
|
perror("mmap() failed");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
printf("a[] address is %p\n", a);
|
|
|
|
/*
|
|
* Enable MTE on the above anonymous mmap. The flag could be passed
|
|
* directly to mmap() and skip this step.
|
|
*/
|
|
if (mprotect(a, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) {
|
|
perror("mprotect() failed");
|
|
return EXIT_FAILURE;
|
|
}
|
|
|
|
/* access with the default tag (0) */
|
|
a[0] = 1;
|
|
a[1] = 2;
|
|
|
|
printf("a[0] = %hhu a[1] = %hhu\n", a[0], a[1]);
|
|
|
|
/* set the logical and allocation tags */
|
|
a = (unsigned char *)insert_random_tag(a);
|
|
set_tag(a);
|
|
|
|
printf("%p\n", a);
|
|
|
|
return 0;
|
|
}
|