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;
}

Reply via email to