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(¶, 0, sizeof(para));
45672fd6d73SWeihong Zhang s->ring_fd = sys_uring_setup(URING_QUEUE_SZ, ¶);
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