xref: /openbmc/linux/tools/testing/selftests/x86/lam.c (revision b13513e7)
13de9745cSWeihong Zhang // SPDX-License-Identifier: GPL-2.0
2dfd7a156SKirill A. Shutemov #define _GNU_SOURCE
33de9745cSWeihong Zhang #include <stdio.h>
43de9745cSWeihong Zhang #include <stdlib.h>
53de9745cSWeihong Zhang #include <string.h>
63de9745cSWeihong Zhang #include <sys/syscall.h>
73de9745cSWeihong Zhang #include <time.h>
83de9745cSWeihong Zhang #include <signal.h>
93de9745cSWeihong Zhang #include <setjmp.h>
103de9745cSWeihong Zhang #include <sys/mman.h>
11e6787696SWeihong Zhang #include <sys/utsname.h>
123de9745cSWeihong Zhang #include <sys/wait.h>
1372fd6d73SWeihong Zhang #include <sys/stat.h>
1472fd6d73SWeihong Zhang #include <fcntl.h>
153de9745cSWeihong Zhang #include <inttypes.h>
16dfd7a156SKirill A. Shutemov #include <sched.h>
173de9745cSWeihong Zhang 
1872fd6d73SWeihong Zhang #include <sys/uio.h>
1972fd6d73SWeihong Zhang #include <linux/io_uring.h>
203de9745cSWeihong Zhang #include "../kselftest.h"
213de9745cSWeihong Zhang 
223de9745cSWeihong Zhang #ifndef __x86_64__
233de9745cSWeihong Zhang # error This test is 64-bit only
243de9745cSWeihong Zhang #endif
253de9745cSWeihong Zhang 
263de9745cSWeihong Zhang /* LAM modes, these definitions were copied from kernel code */
273de9745cSWeihong Zhang #define LAM_NONE                0
283de9745cSWeihong Zhang #define LAM_U57_BITS            6
293de9745cSWeihong Zhang 
303de9745cSWeihong Zhang #define LAM_U57_MASK            (0x3fULL << 57)
313de9745cSWeihong Zhang /* arch prctl for LAM */
323de9745cSWeihong Zhang #define ARCH_GET_UNTAG_MASK     0x4001
333de9745cSWeihong Zhang #define ARCH_ENABLE_TAGGED_ADDR 0x4002
343de9745cSWeihong Zhang #define ARCH_GET_MAX_TAG_BITS   0x4003
3534821473SWeihong Zhang #define ARCH_FORCE_TAGGED_SVA	0x4004
363de9745cSWeihong Zhang 
373de9745cSWeihong Zhang /* Specified test function bits */
383de9745cSWeihong Zhang #define FUNC_MALLOC             0x1
393de9745cSWeihong Zhang #define FUNC_BITS               0x2
40e6787696SWeihong Zhang #define FUNC_MMAP               0x4
41e6787696SWeihong Zhang #define FUNC_SYSCALL            0x8
4272fd6d73SWeihong Zhang #define FUNC_URING              0x10
43833c12ceSWeihong Zhang #define FUNC_INHERITE           0x20
4434821473SWeihong Zhang #define FUNC_PASID              0x40
453de9745cSWeihong Zhang 
4634821473SWeihong Zhang #define TEST_MASK               0x7f
47e6787696SWeihong Zhang 
48e6787696SWeihong Zhang #define LOW_ADDR                (0x1UL << 30)
49e6787696SWeihong Zhang #define HIGH_ADDR               (0x3UL << 48)
503de9745cSWeihong Zhang 
513de9745cSWeihong Zhang #define MALLOC_LEN              32
523de9745cSWeihong Zhang 
53e6787696SWeihong Zhang #define PAGE_SIZE               (4 << 10)
54e6787696SWeihong Zhang 
55dfd7a156SKirill A. Shutemov #define STACK_SIZE		65536
56dfd7a156SKirill A. Shutemov 
5772fd6d73SWeihong Zhang #define barrier() ({						\
5872fd6d73SWeihong Zhang 		   __asm__ __volatile__("" : : : "memory");	\
5972fd6d73SWeihong Zhang })
6072fd6d73SWeihong Zhang 
6172fd6d73SWeihong Zhang #define URING_QUEUE_SZ 1
6272fd6d73SWeihong Zhang #define URING_BLOCK_SZ 2048
6372fd6d73SWeihong Zhang 
6434821473SWeihong Zhang /* Pasid test define */
6534821473SWeihong Zhang #define LAM_CMD_BIT 0x1
6634821473SWeihong Zhang #define PAS_CMD_BIT 0x2
6734821473SWeihong Zhang #define SVA_CMD_BIT 0x4
6834821473SWeihong Zhang 
6934821473SWeihong Zhang #define PAS_CMD(cmd1, cmd2, cmd3) (((cmd3) << 8) | ((cmd2) << 4) | ((cmd1) << 0))
7034821473SWeihong Zhang 
713de9745cSWeihong Zhang struct testcases {
723de9745cSWeihong Zhang 	unsigned int later;
733de9745cSWeihong Zhang 	int expected; /* 2: SIGSEGV Error; 1: other errors */
743de9745cSWeihong Zhang 	unsigned long lam;
753de9745cSWeihong Zhang 	uint64_t addr;
7634821473SWeihong Zhang 	uint64_t cmd;
773de9745cSWeihong Zhang 	int (*test_func)(struct testcases *test);
783de9745cSWeihong Zhang 	const char *msg;
793de9745cSWeihong Zhang };
803de9745cSWeihong Zhang 
8172fd6d73SWeihong Zhang /* Used by CQ of uring, source file handler and file's size */
8272fd6d73SWeihong Zhang struct file_io {
8372fd6d73SWeihong Zhang 	int file_fd;
8472fd6d73SWeihong Zhang 	off_t file_sz;
8572fd6d73SWeihong Zhang 	struct iovec iovecs[];
8672fd6d73SWeihong Zhang };
8772fd6d73SWeihong Zhang 
8872fd6d73SWeihong Zhang struct io_uring_queue {
8972fd6d73SWeihong Zhang 	unsigned int *head;
9072fd6d73SWeihong Zhang 	unsigned int *tail;
9172fd6d73SWeihong Zhang 	unsigned int *ring_mask;
9272fd6d73SWeihong Zhang 	unsigned int *ring_entries;
9372fd6d73SWeihong Zhang 	unsigned int *flags;
9472fd6d73SWeihong Zhang 	unsigned int *array;
9572fd6d73SWeihong Zhang 	union {
9672fd6d73SWeihong Zhang 		struct io_uring_cqe *cqes;
9772fd6d73SWeihong Zhang 		struct io_uring_sqe *sqes;
9872fd6d73SWeihong Zhang 	} queue;
9972fd6d73SWeihong Zhang 	size_t ring_sz;
10072fd6d73SWeihong Zhang };
10172fd6d73SWeihong Zhang 
10272fd6d73SWeihong Zhang struct io_ring {
10372fd6d73SWeihong Zhang 	int ring_fd;
10472fd6d73SWeihong Zhang 	struct io_uring_queue sq_ring;
10572fd6d73SWeihong Zhang 	struct io_uring_queue cq_ring;
10672fd6d73SWeihong Zhang };
10772fd6d73SWeihong Zhang 
1083de9745cSWeihong Zhang int tests_cnt;
1093de9745cSWeihong Zhang jmp_buf segv_env;
1103de9745cSWeihong Zhang 
segv_handler(int sig)1113de9745cSWeihong Zhang static void segv_handler(int sig)
1123de9745cSWeihong Zhang {
1133de9745cSWeihong Zhang 	ksft_print_msg("Get segmentation fault(%d).", sig);
114e6787696SWeihong Zhang 
1153de9745cSWeihong Zhang 	siglongjmp(segv_env, 1);
1163de9745cSWeihong Zhang }
1173de9745cSWeihong Zhang 
cpu_has_lam(void)1183de9745cSWeihong Zhang static inline int cpu_has_lam(void)
1193de9745cSWeihong Zhang {
1203de9745cSWeihong Zhang 	unsigned int cpuinfo[4];
1213de9745cSWeihong Zhang 
1223de9745cSWeihong Zhang 	__cpuid_count(0x7, 1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
1233de9745cSWeihong Zhang 
1243de9745cSWeihong Zhang 	return (cpuinfo[0] & (1 << 26));
1253de9745cSWeihong Zhang }
1263de9745cSWeihong Zhang 
127e6787696SWeihong Zhang /* Check 5-level page table feature in CPUID.(EAX=07H, ECX=00H):ECX.[bit 16] */
cpu_has_la57(void)128e6787696SWeihong Zhang static inline int cpu_has_la57(void)
129e6787696SWeihong Zhang {
130e6787696SWeihong Zhang 	unsigned int cpuinfo[4];
131e6787696SWeihong Zhang 
132e6787696SWeihong Zhang 	__cpuid_count(0x7, 0, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
133e6787696SWeihong Zhang 
134e6787696SWeihong Zhang 	return (cpuinfo[2] & (1 << 16));
135e6787696SWeihong Zhang }
136e6787696SWeihong Zhang 
1373de9745cSWeihong Zhang /*
1383de9745cSWeihong Zhang  * Set tagged address and read back untag mask.
1393de9745cSWeihong Zhang  * check if the untagged mask is expected.
1403de9745cSWeihong Zhang  *
1413de9745cSWeihong Zhang  * @return:
1423de9745cSWeihong Zhang  * 0: Set LAM mode successfully
1433de9745cSWeihong Zhang  * others: failed to set LAM
1443de9745cSWeihong Zhang  */
set_lam(unsigned long lam)1453de9745cSWeihong Zhang static int set_lam(unsigned long lam)
1463de9745cSWeihong Zhang {
1473de9745cSWeihong Zhang 	int ret = 0;
1483de9745cSWeihong Zhang 	uint64_t ptr = 0;
1493de9745cSWeihong Zhang 
1503de9745cSWeihong Zhang 	if (lam != LAM_U57_BITS && lam != LAM_NONE)
1513de9745cSWeihong Zhang 		return -1;
1523de9745cSWeihong Zhang 
1533de9745cSWeihong Zhang 	/* Skip check return */
1543de9745cSWeihong Zhang 	syscall(SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, lam);
1553de9745cSWeihong Zhang 
1563de9745cSWeihong Zhang 	/* Get untagged mask */
1573de9745cSWeihong Zhang 	syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr);
1583de9745cSWeihong Zhang 
1593de9745cSWeihong Zhang 	/* Check mask returned is expected */
1603de9745cSWeihong Zhang 	if (lam == LAM_U57_BITS)
1613de9745cSWeihong Zhang 		ret = (ptr != ~(LAM_U57_MASK));
1623de9745cSWeihong Zhang 	else if (lam == LAM_NONE)
1633de9745cSWeihong Zhang 		ret = (ptr != -1ULL);
1643de9745cSWeihong Zhang 
1653de9745cSWeihong Zhang 	return ret;
1663de9745cSWeihong Zhang }
1673de9745cSWeihong Zhang 
get_default_tag_bits(void)1683de9745cSWeihong Zhang static unsigned long get_default_tag_bits(void)
1693de9745cSWeihong Zhang {
1703de9745cSWeihong Zhang 	pid_t pid;
1713de9745cSWeihong Zhang 	int lam = LAM_NONE;
1723de9745cSWeihong Zhang 	int ret = 0;
1733de9745cSWeihong Zhang 
1743de9745cSWeihong Zhang 	pid = fork();
1753de9745cSWeihong Zhang 	if (pid < 0) {
1763de9745cSWeihong Zhang 		perror("Fork failed.");
1773de9745cSWeihong Zhang 	} else if (pid == 0) {
1783de9745cSWeihong Zhang 		/* Set LAM mode in child process */
1793de9745cSWeihong Zhang 		if (set_lam(LAM_U57_BITS) == 0)
1803de9745cSWeihong Zhang 			lam = LAM_U57_BITS;
1813de9745cSWeihong Zhang 		else
1823de9745cSWeihong Zhang 			lam = LAM_NONE;
1833de9745cSWeihong Zhang 		exit(lam);
1843de9745cSWeihong Zhang 	} else {
1853de9745cSWeihong Zhang 		wait(&ret);
1863de9745cSWeihong Zhang 		lam = WEXITSTATUS(ret);
1873de9745cSWeihong Zhang 	}
1883de9745cSWeihong Zhang 
1893de9745cSWeihong Zhang 	return lam;
1903de9745cSWeihong Zhang }
1913de9745cSWeihong Zhang 
192833c12ceSWeihong Zhang /*
193833c12ceSWeihong Zhang  * Set tagged address and read back untag mask.
194833c12ceSWeihong Zhang  * check if the untag mask is expected.
195833c12ceSWeihong Zhang  */
get_lam(void)196833c12ceSWeihong Zhang static int get_lam(void)
197833c12ceSWeihong Zhang {
198833c12ceSWeihong Zhang 	uint64_t ptr = 0;
199833c12ceSWeihong Zhang 	int ret = -1;
200833c12ceSWeihong Zhang 	/* Get untagged mask */
201833c12ceSWeihong Zhang 	if (syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr) == -1)
202833c12ceSWeihong Zhang 		return -1;
203833c12ceSWeihong Zhang 
204833c12ceSWeihong Zhang 	/* Check mask returned is expected */
205833c12ceSWeihong Zhang 	if (ptr == ~(LAM_U57_MASK))
206833c12ceSWeihong Zhang 		ret = LAM_U57_BITS;
207833c12ceSWeihong Zhang 	else if (ptr == -1ULL)
208833c12ceSWeihong Zhang 		ret = LAM_NONE;
209833c12ceSWeihong Zhang 
210833c12ceSWeihong Zhang 
211833c12ceSWeihong Zhang 	return ret;
212833c12ceSWeihong Zhang }
213833c12ceSWeihong Zhang 
2143de9745cSWeihong Zhang /* According to LAM mode, set metadata in high bits */
set_metadata(uint64_t src,unsigned long lam)2153de9745cSWeihong Zhang static uint64_t set_metadata(uint64_t src, unsigned long lam)
2163de9745cSWeihong Zhang {
2173de9745cSWeihong Zhang 	uint64_t metadata;
2183de9745cSWeihong Zhang 
2193de9745cSWeihong Zhang 	srand(time(NULL));
2203de9745cSWeihong Zhang 
2213de9745cSWeihong Zhang 	switch (lam) {
2223de9745cSWeihong Zhang 	case LAM_U57_BITS: /* Set metadata in bits 62:57 */
2233de9745cSWeihong Zhang 		/* Get a random non-zero value as metadata */
2243de9745cSWeihong Zhang 		metadata = (rand() % ((1UL << LAM_U57_BITS) - 1) + 1) << 57;
2253de9745cSWeihong Zhang 		metadata |= (src & ~(LAM_U57_MASK));
2263de9745cSWeihong Zhang 		break;
2273de9745cSWeihong Zhang 	default:
2283de9745cSWeihong Zhang 		metadata = src;
2293de9745cSWeihong Zhang 		break;
2303de9745cSWeihong Zhang 	}
2313de9745cSWeihong Zhang 
2323de9745cSWeihong Zhang 	return metadata;
2333de9745cSWeihong Zhang }
2343de9745cSWeihong Zhang 
2353de9745cSWeihong Zhang /*
2363de9745cSWeihong Zhang  * Set metadata in user pointer, compare new pointer with original pointer.
2373de9745cSWeihong Zhang  * both pointers should point to the same address.
2383de9745cSWeihong Zhang  *
2393de9745cSWeihong Zhang  * @return:
2403de9745cSWeihong Zhang  * 0: value on the pointer with metadate and value on original are same
2413de9745cSWeihong Zhang  * 1: not same.
2423de9745cSWeihong Zhang  */
handle_lam_test(void * src,unsigned int lam)2433de9745cSWeihong Zhang static int handle_lam_test(void *src, unsigned int lam)
2443de9745cSWeihong Zhang {
2453de9745cSWeihong Zhang 	char *ptr;
2463de9745cSWeihong Zhang 
2473de9745cSWeihong Zhang 	strcpy((char *)src, "USER POINTER");
2483de9745cSWeihong Zhang 
2493de9745cSWeihong Zhang 	ptr = (char *)set_metadata((uint64_t)src, lam);
2503de9745cSWeihong Zhang 	if (src == ptr)
2513de9745cSWeihong Zhang 		return 0;
2523de9745cSWeihong Zhang 
2533de9745cSWeihong Zhang 	/* Copy a string into the pointer with metadata */
2543de9745cSWeihong Zhang 	strcpy((char *)ptr, "METADATA POINTER");
2553de9745cSWeihong Zhang 
2563de9745cSWeihong Zhang 	return (!!strcmp((char *)src, (char *)ptr));
2573de9745cSWeihong Zhang }
2583de9745cSWeihong Zhang 
2593de9745cSWeihong Zhang 
handle_max_bits(struct testcases * test)2603de9745cSWeihong Zhang int handle_max_bits(struct testcases *test)
2613de9745cSWeihong Zhang {
2623de9745cSWeihong Zhang 	unsigned long exp_bits = get_default_tag_bits();
2633de9745cSWeihong Zhang 	unsigned long bits = 0;
2643de9745cSWeihong Zhang 
2653de9745cSWeihong Zhang 	if (exp_bits != LAM_NONE)
2663de9745cSWeihong Zhang 		exp_bits = LAM_U57_BITS;
2673de9745cSWeihong Zhang 
2683de9745cSWeihong Zhang 	/* Get LAM max tag bits */
2693de9745cSWeihong Zhang 	if (syscall(SYS_arch_prctl, ARCH_GET_MAX_TAG_BITS, &bits) == -1)
2703de9745cSWeihong Zhang 		return 1;
2713de9745cSWeihong Zhang 
2723de9745cSWeihong Zhang 	return (exp_bits != bits);
2733de9745cSWeihong Zhang }
2743de9745cSWeihong Zhang 
2753de9745cSWeihong Zhang /*
2763de9745cSWeihong Zhang  * Test lam feature through dereference pointer get from malloc.
2773de9745cSWeihong Zhang  * @return 0: Pass test. 1: Get failure during test 2: Get SIGSEGV
2783de9745cSWeihong Zhang  */
handle_malloc(struct testcases * test)2793de9745cSWeihong Zhang static int handle_malloc(struct testcases *test)
2803de9745cSWeihong Zhang {
2813de9745cSWeihong Zhang 	char *ptr = NULL;
2823de9745cSWeihong Zhang 	int ret = 0;
2833de9745cSWeihong Zhang 
2843de9745cSWeihong Zhang 	if (test->later == 0 && test->lam != 0)
2853de9745cSWeihong Zhang 		if (set_lam(test->lam) == -1)
2863de9745cSWeihong Zhang 			return 1;
2873de9745cSWeihong Zhang 
2883de9745cSWeihong Zhang 	ptr = (char *)malloc(MALLOC_LEN);
2893de9745cSWeihong Zhang 	if (ptr == NULL) {
2903de9745cSWeihong Zhang 		perror("malloc() failure\n");
2913de9745cSWeihong Zhang 		return 1;
2923de9745cSWeihong Zhang 	}
2933de9745cSWeihong Zhang 
2943de9745cSWeihong Zhang 	/* Set signal handler */
2953de9745cSWeihong Zhang 	if (sigsetjmp(segv_env, 1) == 0) {
2963de9745cSWeihong Zhang 		signal(SIGSEGV, segv_handler);
2973de9745cSWeihong Zhang 		ret = handle_lam_test(ptr, test->lam);
2983de9745cSWeihong Zhang 	} else {
2993de9745cSWeihong Zhang 		ret = 2;
3003de9745cSWeihong Zhang 	}
3013de9745cSWeihong Zhang 
3023de9745cSWeihong Zhang 	if (test->later != 0 && test->lam != 0)
3033de9745cSWeihong Zhang 		if (set_lam(test->lam) == -1 && ret == 0)
3043de9745cSWeihong Zhang 			ret = 1;
3053de9745cSWeihong Zhang 
3063de9745cSWeihong Zhang 	free(ptr);
3073de9745cSWeihong Zhang 
3083de9745cSWeihong Zhang 	return ret;
3093de9745cSWeihong Zhang }
3103de9745cSWeihong Zhang 
handle_mmap(struct testcases * test)311e6787696SWeihong Zhang static int handle_mmap(struct testcases *test)
312e6787696SWeihong Zhang {
313e6787696SWeihong Zhang 	void *ptr;
314e6787696SWeihong Zhang 	unsigned int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
315e6787696SWeihong Zhang 	int ret = 0;
316e6787696SWeihong Zhang 
317e6787696SWeihong Zhang 	if (test->later == 0 && test->lam != 0)
318e6787696SWeihong Zhang 		if (set_lam(test->lam) != 0)
319e6787696SWeihong Zhang 			return 1;
320e6787696SWeihong Zhang 
321e6787696SWeihong Zhang 	ptr = mmap((void *)test->addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
322e6787696SWeihong Zhang 		   flags, -1, 0);
323e6787696SWeihong Zhang 	if (ptr == MAP_FAILED) {
324e6787696SWeihong Zhang 		if (test->addr == HIGH_ADDR)
325e6787696SWeihong Zhang 			if (!cpu_has_la57())
326e6787696SWeihong Zhang 				return 3; /* unsupport LA57 */
327e6787696SWeihong Zhang 		return 1;
328e6787696SWeihong Zhang 	}
329e6787696SWeihong Zhang 
330e6787696SWeihong Zhang 	if (test->later != 0 && test->lam != 0)
331e6787696SWeihong Zhang 		if (set_lam(test->lam) != 0)
332e6787696SWeihong Zhang 			ret = 1;
333e6787696SWeihong Zhang 
334e6787696SWeihong Zhang 	if (ret == 0) {
335e6787696SWeihong Zhang 		if (sigsetjmp(segv_env, 1) == 0) {
336e6787696SWeihong Zhang 			signal(SIGSEGV, segv_handler);
337e6787696SWeihong Zhang 			ret = handle_lam_test(ptr, test->lam);
338e6787696SWeihong Zhang 		} else {
339e6787696SWeihong Zhang 			ret = 2;
340e6787696SWeihong Zhang 		}
341e6787696SWeihong Zhang 	}
342e6787696SWeihong Zhang 
343e6787696SWeihong Zhang 	munmap(ptr, PAGE_SIZE);
344e6787696SWeihong Zhang 	return ret;
345e6787696SWeihong Zhang }
346e6787696SWeihong Zhang 
handle_syscall(struct testcases * test)347e6787696SWeihong Zhang static int handle_syscall(struct testcases *test)
348e6787696SWeihong Zhang {
349e6787696SWeihong Zhang 	struct utsname unme, *pu;
350e6787696SWeihong Zhang 	int ret = 0;
351e6787696SWeihong Zhang 
352e6787696SWeihong Zhang 	if (test->later == 0 && test->lam != 0)
353e6787696SWeihong Zhang 		if (set_lam(test->lam) != 0)
354e6787696SWeihong Zhang 			return 1;
355e6787696SWeihong Zhang 
356e6787696SWeihong Zhang 	if (sigsetjmp(segv_env, 1) == 0) {
357e6787696SWeihong Zhang 		signal(SIGSEGV, segv_handler);
358e6787696SWeihong Zhang 		pu = (struct utsname *)set_metadata((uint64_t)&unme, test->lam);
359e6787696SWeihong Zhang 		ret = uname(pu);
360e6787696SWeihong Zhang 		if (ret < 0)
361e6787696SWeihong Zhang 			ret = 1;
362e6787696SWeihong Zhang 	} else {
363e6787696SWeihong Zhang 		ret = 2;
364e6787696SWeihong Zhang 	}
365e6787696SWeihong Zhang 
366e6787696SWeihong Zhang 	if (test->later != 0 && test->lam != 0)
367e6787696SWeihong Zhang 		if (set_lam(test->lam) != -1 && ret == 0)
368e6787696SWeihong Zhang 			ret = 1;
369e6787696SWeihong Zhang 
370e6787696SWeihong Zhang 	return ret;
371e6787696SWeihong Zhang }
372e6787696SWeihong Zhang 
sys_uring_setup(unsigned int entries,struct io_uring_params * p)37372fd6d73SWeihong Zhang int sys_uring_setup(unsigned int entries, struct io_uring_params *p)
37472fd6d73SWeihong Zhang {
37572fd6d73SWeihong Zhang 	return (int)syscall(__NR_io_uring_setup, entries, p);
37672fd6d73SWeihong Zhang }
37772fd6d73SWeihong Zhang 
sys_uring_enter(int fd,unsigned int to,unsigned int min,unsigned int flags)37872fd6d73SWeihong Zhang int sys_uring_enter(int fd, unsigned int to, unsigned int min, unsigned int flags)
37972fd6d73SWeihong Zhang {
38072fd6d73SWeihong Zhang 	return (int)syscall(__NR_io_uring_enter, fd, to, min, flags, NULL, 0);
38172fd6d73SWeihong Zhang }
38272fd6d73SWeihong Zhang 
38372fd6d73SWeihong Zhang /* Init submission queue and completion queue */
mmap_io_uring(struct io_uring_params p,struct io_ring * s)38472fd6d73SWeihong Zhang int mmap_io_uring(struct io_uring_params p, struct io_ring *s)
38572fd6d73SWeihong Zhang {
38672fd6d73SWeihong Zhang 	struct io_uring_queue *sring = &s->sq_ring;
38772fd6d73SWeihong Zhang 	struct io_uring_queue *cring = &s->cq_ring;
38872fd6d73SWeihong Zhang 
38972fd6d73SWeihong Zhang 	sring->ring_sz = p.sq_off.array + p.sq_entries * sizeof(unsigned int);
39072fd6d73SWeihong Zhang 	cring->ring_sz = p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe);
39172fd6d73SWeihong Zhang 
39272fd6d73SWeihong Zhang 	if (p.features & IORING_FEAT_SINGLE_MMAP) {
39372fd6d73SWeihong Zhang 		if (cring->ring_sz > sring->ring_sz)
39472fd6d73SWeihong Zhang 			sring->ring_sz = cring->ring_sz;
39572fd6d73SWeihong Zhang 
39672fd6d73SWeihong Zhang 		cring->ring_sz = sring->ring_sz;
39772fd6d73SWeihong Zhang 	}
39872fd6d73SWeihong Zhang 
39972fd6d73SWeihong Zhang 	void *sq_ptr = mmap(0, sring->ring_sz, PROT_READ | PROT_WRITE,
40072fd6d73SWeihong Zhang 			    MAP_SHARED | MAP_POPULATE, s->ring_fd,
40172fd6d73SWeihong Zhang 			    IORING_OFF_SQ_RING);
40272fd6d73SWeihong Zhang 
40372fd6d73SWeihong Zhang 	if (sq_ptr == MAP_FAILED) {
40472fd6d73SWeihong Zhang 		perror("sub-queue!");
40572fd6d73SWeihong Zhang 		return 1;
40672fd6d73SWeihong Zhang 	}
40772fd6d73SWeihong Zhang 
40872fd6d73SWeihong Zhang 	void *cq_ptr = sq_ptr;
40972fd6d73SWeihong Zhang 
41072fd6d73SWeihong Zhang 	if (!(p.features & IORING_FEAT_SINGLE_MMAP)) {
41172fd6d73SWeihong Zhang 		cq_ptr = mmap(0, cring->ring_sz, PROT_READ | PROT_WRITE,
41272fd6d73SWeihong Zhang 			      MAP_SHARED | MAP_POPULATE, s->ring_fd,
41372fd6d73SWeihong Zhang 			      IORING_OFF_CQ_RING);
41472fd6d73SWeihong Zhang 		if (cq_ptr == MAP_FAILED) {
41572fd6d73SWeihong Zhang 			perror("cpl-queue!");
41672fd6d73SWeihong Zhang 			munmap(sq_ptr, sring->ring_sz);
41772fd6d73SWeihong Zhang 			return 1;
41872fd6d73SWeihong Zhang 		}
41972fd6d73SWeihong Zhang 	}
42072fd6d73SWeihong Zhang 
42172fd6d73SWeihong Zhang 	sring->head = sq_ptr + p.sq_off.head;
42272fd6d73SWeihong Zhang 	sring->tail = sq_ptr + p.sq_off.tail;
42372fd6d73SWeihong Zhang 	sring->ring_mask = sq_ptr + p.sq_off.ring_mask;
42472fd6d73SWeihong Zhang 	sring->ring_entries = sq_ptr + p.sq_off.ring_entries;
42572fd6d73SWeihong Zhang 	sring->flags = sq_ptr + p.sq_off.flags;
42672fd6d73SWeihong Zhang 	sring->array = sq_ptr + p.sq_off.array;
42772fd6d73SWeihong Zhang 
42872fd6d73SWeihong Zhang 	/* Map a queue as mem map */
42972fd6d73SWeihong Zhang 	s->sq_ring.queue.sqes = mmap(0, p.sq_entries * sizeof(struct io_uring_sqe),
43072fd6d73SWeihong Zhang 				     PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
43172fd6d73SWeihong Zhang 				     s->ring_fd, IORING_OFF_SQES);
43272fd6d73SWeihong Zhang 	if (s->sq_ring.queue.sqes == MAP_FAILED) {
43372fd6d73SWeihong Zhang 		munmap(sq_ptr, sring->ring_sz);
43472fd6d73SWeihong Zhang 		if (sq_ptr != cq_ptr) {
43572fd6d73SWeihong Zhang 			ksft_print_msg("failed to mmap uring queue!");
43672fd6d73SWeihong Zhang 			munmap(cq_ptr, cring->ring_sz);
43772fd6d73SWeihong Zhang 			return 1;
43872fd6d73SWeihong Zhang 		}
43972fd6d73SWeihong Zhang 	}
44072fd6d73SWeihong Zhang 
44172fd6d73SWeihong Zhang 	cring->head = cq_ptr + p.cq_off.head;
44272fd6d73SWeihong Zhang 	cring->tail = cq_ptr + p.cq_off.tail;
44372fd6d73SWeihong Zhang 	cring->ring_mask = cq_ptr + p.cq_off.ring_mask;
44472fd6d73SWeihong Zhang 	cring->ring_entries = cq_ptr + p.cq_off.ring_entries;
44572fd6d73SWeihong Zhang 	cring->queue.cqes = cq_ptr + p.cq_off.cqes;
44672fd6d73SWeihong Zhang 
44772fd6d73SWeihong Zhang 	return 0;
44872fd6d73SWeihong Zhang }
44972fd6d73SWeihong Zhang 
45072fd6d73SWeihong Zhang /* Init io_uring queues */
setup_io_uring(struct io_ring * s)45172fd6d73SWeihong Zhang int setup_io_uring(struct io_ring *s)
45272fd6d73SWeihong Zhang {
45372fd6d73SWeihong Zhang 	struct io_uring_params para;
45472fd6d73SWeihong Zhang 
45572fd6d73SWeihong Zhang 	memset(&para, 0, sizeof(para));
45672fd6d73SWeihong Zhang 	s->ring_fd = sys_uring_setup(URING_QUEUE_SZ, &para);
45772fd6d73SWeihong Zhang 	if (s->ring_fd < 0)
45872fd6d73SWeihong Zhang 		return 1;
45972fd6d73SWeihong Zhang 
46072fd6d73SWeihong Zhang 	return mmap_io_uring(para, s);
46172fd6d73SWeihong Zhang }
46272fd6d73SWeihong Zhang 
46372fd6d73SWeihong Zhang /*
46472fd6d73SWeihong Zhang  * Get data from completion queue. the data buffer saved the file data
46572fd6d73SWeihong Zhang  * return 0: success; others: error;
46672fd6d73SWeihong Zhang  */
handle_uring_cq(struct io_ring * s)46772fd6d73SWeihong Zhang int handle_uring_cq(struct io_ring *s)
46872fd6d73SWeihong Zhang {
46972fd6d73SWeihong Zhang 	struct file_io *fi = NULL;
47072fd6d73SWeihong Zhang 	struct io_uring_queue *cring = &s->cq_ring;
47172fd6d73SWeihong Zhang 	struct io_uring_cqe *cqe;
47272fd6d73SWeihong Zhang 	unsigned int head;
47372fd6d73SWeihong Zhang 	off_t len = 0;
47472fd6d73SWeihong Zhang 
47572fd6d73SWeihong Zhang 	head = *cring->head;
47672fd6d73SWeihong Zhang 
47772fd6d73SWeihong Zhang 	do {
47872fd6d73SWeihong Zhang 		barrier();
47972fd6d73SWeihong Zhang 		if (head == *cring->tail)
48072fd6d73SWeihong Zhang 			break;
48172fd6d73SWeihong Zhang 		/* Get the entry */
48272fd6d73SWeihong Zhang 		cqe = &cring->queue.cqes[head & *s->cq_ring.ring_mask];
48372fd6d73SWeihong Zhang 		fi = (struct file_io *)cqe->user_data;
48472fd6d73SWeihong Zhang 		if (cqe->res < 0)
48572fd6d73SWeihong Zhang 			break;
48672fd6d73SWeihong Zhang 
48772fd6d73SWeihong Zhang 		int blocks = (int)(fi->file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
48872fd6d73SWeihong Zhang 
48972fd6d73SWeihong Zhang 		for (int i = 0; i < blocks; i++)
49072fd6d73SWeihong Zhang 			len += fi->iovecs[i].iov_len;
49172fd6d73SWeihong Zhang 
49272fd6d73SWeihong Zhang 		head++;
49372fd6d73SWeihong Zhang 	} while (1);
49472fd6d73SWeihong Zhang 
49572fd6d73SWeihong Zhang 	*cring->head = head;
49672fd6d73SWeihong Zhang 	barrier();
49772fd6d73SWeihong Zhang 
49872fd6d73SWeihong Zhang 	return (len != fi->file_sz);
49972fd6d73SWeihong Zhang }
50072fd6d73SWeihong Zhang 
50172fd6d73SWeihong Zhang /*
50272fd6d73SWeihong Zhang  * Submit squeue. specify via IORING_OP_READV.
50372fd6d73SWeihong Zhang  * the buffer need to be set metadata according to LAM mode
50472fd6d73SWeihong Zhang  */
handle_uring_sq(struct io_ring * ring,struct file_io * fi,unsigned long lam)50572fd6d73SWeihong Zhang int handle_uring_sq(struct io_ring *ring, struct file_io *fi, unsigned long lam)
50672fd6d73SWeihong Zhang {
50772fd6d73SWeihong Zhang 	int file_fd = fi->file_fd;
50872fd6d73SWeihong Zhang 	struct io_uring_queue *sring = &ring->sq_ring;
50972fd6d73SWeihong Zhang 	unsigned int index = 0, cur_block = 0, tail = 0, next_tail = 0;
51072fd6d73SWeihong Zhang 	struct io_uring_sqe *sqe;
51172fd6d73SWeihong Zhang 
51272fd6d73SWeihong Zhang 	off_t remain = fi->file_sz;
51372fd6d73SWeihong Zhang 	int blocks = (int)(remain + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
51472fd6d73SWeihong Zhang 
51572fd6d73SWeihong Zhang 	while (remain) {
51672fd6d73SWeihong Zhang 		off_t bytes = remain;
51772fd6d73SWeihong Zhang 		void *buf;
51872fd6d73SWeihong Zhang 
51972fd6d73SWeihong Zhang 		if (bytes > URING_BLOCK_SZ)
52072fd6d73SWeihong Zhang 			bytes = URING_BLOCK_SZ;
52172fd6d73SWeihong Zhang 
52272fd6d73SWeihong Zhang 		fi->iovecs[cur_block].iov_len = bytes;
52372fd6d73SWeihong Zhang 
52472fd6d73SWeihong Zhang 		if (posix_memalign(&buf, URING_BLOCK_SZ, URING_BLOCK_SZ))
52572fd6d73SWeihong Zhang 			return 1;
52672fd6d73SWeihong Zhang 
52772fd6d73SWeihong Zhang 		fi->iovecs[cur_block].iov_base = (void *)set_metadata((uint64_t)buf, lam);
52872fd6d73SWeihong Zhang 		remain -= bytes;
52972fd6d73SWeihong Zhang 		cur_block++;
53072fd6d73SWeihong Zhang 	}
53172fd6d73SWeihong Zhang 
53272fd6d73SWeihong Zhang 	next_tail = *sring->tail;
53372fd6d73SWeihong Zhang 	tail = next_tail;
53472fd6d73SWeihong Zhang 	next_tail++;
53572fd6d73SWeihong Zhang 
53672fd6d73SWeihong Zhang 	barrier();
53772fd6d73SWeihong Zhang 
53872fd6d73SWeihong Zhang 	index = tail & *ring->sq_ring.ring_mask;
53972fd6d73SWeihong Zhang 
54072fd6d73SWeihong Zhang 	sqe = &ring->sq_ring.queue.sqes[index];
54172fd6d73SWeihong Zhang 	sqe->fd = file_fd;
54272fd6d73SWeihong Zhang 	sqe->flags = 0;
54372fd6d73SWeihong Zhang 	sqe->opcode = IORING_OP_READV;
54472fd6d73SWeihong Zhang 	sqe->addr = (unsigned long)fi->iovecs;
54572fd6d73SWeihong Zhang 	sqe->len = blocks;
54672fd6d73SWeihong Zhang 	sqe->off = 0;
54772fd6d73SWeihong Zhang 	sqe->user_data = (uint64_t)fi;
54872fd6d73SWeihong Zhang 
54972fd6d73SWeihong Zhang 	sring->array[index] = index;
55072fd6d73SWeihong Zhang 	tail = next_tail;
55172fd6d73SWeihong Zhang 
55272fd6d73SWeihong Zhang 	if (*sring->tail != tail) {
55372fd6d73SWeihong Zhang 		*sring->tail = tail;
55472fd6d73SWeihong Zhang 		barrier();
55572fd6d73SWeihong Zhang 	}
55672fd6d73SWeihong Zhang 
55772fd6d73SWeihong Zhang 	if (sys_uring_enter(ring->ring_fd, 1, 1, IORING_ENTER_GETEVENTS) < 0)
55872fd6d73SWeihong Zhang 		return 1;
55972fd6d73SWeihong Zhang 
56072fd6d73SWeihong Zhang 	return 0;
56172fd6d73SWeihong Zhang }
56272fd6d73SWeihong Zhang 
56372fd6d73SWeihong Zhang /*
56472fd6d73SWeihong Zhang  * Test LAM in async I/O and io_uring, read current binery through io_uring
56572fd6d73SWeihong Zhang  * Set metadata in pointers to iovecs buffer.
56672fd6d73SWeihong Zhang  */
do_uring(unsigned long lam)56772fd6d73SWeihong Zhang int do_uring(unsigned long lam)
56872fd6d73SWeihong Zhang {
56972fd6d73SWeihong Zhang 	struct io_ring *ring;
57072fd6d73SWeihong Zhang 	struct file_io *fi;
57172fd6d73SWeihong Zhang 	struct stat st;
57272fd6d73SWeihong Zhang 	int ret = 1;
57334821473SWeihong Zhang 	char path[PATH_MAX] = {0};
57472fd6d73SWeihong Zhang 
57572fd6d73SWeihong Zhang 	/* get current process path */
576*b13513e7SBinbin Wu 	if (readlink("/proc/self/exe", path, PATH_MAX - 1) <= 0)
57772fd6d73SWeihong Zhang 		return 1;
57872fd6d73SWeihong Zhang 
57972fd6d73SWeihong Zhang 	int file_fd = open(path, O_RDONLY);
58072fd6d73SWeihong Zhang 
58172fd6d73SWeihong Zhang 	if (file_fd < 0)
58272fd6d73SWeihong Zhang 		return 1;
58372fd6d73SWeihong Zhang 
58472fd6d73SWeihong Zhang 	if (fstat(file_fd, &st) < 0)
58572fd6d73SWeihong Zhang 		return 1;
58672fd6d73SWeihong Zhang 
58772fd6d73SWeihong Zhang 	off_t file_sz = st.st_size;
58872fd6d73SWeihong Zhang 
58972fd6d73SWeihong Zhang 	int blocks = (int)(file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
59072fd6d73SWeihong Zhang 
59172fd6d73SWeihong Zhang 	fi = malloc(sizeof(*fi) + sizeof(struct iovec) * blocks);
59272fd6d73SWeihong Zhang 	if (!fi)
59372fd6d73SWeihong Zhang 		return 1;
59472fd6d73SWeihong Zhang 
59572fd6d73SWeihong Zhang 	fi->file_sz = file_sz;
59672fd6d73SWeihong Zhang 	fi->file_fd = file_fd;
59772fd6d73SWeihong Zhang 
59872fd6d73SWeihong Zhang 	ring = malloc(sizeof(*ring));
59972fd6d73SWeihong Zhang 	if (!ring)
60072fd6d73SWeihong Zhang 		return 1;
60172fd6d73SWeihong Zhang 
60272fd6d73SWeihong Zhang 	memset(ring, 0, sizeof(struct io_ring));
60372fd6d73SWeihong Zhang 
60472fd6d73SWeihong Zhang 	if (setup_io_uring(ring))
60572fd6d73SWeihong Zhang 		goto out;
60672fd6d73SWeihong Zhang 
60772fd6d73SWeihong Zhang 	if (handle_uring_sq(ring, fi, lam))
60872fd6d73SWeihong Zhang 		goto out;
60972fd6d73SWeihong Zhang 
61072fd6d73SWeihong Zhang 	ret = handle_uring_cq(ring);
61172fd6d73SWeihong Zhang 
61272fd6d73SWeihong Zhang out:
61372fd6d73SWeihong Zhang 	free(ring);
61472fd6d73SWeihong Zhang 
61572fd6d73SWeihong Zhang 	for (int i = 0; i < blocks; i++) {
61672fd6d73SWeihong Zhang 		if (fi->iovecs[i].iov_base) {
61772fd6d73SWeihong Zhang 			uint64_t addr = ((uint64_t)fi->iovecs[i].iov_base);
61872fd6d73SWeihong Zhang 
61972fd6d73SWeihong Zhang 			switch (lam) {
62072fd6d73SWeihong Zhang 			case LAM_U57_BITS: /* Clear bits 62:57 */
621833c12ceSWeihong Zhang 				addr = (addr & ~(LAM_U57_MASK));
62272fd6d73SWeihong Zhang 				break;
62372fd6d73SWeihong Zhang 			}
62472fd6d73SWeihong Zhang 			free((void *)addr);
62572fd6d73SWeihong Zhang 			fi->iovecs[i].iov_base = NULL;
62672fd6d73SWeihong Zhang 		}
62772fd6d73SWeihong Zhang 	}
62872fd6d73SWeihong Zhang 
62972fd6d73SWeihong Zhang 	free(fi);
63072fd6d73SWeihong Zhang 
63172fd6d73SWeihong Zhang 	return ret;
63272fd6d73SWeihong Zhang }
63372fd6d73SWeihong Zhang 
handle_uring(struct testcases * test)63472fd6d73SWeihong Zhang int handle_uring(struct testcases *test)
63572fd6d73SWeihong Zhang {
63672fd6d73SWeihong Zhang 	int ret = 0;
63772fd6d73SWeihong Zhang 
63872fd6d73SWeihong Zhang 	if (test->later == 0 && test->lam != 0)
63972fd6d73SWeihong Zhang 		if (set_lam(test->lam) != 0)
64072fd6d73SWeihong Zhang 			return 1;
64172fd6d73SWeihong Zhang 
64272fd6d73SWeihong Zhang 	if (sigsetjmp(segv_env, 1) == 0) {
64372fd6d73SWeihong Zhang 		signal(SIGSEGV, segv_handler);
64472fd6d73SWeihong Zhang 		ret = do_uring(test->lam);
64572fd6d73SWeihong Zhang 	} else {
64672fd6d73SWeihong Zhang 		ret = 2;
64772fd6d73SWeihong Zhang 	}
64872fd6d73SWeihong Zhang 
64972fd6d73SWeihong Zhang 	return ret;
65072fd6d73SWeihong Zhang }
65172fd6d73SWeihong Zhang 
fork_test(struct testcases * test)6523de9745cSWeihong Zhang static int fork_test(struct testcases *test)
6533de9745cSWeihong Zhang {
6543de9745cSWeihong Zhang 	int ret, child_ret;
6553de9745cSWeihong Zhang 	pid_t pid;
6563de9745cSWeihong Zhang 
6573de9745cSWeihong Zhang 	pid = fork();
6583de9745cSWeihong Zhang 	if (pid < 0) {
6593de9745cSWeihong Zhang 		perror("Fork failed.");
6603de9745cSWeihong Zhang 		ret = 1;
6613de9745cSWeihong Zhang 	} else if (pid == 0) {
6623de9745cSWeihong Zhang 		ret = test->test_func(test);
6633de9745cSWeihong Zhang 		exit(ret);
6643de9745cSWeihong Zhang 	} else {
6653de9745cSWeihong Zhang 		wait(&child_ret);
6663de9745cSWeihong Zhang 		ret = WEXITSTATUS(child_ret);
6673de9745cSWeihong Zhang 	}
6683de9745cSWeihong Zhang 
6693de9745cSWeihong Zhang 	return ret;
6703de9745cSWeihong Zhang }
6713de9745cSWeihong Zhang 
handle_execve(struct testcases * test)672833c12ceSWeihong Zhang static int handle_execve(struct testcases *test)
673833c12ceSWeihong Zhang {
674833c12ceSWeihong Zhang 	int ret, child_ret;
675833c12ceSWeihong Zhang 	int lam = test->lam;
676833c12ceSWeihong Zhang 	pid_t pid;
677833c12ceSWeihong Zhang 
678833c12ceSWeihong Zhang 	pid = fork();
679833c12ceSWeihong Zhang 	if (pid < 0) {
680833c12ceSWeihong Zhang 		perror("Fork failed.");
681833c12ceSWeihong Zhang 		ret = 1;
682833c12ceSWeihong Zhang 	} else if (pid == 0) {
683*b13513e7SBinbin Wu 		char path[PATH_MAX] = {0};
684833c12ceSWeihong Zhang 
685833c12ceSWeihong Zhang 		/* Set LAM mode in parent process */
686833c12ceSWeihong Zhang 		if (set_lam(lam) != 0)
687833c12ceSWeihong Zhang 			return 1;
688833c12ceSWeihong Zhang 
689833c12ceSWeihong Zhang 		/* Get current binary's path and the binary was run by execve */
690*b13513e7SBinbin Wu 		if (readlink("/proc/self/exe", path, PATH_MAX - 1) <= 0)
691833c12ceSWeihong Zhang 			exit(-1);
692833c12ceSWeihong Zhang 
693833c12ceSWeihong Zhang 		/* run binary to get LAM mode and return to parent process */
694833c12ceSWeihong Zhang 		if (execlp(path, path, "-t 0x0", NULL) < 0) {
695833c12ceSWeihong Zhang 			perror("error on exec");
696833c12ceSWeihong Zhang 			exit(-1);
697833c12ceSWeihong Zhang 		}
698833c12ceSWeihong Zhang 	} else {
699833c12ceSWeihong Zhang 		wait(&child_ret);
700833c12ceSWeihong Zhang 		ret = WEXITSTATUS(child_ret);
701833c12ceSWeihong Zhang 		if (ret != LAM_NONE)
702833c12ceSWeihong Zhang 			return 1;
703833c12ceSWeihong Zhang 	}
704833c12ceSWeihong Zhang 
705833c12ceSWeihong Zhang 	return 0;
706833c12ceSWeihong Zhang }
707833c12ceSWeihong Zhang 
handle_inheritance(struct testcases * test)708833c12ceSWeihong Zhang static int handle_inheritance(struct testcases *test)
709833c12ceSWeihong Zhang {
710833c12ceSWeihong Zhang 	int ret, child_ret;
711833c12ceSWeihong Zhang 	int lam = test->lam;
712833c12ceSWeihong Zhang 	pid_t pid;
713833c12ceSWeihong Zhang 
714833c12ceSWeihong Zhang 	/* Set LAM mode in parent process */
715833c12ceSWeihong Zhang 	if (set_lam(lam) != 0)
716833c12ceSWeihong Zhang 		return 1;
717833c12ceSWeihong Zhang 
718833c12ceSWeihong Zhang 	pid = fork();
719833c12ceSWeihong Zhang 	if (pid < 0) {
720833c12ceSWeihong Zhang 		perror("Fork failed.");
721833c12ceSWeihong Zhang 		return 1;
722833c12ceSWeihong Zhang 	} else if (pid == 0) {
723833c12ceSWeihong Zhang 		/* Set LAM mode in parent process */
724833c12ceSWeihong Zhang 		int child_lam = get_lam();
725833c12ceSWeihong Zhang 
726833c12ceSWeihong Zhang 		exit(child_lam);
727833c12ceSWeihong Zhang 	} else {
728833c12ceSWeihong Zhang 		wait(&child_ret);
729833c12ceSWeihong Zhang 		ret = WEXITSTATUS(child_ret);
730833c12ceSWeihong Zhang 
731833c12ceSWeihong Zhang 		if (lam != ret)
732833c12ceSWeihong Zhang 			return 1;
733833c12ceSWeihong Zhang 	}
734833c12ceSWeihong Zhang 
735833c12ceSWeihong Zhang 	return 0;
736833c12ceSWeihong Zhang }
737833c12ceSWeihong Zhang 
thread_fn_get_lam(void * arg)738dfd7a156SKirill A. Shutemov static int thread_fn_get_lam(void *arg)
739dfd7a156SKirill A. Shutemov {
740dfd7a156SKirill A. Shutemov 	return get_lam();
741dfd7a156SKirill A. Shutemov }
742dfd7a156SKirill A. Shutemov 
thread_fn_set_lam(void * arg)743dfd7a156SKirill A. Shutemov static int thread_fn_set_lam(void *arg)
744dfd7a156SKirill A. Shutemov {
745dfd7a156SKirill A. Shutemov 	struct testcases *test = arg;
746dfd7a156SKirill A. Shutemov 
747dfd7a156SKirill A. Shutemov 	return set_lam(test->lam);
748dfd7a156SKirill A. Shutemov }
749dfd7a156SKirill A. Shutemov 
handle_thread(struct testcases * test)750dfd7a156SKirill A. Shutemov static int handle_thread(struct testcases *test)
751dfd7a156SKirill A. Shutemov {
752dfd7a156SKirill A. Shutemov 	char stack[STACK_SIZE];
753dfd7a156SKirill A. Shutemov 	int ret, child_ret;
754dfd7a156SKirill A. Shutemov 	int lam = 0;
755dfd7a156SKirill A. Shutemov 	pid_t pid;
756dfd7a156SKirill A. Shutemov 
757dfd7a156SKirill A. Shutemov 	/* Set LAM mode in parent process */
758dfd7a156SKirill A. Shutemov 	if (!test->later) {
759dfd7a156SKirill A. Shutemov 		lam = test->lam;
760dfd7a156SKirill A. Shutemov 		if (set_lam(lam) != 0)
761dfd7a156SKirill A. Shutemov 			return 1;
762dfd7a156SKirill A. Shutemov 	}
763dfd7a156SKirill A. Shutemov 
764dfd7a156SKirill A. Shutemov 	pid = clone(thread_fn_get_lam, stack + STACK_SIZE,
765dfd7a156SKirill A. Shutemov 		    SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, NULL);
766dfd7a156SKirill A. Shutemov 	if (pid < 0) {
767dfd7a156SKirill A. Shutemov 		perror("Clone failed.");
768dfd7a156SKirill A. Shutemov 		return 1;
769dfd7a156SKirill A. Shutemov 	}
770dfd7a156SKirill A. Shutemov 
771dfd7a156SKirill A. Shutemov 	waitpid(pid, &child_ret, 0);
772dfd7a156SKirill A. Shutemov 	ret = WEXITSTATUS(child_ret);
773dfd7a156SKirill A. Shutemov 
774dfd7a156SKirill A. Shutemov 	if (lam != ret)
775dfd7a156SKirill A. Shutemov 		return 1;
776dfd7a156SKirill A. Shutemov 
777dfd7a156SKirill A. Shutemov 	if (test->later) {
778dfd7a156SKirill A. Shutemov 		if (set_lam(test->lam) != 0)
779dfd7a156SKirill A. Shutemov 			return 1;
780dfd7a156SKirill A. Shutemov 	}
781dfd7a156SKirill A. Shutemov 
782dfd7a156SKirill A. Shutemov 	return 0;
783dfd7a156SKirill A. Shutemov }
784dfd7a156SKirill A. Shutemov 
handle_thread_enable(struct testcases * test)785dfd7a156SKirill A. Shutemov static int handle_thread_enable(struct testcases *test)
786dfd7a156SKirill A. Shutemov {
787dfd7a156SKirill A. Shutemov 	char stack[STACK_SIZE];
788dfd7a156SKirill A. Shutemov 	int ret, child_ret;
789dfd7a156SKirill A. Shutemov 	int lam = test->lam;
790dfd7a156SKirill A. Shutemov 	pid_t pid;
791dfd7a156SKirill A. Shutemov 
792dfd7a156SKirill A. Shutemov 	pid = clone(thread_fn_set_lam, stack + STACK_SIZE,
793dfd7a156SKirill A. Shutemov 		    SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, test);
794dfd7a156SKirill A. Shutemov 	if (pid < 0) {
795dfd7a156SKirill A. Shutemov 		perror("Clone failed.");
796dfd7a156SKirill A. Shutemov 		return 1;
797dfd7a156SKirill A. Shutemov 	}
798dfd7a156SKirill A. Shutemov 
799dfd7a156SKirill A. Shutemov 	waitpid(pid, &child_ret, 0);
800dfd7a156SKirill A. Shutemov 	ret = WEXITSTATUS(child_ret);
801dfd7a156SKirill A. Shutemov 
802dfd7a156SKirill A. Shutemov 	if (lam != ret)
803dfd7a156SKirill A. Shutemov 		return 1;
804dfd7a156SKirill A. Shutemov 
805dfd7a156SKirill A. Shutemov 	return 0;
806dfd7a156SKirill A. Shutemov }
run_test(struct testcases * test,int count)8073de9745cSWeihong Zhang static void run_test(struct testcases *test, int count)
8083de9745cSWeihong Zhang {
8093de9745cSWeihong Zhang 	int i, ret = 0;
8103de9745cSWeihong Zhang 
8113de9745cSWeihong Zhang 	for (i = 0; i < count; i++) {
8123de9745cSWeihong Zhang 		struct testcases *t = test + i;
8133de9745cSWeihong Zhang 
8143de9745cSWeihong Zhang 		/* fork a process to run test case */
815e6787696SWeihong Zhang 		tests_cnt++;
8163de9745cSWeihong Zhang 		ret = fork_test(t);
817e6787696SWeihong Zhang 
818e6787696SWeihong Zhang 		/* return 3 is not support LA57, the case should be skipped */
819e6787696SWeihong Zhang 		if (ret == 3) {
820e6787696SWeihong Zhang 			ksft_test_result_skip(t->msg);
821e6787696SWeihong Zhang 			continue;
822e6787696SWeihong Zhang 		}
823e6787696SWeihong Zhang 
8243de9745cSWeihong Zhang 		if (ret != 0)
8253de9745cSWeihong Zhang 			ret = (t->expected == ret);
8263de9745cSWeihong Zhang 		else
8273de9745cSWeihong Zhang 			ret = !(t->expected);
8283de9745cSWeihong Zhang 
8293de9745cSWeihong Zhang 		ksft_test_result(ret, t->msg);
8303de9745cSWeihong Zhang 	}
8313de9745cSWeihong Zhang }
8323de9745cSWeihong Zhang 
83372fd6d73SWeihong Zhang static struct testcases uring_cases[] = {
83472fd6d73SWeihong Zhang 	{
83572fd6d73SWeihong Zhang 		.later = 0,
83672fd6d73SWeihong Zhang 		.lam = LAM_U57_BITS,
83772fd6d73SWeihong Zhang 		.test_func = handle_uring,
83872fd6d73SWeihong Zhang 		.msg = "URING: LAM_U57. Dereferencing pointer with metadata\n",
83972fd6d73SWeihong Zhang 	},
84072fd6d73SWeihong Zhang 	{
84172fd6d73SWeihong Zhang 		.later = 1,
84272fd6d73SWeihong Zhang 		.expected = 1,
84372fd6d73SWeihong Zhang 		.lam = LAM_U57_BITS,
84472fd6d73SWeihong Zhang 		.test_func = handle_uring,
84572fd6d73SWeihong Zhang 		.msg = "URING:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
84672fd6d73SWeihong Zhang 	},
84772fd6d73SWeihong Zhang };
84872fd6d73SWeihong Zhang 
8493de9745cSWeihong Zhang static struct testcases malloc_cases[] = {
8503de9745cSWeihong Zhang 	{
8513de9745cSWeihong Zhang 		.later = 0,
8523de9745cSWeihong Zhang 		.lam = LAM_U57_BITS,
8533de9745cSWeihong Zhang 		.test_func = handle_malloc,
8543de9745cSWeihong Zhang 		.msg = "MALLOC: LAM_U57. Dereferencing pointer with metadata\n",
8553de9745cSWeihong Zhang 	},
8563de9745cSWeihong Zhang 	{
8573de9745cSWeihong Zhang 		.later = 1,
8583de9745cSWeihong Zhang 		.expected = 2,
8593de9745cSWeihong Zhang 		.lam = LAM_U57_BITS,
8603de9745cSWeihong Zhang 		.test_func = handle_malloc,
8613de9745cSWeihong Zhang 		.msg = "MALLOC:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
8623de9745cSWeihong Zhang 	},
8633de9745cSWeihong Zhang };
8643de9745cSWeihong Zhang 
8653de9745cSWeihong Zhang static struct testcases bits_cases[] = {
8663de9745cSWeihong Zhang 	{
8673de9745cSWeihong Zhang 		.test_func = handle_max_bits,
8683de9745cSWeihong Zhang 		.msg = "BITS: Check default tag bits\n",
8693de9745cSWeihong Zhang 	},
8703de9745cSWeihong Zhang };
8713de9745cSWeihong Zhang 
872e6787696SWeihong Zhang static struct testcases syscall_cases[] = {
873e6787696SWeihong Zhang 	{
874e6787696SWeihong Zhang 		.later = 0,
875e6787696SWeihong Zhang 		.lam = LAM_U57_BITS,
876e6787696SWeihong Zhang 		.test_func = handle_syscall,
877e6787696SWeihong Zhang 		.msg = "SYSCALL: LAM_U57. syscall with metadata\n",
878e6787696SWeihong Zhang 	},
879e6787696SWeihong Zhang 	{
880e6787696SWeihong Zhang 		.later = 1,
881e6787696SWeihong Zhang 		.expected = 1,
882e6787696SWeihong Zhang 		.lam = LAM_U57_BITS,
883e6787696SWeihong Zhang 		.test_func = handle_syscall,
884e6787696SWeihong Zhang 		.msg = "SYSCALL:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
885e6787696SWeihong Zhang 	},
886e6787696SWeihong Zhang };
887e6787696SWeihong Zhang 
888e6787696SWeihong Zhang static struct testcases mmap_cases[] = {
889e6787696SWeihong Zhang 	{
890e6787696SWeihong Zhang 		.later = 1,
891e6787696SWeihong Zhang 		.expected = 0,
892e6787696SWeihong Zhang 		.lam = LAM_U57_BITS,
893e6787696SWeihong Zhang 		.addr = HIGH_ADDR,
894e6787696SWeihong Zhang 		.test_func = handle_mmap,
895e6787696SWeihong Zhang 		.msg = "MMAP: First mmap high address, then set LAM_U57.\n",
896e6787696SWeihong Zhang 	},
897e6787696SWeihong Zhang 	{
898e6787696SWeihong Zhang 		.later = 0,
899e6787696SWeihong Zhang 		.expected = 0,
900e6787696SWeihong Zhang 		.lam = LAM_U57_BITS,
901e6787696SWeihong Zhang 		.addr = HIGH_ADDR,
902e6787696SWeihong Zhang 		.test_func = handle_mmap,
903e6787696SWeihong Zhang 		.msg = "MMAP: First LAM_U57, then High address.\n",
904e6787696SWeihong Zhang 	},
905e6787696SWeihong Zhang 	{
906e6787696SWeihong Zhang 		.later = 0,
907e6787696SWeihong Zhang 		.expected = 0,
908e6787696SWeihong Zhang 		.lam = LAM_U57_BITS,
909e6787696SWeihong Zhang 		.addr = LOW_ADDR,
910e6787696SWeihong Zhang 		.test_func = handle_mmap,
911e6787696SWeihong Zhang 		.msg = "MMAP: First LAM_U57, then Low address.\n",
912e6787696SWeihong Zhang 	},
913e6787696SWeihong Zhang };
914e6787696SWeihong Zhang 
915833c12ceSWeihong Zhang static struct testcases inheritance_cases[] = {
916833c12ceSWeihong Zhang 	{
917833c12ceSWeihong Zhang 		.expected = 0,
918833c12ceSWeihong Zhang 		.lam = LAM_U57_BITS,
919833c12ceSWeihong Zhang 		.test_func = handle_inheritance,
920833c12ceSWeihong Zhang 		.msg = "FORK: LAM_U57, child process should get LAM mode same as parent\n",
921833c12ceSWeihong Zhang 	},
922833c12ceSWeihong Zhang 	{
923833c12ceSWeihong Zhang 		.expected = 0,
924833c12ceSWeihong Zhang 		.lam = LAM_U57_BITS,
925dfd7a156SKirill A. Shutemov 		.test_func = handle_thread,
926dfd7a156SKirill A. Shutemov 		.msg = "THREAD: LAM_U57, child thread should get LAM mode same as parent\n",
927dfd7a156SKirill A. Shutemov 	},
928dfd7a156SKirill A. Shutemov 	{
929dfd7a156SKirill A. Shutemov 		.expected = 1,
930dfd7a156SKirill A. Shutemov 		.lam = LAM_U57_BITS,
931dfd7a156SKirill A. Shutemov 		.test_func = handle_thread_enable,
932dfd7a156SKirill A. Shutemov 		.msg = "THREAD: [NEGATIVE] Enable LAM in child.\n",
933dfd7a156SKirill A. Shutemov 	},
934dfd7a156SKirill A. Shutemov 	{
935dfd7a156SKirill A. Shutemov 		.expected = 1,
936dfd7a156SKirill A. Shutemov 		.later = 1,
937dfd7a156SKirill A. Shutemov 		.lam = LAM_U57_BITS,
938dfd7a156SKirill A. Shutemov 		.test_func = handle_thread,
939dfd7a156SKirill A. Shutemov 		.msg = "THREAD: [NEGATIVE] Enable LAM in parent after thread created.\n",
940dfd7a156SKirill A. Shutemov 	},
941dfd7a156SKirill A. Shutemov 	{
942dfd7a156SKirill A. Shutemov 		.expected = 0,
943dfd7a156SKirill A. Shutemov 		.lam = LAM_U57_BITS,
944833c12ceSWeihong Zhang 		.test_func = handle_execve,
945833c12ceSWeihong Zhang 		.msg = "EXECVE: LAM_U57, child process should get disabled LAM mode\n",
946833c12ceSWeihong Zhang 	},
947833c12ceSWeihong Zhang };
948833c12ceSWeihong Zhang 
cmd_help(void)9493de9745cSWeihong Zhang static void cmd_help(void)
9503de9745cSWeihong Zhang {
9513de9745cSWeihong Zhang 	printf("usage: lam [-h] [-t test list]\n");
9523de9745cSWeihong Zhang 	printf("\t-t test list: run tests specified in the test list, default:0x%x\n", TEST_MASK);
953833c12ceSWeihong Zhang 	printf("\t\t0x1:malloc; 0x2:max_bits; 0x4:mmap; 0x8:syscall; 0x10:io_uring; 0x20:inherit;\n");
9543de9745cSWeihong Zhang 	printf("\t-h: help\n");
9553de9745cSWeihong Zhang }
9563de9745cSWeihong Zhang 
95734821473SWeihong Zhang /* Check for file existence */
file_Exists(const char * fileName)95834821473SWeihong Zhang uint8_t file_Exists(const char *fileName)
95934821473SWeihong Zhang {
96034821473SWeihong Zhang 	struct stat buffer;
96134821473SWeihong Zhang 
96234821473SWeihong Zhang 	uint8_t ret = (stat(fileName, &buffer) == 0);
96334821473SWeihong Zhang 
96434821473SWeihong Zhang 	return ret;
96534821473SWeihong Zhang }
96634821473SWeihong Zhang 
96734821473SWeihong Zhang /* Sysfs idxd files */
96834821473SWeihong Zhang const char *dsa_configs[] = {
96934821473SWeihong Zhang 	"echo 1 > /sys/bus/dsa/devices/dsa0/wq0.1/group_id",
97034821473SWeihong Zhang 	"echo shared > /sys/bus/dsa/devices/dsa0/wq0.1/mode",
97134821473SWeihong Zhang 	"echo 10 > /sys/bus/dsa/devices/dsa0/wq0.1/priority",
97234821473SWeihong Zhang 	"echo 16 > /sys/bus/dsa/devices/dsa0/wq0.1/size",
97334821473SWeihong Zhang 	"echo 15 > /sys/bus/dsa/devices/dsa0/wq0.1/threshold",
97434821473SWeihong Zhang 	"echo user > /sys/bus/dsa/devices/dsa0/wq0.1/type",
97534821473SWeihong Zhang 	"echo MyApp1 > /sys/bus/dsa/devices/dsa0/wq0.1/name",
97634821473SWeihong Zhang 	"echo 1 > /sys/bus/dsa/devices/dsa0/engine0.1/group_id",
97734821473SWeihong Zhang 	"echo dsa0 > /sys/bus/dsa/drivers/idxd/bind",
97834821473SWeihong Zhang 	/* bind files and devices, generated a device file in /dev */
97934821473SWeihong Zhang 	"echo wq0.1 > /sys/bus/dsa/drivers/user/bind",
98034821473SWeihong Zhang };
98134821473SWeihong Zhang 
98234821473SWeihong Zhang /* DSA device file */
98334821473SWeihong Zhang const char *dsaDeviceFile = "/dev/dsa/wq0.1";
98434821473SWeihong Zhang /* file for io*/
98534821473SWeihong Zhang const char *dsaPasidEnable = "/sys/bus/dsa/devices/dsa0/pasid_enabled";
98634821473SWeihong Zhang 
98734821473SWeihong Zhang /*
98834821473SWeihong Zhang  * DSA depends on kernel cmdline "intel_iommu=on,sm_on"
98934821473SWeihong Zhang  * return pasid_enabled (0: disable 1:enable)
99034821473SWeihong Zhang  */
Check_DSA_Kernel_Setting(void)99134821473SWeihong Zhang int Check_DSA_Kernel_Setting(void)
99234821473SWeihong Zhang {
99334821473SWeihong Zhang 	char command[256] = "";
99434821473SWeihong Zhang 	char buf[256] = "";
99534821473SWeihong Zhang 	char *ptr;
99634821473SWeihong Zhang 	int rv = -1;
99734821473SWeihong Zhang 
99834821473SWeihong Zhang 	snprintf(command, sizeof(command) - 1, "cat %s", dsaPasidEnable);
99934821473SWeihong Zhang 
100034821473SWeihong Zhang 	FILE *cmd = popen(command, "r");
100134821473SWeihong Zhang 
100234821473SWeihong Zhang 	if (cmd) {
100334821473SWeihong Zhang 		while (fgets(buf, sizeof(buf) - 1, cmd) != NULL);
100434821473SWeihong Zhang 
100534821473SWeihong Zhang 		pclose(cmd);
100634821473SWeihong Zhang 		rv = strtol(buf, &ptr, 16);
100734821473SWeihong Zhang 	}
100834821473SWeihong Zhang 
100934821473SWeihong Zhang 	return rv;
101034821473SWeihong Zhang }
101134821473SWeihong Zhang 
101234821473SWeihong Zhang /*
101334821473SWeihong Zhang  * Config DSA's sysfs files as shared DSA's WQ.
101434821473SWeihong Zhang  * Generated a device file /dev/dsa/wq0.1
101534821473SWeihong Zhang  * Return:  0 OK; 1 Failed; 3 Skip(SVA disabled).
101634821473SWeihong Zhang  */
Dsa_Init_Sysfs(void)101734821473SWeihong Zhang int Dsa_Init_Sysfs(void)
101834821473SWeihong Zhang {
101934821473SWeihong Zhang 	uint len = ARRAY_SIZE(dsa_configs);
102034821473SWeihong Zhang 	const char **p = dsa_configs;
102134821473SWeihong Zhang 
102234821473SWeihong Zhang 	if (file_Exists(dsaDeviceFile) == 1)
102334821473SWeihong Zhang 		return 0;
102434821473SWeihong Zhang 
102534821473SWeihong Zhang 	/* check the idxd driver */
102634821473SWeihong Zhang 	if (file_Exists(dsaPasidEnable) != 1) {
102734821473SWeihong Zhang 		printf("Please make sure idxd driver was loaded\n");
102834821473SWeihong Zhang 		return 3;
102934821473SWeihong Zhang 	}
103034821473SWeihong Zhang 
103134821473SWeihong Zhang 	/* Check SVA feature */
103234821473SWeihong Zhang 	if (Check_DSA_Kernel_Setting() != 1) {
103334821473SWeihong Zhang 		printf("Please enable SVA.(Add intel_iommu=on,sm_on in kernel cmdline)\n");
103434821473SWeihong Zhang 		return 3;
103534821473SWeihong Zhang 	}
103634821473SWeihong Zhang 
103734821473SWeihong Zhang 	/* Check the idxd device file on /dev/dsa/ */
103834821473SWeihong Zhang 	for (int i = 0; i < len; i++) {
103934821473SWeihong Zhang 		if (system(p[i]))
104034821473SWeihong Zhang 			return 1;
104134821473SWeihong Zhang 	}
104234821473SWeihong Zhang 
104334821473SWeihong Zhang 	/* After config, /dev/dsa/wq0.1 should be generated */
104434821473SWeihong Zhang 	return (file_Exists(dsaDeviceFile) != 1);
104534821473SWeihong Zhang }
104634821473SWeihong Zhang 
104734821473SWeihong Zhang /*
104834821473SWeihong Zhang  * Open DSA device file, triger API: iommu_sva_alloc_pasid
104934821473SWeihong Zhang  */
allocate_dsa_pasid(void)105034821473SWeihong Zhang void *allocate_dsa_pasid(void)
105134821473SWeihong Zhang {
105234821473SWeihong Zhang 	int fd;
105334821473SWeihong Zhang 	void *wq;
105434821473SWeihong Zhang 
105534821473SWeihong Zhang 	fd = open(dsaDeviceFile, O_RDWR);
105634821473SWeihong Zhang 	if (fd < 0) {
105734821473SWeihong Zhang 		perror("open");
105834821473SWeihong Zhang 		return MAP_FAILED;
105934821473SWeihong Zhang 	}
106034821473SWeihong Zhang 
106134821473SWeihong Zhang 	wq = mmap(NULL, 0x1000, PROT_WRITE,
106234821473SWeihong Zhang 			   MAP_SHARED | MAP_POPULATE, fd, 0);
106334821473SWeihong Zhang 	if (wq == MAP_FAILED)
106434821473SWeihong Zhang 		perror("mmap");
106534821473SWeihong Zhang 
106634821473SWeihong Zhang 	return wq;
106734821473SWeihong Zhang }
106834821473SWeihong Zhang 
set_force_svm(void)106934821473SWeihong Zhang int set_force_svm(void)
107034821473SWeihong Zhang {
107134821473SWeihong Zhang 	int ret = 0;
107234821473SWeihong Zhang 
107334821473SWeihong Zhang 	ret = syscall(SYS_arch_prctl, ARCH_FORCE_TAGGED_SVA);
107434821473SWeihong Zhang 
107534821473SWeihong Zhang 	return ret;
107634821473SWeihong Zhang }
107734821473SWeihong Zhang 
handle_pasid(struct testcases * test)107834821473SWeihong Zhang int handle_pasid(struct testcases *test)
107934821473SWeihong Zhang {
108034821473SWeihong Zhang 	uint tmp = test->cmd;
108134821473SWeihong Zhang 	uint runed = 0x0;
108234821473SWeihong Zhang 	int ret = 0;
108334821473SWeihong Zhang 	void *wq = NULL;
108434821473SWeihong Zhang 
108534821473SWeihong Zhang 	ret = Dsa_Init_Sysfs();
108634821473SWeihong Zhang 	if (ret != 0)
108734821473SWeihong Zhang 		return ret;
108834821473SWeihong Zhang 
108934821473SWeihong Zhang 	for (int i = 0; i < 3; i++) {
109034821473SWeihong Zhang 		int err = 0;
109134821473SWeihong Zhang 
109234821473SWeihong Zhang 		if (tmp & 0x1) {
109334821473SWeihong Zhang 			/* run set lam mode*/
109434821473SWeihong Zhang 			if ((runed & 0x1) == 0)	{
109534821473SWeihong Zhang 				err = set_lam(LAM_U57_BITS);
109634821473SWeihong Zhang 				runed = runed | 0x1;
109734821473SWeihong Zhang 			} else
109834821473SWeihong Zhang 				err = 1;
109934821473SWeihong Zhang 		} else if (tmp & 0x4) {
110034821473SWeihong Zhang 			/* run force svm */
110134821473SWeihong Zhang 			if ((runed & 0x4) == 0)	{
110234821473SWeihong Zhang 				err = set_force_svm();
110334821473SWeihong Zhang 				runed = runed | 0x4;
110434821473SWeihong Zhang 			} else
110534821473SWeihong Zhang 				err = 1;
110634821473SWeihong Zhang 		} else if (tmp & 0x2) {
110734821473SWeihong Zhang 			/* run allocate pasid */
110834821473SWeihong Zhang 			if ((runed & 0x2) == 0) {
110934821473SWeihong Zhang 				runed = runed | 0x2;
111034821473SWeihong Zhang 				wq = allocate_dsa_pasid();
111134821473SWeihong Zhang 				if (wq == MAP_FAILED)
111234821473SWeihong Zhang 					err = 1;
111334821473SWeihong Zhang 			} else
111434821473SWeihong Zhang 				err = 1;
111534821473SWeihong Zhang 		}
111634821473SWeihong Zhang 
111734821473SWeihong Zhang 		ret = ret + err;
111834821473SWeihong Zhang 		if (ret > 0)
111934821473SWeihong Zhang 			break;
112034821473SWeihong Zhang 
112134821473SWeihong Zhang 		tmp = tmp >> 4;
112234821473SWeihong Zhang 	}
112334821473SWeihong Zhang 
112434821473SWeihong Zhang 	if (wq != MAP_FAILED && wq != NULL)
112534821473SWeihong Zhang 		if (munmap(wq, 0x1000))
112634821473SWeihong Zhang 			printf("munmap failed %d\n", errno);
112734821473SWeihong Zhang 
112834821473SWeihong Zhang 	if (runed != 0x7)
112934821473SWeihong Zhang 		ret = 1;
113034821473SWeihong Zhang 
113134821473SWeihong Zhang 	return (ret != 0);
113234821473SWeihong Zhang }
113334821473SWeihong Zhang 
113434821473SWeihong Zhang /*
113534821473SWeihong Zhang  * Pasid test depends on idxd and SVA, kernel should enable iommu and sm.
113634821473SWeihong Zhang  * command line(intel_iommu=on,sm_on)
113734821473SWeihong Zhang  */
113834821473SWeihong Zhang static struct testcases pasid_cases[] = {
113934821473SWeihong Zhang 	{
114034821473SWeihong Zhang 		.expected = 1,
114134821473SWeihong Zhang 		.cmd = PAS_CMD(LAM_CMD_BIT, PAS_CMD_BIT, SVA_CMD_BIT),
114234821473SWeihong Zhang 		.test_func = handle_pasid,
114334821473SWeihong Zhang 		.msg = "PASID: [Negative] Execute LAM, PASID, SVA in sequence\n",
114434821473SWeihong Zhang 	},
114534821473SWeihong Zhang 	{
114634821473SWeihong Zhang 		.expected = 0,
114734821473SWeihong Zhang 		.cmd = PAS_CMD(LAM_CMD_BIT, SVA_CMD_BIT, PAS_CMD_BIT),
114834821473SWeihong Zhang 		.test_func = handle_pasid,
114934821473SWeihong Zhang 		.msg = "PASID: Execute LAM, SVA, PASID in sequence\n",
115034821473SWeihong Zhang 	},
115134821473SWeihong Zhang 	{
115234821473SWeihong Zhang 		.expected = 1,
115334821473SWeihong Zhang 		.cmd = PAS_CMD(PAS_CMD_BIT, LAM_CMD_BIT, SVA_CMD_BIT),
115434821473SWeihong Zhang 		.test_func = handle_pasid,
115534821473SWeihong Zhang 		.msg = "PASID: [Negative] Execute PASID, LAM, SVA in sequence\n",
115634821473SWeihong Zhang 	},
115734821473SWeihong Zhang 	{
115834821473SWeihong Zhang 		.expected = 0,
115934821473SWeihong Zhang 		.cmd = PAS_CMD(PAS_CMD_BIT, SVA_CMD_BIT, LAM_CMD_BIT),
116034821473SWeihong Zhang 		.test_func = handle_pasid,
116134821473SWeihong Zhang 		.msg = "PASID: Execute PASID, SVA, LAM in sequence\n",
116234821473SWeihong Zhang 	},
116334821473SWeihong Zhang 	{
116434821473SWeihong Zhang 		.expected = 0,
116534821473SWeihong Zhang 		.cmd = PAS_CMD(SVA_CMD_BIT, LAM_CMD_BIT, PAS_CMD_BIT),
116634821473SWeihong Zhang 		.test_func = handle_pasid,
116734821473SWeihong Zhang 		.msg = "PASID: Execute SVA, LAM, PASID in sequence\n",
116834821473SWeihong Zhang 	},
116934821473SWeihong Zhang 	{
117034821473SWeihong Zhang 		.expected = 0,
117134821473SWeihong Zhang 		.cmd = PAS_CMD(SVA_CMD_BIT, PAS_CMD_BIT, LAM_CMD_BIT),
117234821473SWeihong Zhang 		.test_func = handle_pasid,
117334821473SWeihong Zhang 		.msg = "PASID: Execute SVA, PASID, LAM in sequence\n",
117434821473SWeihong Zhang 	},
117534821473SWeihong Zhang };
117634821473SWeihong Zhang 
main(int argc,char ** argv)11773de9745cSWeihong Zhang int main(int argc, char **argv)
11783de9745cSWeihong Zhang {
11793de9745cSWeihong Zhang 	int c = 0;
11803de9745cSWeihong Zhang 	unsigned int tests = TEST_MASK;
11813de9745cSWeihong Zhang 
11823de9745cSWeihong Zhang 	tests_cnt = 0;
11833de9745cSWeihong Zhang 
11843de9745cSWeihong Zhang 	if (!cpu_has_lam()) {
11853de9745cSWeihong Zhang 		ksft_print_msg("Unsupported LAM feature!\n");
11863de9745cSWeihong Zhang 		return -1;
11873de9745cSWeihong Zhang 	}
11883de9745cSWeihong Zhang 
11893de9745cSWeihong Zhang 	while ((c = getopt(argc, argv, "ht:")) != -1) {
11903de9745cSWeihong Zhang 		switch (c) {
11913de9745cSWeihong Zhang 		case 't':
11923de9745cSWeihong Zhang 			tests = strtoul(optarg, NULL, 16);
1193833c12ceSWeihong Zhang 			if (tests && !(tests & TEST_MASK)) {
11943de9745cSWeihong Zhang 				ksft_print_msg("Invalid argument!\n");
11953de9745cSWeihong Zhang 				return -1;
11963de9745cSWeihong Zhang 			}
11973de9745cSWeihong Zhang 			break;
11983de9745cSWeihong Zhang 		case 'h':
11993de9745cSWeihong Zhang 			cmd_help();
12003de9745cSWeihong Zhang 			return 0;
12013de9745cSWeihong Zhang 		default:
12023de9745cSWeihong Zhang 			ksft_print_msg("Invalid argument\n");
12033de9745cSWeihong Zhang 			return -1;
12043de9745cSWeihong Zhang 		}
12053de9745cSWeihong Zhang 	}
12063de9745cSWeihong Zhang 
1207833c12ceSWeihong Zhang 	/*
1208833c12ceSWeihong Zhang 	 * When tests is 0, it is not a real test case;
1209833c12ceSWeihong Zhang 	 * the option used by test case(execve) to check the lam mode in
1210833c12ceSWeihong Zhang 	 * process generated by execve, the process read back lam mode and
1211833c12ceSWeihong Zhang 	 * check with lam mode in parent process.
1212833c12ceSWeihong Zhang 	 */
1213833c12ceSWeihong Zhang 	if (!tests)
1214833c12ceSWeihong Zhang 		return (get_lam());
1215833c12ceSWeihong Zhang 
1216833c12ceSWeihong Zhang 	/* Run test cases */
12173de9745cSWeihong Zhang 	if (tests & FUNC_MALLOC)
12183de9745cSWeihong Zhang 		run_test(malloc_cases, ARRAY_SIZE(malloc_cases));
12193de9745cSWeihong Zhang 
12203de9745cSWeihong Zhang 	if (tests & FUNC_BITS)
12213de9745cSWeihong Zhang 		run_test(bits_cases, ARRAY_SIZE(bits_cases));
12223de9745cSWeihong Zhang 
1223e6787696SWeihong Zhang 	if (tests & FUNC_MMAP)
1224e6787696SWeihong Zhang 		run_test(mmap_cases, ARRAY_SIZE(mmap_cases));
1225e6787696SWeihong Zhang 
1226e6787696SWeihong Zhang 	if (tests & FUNC_SYSCALL)
1227e6787696SWeihong Zhang 		run_test(syscall_cases, ARRAY_SIZE(syscall_cases));
1228e6787696SWeihong Zhang 
122972fd6d73SWeihong Zhang 	if (tests & FUNC_URING)
123072fd6d73SWeihong Zhang 		run_test(uring_cases, ARRAY_SIZE(uring_cases));
123172fd6d73SWeihong Zhang 
1232833c12ceSWeihong Zhang 	if (tests & FUNC_INHERITE)
1233833c12ceSWeihong Zhang 		run_test(inheritance_cases, ARRAY_SIZE(inheritance_cases));
1234833c12ceSWeihong Zhang 
123534821473SWeihong Zhang 	if (tests & FUNC_PASID)
123634821473SWeihong Zhang 		run_test(pasid_cases, ARRAY_SIZE(pasid_cases));
123734821473SWeihong Zhang 
12383de9745cSWeihong Zhang 	ksft_set_plan(tests_cnt);
12393de9745cSWeihong Zhang 
12403de9745cSWeihong Zhang 	return ksft_exit_pass();
12413de9745cSWeihong Zhang }
1242