xref: /openbmc/linux/tools/testing/selftests/x86/lam.c (revision 34821473)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <sys/syscall.h>
6 #include <time.h>
7 #include <signal.h>
8 #include <setjmp.h>
9 #include <sys/mman.h>
10 #include <sys/utsname.h>
11 #include <sys/wait.h>
12 #include <sys/stat.h>
13 #include <fcntl.h>
14 #include <inttypes.h>
15 
16 #include <sys/uio.h>
17 #include <linux/io_uring.h>
18 #include "../kselftest.h"
19 
20 #ifndef __x86_64__
21 # error This test is 64-bit only
22 #endif
23 
24 /* LAM modes, these definitions were copied from kernel code */
25 #define LAM_NONE                0
26 #define LAM_U57_BITS            6
27 
28 #define LAM_U57_MASK            (0x3fULL << 57)
29 /* arch prctl for LAM */
30 #define ARCH_GET_UNTAG_MASK     0x4001
31 #define ARCH_ENABLE_TAGGED_ADDR 0x4002
32 #define ARCH_GET_MAX_TAG_BITS   0x4003
33 #define ARCH_FORCE_TAGGED_SVA	0x4004
34 
35 /* Specified test function bits */
36 #define FUNC_MALLOC             0x1
37 #define FUNC_BITS               0x2
38 #define FUNC_MMAP               0x4
39 #define FUNC_SYSCALL            0x8
40 #define FUNC_URING              0x10
41 #define FUNC_INHERITE           0x20
42 #define FUNC_PASID              0x40
43 
44 #define TEST_MASK               0x7f
45 
46 #define LOW_ADDR                (0x1UL << 30)
47 #define HIGH_ADDR               (0x3UL << 48)
48 
49 #define MALLOC_LEN              32
50 
51 #define PAGE_SIZE               (4 << 10)
52 
53 #define barrier() ({						\
54 		   __asm__ __volatile__("" : : : "memory");	\
55 })
56 
57 #define URING_QUEUE_SZ 1
58 #define URING_BLOCK_SZ 2048
59 
60 /* Pasid test define */
61 #define LAM_CMD_BIT 0x1
62 #define PAS_CMD_BIT 0x2
63 #define SVA_CMD_BIT 0x4
64 
65 #define PAS_CMD(cmd1, cmd2, cmd3) (((cmd3) << 8) | ((cmd2) << 4) | ((cmd1) << 0))
66 
67 struct testcases {
68 	unsigned int later;
69 	int expected; /* 2: SIGSEGV Error; 1: other errors */
70 	unsigned long lam;
71 	uint64_t addr;
72 	uint64_t cmd;
73 	int (*test_func)(struct testcases *test);
74 	const char *msg;
75 };
76 
77 /* Used by CQ of uring, source file handler and file's size */
78 struct file_io {
79 	int file_fd;
80 	off_t file_sz;
81 	struct iovec iovecs[];
82 };
83 
84 struct io_uring_queue {
85 	unsigned int *head;
86 	unsigned int *tail;
87 	unsigned int *ring_mask;
88 	unsigned int *ring_entries;
89 	unsigned int *flags;
90 	unsigned int *array;
91 	union {
92 		struct io_uring_cqe *cqes;
93 		struct io_uring_sqe *sqes;
94 	} queue;
95 	size_t ring_sz;
96 };
97 
98 struct io_ring {
99 	int ring_fd;
100 	struct io_uring_queue sq_ring;
101 	struct io_uring_queue cq_ring;
102 };
103 
104 int tests_cnt;
105 jmp_buf segv_env;
106 
107 static void segv_handler(int sig)
108 {
109 	ksft_print_msg("Get segmentation fault(%d).", sig);
110 
111 	siglongjmp(segv_env, 1);
112 }
113 
114 static inline int cpu_has_lam(void)
115 {
116 	unsigned int cpuinfo[4];
117 
118 	__cpuid_count(0x7, 1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
119 
120 	return (cpuinfo[0] & (1 << 26));
121 }
122 
123 /* Check 5-level page table feature in CPUID.(EAX=07H, ECX=00H):ECX.[bit 16] */
124 static inline int cpu_has_la57(void)
125 {
126 	unsigned int cpuinfo[4];
127 
128 	__cpuid_count(0x7, 0, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]);
129 
130 	return (cpuinfo[2] & (1 << 16));
131 }
132 
133 /*
134  * Set tagged address and read back untag mask.
135  * check if the untagged mask is expected.
136  *
137  * @return:
138  * 0: Set LAM mode successfully
139  * others: failed to set LAM
140  */
141 static int set_lam(unsigned long lam)
142 {
143 	int ret = 0;
144 	uint64_t ptr = 0;
145 
146 	if (lam != LAM_U57_BITS && lam != LAM_NONE)
147 		return -1;
148 
149 	/* Skip check return */
150 	syscall(SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, lam);
151 
152 	/* Get untagged mask */
153 	syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr);
154 
155 	/* Check mask returned is expected */
156 	if (lam == LAM_U57_BITS)
157 		ret = (ptr != ~(LAM_U57_MASK));
158 	else if (lam == LAM_NONE)
159 		ret = (ptr != -1ULL);
160 
161 	return ret;
162 }
163 
164 static unsigned long get_default_tag_bits(void)
165 {
166 	pid_t pid;
167 	int lam = LAM_NONE;
168 	int ret = 0;
169 
170 	pid = fork();
171 	if (pid < 0) {
172 		perror("Fork failed.");
173 	} else if (pid == 0) {
174 		/* Set LAM mode in child process */
175 		if (set_lam(LAM_U57_BITS) == 0)
176 			lam = LAM_U57_BITS;
177 		else
178 			lam = LAM_NONE;
179 		exit(lam);
180 	} else {
181 		wait(&ret);
182 		lam = WEXITSTATUS(ret);
183 	}
184 
185 	return lam;
186 }
187 
188 /*
189  * Set tagged address and read back untag mask.
190  * check if the untag mask is expected.
191  */
192 static int get_lam(void)
193 {
194 	uint64_t ptr = 0;
195 	int ret = -1;
196 	/* Get untagged mask */
197 	if (syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr) == -1)
198 		return -1;
199 
200 	/* Check mask returned is expected */
201 	if (ptr == ~(LAM_U57_MASK))
202 		ret = LAM_U57_BITS;
203 	else if (ptr == -1ULL)
204 		ret = LAM_NONE;
205 
206 
207 	return ret;
208 }
209 
210 /* According to LAM mode, set metadata in high bits */
211 static uint64_t set_metadata(uint64_t src, unsigned long lam)
212 {
213 	uint64_t metadata;
214 
215 	srand(time(NULL));
216 
217 	switch (lam) {
218 	case LAM_U57_BITS: /* Set metadata in bits 62:57 */
219 		/* Get a random non-zero value as metadata */
220 		metadata = (rand() % ((1UL << LAM_U57_BITS) - 1) + 1) << 57;
221 		metadata |= (src & ~(LAM_U57_MASK));
222 		break;
223 	default:
224 		metadata = src;
225 		break;
226 	}
227 
228 	return metadata;
229 }
230 
231 /*
232  * Set metadata in user pointer, compare new pointer with original pointer.
233  * both pointers should point to the same address.
234  *
235  * @return:
236  * 0: value on the pointer with metadate and value on original are same
237  * 1: not same.
238  */
239 static int handle_lam_test(void *src, unsigned int lam)
240 {
241 	char *ptr;
242 
243 	strcpy((char *)src, "USER POINTER");
244 
245 	ptr = (char *)set_metadata((uint64_t)src, lam);
246 	if (src == ptr)
247 		return 0;
248 
249 	/* Copy a string into the pointer with metadata */
250 	strcpy((char *)ptr, "METADATA POINTER");
251 
252 	return (!!strcmp((char *)src, (char *)ptr));
253 }
254 
255 
256 int handle_max_bits(struct testcases *test)
257 {
258 	unsigned long exp_bits = get_default_tag_bits();
259 	unsigned long bits = 0;
260 
261 	if (exp_bits != LAM_NONE)
262 		exp_bits = LAM_U57_BITS;
263 
264 	/* Get LAM max tag bits */
265 	if (syscall(SYS_arch_prctl, ARCH_GET_MAX_TAG_BITS, &bits) == -1)
266 		return 1;
267 
268 	return (exp_bits != bits);
269 }
270 
271 /*
272  * Test lam feature through dereference pointer get from malloc.
273  * @return 0: Pass test. 1: Get failure during test 2: Get SIGSEGV
274  */
275 static int handle_malloc(struct testcases *test)
276 {
277 	char *ptr = NULL;
278 	int ret = 0;
279 
280 	if (test->later == 0 && test->lam != 0)
281 		if (set_lam(test->lam) == -1)
282 			return 1;
283 
284 	ptr = (char *)malloc(MALLOC_LEN);
285 	if (ptr == NULL) {
286 		perror("malloc() failure\n");
287 		return 1;
288 	}
289 
290 	/* Set signal handler */
291 	if (sigsetjmp(segv_env, 1) == 0) {
292 		signal(SIGSEGV, segv_handler);
293 		ret = handle_lam_test(ptr, test->lam);
294 	} else {
295 		ret = 2;
296 	}
297 
298 	if (test->later != 0 && test->lam != 0)
299 		if (set_lam(test->lam) == -1 && ret == 0)
300 			ret = 1;
301 
302 	free(ptr);
303 
304 	return ret;
305 }
306 
307 static int handle_mmap(struct testcases *test)
308 {
309 	void *ptr;
310 	unsigned int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED;
311 	int ret = 0;
312 
313 	if (test->later == 0 && test->lam != 0)
314 		if (set_lam(test->lam) != 0)
315 			return 1;
316 
317 	ptr = mmap((void *)test->addr, PAGE_SIZE, PROT_READ | PROT_WRITE,
318 		   flags, -1, 0);
319 	if (ptr == MAP_FAILED) {
320 		if (test->addr == HIGH_ADDR)
321 			if (!cpu_has_la57())
322 				return 3; /* unsupport LA57 */
323 		return 1;
324 	}
325 
326 	if (test->later != 0 && test->lam != 0)
327 		if (set_lam(test->lam) != 0)
328 			ret = 1;
329 
330 	if (ret == 0) {
331 		if (sigsetjmp(segv_env, 1) == 0) {
332 			signal(SIGSEGV, segv_handler);
333 			ret = handle_lam_test(ptr, test->lam);
334 		} else {
335 			ret = 2;
336 		}
337 	}
338 
339 	munmap(ptr, PAGE_SIZE);
340 	return ret;
341 }
342 
343 static int handle_syscall(struct testcases *test)
344 {
345 	struct utsname unme, *pu;
346 	int ret = 0;
347 
348 	if (test->later == 0 && test->lam != 0)
349 		if (set_lam(test->lam) != 0)
350 			return 1;
351 
352 	if (sigsetjmp(segv_env, 1) == 0) {
353 		signal(SIGSEGV, segv_handler);
354 		pu = (struct utsname *)set_metadata((uint64_t)&unme, test->lam);
355 		ret = uname(pu);
356 		if (ret < 0)
357 			ret = 1;
358 	} else {
359 		ret = 2;
360 	}
361 
362 	if (test->later != 0 && test->lam != 0)
363 		if (set_lam(test->lam) != -1 && ret == 0)
364 			ret = 1;
365 
366 	return ret;
367 }
368 
369 int sys_uring_setup(unsigned int entries, struct io_uring_params *p)
370 {
371 	return (int)syscall(__NR_io_uring_setup, entries, p);
372 }
373 
374 int sys_uring_enter(int fd, unsigned int to, unsigned int min, unsigned int flags)
375 {
376 	return (int)syscall(__NR_io_uring_enter, fd, to, min, flags, NULL, 0);
377 }
378 
379 /* Init submission queue and completion queue */
380 int mmap_io_uring(struct io_uring_params p, struct io_ring *s)
381 {
382 	struct io_uring_queue *sring = &s->sq_ring;
383 	struct io_uring_queue *cring = &s->cq_ring;
384 
385 	sring->ring_sz = p.sq_off.array + p.sq_entries * sizeof(unsigned int);
386 	cring->ring_sz = p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe);
387 
388 	if (p.features & IORING_FEAT_SINGLE_MMAP) {
389 		if (cring->ring_sz > sring->ring_sz)
390 			sring->ring_sz = cring->ring_sz;
391 
392 		cring->ring_sz = sring->ring_sz;
393 	}
394 
395 	void *sq_ptr = mmap(0, sring->ring_sz, PROT_READ | PROT_WRITE,
396 			    MAP_SHARED | MAP_POPULATE, s->ring_fd,
397 			    IORING_OFF_SQ_RING);
398 
399 	if (sq_ptr == MAP_FAILED) {
400 		perror("sub-queue!");
401 		return 1;
402 	}
403 
404 	void *cq_ptr = sq_ptr;
405 
406 	if (!(p.features & IORING_FEAT_SINGLE_MMAP)) {
407 		cq_ptr = mmap(0, cring->ring_sz, PROT_READ | PROT_WRITE,
408 			      MAP_SHARED | MAP_POPULATE, s->ring_fd,
409 			      IORING_OFF_CQ_RING);
410 		if (cq_ptr == MAP_FAILED) {
411 			perror("cpl-queue!");
412 			munmap(sq_ptr, sring->ring_sz);
413 			return 1;
414 		}
415 	}
416 
417 	sring->head = sq_ptr + p.sq_off.head;
418 	sring->tail = sq_ptr + p.sq_off.tail;
419 	sring->ring_mask = sq_ptr + p.sq_off.ring_mask;
420 	sring->ring_entries = sq_ptr + p.sq_off.ring_entries;
421 	sring->flags = sq_ptr + p.sq_off.flags;
422 	sring->array = sq_ptr + p.sq_off.array;
423 
424 	/* Map a queue as mem map */
425 	s->sq_ring.queue.sqes = mmap(0, p.sq_entries * sizeof(struct io_uring_sqe),
426 				     PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE,
427 				     s->ring_fd, IORING_OFF_SQES);
428 	if (s->sq_ring.queue.sqes == MAP_FAILED) {
429 		munmap(sq_ptr, sring->ring_sz);
430 		if (sq_ptr != cq_ptr) {
431 			ksft_print_msg("failed to mmap uring queue!");
432 			munmap(cq_ptr, cring->ring_sz);
433 			return 1;
434 		}
435 	}
436 
437 	cring->head = cq_ptr + p.cq_off.head;
438 	cring->tail = cq_ptr + p.cq_off.tail;
439 	cring->ring_mask = cq_ptr + p.cq_off.ring_mask;
440 	cring->ring_entries = cq_ptr + p.cq_off.ring_entries;
441 	cring->queue.cqes = cq_ptr + p.cq_off.cqes;
442 
443 	return 0;
444 }
445 
446 /* Init io_uring queues */
447 int setup_io_uring(struct io_ring *s)
448 {
449 	struct io_uring_params para;
450 
451 	memset(&para, 0, sizeof(para));
452 	s->ring_fd = sys_uring_setup(URING_QUEUE_SZ, &para);
453 	if (s->ring_fd < 0)
454 		return 1;
455 
456 	return mmap_io_uring(para, s);
457 }
458 
459 /*
460  * Get data from completion queue. the data buffer saved the file data
461  * return 0: success; others: error;
462  */
463 int handle_uring_cq(struct io_ring *s)
464 {
465 	struct file_io *fi = NULL;
466 	struct io_uring_queue *cring = &s->cq_ring;
467 	struct io_uring_cqe *cqe;
468 	unsigned int head;
469 	off_t len = 0;
470 
471 	head = *cring->head;
472 
473 	do {
474 		barrier();
475 		if (head == *cring->tail)
476 			break;
477 		/* Get the entry */
478 		cqe = &cring->queue.cqes[head & *s->cq_ring.ring_mask];
479 		fi = (struct file_io *)cqe->user_data;
480 		if (cqe->res < 0)
481 			break;
482 
483 		int blocks = (int)(fi->file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
484 
485 		for (int i = 0; i < blocks; i++)
486 			len += fi->iovecs[i].iov_len;
487 
488 		head++;
489 	} while (1);
490 
491 	*cring->head = head;
492 	barrier();
493 
494 	return (len != fi->file_sz);
495 }
496 
497 /*
498  * Submit squeue. specify via IORING_OP_READV.
499  * the buffer need to be set metadata according to LAM mode
500  */
501 int handle_uring_sq(struct io_ring *ring, struct file_io *fi, unsigned long lam)
502 {
503 	int file_fd = fi->file_fd;
504 	struct io_uring_queue *sring = &ring->sq_ring;
505 	unsigned int index = 0, cur_block = 0, tail = 0, next_tail = 0;
506 	struct io_uring_sqe *sqe;
507 
508 	off_t remain = fi->file_sz;
509 	int blocks = (int)(remain + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
510 
511 	while (remain) {
512 		off_t bytes = remain;
513 		void *buf;
514 
515 		if (bytes > URING_BLOCK_SZ)
516 			bytes = URING_BLOCK_SZ;
517 
518 		fi->iovecs[cur_block].iov_len = bytes;
519 
520 		if (posix_memalign(&buf, URING_BLOCK_SZ, URING_BLOCK_SZ))
521 			return 1;
522 
523 		fi->iovecs[cur_block].iov_base = (void *)set_metadata((uint64_t)buf, lam);
524 		remain -= bytes;
525 		cur_block++;
526 	}
527 
528 	next_tail = *sring->tail;
529 	tail = next_tail;
530 	next_tail++;
531 
532 	barrier();
533 
534 	index = tail & *ring->sq_ring.ring_mask;
535 
536 	sqe = &ring->sq_ring.queue.sqes[index];
537 	sqe->fd = file_fd;
538 	sqe->flags = 0;
539 	sqe->opcode = IORING_OP_READV;
540 	sqe->addr = (unsigned long)fi->iovecs;
541 	sqe->len = blocks;
542 	sqe->off = 0;
543 	sqe->user_data = (uint64_t)fi;
544 
545 	sring->array[index] = index;
546 	tail = next_tail;
547 
548 	if (*sring->tail != tail) {
549 		*sring->tail = tail;
550 		barrier();
551 	}
552 
553 	if (sys_uring_enter(ring->ring_fd, 1, 1, IORING_ENTER_GETEVENTS) < 0)
554 		return 1;
555 
556 	return 0;
557 }
558 
559 /*
560  * Test LAM in async I/O and io_uring, read current binery through io_uring
561  * Set metadata in pointers to iovecs buffer.
562  */
563 int do_uring(unsigned long lam)
564 {
565 	struct io_ring *ring;
566 	struct file_io *fi;
567 	struct stat st;
568 	int ret = 1;
569 	char path[PATH_MAX] = {0};
570 
571 	/* get current process path */
572 	if (readlink("/proc/self/exe", path, PATH_MAX) <= 0)
573 		return 1;
574 
575 	int file_fd = open(path, O_RDONLY);
576 
577 	if (file_fd < 0)
578 		return 1;
579 
580 	if (fstat(file_fd, &st) < 0)
581 		return 1;
582 
583 	off_t file_sz = st.st_size;
584 
585 	int blocks = (int)(file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ;
586 
587 	fi = malloc(sizeof(*fi) + sizeof(struct iovec) * blocks);
588 	if (!fi)
589 		return 1;
590 
591 	fi->file_sz = file_sz;
592 	fi->file_fd = file_fd;
593 
594 	ring = malloc(sizeof(*ring));
595 	if (!ring)
596 		return 1;
597 
598 	memset(ring, 0, sizeof(struct io_ring));
599 
600 	if (setup_io_uring(ring))
601 		goto out;
602 
603 	if (handle_uring_sq(ring, fi, lam))
604 		goto out;
605 
606 	ret = handle_uring_cq(ring);
607 
608 out:
609 	free(ring);
610 
611 	for (int i = 0; i < blocks; i++) {
612 		if (fi->iovecs[i].iov_base) {
613 			uint64_t addr = ((uint64_t)fi->iovecs[i].iov_base);
614 
615 			switch (lam) {
616 			case LAM_U57_BITS: /* Clear bits 62:57 */
617 				addr = (addr & ~(LAM_U57_MASK));
618 				break;
619 			}
620 			free((void *)addr);
621 			fi->iovecs[i].iov_base = NULL;
622 		}
623 	}
624 
625 	free(fi);
626 
627 	return ret;
628 }
629 
630 int handle_uring(struct testcases *test)
631 {
632 	int ret = 0;
633 
634 	if (test->later == 0 && test->lam != 0)
635 		if (set_lam(test->lam) != 0)
636 			return 1;
637 
638 	if (sigsetjmp(segv_env, 1) == 0) {
639 		signal(SIGSEGV, segv_handler);
640 		ret = do_uring(test->lam);
641 	} else {
642 		ret = 2;
643 	}
644 
645 	return ret;
646 }
647 
648 static int fork_test(struct testcases *test)
649 {
650 	int ret, child_ret;
651 	pid_t pid;
652 
653 	pid = fork();
654 	if (pid < 0) {
655 		perror("Fork failed.");
656 		ret = 1;
657 	} else if (pid == 0) {
658 		ret = test->test_func(test);
659 		exit(ret);
660 	} else {
661 		wait(&child_ret);
662 		ret = WEXITSTATUS(child_ret);
663 	}
664 
665 	return ret;
666 }
667 
668 static int handle_execve(struct testcases *test)
669 {
670 	int ret, child_ret;
671 	int lam = test->lam;
672 	pid_t pid;
673 
674 	pid = fork();
675 	if (pid < 0) {
676 		perror("Fork failed.");
677 		ret = 1;
678 	} else if (pid == 0) {
679 		char path[PATH_MAX];
680 
681 		/* Set LAM mode in parent process */
682 		if (set_lam(lam) != 0)
683 			return 1;
684 
685 		/* Get current binary's path and the binary was run by execve */
686 		if (readlink("/proc/self/exe", path, PATH_MAX) <= 0)
687 			exit(-1);
688 
689 		/* run binary to get LAM mode and return to parent process */
690 		if (execlp(path, path, "-t 0x0", NULL) < 0) {
691 			perror("error on exec");
692 			exit(-1);
693 		}
694 	} else {
695 		wait(&child_ret);
696 		ret = WEXITSTATUS(child_ret);
697 		if (ret != LAM_NONE)
698 			return 1;
699 	}
700 
701 	return 0;
702 }
703 
704 static int handle_inheritance(struct testcases *test)
705 {
706 	int ret, child_ret;
707 	int lam = test->lam;
708 	pid_t pid;
709 
710 	/* Set LAM mode in parent process */
711 	if (set_lam(lam) != 0)
712 		return 1;
713 
714 	pid = fork();
715 	if (pid < 0) {
716 		perror("Fork failed.");
717 		return 1;
718 	} else if (pid == 0) {
719 		/* Set LAM mode in parent process */
720 		int child_lam = get_lam();
721 
722 		exit(child_lam);
723 	} else {
724 		wait(&child_ret);
725 		ret = WEXITSTATUS(child_ret);
726 
727 		if (lam != ret)
728 			return 1;
729 	}
730 
731 	return 0;
732 }
733 
734 static void run_test(struct testcases *test, int count)
735 {
736 	int i, ret = 0;
737 
738 	for (i = 0; i < count; i++) {
739 		struct testcases *t = test + i;
740 
741 		/* fork a process to run test case */
742 		tests_cnt++;
743 		ret = fork_test(t);
744 
745 		/* return 3 is not support LA57, the case should be skipped */
746 		if (ret == 3) {
747 			ksft_test_result_skip(t->msg);
748 			continue;
749 		}
750 
751 		if (ret != 0)
752 			ret = (t->expected == ret);
753 		else
754 			ret = !(t->expected);
755 
756 		ksft_test_result(ret, t->msg);
757 	}
758 }
759 
760 static struct testcases uring_cases[] = {
761 	{
762 		.later = 0,
763 		.lam = LAM_U57_BITS,
764 		.test_func = handle_uring,
765 		.msg = "URING: LAM_U57. Dereferencing pointer with metadata\n",
766 	},
767 	{
768 		.later = 1,
769 		.expected = 1,
770 		.lam = LAM_U57_BITS,
771 		.test_func = handle_uring,
772 		.msg = "URING:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
773 	},
774 };
775 
776 static struct testcases malloc_cases[] = {
777 	{
778 		.later = 0,
779 		.lam = LAM_U57_BITS,
780 		.test_func = handle_malloc,
781 		.msg = "MALLOC: LAM_U57. Dereferencing pointer with metadata\n",
782 	},
783 	{
784 		.later = 1,
785 		.expected = 2,
786 		.lam = LAM_U57_BITS,
787 		.test_func = handle_malloc,
788 		.msg = "MALLOC:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
789 	},
790 };
791 
792 static struct testcases bits_cases[] = {
793 	{
794 		.test_func = handle_max_bits,
795 		.msg = "BITS: Check default tag bits\n",
796 	},
797 };
798 
799 static struct testcases syscall_cases[] = {
800 	{
801 		.later = 0,
802 		.lam = LAM_U57_BITS,
803 		.test_func = handle_syscall,
804 		.msg = "SYSCALL: LAM_U57. syscall with metadata\n",
805 	},
806 	{
807 		.later = 1,
808 		.expected = 1,
809 		.lam = LAM_U57_BITS,
810 		.test_func = handle_syscall,
811 		.msg = "SYSCALL:[Negative] Disable LAM. Dereferencing pointer with metadata.\n",
812 	},
813 };
814 
815 static struct testcases mmap_cases[] = {
816 	{
817 		.later = 1,
818 		.expected = 0,
819 		.lam = LAM_U57_BITS,
820 		.addr = HIGH_ADDR,
821 		.test_func = handle_mmap,
822 		.msg = "MMAP: First mmap high address, then set LAM_U57.\n",
823 	},
824 	{
825 		.later = 0,
826 		.expected = 0,
827 		.lam = LAM_U57_BITS,
828 		.addr = HIGH_ADDR,
829 		.test_func = handle_mmap,
830 		.msg = "MMAP: First LAM_U57, then High address.\n",
831 	},
832 	{
833 		.later = 0,
834 		.expected = 0,
835 		.lam = LAM_U57_BITS,
836 		.addr = LOW_ADDR,
837 		.test_func = handle_mmap,
838 		.msg = "MMAP: First LAM_U57, then Low address.\n",
839 	},
840 };
841 
842 static struct testcases inheritance_cases[] = {
843 	{
844 		.expected = 0,
845 		.lam = LAM_U57_BITS,
846 		.test_func = handle_inheritance,
847 		.msg = "FORK: LAM_U57, child process should get LAM mode same as parent\n",
848 	},
849 	{
850 		.expected = 0,
851 		.lam = LAM_U57_BITS,
852 		.test_func = handle_execve,
853 		.msg = "EXECVE: LAM_U57, child process should get disabled LAM mode\n",
854 	},
855 };
856 
857 static void cmd_help(void)
858 {
859 	printf("usage: lam [-h] [-t test list]\n");
860 	printf("\t-t test list: run tests specified in the test list, default:0x%x\n", TEST_MASK);
861 	printf("\t\t0x1:malloc; 0x2:max_bits; 0x4:mmap; 0x8:syscall; 0x10:io_uring; 0x20:inherit;\n");
862 	printf("\t-h: help\n");
863 }
864 
865 /* Check for file existence */
866 uint8_t file_Exists(const char *fileName)
867 {
868 	struct stat buffer;
869 
870 	uint8_t ret = (stat(fileName, &buffer) == 0);
871 
872 	return ret;
873 }
874 
875 /* Sysfs idxd files */
876 const char *dsa_configs[] = {
877 	"echo 1 > /sys/bus/dsa/devices/dsa0/wq0.1/group_id",
878 	"echo shared > /sys/bus/dsa/devices/dsa0/wq0.1/mode",
879 	"echo 10 > /sys/bus/dsa/devices/dsa0/wq0.1/priority",
880 	"echo 16 > /sys/bus/dsa/devices/dsa0/wq0.1/size",
881 	"echo 15 > /sys/bus/dsa/devices/dsa0/wq0.1/threshold",
882 	"echo user > /sys/bus/dsa/devices/dsa0/wq0.1/type",
883 	"echo MyApp1 > /sys/bus/dsa/devices/dsa0/wq0.1/name",
884 	"echo 1 > /sys/bus/dsa/devices/dsa0/engine0.1/group_id",
885 	"echo dsa0 > /sys/bus/dsa/drivers/idxd/bind",
886 	/* bind files and devices, generated a device file in /dev */
887 	"echo wq0.1 > /sys/bus/dsa/drivers/user/bind",
888 };
889 
890 /* DSA device file */
891 const char *dsaDeviceFile = "/dev/dsa/wq0.1";
892 /* file for io*/
893 const char *dsaPasidEnable = "/sys/bus/dsa/devices/dsa0/pasid_enabled";
894 
895 /*
896  * DSA depends on kernel cmdline "intel_iommu=on,sm_on"
897  * return pasid_enabled (0: disable 1:enable)
898  */
899 int Check_DSA_Kernel_Setting(void)
900 {
901 	char command[256] = "";
902 	char buf[256] = "";
903 	char *ptr;
904 	int rv = -1;
905 
906 	snprintf(command, sizeof(command) - 1, "cat %s", dsaPasidEnable);
907 
908 	FILE *cmd = popen(command, "r");
909 
910 	if (cmd) {
911 		while (fgets(buf, sizeof(buf) - 1, cmd) != NULL);
912 
913 		pclose(cmd);
914 		rv = strtol(buf, &ptr, 16);
915 	}
916 
917 	return rv;
918 }
919 
920 /*
921  * Config DSA's sysfs files as shared DSA's WQ.
922  * Generated a device file /dev/dsa/wq0.1
923  * Return:  0 OK; 1 Failed; 3 Skip(SVA disabled).
924  */
925 int Dsa_Init_Sysfs(void)
926 {
927 	uint len = ARRAY_SIZE(dsa_configs);
928 	const char **p = dsa_configs;
929 
930 	if (file_Exists(dsaDeviceFile) == 1)
931 		return 0;
932 
933 	/* check the idxd driver */
934 	if (file_Exists(dsaPasidEnable) != 1) {
935 		printf("Please make sure idxd driver was loaded\n");
936 		return 3;
937 	}
938 
939 	/* Check SVA feature */
940 	if (Check_DSA_Kernel_Setting() != 1) {
941 		printf("Please enable SVA.(Add intel_iommu=on,sm_on in kernel cmdline)\n");
942 		return 3;
943 	}
944 
945 	/* Check the idxd device file on /dev/dsa/ */
946 	for (int i = 0; i < len; i++) {
947 		if (system(p[i]))
948 			return 1;
949 	}
950 
951 	/* After config, /dev/dsa/wq0.1 should be generated */
952 	return (file_Exists(dsaDeviceFile) != 1);
953 }
954 
955 /*
956  * Open DSA device file, triger API: iommu_sva_alloc_pasid
957  */
958 void *allocate_dsa_pasid(void)
959 {
960 	int fd;
961 	void *wq;
962 
963 	fd = open(dsaDeviceFile, O_RDWR);
964 	if (fd < 0) {
965 		perror("open");
966 		return MAP_FAILED;
967 	}
968 
969 	wq = mmap(NULL, 0x1000, PROT_WRITE,
970 			   MAP_SHARED | MAP_POPULATE, fd, 0);
971 	if (wq == MAP_FAILED)
972 		perror("mmap");
973 
974 	return wq;
975 }
976 
977 int set_force_svm(void)
978 {
979 	int ret = 0;
980 
981 	ret = syscall(SYS_arch_prctl, ARCH_FORCE_TAGGED_SVA);
982 
983 	return ret;
984 }
985 
986 int handle_pasid(struct testcases *test)
987 {
988 	uint tmp = test->cmd;
989 	uint runed = 0x0;
990 	int ret = 0;
991 	void *wq = NULL;
992 
993 	ret = Dsa_Init_Sysfs();
994 	if (ret != 0)
995 		return ret;
996 
997 	for (int i = 0; i < 3; i++) {
998 		int err = 0;
999 
1000 		if (tmp & 0x1) {
1001 			/* run set lam mode*/
1002 			if ((runed & 0x1) == 0)	{
1003 				err = set_lam(LAM_U57_BITS);
1004 				runed = runed | 0x1;
1005 			} else
1006 				err = 1;
1007 		} else if (tmp & 0x4) {
1008 			/* run force svm */
1009 			if ((runed & 0x4) == 0)	{
1010 				err = set_force_svm();
1011 				runed = runed | 0x4;
1012 			} else
1013 				err = 1;
1014 		} else if (tmp & 0x2) {
1015 			/* run allocate pasid */
1016 			if ((runed & 0x2) == 0) {
1017 				runed = runed | 0x2;
1018 				wq = allocate_dsa_pasid();
1019 				if (wq == MAP_FAILED)
1020 					err = 1;
1021 			} else
1022 				err = 1;
1023 		}
1024 
1025 		ret = ret + err;
1026 		if (ret > 0)
1027 			break;
1028 
1029 		tmp = tmp >> 4;
1030 	}
1031 
1032 	if (wq != MAP_FAILED && wq != NULL)
1033 		if (munmap(wq, 0x1000))
1034 			printf("munmap failed %d\n", errno);
1035 
1036 	if (runed != 0x7)
1037 		ret = 1;
1038 
1039 	return (ret != 0);
1040 }
1041 
1042 /*
1043  * Pasid test depends on idxd and SVA, kernel should enable iommu and sm.
1044  * command line(intel_iommu=on,sm_on)
1045  */
1046 static struct testcases pasid_cases[] = {
1047 	{
1048 		.expected = 1,
1049 		.cmd = PAS_CMD(LAM_CMD_BIT, PAS_CMD_BIT, SVA_CMD_BIT),
1050 		.test_func = handle_pasid,
1051 		.msg = "PASID: [Negative] Execute LAM, PASID, SVA in sequence\n",
1052 	},
1053 	{
1054 		.expected = 0,
1055 		.cmd = PAS_CMD(LAM_CMD_BIT, SVA_CMD_BIT, PAS_CMD_BIT),
1056 		.test_func = handle_pasid,
1057 		.msg = "PASID: Execute LAM, SVA, PASID in sequence\n",
1058 	},
1059 	{
1060 		.expected = 1,
1061 		.cmd = PAS_CMD(PAS_CMD_BIT, LAM_CMD_BIT, SVA_CMD_BIT),
1062 		.test_func = handle_pasid,
1063 		.msg = "PASID: [Negative] Execute PASID, LAM, SVA in sequence\n",
1064 	},
1065 	{
1066 		.expected = 0,
1067 		.cmd = PAS_CMD(PAS_CMD_BIT, SVA_CMD_BIT, LAM_CMD_BIT),
1068 		.test_func = handle_pasid,
1069 		.msg = "PASID: Execute PASID, SVA, LAM in sequence\n",
1070 	},
1071 	{
1072 		.expected = 0,
1073 		.cmd = PAS_CMD(SVA_CMD_BIT, LAM_CMD_BIT, PAS_CMD_BIT),
1074 		.test_func = handle_pasid,
1075 		.msg = "PASID: Execute SVA, LAM, PASID in sequence\n",
1076 	},
1077 	{
1078 		.expected = 0,
1079 		.cmd = PAS_CMD(SVA_CMD_BIT, PAS_CMD_BIT, LAM_CMD_BIT),
1080 		.test_func = handle_pasid,
1081 		.msg = "PASID: Execute SVA, PASID, LAM in sequence\n",
1082 	},
1083 };
1084 
1085 int main(int argc, char **argv)
1086 {
1087 	int c = 0;
1088 	unsigned int tests = TEST_MASK;
1089 
1090 	tests_cnt = 0;
1091 
1092 	if (!cpu_has_lam()) {
1093 		ksft_print_msg("Unsupported LAM feature!\n");
1094 		return -1;
1095 	}
1096 
1097 	while ((c = getopt(argc, argv, "ht:")) != -1) {
1098 		switch (c) {
1099 		case 't':
1100 			tests = strtoul(optarg, NULL, 16);
1101 			if (tests && !(tests & TEST_MASK)) {
1102 				ksft_print_msg("Invalid argument!\n");
1103 				return -1;
1104 			}
1105 			break;
1106 		case 'h':
1107 			cmd_help();
1108 			return 0;
1109 		default:
1110 			ksft_print_msg("Invalid argument\n");
1111 			return -1;
1112 		}
1113 	}
1114 
1115 	/*
1116 	 * When tests is 0, it is not a real test case;
1117 	 * the option used by test case(execve) to check the lam mode in
1118 	 * process generated by execve, the process read back lam mode and
1119 	 * check with lam mode in parent process.
1120 	 */
1121 	if (!tests)
1122 		return (get_lam());
1123 
1124 	/* Run test cases */
1125 	if (tests & FUNC_MALLOC)
1126 		run_test(malloc_cases, ARRAY_SIZE(malloc_cases));
1127 
1128 	if (tests & FUNC_BITS)
1129 		run_test(bits_cases, ARRAY_SIZE(bits_cases));
1130 
1131 	if (tests & FUNC_MMAP)
1132 		run_test(mmap_cases, ARRAY_SIZE(mmap_cases));
1133 
1134 	if (tests & FUNC_SYSCALL)
1135 		run_test(syscall_cases, ARRAY_SIZE(syscall_cases));
1136 
1137 	if (tests & FUNC_URING)
1138 		run_test(uring_cases, ARRAY_SIZE(uring_cases));
1139 
1140 	if (tests & FUNC_INHERITE)
1141 		run_test(inheritance_cases, ARRAY_SIZE(inheritance_cases));
1142 
1143 	if (tests & FUNC_PASID)
1144 		run_test(pasid_cases, ARRAY_SIZE(pasid_cases));
1145 
1146 	ksft_set_plan(tests_cnt);
1147 
1148 	return ksft_exit_pass();
1149 }
1150