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