1*340ca46bSGustavo Romero /* 2*340ca46bSGustavo Romero * To be compiled with -march=armv8.5-a+memtag 3*340ca46bSGustavo Romero * 4*340ca46bSGustavo Romero * This test is adapted from a Linux test. Please see: 5*340ca46bSGustavo Romero * 6*340ca46bSGustavo Romero * https://www.kernel.org/doc/html/next/arch/arm64/memory-tagging-extension.html#example-of-correct-usage 7*340ca46bSGustavo Romero */ 8*340ca46bSGustavo Romero #include <errno.h> 9*340ca46bSGustavo Romero #include <stdint.h> 10*340ca46bSGustavo Romero #include <stdio.h> 11*340ca46bSGustavo Romero #include <stdlib.h> 12*340ca46bSGustavo Romero #include <unistd.h> 13*340ca46bSGustavo Romero #include <sys/auxv.h> 14*340ca46bSGustavo Romero #include <sys/mman.h> 15*340ca46bSGustavo Romero #include <sys/prctl.h> 16*340ca46bSGustavo Romero #include <string.h> 17*340ca46bSGustavo Romero /* 18*340ca46bSGustavo Romero * From arch/arm64/include/uapi/asm/hwcap.h 19*340ca46bSGustavo Romero */ 20*340ca46bSGustavo Romero #define HWCAP2_MTE (1 << 18) 21*340ca46bSGustavo Romero 22*340ca46bSGustavo Romero /* 23*340ca46bSGustavo Romero * From arch/arm64/include/uapi/asm/mman.h 24*340ca46bSGustavo Romero */ 25*340ca46bSGustavo Romero #define PROT_MTE 0x20 26*340ca46bSGustavo Romero 27*340ca46bSGustavo Romero /* 28*340ca46bSGustavo Romero * Insert a random logical tag into the given pointer. 29*340ca46bSGustavo Romero */ 30*340ca46bSGustavo Romero #define insert_random_tag(ptr) ({ \ 31*340ca46bSGustavo Romero uint64_t __val; \ 32*340ca46bSGustavo Romero asm("irg %0, %1" : "=r" (__val) : "r" (ptr)); \ 33*340ca46bSGustavo Romero __val; \ 34*340ca46bSGustavo Romero }) 35*340ca46bSGustavo Romero 36*340ca46bSGustavo Romero /* 37*340ca46bSGustavo Romero * Set the allocation tag on the destination address. 38*340ca46bSGustavo Romero */ 39*340ca46bSGustavo Romero #define set_tag(tagged_addr) do { \ 40*340ca46bSGustavo Romero asm volatile("stg %0, [%0]" : : "r" (tagged_addr) : "memory"); \ 41*340ca46bSGustavo Romero } while (0) 42*340ca46bSGustavo Romero 43*340ca46bSGustavo Romero 44*340ca46bSGustavo Romero int main(int argc, char *argv[]) 45*340ca46bSGustavo Romero { 46*340ca46bSGustavo Romero unsigned char *a; 47*340ca46bSGustavo Romero unsigned long page_sz = sysconf(_SC_PAGESIZE); 48*340ca46bSGustavo Romero unsigned long hwcap2 = getauxval(AT_HWCAP2); 49*340ca46bSGustavo Romero 50*340ca46bSGustavo Romero /* check if MTE is present */ 51*340ca46bSGustavo Romero if (!(hwcap2 & HWCAP2_MTE)) { 52*340ca46bSGustavo Romero return EXIT_FAILURE; 53*340ca46bSGustavo Romero } 54*340ca46bSGustavo Romero 55*340ca46bSGustavo Romero /* 56*340ca46bSGustavo Romero * Enable the tagged address ABI, synchronous or asynchronous MTE 57*340ca46bSGustavo Romero * tag check faults (based on per-CPU preference) and allow all 58*340ca46bSGustavo Romero * non-zero tags in the randomly generated set. 59*340ca46bSGustavo Romero */ 60*340ca46bSGustavo Romero if (prctl(PR_SET_TAGGED_ADDR_CTRL, 61*340ca46bSGustavo Romero PR_TAGGED_ADDR_ENABLE | PR_MTE_TCF_SYNC | PR_MTE_TCF_ASYNC | 62*340ca46bSGustavo Romero (0xfffe << PR_MTE_TAG_SHIFT), 63*340ca46bSGustavo Romero 0, 0, 0)) { 64*340ca46bSGustavo Romero perror("prctl() failed"); 65*340ca46bSGustavo Romero return EXIT_FAILURE; 66*340ca46bSGustavo Romero } 67*340ca46bSGustavo Romero 68*340ca46bSGustavo Romero a = mmap(0, page_sz, PROT_READ | PROT_WRITE, 69*340ca46bSGustavo Romero MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 70*340ca46bSGustavo Romero if (a == MAP_FAILED) { 71*340ca46bSGustavo Romero perror("mmap() failed"); 72*340ca46bSGustavo Romero return EXIT_FAILURE; 73*340ca46bSGustavo Romero } 74*340ca46bSGustavo Romero 75*340ca46bSGustavo Romero printf("a[] address is %p\n", a); 76*340ca46bSGustavo Romero 77*340ca46bSGustavo Romero /* 78*340ca46bSGustavo Romero * Enable MTE on the above anonymous mmap. The flag could be passed 79*340ca46bSGustavo Romero * directly to mmap() and skip this step. 80*340ca46bSGustavo Romero */ 81*340ca46bSGustavo Romero if (mprotect(a, page_sz, PROT_READ | PROT_WRITE | PROT_MTE)) { 82*340ca46bSGustavo Romero perror("mprotect() failed"); 83*340ca46bSGustavo Romero return EXIT_FAILURE; 84*340ca46bSGustavo Romero } 85*340ca46bSGustavo Romero 86*340ca46bSGustavo Romero /* access with the default tag (0) */ 87*340ca46bSGustavo Romero a[0] = 1; 88*340ca46bSGustavo Romero a[1] = 2; 89*340ca46bSGustavo Romero 90*340ca46bSGustavo Romero printf("a[0] = %hhu a[1] = %hhu\n", a[0], a[1]); 91*340ca46bSGustavo Romero 92*340ca46bSGustavo Romero /* set the logical and allocation tags */ 93*340ca46bSGustavo Romero a = (unsigned char *)insert_random_tag(a); 94*340ca46bSGustavo Romero set_tag(a); 95*340ca46bSGustavo Romero 96*340ca46bSGustavo Romero printf("%p\n", a); 97*340ca46bSGustavo Romero 98*340ca46bSGustavo Romero return 0; 99*340ca46bSGustavo Romero } 100