~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/x86/lam.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
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 
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] */
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  */
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 
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  */
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 */
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  */
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 
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  */
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 
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 
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 
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 
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 */
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 */
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  */
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  */
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  */
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 
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 
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 
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 
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 
738 static int thread_fn_get_lam(void *arg)
739 {
740         return get_lam();
741 }
742 
743 static int thread_fn_set_lam(void *arg)
744 {
745         struct testcases *test = arg;
746 
747         return set_lam(test->lam);
748 }
749 
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 
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 }
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("%s", 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, "%s", 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 
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 */
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  */
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  */
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  */
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 
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 
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 
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 KSFT_SKIP;
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         ksft_exit_pass();
1241 }
1242 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php