162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#define _GNU_SOURCE
362306a36Sopenharmony_ci#include <stdio.h>
462306a36Sopenharmony_ci#include <stdlib.h>
562306a36Sopenharmony_ci#include <string.h>
662306a36Sopenharmony_ci#include <sys/syscall.h>
762306a36Sopenharmony_ci#include <time.h>
862306a36Sopenharmony_ci#include <signal.h>
962306a36Sopenharmony_ci#include <setjmp.h>
1062306a36Sopenharmony_ci#include <sys/mman.h>
1162306a36Sopenharmony_ci#include <sys/utsname.h>
1262306a36Sopenharmony_ci#include <sys/wait.h>
1362306a36Sopenharmony_ci#include <sys/stat.h>
1462306a36Sopenharmony_ci#include <fcntl.h>
1562306a36Sopenharmony_ci#include <inttypes.h>
1662306a36Sopenharmony_ci#include <sched.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <sys/uio.h>
1962306a36Sopenharmony_ci#include <linux/io_uring.h>
2062306a36Sopenharmony_ci#include "../kselftest.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#ifndef __x86_64__
2362306a36Sopenharmony_ci# error This test is 64-bit only
2462306a36Sopenharmony_ci#endif
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/* LAM modes, these definitions were copied from kernel code */
2762306a36Sopenharmony_ci#define LAM_NONE                0
2862306a36Sopenharmony_ci#define LAM_U57_BITS            6
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci#define LAM_U57_MASK            (0x3fULL << 57)
3162306a36Sopenharmony_ci/* arch prctl for LAM */
3262306a36Sopenharmony_ci#define ARCH_GET_UNTAG_MASK     0x4001
3362306a36Sopenharmony_ci#define ARCH_ENABLE_TAGGED_ADDR 0x4002
3462306a36Sopenharmony_ci#define ARCH_GET_MAX_TAG_BITS   0x4003
3562306a36Sopenharmony_ci#define ARCH_FORCE_TAGGED_SVA	0x4004
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/* Specified test function bits */
3862306a36Sopenharmony_ci#define FUNC_MALLOC             0x1
3962306a36Sopenharmony_ci#define FUNC_BITS               0x2
4062306a36Sopenharmony_ci#define FUNC_MMAP               0x4
4162306a36Sopenharmony_ci#define FUNC_SYSCALL            0x8
4262306a36Sopenharmony_ci#define FUNC_URING              0x10
4362306a36Sopenharmony_ci#define FUNC_INHERITE           0x20
4462306a36Sopenharmony_ci#define FUNC_PASID              0x40
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci#define TEST_MASK               0x7f
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci#define LOW_ADDR                (0x1UL << 30)
4962306a36Sopenharmony_ci#define HIGH_ADDR               (0x3UL << 48)
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define MALLOC_LEN              32
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define PAGE_SIZE               (4 << 10)
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci#define STACK_SIZE		65536
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci#define barrier() ({						\
5862306a36Sopenharmony_ci		   __asm__ __volatile__("" : : : "memory");	\
5962306a36Sopenharmony_ci})
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci#define URING_QUEUE_SZ 1
6262306a36Sopenharmony_ci#define URING_BLOCK_SZ 2048
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci/* Pasid test define */
6562306a36Sopenharmony_ci#define LAM_CMD_BIT 0x1
6662306a36Sopenharmony_ci#define PAS_CMD_BIT 0x2
6762306a36Sopenharmony_ci#define SVA_CMD_BIT 0x4
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci#define PAS_CMD(cmd1, cmd2, cmd3) (((cmd3) << 8) | ((cmd2) << 4) | ((cmd1) << 0))
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_cistruct testcases {
7262306a36Sopenharmony_ci	unsigned int later;
7362306a36Sopenharmony_ci	int expected; /* 2: SIGSEGV Error; 1: other errors */
7462306a36Sopenharmony_ci	unsigned long lam;
7562306a36Sopenharmony_ci	uint64_t addr;
7662306a36Sopenharmony_ci	uint64_t cmd;
7762306a36Sopenharmony_ci	int (*test_func)(struct testcases *test);
7862306a36Sopenharmony_ci	const char *msg;
7962306a36Sopenharmony_ci};
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci/* Used by CQ of uring, source file handler and file's size */
8262306a36Sopenharmony_cistruct file_io {
8362306a36Sopenharmony_ci	int file_fd;
8462306a36Sopenharmony_ci	off_t file_sz;
8562306a36Sopenharmony_ci	struct iovec iovecs[];
8662306a36Sopenharmony_ci};
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistruct io_uring_queue {
8962306a36Sopenharmony_ci	unsigned int *head;
9062306a36Sopenharmony_ci	unsigned int *tail;
9162306a36Sopenharmony_ci	unsigned int *ring_mask;
9262306a36Sopenharmony_ci	unsigned int *ring_entries;
9362306a36Sopenharmony_ci	unsigned int *flags;
9462306a36Sopenharmony_ci	unsigned int *array;
9562306a36Sopenharmony_ci	union {
9662306a36Sopenharmony_ci		struct io_uring_cqe *cqes;
9762306a36Sopenharmony_ci		struct io_uring_sqe *sqes;
9862306a36Sopenharmony_ci	} queue;
9962306a36Sopenharmony_ci	size_t ring_sz;
10062306a36Sopenharmony_ci};
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistruct io_ring {
10362306a36Sopenharmony_ci	int ring_fd;
10462306a36Sopenharmony_ci	struct io_uring_queue sq_ring;
10562306a36Sopenharmony_ci	struct io_uring_queue cq_ring;
10662306a36Sopenharmony_ci};
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ciint tests_cnt;
10962306a36Sopenharmony_cijmp_buf segv_env;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_cistatic void segv_handler(int sig)
11262306a36Sopenharmony_ci{
11362306a36Sopenharmony_ci	ksft_print_msg("Get segmentation fault(%d).", sig);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	siglongjmp(segv_env, 1);
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_cistatic inline int cpu_has_lam(void)
11962306a36Sopenharmony_ci{
12062306a36Sopenharmony_ci	unsigned int cpuinfo[4];
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	__cpuid_count(0x7, 1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	return (cpuinfo[0] & (1 << 26));
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_ci/* Check 5-level page table feature in CPUID.(EAX=07H, ECX=00H):ECX.[bit 16] */
12862306a36Sopenharmony_cistatic inline int cpu_has_la57(void)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	unsigned int cpuinfo[4];
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	__cpuid_count(0x7, 0, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	return (cpuinfo[2] & (1 << 16));
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci/*
13862306a36Sopenharmony_ci * Set tagged address and read back untag mask.
13962306a36Sopenharmony_ci * check if the untagged mask is expected.
14062306a36Sopenharmony_ci *
14162306a36Sopenharmony_ci * @return:
14262306a36Sopenharmony_ci * 0: Set LAM mode successfully
14362306a36Sopenharmony_ci * others: failed to set LAM
14462306a36Sopenharmony_ci */
14562306a36Sopenharmony_cistatic int set_lam(unsigned long lam)
14662306a36Sopenharmony_ci{
14762306a36Sopenharmony_ci	int ret = 0;
14862306a36Sopenharmony_ci	uint64_t ptr = 0;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	if (lam != LAM_U57_BITS && lam != LAM_NONE)
15162306a36Sopenharmony_ci		return -1;
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* Skip check return */
15462306a36Sopenharmony_ci	syscall(SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, lam);
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	/* Get untagged mask */
15762306a36Sopenharmony_ci	syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	/* Check mask returned is expected */
16062306a36Sopenharmony_ci	if (lam == LAM_U57_BITS)
16162306a36Sopenharmony_ci		ret = (ptr != ~(LAM_U57_MASK));
16262306a36Sopenharmony_ci	else if (lam == LAM_NONE)
16362306a36Sopenharmony_ci		ret = (ptr != -1ULL);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	return ret;
16662306a36Sopenharmony_ci}
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_cistatic unsigned long get_default_tag_bits(void)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	pid_t pid;
17162306a36Sopenharmony_ci	int lam = LAM_NONE;
17262306a36Sopenharmony_ci	int ret = 0;
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	pid = fork();
17562306a36Sopenharmony_ci	if (pid < 0) {
17662306a36Sopenharmony_ci		perror("Fork failed.");
17762306a36Sopenharmony_ci	} else if (pid == 0) {
17862306a36Sopenharmony_ci		/* Set LAM mode in child process */
17962306a36Sopenharmony_ci		if (set_lam(LAM_U57_BITS) == 0)
18062306a36Sopenharmony_ci			lam = LAM_U57_BITS;
18162306a36Sopenharmony_ci		else
18262306a36Sopenharmony_ci			lam = LAM_NONE;
18362306a36Sopenharmony_ci		exit(lam);
18462306a36Sopenharmony_ci	} else {
18562306a36Sopenharmony_ci		wait(&ret);
18662306a36Sopenharmony_ci		lam = WEXITSTATUS(ret);
18762306a36Sopenharmony_ci	}
18862306a36Sopenharmony_ci
18962306a36Sopenharmony_ci	return lam;
19062306a36Sopenharmony_ci}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci/*
19362306a36Sopenharmony_ci * Set tagged address and read back untag mask.
19462306a36Sopenharmony_ci * check if the untag mask is expected.
19562306a36Sopenharmony_ci */
19662306a36Sopenharmony_cistatic int get_lam(void)
19762306a36Sopenharmony_ci{
19862306a36Sopenharmony_ci	uint64_t ptr = 0;
19962306a36Sopenharmony_ci	int ret = -1;
20062306a36Sopenharmony_ci	/* Get untagged mask */
20162306a36Sopenharmony_ci	if (syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr) == -1)
20262306a36Sopenharmony_ci		return -1;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	/* Check mask returned is expected */
20562306a36Sopenharmony_ci	if (ptr == ~(LAM_U57_MASK))
20662306a36Sopenharmony_ci		ret = LAM_U57_BITS;
20762306a36Sopenharmony_ci	else if (ptr == -1ULL)
20862306a36Sopenharmony_ci		ret = LAM_NONE;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	return ret;
21262306a36Sopenharmony_ci}
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci/* According to LAM mode, set metadata in high bits */
21562306a36Sopenharmony_cistatic uint64_t set_metadata(uint64_t src, unsigned long lam)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	uint64_t metadata;
21862306a36Sopenharmony_ci
21962306a36Sopenharmony_ci	srand(time(NULL));
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	switch (lam) {
22262306a36Sopenharmony_ci	case LAM_U57_BITS: /* Set metadata in bits 62:57 */
22362306a36Sopenharmony_ci		/* Get a random non-zero value as metadata */
22462306a36Sopenharmony_ci		metadata = (rand() % ((1UL << LAM_U57_BITS) - 1) + 1) << 57;
22562306a36Sopenharmony_ci		metadata |= (src & ~(LAM_U57_MASK));
22662306a36Sopenharmony_ci		break;
22762306a36Sopenharmony_ci	default:
22862306a36Sopenharmony_ci		metadata = src;
22962306a36Sopenharmony_ci		break;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	return metadata;
23362306a36Sopenharmony_ci}
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci/*
23662306a36Sopenharmony_ci * Set metadata in user pointer, compare new pointer with original pointer.
23762306a36Sopenharmony_ci * both pointers should point to the same address.
23862306a36Sopenharmony_ci *
23962306a36Sopenharmony_ci * @return:
24062306a36Sopenharmony_ci * 0: value on the pointer with metadate and value on original are same
24162306a36Sopenharmony_ci * 1: not same.
24262306a36Sopenharmony_ci */
24362306a36Sopenharmony_cistatic int handle_lam_test(void *src, unsigned int lam)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	char *ptr;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci	strcpy((char *)src, "USER POINTER");
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	ptr = (char *)set_metadata((uint64_t)src, lam);
25062306a36Sopenharmony_ci	if (src == ptr)
25162306a36Sopenharmony_ci		return 0;
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_ci	/* Copy a string into the pointer with metadata */
25462306a36Sopenharmony_ci	strcpy((char *)ptr, "METADATA POINTER");
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci	return (!!strcmp((char *)src, (char *)ptr));
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ciint handle_max_bits(struct testcases *test)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	unsigned long exp_bits = get_default_tag_bits();
26362306a36Sopenharmony_ci	unsigned long bits = 0;
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_ci	if (exp_bits != LAM_NONE)
26662306a36Sopenharmony_ci		exp_bits = LAM_U57_BITS;
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	/* Get LAM max tag bits */
26962306a36Sopenharmony_ci	if (syscall(SYS_arch_prctl, ARCH_GET_MAX_TAG_BITS, &bits) == -1)
27062306a36Sopenharmony_ci		return 1;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci	return (exp_bits != bits);
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci/*
27662306a36Sopenharmony_ci * Test lam feature through dereference pointer get from malloc.
27762306a36Sopenharmony_ci * @return 0: Pass test. 1: Get failure during test 2: Get SIGSEGV
27862306a36Sopenharmony_ci */
27962306a36Sopenharmony_cistatic int handle_malloc(struct testcases *test)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	char *ptr = NULL;
28262306a36Sopenharmony_ci	int ret = 0;
28362306a36Sopenharmony_ci
28462306a36Sopenharmony_ci	if (test->later == 0 && test->lam != 0)
28562306a36Sopenharmony_ci		if (set_lam(test->lam) == -1)
28662306a36Sopenharmony_ci			return 1;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	ptr = (char *)malloc(MALLOC_LEN);
28962306a36Sopenharmony_ci	if (ptr == NULL) {
29062306a36Sopenharmony_ci		perror("malloc() failure\n");
29162306a36Sopenharmony_ci		return 1;
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* Set signal handler */
29562306a36Sopenharmony_ci	if (sigsetjmp(segv_env, 1) == 0) {
29662306a36Sopenharmony_ci		signal(SIGSEGV, segv_handler);
29762306a36Sopenharmony_ci		ret = handle_lam_test(ptr, test->lam);
29862306a36Sopenharmony_ci	} else {
29962306a36Sopenharmony_ci		ret = 2;
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	if (test->later != 0 && test->lam != 0)
30362306a36Sopenharmony_ci		if (set_lam(test->lam) == -1 && ret == 0)
30462306a36Sopenharmony_ci			ret = 1;
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_ci	free(ptr);
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	return ret;
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic int handle_mmap(struct testcases *test)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	void *ptr;
31462306a36Sopenharmony_ci	unsigned int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
31562306a36Sopenharmony_ci	int ret = 0;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	if (test->later == 0 && test->lam != 0)
31862306a36Sopenharmony_ci		if (set_lam(test->lam) != 0)
31962306a36Sopenharmony_ci			return 1;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	ptr = mmap((void *)test->addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
32262306a36Sopenharmony_ci		   flags, -1, 0);
32362306a36Sopenharmony_ci	if (ptr == MAP_FAILED) {
32462306a36Sopenharmony_ci		if (test->addr == HIGH_ADDR)
32562306a36Sopenharmony_ci			if (!cpu_has_la57())
32662306a36Sopenharmony_ci				return 3; /* unsupport LA57 */
32762306a36Sopenharmony_ci		return 1;
32862306a36Sopenharmony_ci	}
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	if (test->later != 0 && test->lam != 0)
33162306a36Sopenharmony_ci		if (set_lam(test->lam) != 0)
33262306a36Sopenharmony_ci			ret = 1;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (ret == 0) {
33562306a36Sopenharmony_ci		if (sigsetjmp(segv_env, 1) == 0) {
33662306a36Sopenharmony_ci			signal(SIGSEGV, segv_handler);
33762306a36Sopenharmony_ci			ret = handle_lam_test(ptr, test->lam);
33862306a36Sopenharmony_ci		} else {
33962306a36Sopenharmony_ci			ret = 2;
34062306a36Sopenharmony_ci		}
34162306a36Sopenharmony_ci	}
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	munmap(ptr, PAGE_SIZE);
34462306a36Sopenharmony_ci	return ret;
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int handle_syscall(struct testcases *test)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct utsname unme, *pu;
35062306a36Sopenharmony_ci	int ret = 0;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	if (test->later == 0 && test->lam != 0)
35362306a36Sopenharmony_ci		if (set_lam(test->lam) != 0)
35462306a36Sopenharmony_ci			return 1;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	if (sigsetjmp(segv_env, 1) == 0) {
35762306a36Sopenharmony_ci		signal(SIGSEGV, segv_handler);
35862306a36Sopenharmony_ci		pu = (struct utsname *)set_metadata((uint64_t)&unme, test->lam);
35962306a36Sopenharmony_ci		ret = uname(pu);
36062306a36Sopenharmony_ci		if (ret < 0)
36162306a36Sopenharmony_ci			ret = 1;
36262306a36Sopenharmony_ci	} else {
36362306a36Sopenharmony_ci		ret = 2;
36462306a36Sopenharmony_ci	}
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	if (test->later != 0 && test->lam != 0)
36762306a36Sopenharmony_ci		if (set_lam(test->lam) != -1 && ret == 0)
36862306a36Sopenharmony_ci			ret = 1;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	return ret;
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_ciint sys_uring_setup(unsigned int entries, struct io_uring_params *p)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	return (int)syscall(__NR_io_uring_setup, entries, p);
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ciint sys_uring_enter(int fd, unsigned int to, unsigned int min, unsigned int flags)
37962306a36Sopenharmony_ci{
38062306a36Sopenharmony_ci	return (int)syscall(__NR_io_uring_enter, fd, to, min, flags, NULL, 0);
38162306a36Sopenharmony_ci}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci/* Init submission queue and completion queue */
38462306a36Sopenharmony_ciint mmap_io_uring(struct io_uring_params p, struct io_ring *s)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct io_uring_queue *sring = &s->sq_ring;
38762306a36Sopenharmony_ci	struct io_uring_queue *cring = &s->cq_ring;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	sring->ring_sz = p.sq_off.array + p.sq_entries * sizeof(unsigned int);
39062306a36Sopenharmony_ci	cring->ring_sz = p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	if (p.features & IORING_FEAT_SINGLE_MMAP) {
39362306a36Sopenharmony_ci		if (cring->ring_sz > sring->ring_sz)
39462306a36Sopenharmony_ci			sring->ring_sz = cring->ring_sz;
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci		cring->ring_sz = sring->ring_sz;
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	void *sq_ptr = mmap(0, sring->ring_sz, PROT_READ | PROT_WRITE,
40062306a36Sopenharmony_ci			    MAP_SHARED | MAP_POPULATE, s->ring_fd,
40162306a36Sopenharmony_ci			    IORING_OFF_SQ_RING);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (sq_ptr == MAP_FAILED) {
40462306a36Sopenharmony_ci		perror("sub-queue!");
40562306a36Sopenharmony_ci		return 1;
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	void *cq_ptr = sq_ptr;
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	if (!(p.features & IORING_FEAT_SINGLE_MMAP)) {
41162306a36Sopenharmony_ci		cq_ptr = mmap(0, cring->ring_sz, PROT_READ | PROT_WRITE,
41262306a36Sopenharmony_ci			      MAP_SHARED | MAP_POPULATE, s->ring_fd,
41362306a36Sopenharmony_ci			      IORING_OFF_CQ_RING);
41462306a36Sopenharmony_ci		if (cq_ptr == MAP_FAILED) {
41562306a36Sopenharmony_ci			perror("cpl-queue!");
41662306a36Sopenharmony_ci			munmap(sq_ptr, sring->ring_sz);
41762306a36Sopenharmony_ci			return 1;
41862306a36Sopenharmony_ci		}
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	sring->head = sq_ptr + p.sq_off.head;
42262306a36Sopenharmony_ci	sring->tail = sq_ptr + p.sq_off.tail;
42362306a36Sopenharmony_ci	sring->ring_mask = sq_ptr + p.sq_off.ring_mask;
42462306a36Sopenharmony_ci	sring->ring_entries = sq_ptr + p.sq_off.ring_entries;
42562306a36Sopenharmony_ci	sring->flags = sq_ptr + p.sq_off.flags;
42662306a36Sopenharmony_ci	sring->array = sq_ptr + p.sq_off.array;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	/* Map a queue as mem map */
42962306a36Sopenharmony_ci	s->sq_ring.queue.sqes = mmap(0, p.sq_entries * sizeof(struct io_uring_sqe),
43062306a36Sopenharmony_ci				     PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
43162306a36Sopenharmony_ci				     s->ring_fd, IORING_OFF_SQES);
43262306a36Sopenharmony_ci	if (s->sq_ring.queue.sqes == MAP_FAILED) {
43362306a36Sopenharmony_ci		munmap(sq_ptr, sring->ring_sz);
43462306a36Sopenharmony_ci		if (sq_ptr != cq_ptr) {
43562306a36Sopenharmony_ci			ksft_print_msg("failed to mmap uring queue!");
43662306a36Sopenharmony_ci			munmap(cq_ptr, cring->ring_sz);
43762306a36Sopenharmony_ci			return 1;
43862306a36Sopenharmony_ci		}
43962306a36Sopenharmony_ci	}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	cring->head = cq_ptr + p.cq_off.head;
44262306a36Sopenharmony_ci	cring->tail = cq_ptr + p.cq_off.tail;
44362306a36Sopenharmony_ci	cring->ring_mask = cq_ptr + p.cq_off.ring_mask;
44462306a36Sopenharmony_ci	cring->ring_entries = cq_ptr + p.cq_off.ring_entries;
44562306a36Sopenharmony_ci	cring->queue.cqes = cq_ptr + p.cq_off.cqes;
44662306a36Sopenharmony_ci
44762306a36Sopenharmony_ci	return 0;
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci/* Init io_uring queues */
45162306a36Sopenharmony_ciint setup_io_uring(struct io_ring *s)
45262306a36Sopenharmony_ci{
45362306a36Sopenharmony_ci	struct io_uring_params para;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	memset(&para, 0, sizeof(para));
45662306a36Sopenharmony_ci	s->ring_fd = sys_uring_setup(URING_QUEUE_SZ, &para);
45762306a36Sopenharmony_ci	if (s->ring_fd < 0)
45862306a36Sopenharmony_ci		return 1;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci	return mmap_io_uring(para, s);
46162306a36Sopenharmony_ci}
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci/*
46462306a36Sopenharmony_ci * Get data from completion queue. the data buffer saved the file data
46562306a36Sopenharmony_ci * return 0: success; others: error;
46662306a36Sopenharmony_ci */
46762306a36Sopenharmony_ciint handle_uring_cq(struct io_ring *s)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct file_io *fi = NULL;
47062306a36Sopenharmony_ci	struct io_uring_queue *cring = &s->cq_ring;
47162306a36Sopenharmony_ci	struct io_uring_cqe *cqe;
47262306a36Sopenharmony_ci	unsigned int head;
47362306a36Sopenharmony_ci	off_t len = 0;
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	head = *cring->head;
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	do {
47862306a36Sopenharmony_ci		barrier();
47962306a36Sopenharmony_ci		if (head == *cring->tail)
48062306a36Sopenharmony_ci			break;
48162306a36Sopenharmony_ci		/* Get the entry */
48262306a36Sopenharmony_ci		cqe = &cring->queue.cqes[head & *s->cq_ring.ring_mask];
48362306a36Sopenharmony_ci		fi = (struct file_io *)cqe->user_data;
48462306a36Sopenharmony_ci		if (cqe->res < 0)
48562306a36Sopenharmony_ci			break;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci		int blocks = (int)(fi->file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
48862306a36Sopenharmony_ci
48962306a36Sopenharmony_ci		for (int i = 0; i < blocks; i++)
49062306a36Sopenharmony_ci			len += fi->iovecs[i].iov_len;
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci		head++;
49362306a36Sopenharmony_ci	} while (1);
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	*cring->head = head;
49662306a36Sopenharmony_ci	barrier();
49762306a36Sopenharmony_ci
49862306a36Sopenharmony_ci	return (len != fi->file_sz);
49962306a36Sopenharmony_ci}
50062306a36Sopenharmony_ci
50162306a36Sopenharmony_ci/*
50262306a36Sopenharmony_ci * Submit squeue. specify via IORING_OP_READV.
50362306a36Sopenharmony_ci * the buffer need to be set metadata according to LAM mode
50462306a36Sopenharmony_ci */
50562306a36Sopenharmony_ciint handle_uring_sq(struct io_ring *ring, struct file_io *fi, unsigned long lam)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	int file_fd = fi->file_fd;
50862306a36Sopenharmony_ci	struct io_uring_queue *sring = &ring->sq_ring;
50962306a36Sopenharmony_ci	unsigned int index = 0, cur_block = 0, tail = 0, next_tail = 0;
51062306a36Sopenharmony_ci	struct io_uring_sqe *sqe;
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	off_t remain = fi->file_sz;
51362306a36Sopenharmony_ci	int blocks = (int)(remain + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci	while (remain) {
51662306a36Sopenharmony_ci		off_t bytes = remain;
51762306a36Sopenharmony_ci		void *buf;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci		if (bytes > URING_BLOCK_SZ)
52062306a36Sopenharmony_ci			bytes = URING_BLOCK_SZ;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci		fi->iovecs[cur_block].iov_len = bytes;
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci		if (posix_memalign(&buf, URING_BLOCK_SZ, URING_BLOCK_SZ))
52562306a36Sopenharmony_ci			return 1;
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci		fi->iovecs[cur_block].iov_base = (void *)set_metadata((uint64_t)buf, lam);
52862306a36Sopenharmony_ci		remain -= bytes;
52962306a36Sopenharmony_ci		cur_block++;
53062306a36Sopenharmony_ci	}
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	next_tail = *sring->tail;
53362306a36Sopenharmony_ci	tail = next_tail;
53462306a36Sopenharmony_ci	next_tail++;
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	barrier();
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_ci	index = tail & *ring->sq_ring.ring_mask;
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_ci	sqe = &ring->sq_ring.queue.sqes[index];
54162306a36Sopenharmony_ci	sqe->fd = file_fd;
54262306a36Sopenharmony_ci	sqe->flags = 0;
54362306a36Sopenharmony_ci	sqe->opcode = IORING_OP_READV;
54462306a36Sopenharmony_ci	sqe->addr = (unsigned long)fi->iovecs;
54562306a36Sopenharmony_ci	sqe->len = blocks;
54662306a36Sopenharmony_ci	sqe->off = 0;
54762306a36Sopenharmony_ci	sqe->user_data = (uint64_t)fi;
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	sring->array[index] = index;
55062306a36Sopenharmony_ci	tail = next_tail;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	if (*sring->tail != tail) {
55362306a36Sopenharmony_ci		*sring->tail = tail;
55462306a36Sopenharmony_ci		barrier();
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (sys_uring_enter(ring->ring_fd, 1, 1, IORING_ENTER_GETEVENTS) < 0)
55862306a36Sopenharmony_ci		return 1;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	return 0;
56162306a36Sopenharmony_ci}
56262306a36Sopenharmony_ci
56362306a36Sopenharmony_ci/*
56462306a36Sopenharmony_ci * Test LAM in async I/O and io_uring, read current binery through io_uring
56562306a36Sopenharmony_ci * Set metadata in pointers to iovecs buffer.
56662306a36Sopenharmony_ci */
56762306a36Sopenharmony_ciint do_uring(unsigned long lam)
56862306a36Sopenharmony_ci{
56962306a36Sopenharmony_ci	struct io_ring *ring;
57062306a36Sopenharmony_ci	struct file_io *fi;
57162306a36Sopenharmony_ci	struct stat st;
57262306a36Sopenharmony_ci	int ret = 1;
57362306a36Sopenharmony_ci	char path[PATH_MAX] = {0};
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	/* get current process path */
57662306a36Sopenharmony_ci	if (readlink("/proc/self/exe", path, PATH_MAX - 1) <= 0)
57762306a36Sopenharmony_ci		return 1;
57862306a36Sopenharmony_ci
57962306a36Sopenharmony_ci	int file_fd = open(path, O_RDONLY);
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ci	if (file_fd < 0)
58262306a36Sopenharmony_ci		return 1;
58362306a36Sopenharmony_ci
58462306a36Sopenharmony_ci	if (fstat(file_fd, &st) < 0)
58562306a36Sopenharmony_ci		return 1;
58662306a36Sopenharmony_ci
58762306a36Sopenharmony_ci	off_t file_sz = st.st_size;
58862306a36Sopenharmony_ci
58962306a36Sopenharmony_ci	int blocks = (int)(file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	fi = malloc(sizeof(*fi) + sizeof(struct iovec) * blocks);
59262306a36Sopenharmony_ci	if (!fi)
59362306a36Sopenharmony_ci		return 1;
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	fi->file_sz = file_sz;
59662306a36Sopenharmony_ci	fi->file_fd = file_fd;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	ring = malloc(sizeof(*ring));
59962306a36Sopenharmony_ci	if (!ring)
60062306a36Sopenharmony_ci		return 1;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	memset(ring, 0, sizeof(struct io_ring));
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (setup_io_uring(ring))
60562306a36Sopenharmony_ci		goto out;
60662306a36Sopenharmony_ci
60762306a36Sopenharmony_ci	if (handle_uring_sq(ring, fi, lam))
60862306a36Sopenharmony_ci		goto out;
60962306a36Sopenharmony_ci
61062306a36Sopenharmony_ci	ret = handle_uring_cq(ring);
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ciout:
61362306a36Sopenharmony_ci	free(ring);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	for (int i = 0; i < blocks; i++) {
61662306a36Sopenharmony_ci		if (fi->iovecs[i].iov_base) {
61762306a36Sopenharmony_ci			uint64_t addr = ((uint64_t)fi->iovecs[i].iov_base);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci			switch (lam) {
62062306a36Sopenharmony_ci			case LAM_U57_BITS: /* Clear bits 62:57 */
62162306a36Sopenharmony_ci				addr = (addr & ~(LAM_U57_MASK));
62262306a36Sopenharmony_ci				break;
62362306a36Sopenharmony_ci			}
62462306a36Sopenharmony_ci			free((void *)addr);
62562306a36Sopenharmony_ci			fi->iovecs[i].iov_base = NULL;
62662306a36Sopenharmony_ci		}
62762306a36Sopenharmony_ci	}
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	free(fi);
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	return ret;
63262306a36Sopenharmony_ci}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ciint handle_uring(struct testcases *test)
63562306a36Sopenharmony_ci{
63662306a36Sopenharmony_ci	int ret = 0;
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	if (test->later == 0 && test->lam != 0)
63962306a36Sopenharmony_ci		if (set_lam(test->lam) != 0)
64062306a36Sopenharmony_ci			return 1;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	if (sigsetjmp(segv_env, 1) == 0) {
64362306a36Sopenharmony_ci		signal(SIGSEGV, segv_handler);
64462306a36Sopenharmony_ci		ret = do_uring(test->lam);
64562306a36Sopenharmony_ci	} else {
64662306a36Sopenharmony_ci		ret = 2;
64762306a36Sopenharmony_ci	}
64862306a36Sopenharmony_ci
64962306a36Sopenharmony_ci	return ret;
65062306a36Sopenharmony_ci}
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_cistatic int fork_test(struct testcases *test)
65362306a36Sopenharmony_ci{
65462306a36Sopenharmony_ci	int ret, child_ret;
65562306a36Sopenharmony_ci	pid_t pid;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	pid = fork();
65862306a36Sopenharmony_ci	if (pid < 0) {
65962306a36Sopenharmony_ci		perror("Fork failed.");
66062306a36Sopenharmony_ci		ret = 1;
66162306a36Sopenharmony_ci	} else if (pid == 0) {
66262306a36Sopenharmony_ci		ret = test->test_func(test);
66362306a36Sopenharmony_ci		exit(ret);
66462306a36Sopenharmony_ci	} else {
66562306a36Sopenharmony_ci		wait(&child_ret);
66662306a36Sopenharmony_ci		ret = WEXITSTATUS(child_ret);
66762306a36Sopenharmony_ci	}
66862306a36Sopenharmony_ci
66962306a36Sopenharmony_ci	return ret;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_cistatic int handle_execve(struct testcases *test)
67362306a36Sopenharmony_ci{
67462306a36Sopenharmony_ci	int ret, child_ret;
67562306a36Sopenharmony_ci	int lam = test->lam;
67662306a36Sopenharmony_ci	pid_t pid;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	pid = fork();
67962306a36Sopenharmony_ci	if (pid < 0) {
68062306a36Sopenharmony_ci		perror("Fork failed.");
68162306a36Sopenharmony_ci		ret = 1;
68262306a36Sopenharmony_ci	} else if (pid == 0) {
68362306a36Sopenharmony_ci		char path[PATH_MAX] = {0};
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci		/* Set LAM mode in parent process */
68662306a36Sopenharmony_ci		if (set_lam(lam) != 0)
68762306a36Sopenharmony_ci			return 1;
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci		/* Get current binary's path and the binary was run by execve */
69062306a36Sopenharmony_ci		if (readlink("/proc/self/exe", path, PATH_MAX - 1) <= 0)
69162306a36Sopenharmony_ci			exit(-1);
69262306a36Sopenharmony_ci
69362306a36Sopenharmony_ci		/* run binary to get LAM mode and return to parent process */
69462306a36Sopenharmony_ci		if (execlp(path, path, "-t 0x0", NULL) < 0) {
69562306a36Sopenharmony_ci			perror("error on exec");
69662306a36Sopenharmony_ci			exit(-1);
69762306a36Sopenharmony_ci		}
69862306a36Sopenharmony_ci	} else {
69962306a36Sopenharmony_ci		wait(&child_ret);
70062306a36Sopenharmony_ci		ret = WEXITSTATUS(child_ret);
70162306a36Sopenharmony_ci		if (ret != LAM_NONE)
70262306a36Sopenharmony_ci			return 1;
70362306a36Sopenharmony_ci	}
70462306a36Sopenharmony_ci
70562306a36Sopenharmony_ci	return 0;
70662306a36Sopenharmony_ci}
70762306a36Sopenharmony_ci
70862306a36Sopenharmony_cistatic int handle_inheritance(struct testcases *test)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	int ret, child_ret;
71162306a36Sopenharmony_ci	int lam = test->lam;
71262306a36Sopenharmony_ci	pid_t pid;
71362306a36Sopenharmony_ci
71462306a36Sopenharmony_ci	/* Set LAM mode in parent process */
71562306a36Sopenharmony_ci	if (set_lam(lam) != 0)
71662306a36Sopenharmony_ci		return 1;
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	pid = fork();
71962306a36Sopenharmony_ci	if (pid < 0) {
72062306a36Sopenharmony_ci		perror("Fork failed.");
72162306a36Sopenharmony_ci		return 1;
72262306a36Sopenharmony_ci	} else if (pid == 0) {
72362306a36Sopenharmony_ci		/* Set LAM mode in parent process */
72462306a36Sopenharmony_ci		int child_lam = get_lam();
72562306a36Sopenharmony_ci
72662306a36Sopenharmony_ci		exit(child_lam);
72762306a36Sopenharmony_ci	} else {
72862306a36Sopenharmony_ci		wait(&child_ret);
72962306a36Sopenharmony_ci		ret = WEXITSTATUS(child_ret);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci		if (lam != ret)
73262306a36Sopenharmony_ci			return 1;
73362306a36Sopenharmony_ci	}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci	return 0;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic int thread_fn_get_lam(void *arg)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	return get_lam();
74162306a36Sopenharmony_ci}
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_cistatic int thread_fn_set_lam(void *arg)
74462306a36Sopenharmony_ci{
74562306a36Sopenharmony_ci	struct testcases *test = arg;
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	return set_lam(test->lam);
74862306a36Sopenharmony_ci}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_cistatic int handle_thread(struct testcases *test)
75162306a36Sopenharmony_ci{
75262306a36Sopenharmony_ci	char stack[STACK_SIZE];
75362306a36Sopenharmony_ci	int ret, child_ret;
75462306a36Sopenharmony_ci	int lam = 0;
75562306a36Sopenharmony_ci	pid_t pid;
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	/* Set LAM mode in parent process */
75862306a36Sopenharmony_ci	if (!test->later) {
75962306a36Sopenharmony_ci		lam = test->lam;
76062306a36Sopenharmony_ci		if (set_lam(lam) != 0)
76162306a36Sopenharmony_ci			return 1;
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_ci	pid = clone(thread_fn_get_lam, stack + STACK_SIZE,
76562306a36Sopenharmony_ci		    SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, NULL);
76662306a36Sopenharmony_ci	if (pid < 0) {
76762306a36Sopenharmony_ci		perror("Clone failed.");
76862306a36Sopenharmony_ci		return 1;
76962306a36Sopenharmony_ci	}
77062306a36Sopenharmony_ci
77162306a36Sopenharmony_ci	waitpid(pid, &child_ret, 0);
77262306a36Sopenharmony_ci	ret = WEXITSTATUS(child_ret);
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_ci	if (lam != ret)
77562306a36Sopenharmony_ci		return 1;
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	if (test->later) {
77862306a36Sopenharmony_ci		if (set_lam(test->lam) != 0)
77962306a36Sopenharmony_ci			return 1;
78062306a36Sopenharmony_ci	}
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	return 0;
78362306a36Sopenharmony_ci}
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_cistatic int handle_thread_enable(struct testcases *test)
78662306a36Sopenharmony_ci{
78762306a36Sopenharmony_ci	char stack[STACK_SIZE];
78862306a36Sopenharmony_ci	int ret, child_ret;
78962306a36Sopenharmony_ci	int lam = test->lam;
79062306a36Sopenharmony_ci	pid_t pid;
79162306a36Sopenharmony_ci
79262306a36Sopenharmony_ci	pid = clone(thread_fn_set_lam, stack + STACK_SIZE,
79362306a36Sopenharmony_ci		    SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, test);
79462306a36Sopenharmony_ci	if (pid < 0) {
79562306a36Sopenharmony_ci		perror("Clone failed.");
79662306a36Sopenharmony_ci		return 1;
79762306a36Sopenharmony_ci	}
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	waitpid(pid, &child_ret, 0);
80062306a36Sopenharmony_ci	ret = WEXITSTATUS(child_ret);
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	if (lam != ret)
80362306a36Sopenharmony_ci		return 1;
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci	return 0;
80662306a36Sopenharmony_ci}
80762306a36Sopenharmony_cistatic void run_test(struct testcases *test, int count)
80862306a36Sopenharmony_ci{
80962306a36Sopenharmony_ci	int i, ret = 0;
81062306a36Sopenharmony_ci
81162306a36Sopenharmony_ci	for (i = 0; i < count; i++) {
81262306a36Sopenharmony_ci		struct testcases *t = test + i;
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_ci		/* fork a process to run test case */
81562306a36Sopenharmony_ci		tests_cnt++;
81662306a36Sopenharmony_ci		ret = fork_test(t);
81762306a36Sopenharmony_ci
81862306a36Sopenharmony_ci		/* return 3 is not support LA57, the case should be skipped */
81962306a36Sopenharmony_ci		if (ret == 3) {
82062306a36Sopenharmony_ci			ksft_test_result_skip(t->msg);
82162306a36Sopenharmony_ci			continue;
82262306a36Sopenharmony_ci		}
82362306a36Sopenharmony_ci
82462306a36Sopenharmony_ci		if (ret != 0)
82562306a36Sopenharmony_ci			ret = (t->expected == ret);
82662306a36Sopenharmony_ci		else
82762306a36Sopenharmony_ci			ret = !(t->expected);
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci		ksft_test_result(ret, t->msg);
83062306a36Sopenharmony_ci	}
83162306a36Sopenharmony_ci}
83262306a36Sopenharmony_ci
83362306a36Sopenharmony_cistatic struct testcases uring_cases[] = {
83462306a36Sopenharmony_ci	{
83562306a36Sopenharmony_ci		.later = 0,
83662306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
83762306a36Sopenharmony_ci		.test_func = handle_uring,
83862306a36Sopenharmony_ci		.msg = "URING: LAM_U57. Dereferencing pointer with metadata\n",
83962306a36Sopenharmony_ci	},
84062306a36Sopenharmony_ci	{
84162306a36Sopenharmony_ci		.later = 1,
84262306a36Sopenharmony_ci		.expected = 1,
84362306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
84462306a36Sopenharmony_ci		.test_func = handle_uring,
84562306a36Sopenharmony_ci		.msg = "URING:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
84662306a36Sopenharmony_ci	},
84762306a36Sopenharmony_ci};
84862306a36Sopenharmony_ci
84962306a36Sopenharmony_cistatic struct testcases malloc_cases[] = {
85062306a36Sopenharmony_ci	{
85162306a36Sopenharmony_ci		.later = 0,
85262306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
85362306a36Sopenharmony_ci		.test_func = handle_malloc,
85462306a36Sopenharmony_ci		.msg = "MALLOC: LAM_U57. Dereferencing pointer with metadata\n",
85562306a36Sopenharmony_ci	},
85662306a36Sopenharmony_ci	{
85762306a36Sopenharmony_ci		.later = 1,
85862306a36Sopenharmony_ci		.expected = 2,
85962306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
86062306a36Sopenharmony_ci		.test_func = handle_malloc,
86162306a36Sopenharmony_ci		.msg = "MALLOC:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
86262306a36Sopenharmony_ci	},
86362306a36Sopenharmony_ci};
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_cistatic struct testcases bits_cases[] = {
86662306a36Sopenharmony_ci	{
86762306a36Sopenharmony_ci		.test_func = handle_max_bits,
86862306a36Sopenharmony_ci		.msg = "BITS: Check default tag bits\n",
86962306a36Sopenharmony_ci	},
87062306a36Sopenharmony_ci};
87162306a36Sopenharmony_ci
87262306a36Sopenharmony_cistatic struct testcases syscall_cases[] = {
87362306a36Sopenharmony_ci	{
87462306a36Sopenharmony_ci		.later = 0,
87562306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
87662306a36Sopenharmony_ci		.test_func = handle_syscall,
87762306a36Sopenharmony_ci		.msg = "SYSCALL: LAM_U57. syscall with metadata\n",
87862306a36Sopenharmony_ci	},
87962306a36Sopenharmony_ci	{
88062306a36Sopenharmony_ci		.later = 1,
88162306a36Sopenharmony_ci		.expected = 1,
88262306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
88362306a36Sopenharmony_ci		.test_func = handle_syscall,
88462306a36Sopenharmony_ci		.msg = "SYSCALL:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
88562306a36Sopenharmony_ci	},
88662306a36Sopenharmony_ci};
88762306a36Sopenharmony_ci
88862306a36Sopenharmony_cistatic struct testcases mmap_cases[] = {
88962306a36Sopenharmony_ci	{
89062306a36Sopenharmony_ci		.later = 1,
89162306a36Sopenharmony_ci		.expected = 0,
89262306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
89362306a36Sopenharmony_ci		.addr = HIGH_ADDR,
89462306a36Sopenharmony_ci		.test_func = handle_mmap,
89562306a36Sopenharmony_ci		.msg = "MMAP: First mmap high address, then set LAM_U57.\n",
89662306a36Sopenharmony_ci	},
89762306a36Sopenharmony_ci	{
89862306a36Sopenharmony_ci		.later = 0,
89962306a36Sopenharmony_ci		.expected = 0,
90062306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
90162306a36Sopenharmony_ci		.addr = HIGH_ADDR,
90262306a36Sopenharmony_ci		.test_func = handle_mmap,
90362306a36Sopenharmony_ci		.msg = "MMAP: First LAM_U57, then High address.\n",
90462306a36Sopenharmony_ci	},
90562306a36Sopenharmony_ci	{
90662306a36Sopenharmony_ci		.later = 0,
90762306a36Sopenharmony_ci		.expected = 0,
90862306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
90962306a36Sopenharmony_ci		.addr = LOW_ADDR,
91062306a36Sopenharmony_ci		.test_func = handle_mmap,
91162306a36Sopenharmony_ci		.msg = "MMAP: First LAM_U57, then Low address.\n",
91262306a36Sopenharmony_ci	},
91362306a36Sopenharmony_ci};
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_cistatic struct testcases inheritance_cases[] = {
91662306a36Sopenharmony_ci	{
91762306a36Sopenharmony_ci		.expected = 0,
91862306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
91962306a36Sopenharmony_ci		.test_func = handle_inheritance,
92062306a36Sopenharmony_ci		.msg = "FORK: LAM_U57, child process should get LAM mode same as parent\n",
92162306a36Sopenharmony_ci	},
92262306a36Sopenharmony_ci	{
92362306a36Sopenharmony_ci		.expected = 0,
92462306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
92562306a36Sopenharmony_ci		.test_func = handle_thread,
92662306a36Sopenharmony_ci		.msg = "THREAD: LAM_U57, child thread should get LAM mode same as parent\n",
92762306a36Sopenharmony_ci	},
92862306a36Sopenharmony_ci	{
92962306a36Sopenharmony_ci		.expected = 1,
93062306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
93162306a36Sopenharmony_ci		.test_func = handle_thread_enable,
93262306a36Sopenharmony_ci		.msg = "THREAD: [NEGATIVE] Enable LAM in child.\n",
93362306a36Sopenharmony_ci	},
93462306a36Sopenharmony_ci	{
93562306a36Sopenharmony_ci		.expected = 1,
93662306a36Sopenharmony_ci		.later = 1,
93762306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
93862306a36Sopenharmony_ci		.test_func = handle_thread,
93962306a36Sopenharmony_ci		.msg = "THREAD: [NEGATIVE] Enable LAM in parent after thread created.\n",
94062306a36Sopenharmony_ci	},
94162306a36Sopenharmony_ci	{
94262306a36Sopenharmony_ci		.expected = 0,
94362306a36Sopenharmony_ci		.lam = LAM_U57_BITS,
94462306a36Sopenharmony_ci		.test_func = handle_execve,
94562306a36Sopenharmony_ci		.msg = "EXECVE: LAM_U57, child process should get disabled LAM mode\n",
94662306a36Sopenharmony_ci	},
94762306a36Sopenharmony_ci};
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_cistatic void cmd_help(void)
95062306a36Sopenharmony_ci{
95162306a36Sopenharmony_ci	printf("usage: lam [-h] [-t test list]\n");
95262306a36Sopenharmony_ci	printf("\t-t test list: run tests specified in the test list, default:0x%x\n", TEST_MASK);
95362306a36Sopenharmony_ci	printf("\t\t0x1:malloc; 0x2:max_bits; 0x4:mmap; 0x8:syscall; 0x10:io_uring; 0x20:inherit;\n");
95462306a36Sopenharmony_ci	printf("\t-h: help\n");
95562306a36Sopenharmony_ci}
95662306a36Sopenharmony_ci
95762306a36Sopenharmony_ci/* Check for file existence */
95862306a36Sopenharmony_ciuint8_t file_Exists(const char *fileName)
95962306a36Sopenharmony_ci{
96062306a36Sopenharmony_ci	struct stat buffer;
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	uint8_t ret = (stat(fileName, &buffer) == 0);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	return ret;
96562306a36Sopenharmony_ci}
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_ci/* Sysfs idxd files */
96862306a36Sopenharmony_ciconst char *dsa_configs[] = {
96962306a36Sopenharmony_ci	"echo 1 > /sys/bus/dsa/devices/dsa0/wq0.1/group_id",
97062306a36Sopenharmony_ci	"echo shared > /sys/bus/dsa/devices/dsa0/wq0.1/mode",
97162306a36Sopenharmony_ci	"echo 10 > /sys/bus/dsa/devices/dsa0/wq0.1/priority",
97262306a36Sopenharmony_ci	"echo 16 > /sys/bus/dsa/devices/dsa0/wq0.1/size",
97362306a36Sopenharmony_ci	"echo 15 > /sys/bus/dsa/devices/dsa0/wq0.1/threshold",
97462306a36Sopenharmony_ci	"echo user > /sys/bus/dsa/devices/dsa0/wq0.1/type",
97562306a36Sopenharmony_ci	"echo MyApp1 > /sys/bus/dsa/devices/dsa0/wq0.1/name",
97662306a36Sopenharmony_ci	"echo 1 > /sys/bus/dsa/devices/dsa0/engine0.1/group_id",
97762306a36Sopenharmony_ci	"echo dsa0 > /sys/bus/dsa/drivers/idxd/bind",
97862306a36Sopenharmony_ci	/* bind files and devices, generated a device file in /dev */
97962306a36Sopenharmony_ci	"echo wq0.1 > /sys/bus/dsa/drivers/user/bind",
98062306a36Sopenharmony_ci};
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_ci/* DSA device file */
98362306a36Sopenharmony_ciconst char *dsaDeviceFile = "/dev/dsa/wq0.1";
98462306a36Sopenharmony_ci/* file for io*/
98562306a36Sopenharmony_ciconst char *dsaPasidEnable = "/sys/bus/dsa/devices/dsa0/pasid_enabled";
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci/*
98862306a36Sopenharmony_ci * DSA depends on kernel cmdline "intel_iommu=on,sm_on"
98962306a36Sopenharmony_ci * return pasid_enabled (0: disable 1:enable)
99062306a36Sopenharmony_ci */
99162306a36Sopenharmony_ciint Check_DSA_Kernel_Setting(void)
99262306a36Sopenharmony_ci{
99362306a36Sopenharmony_ci	char command[256] = "";
99462306a36Sopenharmony_ci	char buf[256] = "";
99562306a36Sopenharmony_ci	char *ptr;
99662306a36Sopenharmony_ci	int rv = -1;
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_ci	snprintf(command, sizeof(command) - 1, "cat %s", dsaPasidEnable);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	FILE *cmd = popen(command, "r");
100162306a36Sopenharmony_ci
100262306a36Sopenharmony_ci	if (cmd) {
100362306a36Sopenharmony_ci		while (fgets(buf, sizeof(buf) - 1, cmd) != NULL);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci		pclose(cmd);
100662306a36Sopenharmony_ci		rv = strtol(buf, &ptr, 16);
100762306a36Sopenharmony_ci	}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	return rv;
101062306a36Sopenharmony_ci}
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci/*
101362306a36Sopenharmony_ci * Config DSA's sysfs files as shared DSA's WQ.
101462306a36Sopenharmony_ci * Generated a device file /dev/dsa/wq0.1
101562306a36Sopenharmony_ci * Return:  0 OK; 1 Failed; 3 Skip(SVA disabled).
101662306a36Sopenharmony_ci */
101762306a36Sopenharmony_ciint Dsa_Init_Sysfs(void)
101862306a36Sopenharmony_ci{
101962306a36Sopenharmony_ci	uint len = ARRAY_SIZE(dsa_configs);
102062306a36Sopenharmony_ci	const char **p = dsa_configs;
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	if (file_Exists(dsaDeviceFile) == 1)
102362306a36Sopenharmony_ci		return 0;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	/* check the idxd driver */
102662306a36Sopenharmony_ci	if (file_Exists(dsaPasidEnable) != 1) {
102762306a36Sopenharmony_ci		printf("Please make sure idxd driver was loaded\n");
102862306a36Sopenharmony_ci		return 3;
102962306a36Sopenharmony_ci	}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	/* Check SVA feature */
103262306a36Sopenharmony_ci	if (Check_DSA_Kernel_Setting() != 1) {
103362306a36Sopenharmony_ci		printf("Please enable SVA.(Add intel_iommu=on,sm_on in kernel cmdline)\n");
103462306a36Sopenharmony_ci		return 3;
103562306a36Sopenharmony_ci	}
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	/* Check the idxd device file on /dev/dsa/ */
103862306a36Sopenharmony_ci	for (int i = 0; i < len; i++) {
103962306a36Sopenharmony_ci		if (system(p[i]))
104062306a36Sopenharmony_ci			return 1;
104162306a36Sopenharmony_ci	}
104262306a36Sopenharmony_ci
104362306a36Sopenharmony_ci	/* After config, /dev/dsa/wq0.1 should be generated */
104462306a36Sopenharmony_ci	return (file_Exists(dsaDeviceFile) != 1);
104562306a36Sopenharmony_ci}
104662306a36Sopenharmony_ci
104762306a36Sopenharmony_ci/*
104862306a36Sopenharmony_ci * Open DSA device file, triger API: iommu_sva_alloc_pasid
104962306a36Sopenharmony_ci */
105062306a36Sopenharmony_civoid *allocate_dsa_pasid(void)
105162306a36Sopenharmony_ci{
105262306a36Sopenharmony_ci	int fd;
105362306a36Sopenharmony_ci	void *wq;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	fd = open(dsaDeviceFile, O_RDWR);
105662306a36Sopenharmony_ci	if (fd < 0) {
105762306a36Sopenharmony_ci		perror("open");
105862306a36Sopenharmony_ci		return MAP_FAILED;
105962306a36Sopenharmony_ci	}
106062306a36Sopenharmony_ci
106162306a36Sopenharmony_ci	wq = mmap(NULL, 0x1000, PROT_WRITE,
106262306a36Sopenharmony_ci			   MAP_SHARED | MAP_POPULATE, fd, 0);
106362306a36Sopenharmony_ci	if (wq == MAP_FAILED)
106462306a36Sopenharmony_ci		perror("mmap");
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	return wq;
106762306a36Sopenharmony_ci}
106862306a36Sopenharmony_ci
106962306a36Sopenharmony_ciint set_force_svm(void)
107062306a36Sopenharmony_ci{
107162306a36Sopenharmony_ci	int ret = 0;
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	ret = syscall(SYS_arch_prctl, ARCH_FORCE_TAGGED_SVA);
107462306a36Sopenharmony_ci
107562306a36Sopenharmony_ci	return ret;
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ciint handle_pasid(struct testcases *test)
107962306a36Sopenharmony_ci{
108062306a36Sopenharmony_ci	uint tmp = test->cmd;
108162306a36Sopenharmony_ci	uint runed = 0x0;
108262306a36Sopenharmony_ci	int ret = 0;
108362306a36Sopenharmony_ci	void *wq = NULL;
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	ret = Dsa_Init_Sysfs();
108662306a36Sopenharmony_ci	if (ret != 0)
108762306a36Sopenharmony_ci		return ret;
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci	for (int i = 0; i < 3; i++) {
109062306a36Sopenharmony_ci		int err = 0;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci		if (tmp & 0x1) {
109362306a36Sopenharmony_ci			/* run set lam mode*/
109462306a36Sopenharmony_ci			if ((runed & 0x1) == 0)	{
109562306a36Sopenharmony_ci				err = set_lam(LAM_U57_BITS);
109662306a36Sopenharmony_ci				runed = runed | 0x1;
109762306a36Sopenharmony_ci			} else
109862306a36Sopenharmony_ci				err = 1;
109962306a36Sopenharmony_ci		} else if (tmp & 0x4) {
110062306a36Sopenharmony_ci			/* run force svm */
110162306a36Sopenharmony_ci			if ((runed & 0x4) == 0)	{
110262306a36Sopenharmony_ci				err = set_force_svm();
110362306a36Sopenharmony_ci				runed = runed | 0x4;
110462306a36Sopenharmony_ci			} else
110562306a36Sopenharmony_ci				err = 1;
110662306a36Sopenharmony_ci		} else if (tmp & 0x2) {
110762306a36Sopenharmony_ci			/* run allocate pasid */
110862306a36Sopenharmony_ci			if ((runed & 0x2) == 0) {
110962306a36Sopenharmony_ci				runed = runed | 0x2;
111062306a36Sopenharmony_ci				wq = allocate_dsa_pasid();
111162306a36Sopenharmony_ci				if (wq == MAP_FAILED)
111262306a36Sopenharmony_ci					err = 1;
111362306a36Sopenharmony_ci			} else
111462306a36Sopenharmony_ci				err = 1;
111562306a36Sopenharmony_ci		}
111662306a36Sopenharmony_ci
111762306a36Sopenharmony_ci		ret = ret + err;
111862306a36Sopenharmony_ci		if (ret > 0)
111962306a36Sopenharmony_ci			break;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		tmp = tmp >> 4;
112262306a36Sopenharmony_ci	}
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci	if (wq != MAP_FAILED && wq != NULL)
112562306a36Sopenharmony_ci		if (munmap(wq, 0x1000))
112662306a36Sopenharmony_ci			printf("munmap failed %d\n", errno);
112762306a36Sopenharmony_ci
112862306a36Sopenharmony_ci	if (runed != 0x7)
112962306a36Sopenharmony_ci		ret = 1;
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	return (ret != 0);
113262306a36Sopenharmony_ci}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci/*
113562306a36Sopenharmony_ci * Pasid test depends on idxd and SVA, kernel should enable iommu and sm.
113662306a36Sopenharmony_ci * command line(intel_iommu=on,sm_on)
113762306a36Sopenharmony_ci */
113862306a36Sopenharmony_cistatic struct testcases pasid_cases[] = {
113962306a36Sopenharmony_ci	{
114062306a36Sopenharmony_ci		.expected = 1,
114162306a36Sopenharmony_ci		.cmd = PAS_CMD(LAM_CMD_BIT, PAS_CMD_BIT, SVA_CMD_BIT),
114262306a36Sopenharmony_ci		.test_func = handle_pasid,
114362306a36Sopenharmony_ci		.msg = "PASID: [Negative] Execute LAM, PASID, SVA in sequence\n",
114462306a36Sopenharmony_ci	},
114562306a36Sopenharmony_ci	{
114662306a36Sopenharmony_ci		.expected = 0,
114762306a36Sopenharmony_ci		.cmd = PAS_CMD(LAM_CMD_BIT, SVA_CMD_BIT, PAS_CMD_BIT),
114862306a36Sopenharmony_ci		.test_func = handle_pasid,
114962306a36Sopenharmony_ci		.msg = "PASID: Execute LAM, SVA, PASID in sequence\n",
115062306a36Sopenharmony_ci	},
115162306a36Sopenharmony_ci	{
115262306a36Sopenharmony_ci		.expected = 1,
115362306a36Sopenharmony_ci		.cmd = PAS_CMD(PAS_CMD_BIT, LAM_CMD_BIT, SVA_CMD_BIT),
115462306a36Sopenharmony_ci		.test_func = handle_pasid,
115562306a36Sopenharmony_ci		.msg = "PASID: [Negative] Execute PASID, LAM, SVA in sequence\n",
115662306a36Sopenharmony_ci	},
115762306a36Sopenharmony_ci	{
115862306a36Sopenharmony_ci		.expected = 0,
115962306a36Sopenharmony_ci		.cmd = PAS_CMD(PAS_CMD_BIT, SVA_CMD_BIT, LAM_CMD_BIT),
116062306a36Sopenharmony_ci		.test_func = handle_pasid,
116162306a36Sopenharmony_ci		.msg = "PASID: Execute PASID, SVA, LAM in sequence\n",
116262306a36Sopenharmony_ci	},
116362306a36Sopenharmony_ci	{
116462306a36Sopenharmony_ci		.expected = 0,
116562306a36Sopenharmony_ci		.cmd = PAS_CMD(SVA_CMD_BIT, LAM_CMD_BIT, PAS_CMD_BIT),
116662306a36Sopenharmony_ci		.test_func = handle_pasid,
116762306a36Sopenharmony_ci		.msg = "PASID: Execute SVA, LAM, PASID in sequence\n",
116862306a36Sopenharmony_ci	},
116962306a36Sopenharmony_ci	{
117062306a36Sopenharmony_ci		.expected = 0,
117162306a36Sopenharmony_ci		.cmd = PAS_CMD(SVA_CMD_BIT, PAS_CMD_BIT, LAM_CMD_BIT),
117262306a36Sopenharmony_ci		.test_func = handle_pasid,
117362306a36Sopenharmony_ci		.msg = "PASID: Execute SVA, PASID, LAM in sequence\n",
117462306a36Sopenharmony_ci	},
117562306a36Sopenharmony_ci};
117662306a36Sopenharmony_ci
117762306a36Sopenharmony_ciint main(int argc, char **argv)
117862306a36Sopenharmony_ci{
117962306a36Sopenharmony_ci	int c = 0;
118062306a36Sopenharmony_ci	unsigned int tests = TEST_MASK;
118162306a36Sopenharmony_ci
118262306a36Sopenharmony_ci	tests_cnt = 0;
118362306a36Sopenharmony_ci
118462306a36Sopenharmony_ci	if (!cpu_has_lam()) {
118562306a36Sopenharmony_ci		ksft_print_msg("Unsupported LAM feature!\n");
118662306a36Sopenharmony_ci		return -1;
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	while ((c = getopt(argc, argv, "ht:")) != -1) {
119062306a36Sopenharmony_ci		switch (c) {
119162306a36Sopenharmony_ci		case 't':
119262306a36Sopenharmony_ci			tests = strtoul(optarg, NULL, 16);
119362306a36Sopenharmony_ci			if (tests && !(tests & TEST_MASK)) {
119462306a36Sopenharmony_ci				ksft_print_msg("Invalid argument!\n");
119562306a36Sopenharmony_ci				return -1;
119662306a36Sopenharmony_ci			}
119762306a36Sopenharmony_ci			break;
119862306a36Sopenharmony_ci		case 'h':
119962306a36Sopenharmony_ci			cmd_help();
120062306a36Sopenharmony_ci			return 0;
120162306a36Sopenharmony_ci		default:
120262306a36Sopenharmony_ci			ksft_print_msg("Invalid argument\n");
120362306a36Sopenharmony_ci			return -1;
120462306a36Sopenharmony_ci		}
120562306a36Sopenharmony_ci	}
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	/*
120862306a36Sopenharmony_ci	 * When tests is 0, it is not a real test case;
120962306a36Sopenharmony_ci	 * the option used by test case(execve) to check the lam mode in
121062306a36Sopenharmony_ci	 * process generated by execve, the process read back lam mode and
121162306a36Sopenharmony_ci	 * check with lam mode in parent process.
121262306a36Sopenharmony_ci	 */
121362306a36Sopenharmony_ci	if (!tests)
121462306a36Sopenharmony_ci		return (get_lam());
121562306a36Sopenharmony_ci
121662306a36Sopenharmony_ci	/* Run test cases */
121762306a36Sopenharmony_ci	if (tests & FUNC_MALLOC)
121862306a36Sopenharmony_ci		run_test(malloc_cases, ARRAY_SIZE(malloc_cases));
121962306a36Sopenharmony_ci
122062306a36Sopenharmony_ci	if (tests & FUNC_BITS)
122162306a36Sopenharmony_ci		run_test(bits_cases, ARRAY_SIZE(bits_cases));
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci	if (tests & FUNC_MMAP)
122462306a36Sopenharmony_ci		run_test(mmap_cases, ARRAY_SIZE(mmap_cases));
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	if (tests & FUNC_SYSCALL)
122762306a36Sopenharmony_ci		run_test(syscall_cases, ARRAY_SIZE(syscall_cases));
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	if (tests & FUNC_URING)
123062306a36Sopenharmony_ci		run_test(uring_cases, ARRAY_SIZE(uring_cases));
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_ci	if (tests & FUNC_INHERITE)
123362306a36Sopenharmony_ci		run_test(inheritance_cases, ARRAY_SIZE(inheritance_cases));
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci	if (tests & FUNC_PASID)
123662306a36Sopenharmony_ci		run_test(pasid_cases, ARRAY_SIZE(pasid_cases));
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci	ksft_set_plan(tests_cnt);
123962306a36Sopenharmony_ci
124062306a36Sopenharmony_ci	return ksft_exit_pass();
124162306a36Sopenharmony_ci}
1242