i'm using the branch at https://github.com/rth7680/qemu/tree/tgt-arm-mte
to test armv8.5-a mte and hope this is ok to report bugs here. i'm doing tests in qemu-system-aarch64 with linux userspace code and it seems TCO bit gets cleared after syscalls or other kernel entry, but PSTATE is expected to be restored, so i suspect it is a qemu bug. i think the architecture saves/restores PSTATE using SPSR_ELx on exceptions. i used the linux branch https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/log/?h=devel/mte-v2 attached a reproducer that segfaults in qemu but should work. thanks.
// CFLAGS = -march=armv8.5-a+memtag #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/mman.h> #include <sys/prctl.h> #define TAG_SHIFT 56 #ifndef PROT_MTE #define PROT_MTE 0x20 #endif #ifndef PR_SET_TAGGED_ADDR_CTRL #define PR_SET_TAGGED_ADDR_CTRL 55 #define PR_GET_TAGGED_ADDR_CTRL 56 #define PR_TAGGED_ADDR_ENABLE 1UL #endif #ifndef PR_MTE_TCF_SYNC #define PR_MTE_TCF_SYNC 2UL #define PR_MTE_TAG_SHIFT 3 #endif int main() { if (prctl(PR_SET_TAGGED_ADDR_CTRL, PR_TAGGED_ADDR_ENABLE|PR_MTE_TCF_SYNC|(0xffff << PR_MTE_TAG_SHIFT), 0, 0, 0)) abort(); unsigned long *a = mmap(0, 1<<12, PROT_READ|PROT_WRITE|PROT_MTE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); if (a == MAP_FAILED) abort(); // tag ptr a a = (void*)((unsigned long)a|(1UL<<TAG_SHIFT)); // tag memory a[0], a[1] asm volatile ("stg %1, %0" : "=Q"(*a) : "r"(a)); // turn tag checks off asm volatile ("msr tco, 1"); a[0]=1; // ok a[1]=2; // ok a[2]=3; // tag mismatch but tco==1 so ok write(1, "foo\n", 4); // PSTATE.TCO (bit 25) should be still set after the syscall unsigned long x; asm volatile ("mrs %0, tco" : "=r"(x)); printf("tco = 0x%lx\n", x); a[3]=4; // tag mismatch, segfaults if tco==0 return 0; }