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