162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci#define _GNU_SOURCE 362306a36Sopenharmony_ci#include <stdio.h> 462306a36Sopenharmony_ci#include <stdlib.h> 562306a36Sopenharmony_ci#include <string.h> 662306a36Sopenharmony_ci#include <sys/syscall.h> 762306a36Sopenharmony_ci#include <time.h> 862306a36Sopenharmony_ci#include <signal.h> 962306a36Sopenharmony_ci#include <setjmp.h> 1062306a36Sopenharmony_ci#include <sys/mman.h> 1162306a36Sopenharmony_ci#include <sys/utsname.h> 1262306a36Sopenharmony_ci#include <sys/wait.h> 1362306a36Sopenharmony_ci#include <sys/stat.h> 1462306a36Sopenharmony_ci#include <fcntl.h> 1562306a36Sopenharmony_ci#include <inttypes.h> 1662306a36Sopenharmony_ci#include <sched.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include <sys/uio.h> 1962306a36Sopenharmony_ci#include <linux/io_uring.h> 2062306a36Sopenharmony_ci#include "../kselftest.h" 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#ifndef __x86_64__ 2362306a36Sopenharmony_ci# error This test is 64-bit only 2462306a36Sopenharmony_ci#endif 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* LAM modes, these definitions were copied from kernel code */ 2762306a36Sopenharmony_ci#define LAM_NONE 0 2862306a36Sopenharmony_ci#define LAM_U57_BITS 6 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci#define LAM_U57_MASK (0x3fULL << 57) 3162306a36Sopenharmony_ci/* arch prctl for LAM */ 3262306a36Sopenharmony_ci#define ARCH_GET_UNTAG_MASK 0x4001 3362306a36Sopenharmony_ci#define ARCH_ENABLE_TAGGED_ADDR 0x4002 3462306a36Sopenharmony_ci#define ARCH_GET_MAX_TAG_BITS 0x4003 3562306a36Sopenharmony_ci#define ARCH_FORCE_TAGGED_SVA 0x4004 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* Specified test function bits */ 3862306a36Sopenharmony_ci#define FUNC_MALLOC 0x1 3962306a36Sopenharmony_ci#define FUNC_BITS 0x2 4062306a36Sopenharmony_ci#define FUNC_MMAP 0x4 4162306a36Sopenharmony_ci#define FUNC_SYSCALL 0x8 4262306a36Sopenharmony_ci#define FUNC_URING 0x10 4362306a36Sopenharmony_ci#define FUNC_INHERITE 0x20 4462306a36Sopenharmony_ci#define FUNC_PASID 0x40 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci#define TEST_MASK 0x7f 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define LOW_ADDR (0x1UL << 30) 4962306a36Sopenharmony_ci#define HIGH_ADDR (0x3UL << 48) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci#define MALLOC_LEN 32 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci#define PAGE_SIZE (4 << 10) 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci#define STACK_SIZE 65536 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#define barrier() ({ \ 5862306a36Sopenharmony_ci __asm__ __volatile__("" : : : "memory"); \ 5962306a36Sopenharmony_ci}) 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci#define URING_QUEUE_SZ 1 6262306a36Sopenharmony_ci#define URING_BLOCK_SZ 2048 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Pasid test define */ 6562306a36Sopenharmony_ci#define LAM_CMD_BIT 0x1 6662306a36Sopenharmony_ci#define PAS_CMD_BIT 0x2 6762306a36Sopenharmony_ci#define SVA_CMD_BIT 0x4 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci#define PAS_CMD(cmd1, cmd2, cmd3) (((cmd3) << 8) | ((cmd2) << 4) | ((cmd1) << 0)) 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_cistruct testcases { 7262306a36Sopenharmony_ci unsigned int later; 7362306a36Sopenharmony_ci int expected; /* 2: SIGSEGV Error; 1: other errors */ 7462306a36Sopenharmony_ci unsigned long lam; 7562306a36Sopenharmony_ci uint64_t addr; 7662306a36Sopenharmony_ci uint64_t cmd; 7762306a36Sopenharmony_ci int (*test_func)(struct testcases *test); 7862306a36Sopenharmony_ci const char *msg; 7962306a36Sopenharmony_ci}; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci/* Used by CQ of uring, source file handler and file's size */ 8262306a36Sopenharmony_cistruct file_io { 8362306a36Sopenharmony_ci int file_fd; 8462306a36Sopenharmony_ci off_t file_sz; 8562306a36Sopenharmony_ci struct iovec iovecs[]; 8662306a36Sopenharmony_ci}; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistruct io_uring_queue { 8962306a36Sopenharmony_ci unsigned int *head; 9062306a36Sopenharmony_ci unsigned int *tail; 9162306a36Sopenharmony_ci unsigned int *ring_mask; 9262306a36Sopenharmony_ci unsigned int *ring_entries; 9362306a36Sopenharmony_ci unsigned int *flags; 9462306a36Sopenharmony_ci unsigned int *array; 9562306a36Sopenharmony_ci union { 9662306a36Sopenharmony_ci struct io_uring_cqe *cqes; 9762306a36Sopenharmony_ci struct io_uring_sqe *sqes; 9862306a36Sopenharmony_ci } queue; 9962306a36Sopenharmony_ci size_t ring_sz; 10062306a36Sopenharmony_ci}; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistruct io_ring { 10362306a36Sopenharmony_ci int ring_fd; 10462306a36Sopenharmony_ci struct io_uring_queue sq_ring; 10562306a36Sopenharmony_ci struct io_uring_queue cq_ring; 10662306a36Sopenharmony_ci}; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ciint tests_cnt; 10962306a36Sopenharmony_cijmp_buf segv_env; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic void segv_handler(int sig) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci ksft_print_msg("Get segmentation fault(%d).", sig); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci siglongjmp(segv_env, 1); 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic inline int cpu_has_lam(void) 11962306a36Sopenharmony_ci{ 12062306a36Sopenharmony_ci unsigned int cpuinfo[4]; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci __cpuid_count(0x7, 1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci return (cpuinfo[0] & (1 << 26)); 12562306a36Sopenharmony_ci} 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci/* Check 5-level page table feature in CPUID.(EAX=07H, ECX=00H):ECX.[bit 16] */ 12862306a36Sopenharmony_cistatic inline int cpu_has_la57(void) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci unsigned int cpuinfo[4]; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci __cpuid_count(0x7, 0, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci return (cpuinfo[2] & (1 << 16)); 13562306a36Sopenharmony_ci} 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci/* 13862306a36Sopenharmony_ci * Set tagged address and read back untag mask. 13962306a36Sopenharmony_ci * check if the untagged mask is expected. 14062306a36Sopenharmony_ci * 14162306a36Sopenharmony_ci * @return: 14262306a36Sopenharmony_ci * 0: Set LAM mode successfully 14362306a36Sopenharmony_ci * others: failed to set LAM 14462306a36Sopenharmony_ci */ 14562306a36Sopenharmony_cistatic int set_lam(unsigned long lam) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci int ret = 0; 14862306a36Sopenharmony_ci uint64_t ptr = 0; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (lam != LAM_U57_BITS && lam != LAM_NONE) 15162306a36Sopenharmony_ci return -1; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* Skip check return */ 15462306a36Sopenharmony_ci syscall(SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, lam); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* Get untagged mask */ 15762306a36Sopenharmony_ci syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr); 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Check mask returned is expected */ 16062306a36Sopenharmony_ci if (lam == LAM_U57_BITS) 16162306a36Sopenharmony_ci ret = (ptr != ~(LAM_U57_MASK)); 16262306a36Sopenharmony_ci else if (lam == LAM_NONE) 16362306a36Sopenharmony_ci ret = (ptr != -1ULL); 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci return ret; 16662306a36Sopenharmony_ci} 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_cistatic unsigned long get_default_tag_bits(void) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci pid_t pid; 17162306a36Sopenharmony_ci int lam = LAM_NONE; 17262306a36Sopenharmony_ci int ret = 0; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci pid = fork(); 17562306a36Sopenharmony_ci if (pid < 0) { 17662306a36Sopenharmony_ci perror("Fork failed."); 17762306a36Sopenharmony_ci } else if (pid == 0) { 17862306a36Sopenharmony_ci /* Set LAM mode in child process */ 17962306a36Sopenharmony_ci if (set_lam(LAM_U57_BITS) == 0) 18062306a36Sopenharmony_ci lam = LAM_U57_BITS; 18162306a36Sopenharmony_ci else 18262306a36Sopenharmony_ci lam = LAM_NONE; 18362306a36Sopenharmony_ci exit(lam); 18462306a36Sopenharmony_ci } else { 18562306a36Sopenharmony_ci wait(&ret); 18662306a36Sopenharmony_ci lam = WEXITSTATUS(ret); 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci return lam; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/* 19362306a36Sopenharmony_ci * Set tagged address and read back untag mask. 19462306a36Sopenharmony_ci * check if the untag mask is expected. 19562306a36Sopenharmony_ci */ 19662306a36Sopenharmony_cistatic int get_lam(void) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci uint64_t ptr = 0; 19962306a36Sopenharmony_ci int ret = -1; 20062306a36Sopenharmony_ci /* Get untagged mask */ 20162306a36Sopenharmony_ci if (syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr) == -1) 20262306a36Sopenharmony_ci return -1; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* Check mask returned is expected */ 20562306a36Sopenharmony_ci if (ptr == ~(LAM_U57_MASK)) 20662306a36Sopenharmony_ci ret = LAM_U57_BITS; 20762306a36Sopenharmony_ci else if (ptr == -1ULL) 20862306a36Sopenharmony_ci ret = LAM_NONE; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci return ret; 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci/* According to LAM mode, set metadata in high bits */ 21562306a36Sopenharmony_cistatic uint64_t set_metadata(uint64_t src, unsigned long lam) 21662306a36Sopenharmony_ci{ 21762306a36Sopenharmony_ci uint64_t metadata; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci srand(time(NULL)); 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci switch (lam) { 22262306a36Sopenharmony_ci case LAM_U57_BITS: /* Set metadata in bits 62:57 */ 22362306a36Sopenharmony_ci /* Get a random non-zero value as metadata */ 22462306a36Sopenharmony_ci metadata = (rand() % ((1UL << LAM_U57_BITS) - 1) + 1) << 57; 22562306a36Sopenharmony_ci metadata |= (src & ~(LAM_U57_MASK)); 22662306a36Sopenharmony_ci break; 22762306a36Sopenharmony_ci default: 22862306a36Sopenharmony_ci metadata = src; 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci return metadata; 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci/* 23662306a36Sopenharmony_ci * Set metadata in user pointer, compare new pointer with original pointer. 23762306a36Sopenharmony_ci * both pointers should point to the same address. 23862306a36Sopenharmony_ci * 23962306a36Sopenharmony_ci * @return: 24062306a36Sopenharmony_ci * 0: value on the pointer with metadate and value on original are same 24162306a36Sopenharmony_ci * 1: not same. 24262306a36Sopenharmony_ci */ 24362306a36Sopenharmony_cistatic int handle_lam_test(void *src, unsigned int lam) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci char *ptr; 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci strcpy((char *)src, "USER POINTER"); 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci ptr = (char *)set_metadata((uint64_t)src, lam); 25062306a36Sopenharmony_ci if (src == ptr) 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci /* Copy a string into the pointer with metadata */ 25462306a36Sopenharmony_ci strcpy((char *)ptr, "METADATA POINTER"); 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return (!!strcmp((char *)src, (char *)ptr)); 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ciint handle_max_bits(struct testcases *test) 26162306a36Sopenharmony_ci{ 26262306a36Sopenharmony_ci unsigned long exp_bits = get_default_tag_bits(); 26362306a36Sopenharmony_ci unsigned long bits = 0; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci if (exp_bits != LAM_NONE) 26662306a36Sopenharmony_ci exp_bits = LAM_U57_BITS; 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci /* Get LAM max tag bits */ 26962306a36Sopenharmony_ci if (syscall(SYS_arch_prctl, ARCH_GET_MAX_TAG_BITS, &bits) == -1) 27062306a36Sopenharmony_ci return 1; 27162306a36Sopenharmony_ci 27262306a36Sopenharmony_ci return (exp_bits != bits); 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/* 27662306a36Sopenharmony_ci * Test lam feature through dereference pointer get from malloc. 27762306a36Sopenharmony_ci * @return 0: Pass test. 1: Get failure during test 2: Get SIGSEGV 27862306a36Sopenharmony_ci */ 27962306a36Sopenharmony_cistatic int handle_malloc(struct testcases *test) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci char *ptr = NULL; 28262306a36Sopenharmony_ci int ret = 0; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci if (test->later == 0 && test->lam != 0) 28562306a36Sopenharmony_ci if (set_lam(test->lam) == -1) 28662306a36Sopenharmony_ci return 1; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci ptr = (char *)malloc(MALLOC_LEN); 28962306a36Sopenharmony_ci if (ptr == NULL) { 29062306a36Sopenharmony_ci perror("malloc() failure\n"); 29162306a36Sopenharmony_ci return 1; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci /* Set signal handler */ 29562306a36Sopenharmony_ci if (sigsetjmp(segv_env, 1) == 0) { 29662306a36Sopenharmony_ci signal(SIGSEGV, segv_handler); 29762306a36Sopenharmony_ci ret = handle_lam_test(ptr, test->lam); 29862306a36Sopenharmony_ci } else { 29962306a36Sopenharmony_ci ret = 2; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (test->later != 0 && test->lam != 0) 30362306a36Sopenharmony_ci if (set_lam(test->lam) == -1 && ret == 0) 30462306a36Sopenharmony_ci ret = 1; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci free(ptr); 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci return ret; 30962306a36Sopenharmony_ci} 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic int handle_mmap(struct testcases *test) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci void *ptr; 31462306a36Sopenharmony_ci unsigned int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; 31562306a36Sopenharmony_ci int ret = 0; 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci if (test->later == 0 && test->lam != 0) 31862306a36Sopenharmony_ci if (set_lam(test->lam) != 0) 31962306a36Sopenharmony_ci return 1; 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_ci ptr = mmap((void *)test->addr, PAGE_SIZE, PROT_READ | PROT_WRITE, 32262306a36Sopenharmony_ci flags, -1, 0); 32362306a36Sopenharmony_ci if (ptr == MAP_FAILED) { 32462306a36Sopenharmony_ci if (test->addr == HIGH_ADDR) 32562306a36Sopenharmony_ci if (!cpu_has_la57()) 32662306a36Sopenharmony_ci return 3; /* unsupport LA57 */ 32762306a36Sopenharmony_ci return 1; 32862306a36Sopenharmony_ci } 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci if (test->later != 0 && test->lam != 0) 33162306a36Sopenharmony_ci if (set_lam(test->lam) != 0) 33262306a36Sopenharmony_ci ret = 1; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (ret == 0) { 33562306a36Sopenharmony_ci if (sigsetjmp(segv_env, 1) == 0) { 33662306a36Sopenharmony_ci signal(SIGSEGV, segv_handler); 33762306a36Sopenharmony_ci ret = handle_lam_test(ptr, test->lam); 33862306a36Sopenharmony_ci } else { 33962306a36Sopenharmony_ci ret = 2; 34062306a36Sopenharmony_ci } 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_ci munmap(ptr, PAGE_SIZE); 34462306a36Sopenharmony_ci return ret; 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic int handle_syscall(struct testcases *test) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci struct utsname unme, *pu; 35062306a36Sopenharmony_ci int ret = 0; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci if (test->later == 0 && test->lam != 0) 35362306a36Sopenharmony_ci if (set_lam(test->lam) != 0) 35462306a36Sopenharmony_ci return 1; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (sigsetjmp(segv_env, 1) == 0) { 35762306a36Sopenharmony_ci signal(SIGSEGV, segv_handler); 35862306a36Sopenharmony_ci pu = (struct utsname *)set_metadata((uint64_t)&unme, test->lam); 35962306a36Sopenharmony_ci ret = uname(pu); 36062306a36Sopenharmony_ci if (ret < 0) 36162306a36Sopenharmony_ci ret = 1; 36262306a36Sopenharmony_ci } else { 36362306a36Sopenharmony_ci ret = 2; 36462306a36Sopenharmony_ci } 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci if (test->later != 0 && test->lam != 0) 36762306a36Sopenharmony_ci if (set_lam(test->lam) != -1 && ret == 0) 36862306a36Sopenharmony_ci ret = 1; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return ret; 37162306a36Sopenharmony_ci} 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ciint sys_uring_setup(unsigned int entries, struct io_uring_params *p) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci return (int)syscall(__NR_io_uring_setup, entries, p); 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ci 37862306a36Sopenharmony_ciint sys_uring_enter(int fd, unsigned int to, unsigned int min, unsigned int flags) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci return (int)syscall(__NR_io_uring_enter, fd, to, min, flags, NULL, 0); 38162306a36Sopenharmony_ci} 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci/* Init submission queue and completion queue */ 38462306a36Sopenharmony_ciint mmap_io_uring(struct io_uring_params p, struct io_ring *s) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct io_uring_queue *sring = &s->sq_ring; 38762306a36Sopenharmony_ci struct io_uring_queue *cring = &s->cq_ring; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci sring->ring_sz = p.sq_off.array + p.sq_entries * sizeof(unsigned int); 39062306a36Sopenharmony_ci cring->ring_sz = p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe); 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (p.features & IORING_FEAT_SINGLE_MMAP) { 39362306a36Sopenharmony_ci if (cring->ring_sz > sring->ring_sz) 39462306a36Sopenharmony_ci sring->ring_sz = cring->ring_sz; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci cring->ring_sz = sring->ring_sz; 39762306a36Sopenharmony_ci } 39862306a36Sopenharmony_ci 39962306a36Sopenharmony_ci void *sq_ptr = mmap(0, sring->ring_sz, PROT_READ | PROT_WRITE, 40062306a36Sopenharmony_ci MAP_SHARED | MAP_POPULATE, s->ring_fd, 40162306a36Sopenharmony_ci IORING_OFF_SQ_RING); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci if (sq_ptr == MAP_FAILED) { 40462306a36Sopenharmony_ci perror("sub-queue!"); 40562306a36Sopenharmony_ci return 1; 40662306a36Sopenharmony_ci } 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ci void *cq_ptr = sq_ptr; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci if (!(p.features & IORING_FEAT_SINGLE_MMAP)) { 41162306a36Sopenharmony_ci cq_ptr = mmap(0, cring->ring_sz, PROT_READ | PROT_WRITE, 41262306a36Sopenharmony_ci MAP_SHARED | MAP_POPULATE, s->ring_fd, 41362306a36Sopenharmony_ci IORING_OFF_CQ_RING); 41462306a36Sopenharmony_ci if (cq_ptr == MAP_FAILED) { 41562306a36Sopenharmony_ci perror("cpl-queue!"); 41662306a36Sopenharmony_ci munmap(sq_ptr, sring->ring_sz); 41762306a36Sopenharmony_ci return 1; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci sring->head = sq_ptr + p.sq_off.head; 42262306a36Sopenharmony_ci sring->tail = sq_ptr + p.sq_off.tail; 42362306a36Sopenharmony_ci sring->ring_mask = sq_ptr + p.sq_off.ring_mask; 42462306a36Sopenharmony_ci sring->ring_entries = sq_ptr + p.sq_off.ring_entries; 42562306a36Sopenharmony_ci sring->flags = sq_ptr + p.sq_off.flags; 42662306a36Sopenharmony_ci sring->array = sq_ptr + p.sq_off.array; 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* Map a queue as mem map */ 42962306a36Sopenharmony_ci s->sq_ring.queue.sqes = mmap(0, p.sq_entries * sizeof(struct io_uring_sqe), 43062306a36Sopenharmony_ci PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, 43162306a36Sopenharmony_ci s->ring_fd, IORING_OFF_SQES); 43262306a36Sopenharmony_ci if (s->sq_ring.queue.sqes == MAP_FAILED) { 43362306a36Sopenharmony_ci munmap(sq_ptr, sring->ring_sz); 43462306a36Sopenharmony_ci if (sq_ptr != cq_ptr) { 43562306a36Sopenharmony_ci ksft_print_msg("failed to mmap uring queue!"); 43662306a36Sopenharmony_ci munmap(cq_ptr, cring->ring_sz); 43762306a36Sopenharmony_ci return 1; 43862306a36Sopenharmony_ci } 43962306a36Sopenharmony_ci } 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci cring->head = cq_ptr + p.cq_off.head; 44262306a36Sopenharmony_ci cring->tail = cq_ptr + p.cq_off.tail; 44362306a36Sopenharmony_ci cring->ring_mask = cq_ptr + p.cq_off.ring_mask; 44462306a36Sopenharmony_ci cring->ring_entries = cq_ptr + p.cq_off.ring_entries; 44562306a36Sopenharmony_ci cring->queue.cqes = cq_ptr + p.cq_off.cqes; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci return 0; 44862306a36Sopenharmony_ci} 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci/* Init io_uring queues */ 45162306a36Sopenharmony_ciint setup_io_uring(struct io_ring *s) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct io_uring_params para; 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci memset(¶, 0, sizeof(para)); 45662306a36Sopenharmony_ci s->ring_fd = sys_uring_setup(URING_QUEUE_SZ, ¶); 45762306a36Sopenharmony_ci if (s->ring_fd < 0) 45862306a36Sopenharmony_ci return 1; 45962306a36Sopenharmony_ci 46062306a36Sopenharmony_ci return mmap_io_uring(para, s); 46162306a36Sopenharmony_ci} 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci/* 46462306a36Sopenharmony_ci * Get data from completion queue. the data buffer saved the file data 46562306a36Sopenharmony_ci * return 0: success; others: error; 46662306a36Sopenharmony_ci */ 46762306a36Sopenharmony_ciint handle_uring_cq(struct io_ring *s) 46862306a36Sopenharmony_ci{ 46962306a36Sopenharmony_ci struct file_io *fi = NULL; 47062306a36Sopenharmony_ci struct io_uring_queue *cring = &s->cq_ring; 47162306a36Sopenharmony_ci struct io_uring_cqe *cqe; 47262306a36Sopenharmony_ci unsigned int head; 47362306a36Sopenharmony_ci off_t len = 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci head = *cring->head; 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_ci do { 47862306a36Sopenharmony_ci barrier(); 47962306a36Sopenharmony_ci if (head == *cring->tail) 48062306a36Sopenharmony_ci break; 48162306a36Sopenharmony_ci /* Get the entry */ 48262306a36Sopenharmony_ci cqe = &cring->queue.cqes[head & *s->cq_ring.ring_mask]; 48362306a36Sopenharmony_ci fi = (struct file_io *)cqe->user_data; 48462306a36Sopenharmony_ci if (cqe->res < 0) 48562306a36Sopenharmony_ci break; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci int blocks = (int)(fi->file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci for (int i = 0; i < blocks; i++) 49062306a36Sopenharmony_ci len += fi->iovecs[i].iov_len; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci head++; 49362306a36Sopenharmony_ci } while (1); 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci *cring->head = head; 49662306a36Sopenharmony_ci barrier(); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci return (len != fi->file_sz); 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci/* 50262306a36Sopenharmony_ci * Submit squeue. specify via IORING_OP_READV. 50362306a36Sopenharmony_ci * the buffer need to be set metadata according to LAM mode 50462306a36Sopenharmony_ci */ 50562306a36Sopenharmony_ciint handle_uring_sq(struct io_ring *ring, struct file_io *fi, unsigned long lam) 50662306a36Sopenharmony_ci{ 50762306a36Sopenharmony_ci int file_fd = fi->file_fd; 50862306a36Sopenharmony_ci struct io_uring_queue *sring = &ring->sq_ring; 50962306a36Sopenharmony_ci unsigned int index = 0, cur_block = 0, tail = 0, next_tail = 0; 51062306a36Sopenharmony_ci struct io_uring_sqe *sqe; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci off_t remain = fi->file_sz; 51362306a36Sopenharmony_ci int blocks = (int)(remain + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ; 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci while (remain) { 51662306a36Sopenharmony_ci off_t bytes = remain; 51762306a36Sopenharmony_ci void *buf; 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci if (bytes > URING_BLOCK_SZ) 52062306a36Sopenharmony_ci bytes = URING_BLOCK_SZ; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci fi->iovecs[cur_block].iov_len = bytes; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci if (posix_memalign(&buf, URING_BLOCK_SZ, URING_BLOCK_SZ)) 52562306a36Sopenharmony_ci return 1; 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci fi->iovecs[cur_block].iov_base = (void *)set_metadata((uint64_t)buf, lam); 52862306a36Sopenharmony_ci remain -= bytes; 52962306a36Sopenharmony_ci cur_block++; 53062306a36Sopenharmony_ci } 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci next_tail = *sring->tail; 53362306a36Sopenharmony_ci tail = next_tail; 53462306a36Sopenharmony_ci next_tail++; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci barrier(); 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci index = tail & *ring->sq_ring.ring_mask; 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci sqe = &ring->sq_ring.queue.sqes[index]; 54162306a36Sopenharmony_ci sqe->fd = file_fd; 54262306a36Sopenharmony_ci sqe->flags = 0; 54362306a36Sopenharmony_ci sqe->opcode = IORING_OP_READV; 54462306a36Sopenharmony_ci sqe->addr = (unsigned long)fi->iovecs; 54562306a36Sopenharmony_ci sqe->len = blocks; 54662306a36Sopenharmony_ci sqe->off = 0; 54762306a36Sopenharmony_ci sqe->user_data = (uint64_t)fi; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci sring->array[index] = index; 55062306a36Sopenharmony_ci tail = next_tail; 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_ci if (*sring->tail != tail) { 55362306a36Sopenharmony_ci *sring->tail = tail; 55462306a36Sopenharmony_ci barrier(); 55562306a36Sopenharmony_ci } 55662306a36Sopenharmony_ci 55762306a36Sopenharmony_ci if (sys_uring_enter(ring->ring_fd, 1, 1, IORING_ENTER_GETEVENTS) < 0) 55862306a36Sopenharmony_ci return 1; 55962306a36Sopenharmony_ci 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci} 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci/* 56462306a36Sopenharmony_ci * Test LAM in async I/O and io_uring, read current binery through io_uring 56562306a36Sopenharmony_ci * Set metadata in pointers to iovecs buffer. 56662306a36Sopenharmony_ci */ 56762306a36Sopenharmony_ciint do_uring(unsigned long lam) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct io_ring *ring; 57062306a36Sopenharmony_ci struct file_io *fi; 57162306a36Sopenharmony_ci struct stat st; 57262306a36Sopenharmony_ci int ret = 1; 57362306a36Sopenharmony_ci char path[PATH_MAX] = {0}; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci /* get current process path */ 57662306a36Sopenharmony_ci if (readlink("/proc/self/exe", path, PATH_MAX - 1) <= 0) 57762306a36Sopenharmony_ci return 1; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci int file_fd = open(path, O_RDONLY); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci if (file_fd < 0) 58262306a36Sopenharmony_ci return 1; 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci if (fstat(file_fd, &st) < 0) 58562306a36Sopenharmony_ci return 1; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci off_t file_sz = st.st_size; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci int blocks = (int)(file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci fi = malloc(sizeof(*fi) + sizeof(struct iovec) * blocks); 59262306a36Sopenharmony_ci if (!fi) 59362306a36Sopenharmony_ci return 1; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci fi->file_sz = file_sz; 59662306a36Sopenharmony_ci fi->file_fd = file_fd; 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ci ring = malloc(sizeof(*ring)); 59962306a36Sopenharmony_ci if (!ring) 60062306a36Sopenharmony_ci return 1; 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci memset(ring, 0, sizeof(struct io_ring)); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci if (setup_io_uring(ring)) 60562306a36Sopenharmony_ci goto out; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci if (handle_uring_sq(ring, fi, lam)) 60862306a36Sopenharmony_ci goto out; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci ret = handle_uring_cq(ring); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ciout: 61362306a36Sopenharmony_ci free(ring); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci for (int i = 0; i < blocks; i++) { 61662306a36Sopenharmony_ci if (fi->iovecs[i].iov_base) { 61762306a36Sopenharmony_ci uint64_t addr = ((uint64_t)fi->iovecs[i].iov_base); 61862306a36Sopenharmony_ci 61962306a36Sopenharmony_ci switch (lam) { 62062306a36Sopenharmony_ci case LAM_U57_BITS: /* Clear bits 62:57 */ 62162306a36Sopenharmony_ci addr = (addr & ~(LAM_U57_MASK)); 62262306a36Sopenharmony_ci break; 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci free((void *)addr); 62562306a36Sopenharmony_ci fi->iovecs[i].iov_base = NULL; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci } 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci free(fi); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci return ret; 63262306a36Sopenharmony_ci} 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ciint handle_uring(struct testcases *test) 63562306a36Sopenharmony_ci{ 63662306a36Sopenharmony_ci int ret = 0; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (test->later == 0 && test->lam != 0) 63962306a36Sopenharmony_ci if (set_lam(test->lam) != 0) 64062306a36Sopenharmony_ci return 1; 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci if (sigsetjmp(segv_env, 1) == 0) { 64362306a36Sopenharmony_ci signal(SIGSEGV, segv_handler); 64462306a36Sopenharmony_ci ret = do_uring(test->lam); 64562306a36Sopenharmony_ci } else { 64662306a36Sopenharmony_ci ret = 2; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci return ret; 65062306a36Sopenharmony_ci} 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cistatic int fork_test(struct testcases *test) 65362306a36Sopenharmony_ci{ 65462306a36Sopenharmony_ci int ret, child_ret; 65562306a36Sopenharmony_ci pid_t pid; 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci pid = fork(); 65862306a36Sopenharmony_ci if (pid < 0) { 65962306a36Sopenharmony_ci perror("Fork failed."); 66062306a36Sopenharmony_ci ret = 1; 66162306a36Sopenharmony_ci } else if (pid == 0) { 66262306a36Sopenharmony_ci ret = test->test_func(test); 66362306a36Sopenharmony_ci exit(ret); 66462306a36Sopenharmony_ci } else { 66562306a36Sopenharmony_ci wait(&child_ret); 66662306a36Sopenharmony_ci ret = WEXITSTATUS(child_ret); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci return ret; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic int handle_execve(struct testcases *test) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci int ret, child_ret; 67562306a36Sopenharmony_ci int lam = test->lam; 67662306a36Sopenharmony_ci pid_t pid; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci pid = fork(); 67962306a36Sopenharmony_ci if (pid < 0) { 68062306a36Sopenharmony_ci perror("Fork failed."); 68162306a36Sopenharmony_ci ret = 1; 68262306a36Sopenharmony_ci } else if (pid == 0) { 68362306a36Sopenharmony_ci char path[PATH_MAX] = {0}; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci /* Set LAM mode in parent process */ 68662306a36Sopenharmony_ci if (set_lam(lam) != 0) 68762306a36Sopenharmony_ci return 1; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Get current binary's path and the binary was run by execve */ 69062306a36Sopenharmony_ci if (readlink("/proc/self/exe", path, PATH_MAX - 1) <= 0) 69162306a36Sopenharmony_ci exit(-1); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci /* run binary to get LAM mode and return to parent process */ 69462306a36Sopenharmony_ci if (execlp(path, path, "-t 0x0", NULL) < 0) { 69562306a36Sopenharmony_ci perror("error on exec"); 69662306a36Sopenharmony_ci exit(-1); 69762306a36Sopenharmony_ci } 69862306a36Sopenharmony_ci } else { 69962306a36Sopenharmony_ci wait(&child_ret); 70062306a36Sopenharmony_ci ret = WEXITSTATUS(child_ret); 70162306a36Sopenharmony_ci if (ret != LAM_NONE) 70262306a36Sopenharmony_ci return 1; 70362306a36Sopenharmony_ci } 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci return 0; 70662306a36Sopenharmony_ci} 70762306a36Sopenharmony_ci 70862306a36Sopenharmony_cistatic int handle_inheritance(struct testcases *test) 70962306a36Sopenharmony_ci{ 71062306a36Sopenharmony_ci int ret, child_ret; 71162306a36Sopenharmony_ci int lam = test->lam; 71262306a36Sopenharmony_ci pid_t pid; 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci /* Set LAM mode in parent process */ 71562306a36Sopenharmony_ci if (set_lam(lam) != 0) 71662306a36Sopenharmony_ci return 1; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci pid = fork(); 71962306a36Sopenharmony_ci if (pid < 0) { 72062306a36Sopenharmony_ci perror("Fork failed."); 72162306a36Sopenharmony_ci return 1; 72262306a36Sopenharmony_ci } else if (pid == 0) { 72362306a36Sopenharmony_ci /* Set LAM mode in parent process */ 72462306a36Sopenharmony_ci int child_lam = get_lam(); 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci exit(child_lam); 72762306a36Sopenharmony_ci } else { 72862306a36Sopenharmony_ci wait(&child_ret); 72962306a36Sopenharmony_ci ret = WEXITSTATUS(child_ret); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (lam != ret) 73262306a36Sopenharmony_ci return 1; 73362306a36Sopenharmony_ci } 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci return 0; 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_cistatic int thread_fn_get_lam(void *arg) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci return get_lam(); 74162306a36Sopenharmony_ci} 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_cistatic int thread_fn_set_lam(void *arg) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct testcases *test = arg; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci return set_lam(test->lam); 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cistatic int handle_thread(struct testcases *test) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci char stack[STACK_SIZE]; 75362306a36Sopenharmony_ci int ret, child_ret; 75462306a36Sopenharmony_ci int lam = 0; 75562306a36Sopenharmony_ci pid_t pid; 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci /* Set LAM mode in parent process */ 75862306a36Sopenharmony_ci if (!test->later) { 75962306a36Sopenharmony_ci lam = test->lam; 76062306a36Sopenharmony_ci if (set_lam(lam) != 0) 76162306a36Sopenharmony_ci return 1; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci pid = clone(thread_fn_get_lam, stack + STACK_SIZE, 76562306a36Sopenharmony_ci SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, NULL); 76662306a36Sopenharmony_ci if (pid < 0) { 76762306a36Sopenharmony_ci perror("Clone failed."); 76862306a36Sopenharmony_ci return 1; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci waitpid(pid, &child_ret, 0); 77262306a36Sopenharmony_ci ret = WEXITSTATUS(child_ret); 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_ci if (lam != ret) 77562306a36Sopenharmony_ci return 1; 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci if (test->later) { 77862306a36Sopenharmony_ci if (set_lam(test->lam) != 0) 77962306a36Sopenharmony_ci return 1; 78062306a36Sopenharmony_ci } 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci return 0; 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_cistatic int handle_thread_enable(struct testcases *test) 78662306a36Sopenharmony_ci{ 78762306a36Sopenharmony_ci char stack[STACK_SIZE]; 78862306a36Sopenharmony_ci int ret, child_ret; 78962306a36Sopenharmony_ci int lam = test->lam; 79062306a36Sopenharmony_ci pid_t pid; 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci pid = clone(thread_fn_set_lam, stack + STACK_SIZE, 79362306a36Sopenharmony_ci SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, test); 79462306a36Sopenharmony_ci if (pid < 0) { 79562306a36Sopenharmony_ci perror("Clone failed."); 79662306a36Sopenharmony_ci return 1; 79762306a36Sopenharmony_ci } 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci waitpid(pid, &child_ret, 0); 80062306a36Sopenharmony_ci ret = WEXITSTATUS(child_ret); 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci if (lam != ret) 80362306a36Sopenharmony_ci return 1; 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci return 0; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_cistatic void run_test(struct testcases *test, int count) 80862306a36Sopenharmony_ci{ 80962306a36Sopenharmony_ci int i, ret = 0; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci for (i = 0; i < count; i++) { 81262306a36Sopenharmony_ci struct testcases *t = test + i; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* fork a process to run test case */ 81562306a36Sopenharmony_ci tests_cnt++; 81662306a36Sopenharmony_ci ret = fork_test(t); 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* return 3 is not support LA57, the case should be skipped */ 81962306a36Sopenharmony_ci if (ret == 3) { 82062306a36Sopenharmony_ci ksft_test_result_skip(t->msg); 82162306a36Sopenharmony_ci continue; 82262306a36Sopenharmony_ci } 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci if (ret != 0) 82562306a36Sopenharmony_ci ret = (t->expected == ret); 82662306a36Sopenharmony_ci else 82762306a36Sopenharmony_ci ret = !(t->expected); 82862306a36Sopenharmony_ci 82962306a36Sopenharmony_ci ksft_test_result(ret, t->msg); 83062306a36Sopenharmony_ci } 83162306a36Sopenharmony_ci} 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_cistatic struct testcases uring_cases[] = { 83462306a36Sopenharmony_ci { 83562306a36Sopenharmony_ci .later = 0, 83662306a36Sopenharmony_ci .lam = LAM_U57_BITS, 83762306a36Sopenharmony_ci .test_func = handle_uring, 83862306a36Sopenharmony_ci .msg = "URING: LAM_U57. Dereferencing pointer with metadata\n", 83962306a36Sopenharmony_ci }, 84062306a36Sopenharmony_ci { 84162306a36Sopenharmony_ci .later = 1, 84262306a36Sopenharmony_ci .expected = 1, 84362306a36Sopenharmony_ci .lam = LAM_U57_BITS, 84462306a36Sopenharmony_ci .test_func = handle_uring, 84562306a36Sopenharmony_ci .msg = "URING:[Negative] Disable LAM. Dereferencing pointer with metadata.\n", 84662306a36Sopenharmony_ci }, 84762306a36Sopenharmony_ci}; 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_cistatic struct testcases malloc_cases[] = { 85062306a36Sopenharmony_ci { 85162306a36Sopenharmony_ci .later = 0, 85262306a36Sopenharmony_ci .lam = LAM_U57_BITS, 85362306a36Sopenharmony_ci .test_func = handle_malloc, 85462306a36Sopenharmony_ci .msg = "MALLOC: LAM_U57. Dereferencing pointer with metadata\n", 85562306a36Sopenharmony_ci }, 85662306a36Sopenharmony_ci { 85762306a36Sopenharmony_ci .later = 1, 85862306a36Sopenharmony_ci .expected = 2, 85962306a36Sopenharmony_ci .lam = LAM_U57_BITS, 86062306a36Sopenharmony_ci .test_func = handle_malloc, 86162306a36Sopenharmony_ci .msg = "MALLOC:[Negative] Disable LAM. Dereferencing pointer with metadata.\n", 86262306a36Sopenharmony_ci }, 86362306a36Sopenharmony_ci}; 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic struct testcases bits_cases[] = { 86662306a36Sopenharmony_ci { 86762306a36Sopenharmony_ci .test_func = handle_max_bits, 86862306a36Sopenharmony_ci .msg = "BITS: Check default tag bits\n", 86962306a36Sopenharmony_ci }, 87062306a36Sopenharmony_ci}; 87162306a36Sopenharmony_ci 87262306a36Sopenharmony_cistatic struct testcases syscall_cases[] = { 87362306a36Sopenharmony_ci { 87462306a36Sopenharmony_ci .later = 0, 87562306a36Sopenharmony_ci .lam = LAM_U57_BITS, 87662306a36Sopenharmony_ci .test_func = handle_syscall, 87762306a36Sopenharmony_ci .msg = "SYSCALL: LAM_U57. syscall with metadata\n", 87862306a36Sopenharmony_ci }, 87962306a36Sopenharmony_ci { 88062306a36Sopenharmony_ci .later = 1, 88162306a36Sopenharmony_ci .expected = 1, 88262306a36Sopenharmony_ci .lam = LAM_U57_BITS, 88362306a36Sopenharmony_ci .test_func = handle_syscall, 88462306a36Sopenharmony_ci .msg = "SYSCALL:[Negative] Disable LAM. Dereferencing pointer with metadata.\n", 88562306a36Sopenharmony_ci }, 88662306a36Sopenharmony_ci}; 88762306a36Sopenharmony_ci 88862306a36Sopenharmony_cistatic struct testcases mmap_cases[] = { 88962306a36Sopenharmony_ci { 89062306a36Sopenharmony_ci .later = 1, 89162306a36Sopenharmony_ci .expected = 0, 89262306a36Sopenharmony_ci .lam = LAM_U57_BITS, 89362306a36Sopenharmony_ci .addr = HIGH_ADDR, 89462306a36Sopenharmony_ci .test_func = handle_mmap, 89562306a36Sopenharmony_ci .msg = "MMAP: First mmap high address, then set LAM_U57.\n", 89662306a36Sopenharmony_ci }, 89762306a36Sopenharmony_ci { 89862306a36Sopenharmony_ci .later = 0, 89962306a36Sopenharmony_ci .expected = 0, 90062306a36Sopenharmony_ci .lam = LAM_U57_BITS, 90162306a36Sopenharmony_ci .addr = HIGH_ADDR, 90262306a36Sopenharmony_ci .test_func = handle_mmap, 90362306a36Sopenharmony_ci .msg = "MMAP: First LAM_U57, then High address.\n", 90462306a36Sopenharmony_ci }, 90562306a36Sopenharmony_ci { 90662306a36Sopenharmony_ci .later = 0, 90762306a36Sopenharmony_ci .expected = 0, 90862306a36Sopenharmony_ci .lam = LAM_U57_BITS, 90962306a36Sopenharmony_ci .addr = LOW_ADDR, 91062306a36Sopenharmony_ci .test_func = handle_mmap, 91162306a36Sopenharmony_ci .msg = "MMAP: First LAM_U57, then Low address.\n", 91262306a36Sopenharmony_ci }, 91362306a36Sopenharmony_ci}; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_cistatic struct testcases inheritance_cases[] = { 91662306a36Sopenharmony_ci { 91762306a36Sopenharmony_ci .expected = 0, 91862306a36Sopenharmony_ci .lam = LAM_U57_BITS, 91962306a36Sopenharmony_ci .test_func = handle_inheritance, 92062306a36Sopenharmony_ci .msg = "FORK: LAM_U57, child process should get LAM mode same as parent\n", 92162306a36Sopenharmony_ci }, 92262306a36Sopenharmony_ci { 92362306a36Sopenharmony_ci .expected = 0, 92462306a36Sopenharmony_ci .lam = LAM_U57_BITS, 92562306a36Sopenharmony_ci .test_func = handle_thread, 92662306a36Sopenharmony_ci .msg = "THREAD: LAM_U57, child thread should get LAM mode same as parent\n", 92762306a36Sopenharmony_ci }, 92862306a36Sopenharmony_ci { 92962306a36Sopenharmony_ci .expected = 1, 93062306a36Sopenharmony_ci .lam = LAM_U57_BITS, 93162306a36Sopenharmony_ci .test_func = handle_thread_enable, 93262306a36Sopenharmony_ci .msg = "THREAD: [NEGATIVE] Enable LAM in child.\n", 93362306a36Sopenharmony_ci }, 93462306a36Sopenharmony_ci { 93562306a36Sopenharmony_ci .expected = 1, 93662306a36Sopenharmony_ci .later = 1, 93762306a36Sopenharmony_ci .lam = LAM_U57_BITS, 93862306a36Sopenharmony_ci .test_func = handle_thread, 93962306a36Sopenharmony_ci .msg = "THREAD: [NEGATIVE] Enable LAM in parent after thread created.\n", 94062306a36Sopenharmony_ci }, 94162306a36Sopenharmony_ci { 94262306a36Sopenharmony_ci .expected = 0, 94362306a36Sopenharmony_ci .lam = LAM_U57_BITS, 94462306a36Sopenharmony_ci .test_func = handle_execve, 94562306a36Sopenharmony_ci .msg = "EXECVE: LAM_U57, child process should get disabled LAM mode\n", 94662306a36Sopenharmony_ci }, 94762306a36Sopenharmony_ci}; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_cistatic void cmd_help(void) 95062306a36Sopenharmony_ci{ 95162306a36Sopenharmony_ci printf("usage: lam [-h] [-t test list]\n"); 95262306a36Sopenharmony_ci printf("\t-t test list: run tests specified in the test list, default:0x%x\n", TEST_MASK); 95362306a36Sopenharmony_ci printf("\t\t0x1:malloc; 0x2:max_bits; 0x4:mmap; 0x8:syscall; 0x10:io_uring; 0x20:inherit;\n"); 95462306a36Sopenharmony_ci printf("\t-h: help\n"); 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci/* Check for file existence */ 95862306a36Sopenharmony_ciuint8_t file_Exists(const char *fileName) 95962306a36Sopenharmony_ci{ 96062306a36Sopenharmony_ci struct stat buffer; 96162306a36Sopenharmony_ci 96262306a36Sopenharmony_ci uint8_t ret = (stat(fileName, &buffer) == 0); 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci return ret; 96562306a36Sopenharmony_ci} 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci/* Sysfs idxd files */ 96862306a36Sopenharmony_ciconst char *dsa_configs[] = { 96962306a36Sopenharmony_ci "echo 1 > /sys/bus/dsa/devices/dsa0/wq0.1/group_id", 97062306a36Sopenharmony_ci "echo shared > /sys/bus/dsa/devices/dsa0/wq0.1/mode", 97162306a36Sopenharmony_ci "echo 10 > /sys/bus/dsa/devices/dsa0/wq0.1/priority", 97262306a36Sopenharmony_ci "echo 16 > /sys/bus/dsa/devices/dsa0/wq0.1/size", 97362306a36Sopenharmony_ci "echo 15 > /sys/bus/dsa/devices/dsa0/wq0.1/threshold", 97462306a36Sopenharmony_ci "echo user > /sys/bus/dsa/devices/dsa0/wq0.1/type", 97562306a36Sopenharmony_ci "echo MyApp1 > /sys/bus/dsa/devices/dsa0/wq0.1/name", 97662306a36Sopenharmony_ci "echo 1 > /sys/bus/dsa/devices/dsa0/engine0.1/group_id", 97762306a36Sopenharmony_ci "echo dsa0 > /sys/bus/dsa/drivers/idxd/bind", 97862306a36Sopenharmony_ci /* bind files and devices, generated a device file in /dev */ 97962306a36Sopenharmony_ci "echo wq0.1 > /sys/bus/dsa/drivers/user/bind", 98062306a36Sopenharmony_ci}; 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci/* DSA device file */ 98362306a36Sopenharmony_ciconst char *dsaDeviceFile = "/dev/dsa/wq0.1"; 98462306a36Sopenharmony_ci/* file for io*/ 98562306a36Sopenharmony_ciconst char *dsaPasidEnable = "/sys/bus/dsa/devices/dsa0/pasid_enabled"; 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_ci/* 98862306a36Sopenharmony_ci * DSA depends on kernel cmdline "intel_iommu=on,sm_on" 98962306a36Sopenharmony_ci * return pasid_enabled (0: disable 1:enable) 99062306a36Sopenharmony_ci */ 99162306a36Sopenharmony_ciint Check_DSA_Kernel_Setting(void) 99262306a36Sopenharmony_ci{ 99362306a36Sopenharmony_ci char command[256] = ""; 99462306a36Sopenharmony_ci char buf[256] = ""; 99562306a36Sopenharmony_ci char *ptr; 99662306a36Sopenharmony_ci int rv = -1; 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci snprintf(command, sizeof(command) - 1, "cat %s", dsaPasidEnable); 99962306a36Sopenharmony_ci 100062306a36Sopenharmony_ci FILE *cmd = popen(command, "r"); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci if (cmd) { 100362306a36Sopenharmony_ci while (fgets(buf, sizeof(buf) - 1, cmd) != NULL); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci pclose(cmd); 100662306a36Sopenharmony_ci rv = strtol(buf, &ptr, 16); 100762306a36Sopenharmony_ci } 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci return rv; 101062306a36Sopenharmony_ci} 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci/* 101362306a36Sopenharmony_ci * Config DSA's sysfs files as shared DSA's WQ. 101462306a36Sopenharmony_ci * Generated a device file /dev/dsa/wq0.1 101562306a36Sopenharmony_ci * Return: 0 OK; 1 Failed; 3 Skip(SVA disabled). 101662306a36Sopenharmony_ci */ 101762306a36Sopenharmony_ciint Dsa_Init_Sysfs(void) 101862306a36Sopenharmony_ci{ 101962306a36Sopenharmony_ci uint len = ARRAY_SIZE(dsa_configs); 102062306a36Sopenharmony_ci const char **p = dsa_configs; 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci if (file_Exists(dsaDeviceFile) == 1) 102362306a36Sopenharmony_ci return 0; 102462306a36Sopenharmony_ci 102562306a36Sopenharmony_ci /* check the idxd driver */ 102662306a36Sopenharmony_ci if (file_Exists(dsaPasidEnable) != 1) { 102762306a36Sopenharmony_ci printf("Please make sure idxd driver was loaded\n"); 102862306a36Sopenharmony_ci return 3; 102962306a36Sopenharmony_ci } 103062306a36Sopenharmony_ci 103162306a36Sopenharmony_ci /* Check SVA feature */ 103262306a36Sopenharmony_ci if (Check_DSA_Kernel_Setting() != 1) { 103362306a36Sopenharmony_ci printf("Please enable SVA.(Add intel_iommu=on,sm_on in kernel cmdline)\n"); 103462306a36Sopenharmony_ci return 3; 103562306a36Sopenharmony_ci } 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci /* Check the idxd device file on /dev/dsa/ */ 103862306a36Sopenharmony_ci for (int i = 0; i < len; i++) { 103962306a36Sopenharmony_ci if (system(p[i])) 104062306a36Sopenharmony_ci return 1; 104162306a36Sopenharmony_ci } 104262306a36Sopenharmony_ci 104362306a36Sopenharmony_ci /* After config, /dev/dsa/wq0.1 should be generated */ 104462306a36Sopenharmony_ci return (file_Exists(dsaDeviceFile) != 1); 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_ci/* 104862306a36Sopenharmony_ci * Open DSA device file, triger API: iommu_sva_alloc_pasid 104962306a36Sopenharmony_ci */ 105062306a36Sopenharmony_civoid *allocate_dsa_pasid(void) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci int fd; 105362306a36Sopenharmony_ci void *wq; 105462306a36Sopenharmony_ci 105562306a36Sopenharmony_ci fd = open(dsaDeviceFile, O_RDWR); 105662306a36Sopenharmony_ci if (fd < 0) { 105762306a36Sopenharmony_ci perror("open"); 105862306a36Sopenharmony_ci return MAP_FAILED; 105962306a36Sopenharmony_ci } 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci wq = mmap(NULL, 0x1000, PROT_WRITE, 106262306a36Sopenharmony_ci MAP_SHARED | MAP_POPULATE, fd, 0); 106362306a36Sopenharmony_ci if (wq == MAP_FAILED) 106462306a36Sopenharmony_ci perror("mmap"); 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_ci return wq; 106762306a36Sopenharmony_ci} 106862306a36Sopenharmony_ci 106962306a36Sopenharmony_ciint set_force_svm(void) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci int ret = 0; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci ret = syscall(SYS_arch_prctl, ARCH_FORCE_TAGGED_SVA); 107462306a36Sopenharmony_ci 107562306a36Sopenharmony_ci return ret; 107662306a36Sopenharmony_ci} 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ciint handle_pasid(struct testcases *test) 107962306a36Sopenharmony_ci{ 108062306a36Sopenharmony_ci uint tmp = test->cmd; 108162306a36Sopenharmony_ci uint runed = 0x0; 108262306a36Sopenharmony_ci int ret = 0; 108362306a36Sopenharmony_ci void *wq = NULL; 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci ret = Dsa_Init_Sysfs(); 108662306a36Sopenharmony_ci if (ret != 0) 108762306a36Sopenharmony_ci return ret; 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_ci for (int i = 0; i < 3; i++) { 109062306a36Sopenharmony_ci int err = 0; 109162306a36Sopenharmony_ci 109262306a36Sopenharmony_ci if (tmp & 0x1) { 109362306a36Sopenharmony_ci /* run set lam mode*/ 109462306a36Sopenharmony_ci if ((runed & 0x1) == 0) { 109562306a36Sopenharmony_ci err = set_lam(LAM_U57_BITS); 109662306a36Sopenharmony_ci runed = runed | 0x1; 109762306a36Sopenharmony_ci } else 109862306a36Sopenharmony_ci err = 1; 109962306a36Sopenharmony_ci } else if (tmp & 0x4) { 110062306a36Sopenharmony_ci /* run force svm */ 110162306a36Sopenharmony_ci if ((runed & 0x4) == 0) { 110262306a36Sopenharmony_ci err = set_force_svm(); 110362306a36Sopenharmony_ci runed = runed | 0x4; 110462306a36Sopenharmony_ci } else 110562306a36Sopenharmony_ci err = 1; 110662306a36Sopenharmony_ci } else if (tmp & 0x2) { 110762306a36Sopenharmony_ci /* run allocate pasid */ 110862306a36Sopenharmony_ci if ((runed & 0x2) == 0) { 110962306a36Sopenharmony_ci runed = runed | 0x2; 111062306a36Sopenharmony_ci wq = allocate_dsa_pasid(); 111162306a36Sopenharmony_ci if (wq == MAP_FAILED) 111262306a36Sopenharmony_ci err = 1; 111362306a36Sopenharmony_ci } else 111462306a36Sopenharmony_ci err = 1; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci ret = ret + err; 111862306a36Sopenharmony_ci if (ret > 0) 111962306a36Sopenharmony_ci break; 112062306a36Sopenharmony_ci 112162306a36Sopenharmony_ci tmp = tmp >> 4; 112262306a36Sopenharmony_ci } 112362306a36Sopenharmony_ci 112462306a36Sopenharmony_ci if (wq != MAP_FAILED && wq != NULL) 112562306a36Sopenharmony_ci if (munmap(wq, 0x1000)) 112662306a36Sopenharmony_ci printf("munmap failed %d\n", errno); 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_ci if (runed != 0x7) 112962306a36Sopenharmony_ci ret = 1; 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci return (ret != 0); 113262306a36Sopenharmony_ci} 113362306a36Sopenharmony_ci 113462306a36Sopenharmony_ci/* 113562306a36Sopenharmony_ci * Pasid test depends on idxd and SVA, kernel should enable iommu and sm. 113662306a36Sopenharmony_ci * command line(intel_iommu=on,sm_on) 113762306a36Sopenharmony_ci */ 113862306a36Sopenharmony_cistatic struct testcases pasid_cases[] = { 113962306a36Sopenharmony_ci { 114062306a36Sopenharmony_ci .expected = 1, 114162306a36Sopenharmony_ci .cmd = PAS_CMD(LAM_CMD_BIT, PAS_CMD_BIT, SVA_CMD_BIT), 114262306a36Sopenharmony_ci .test_func = handle_pasid, 114362306a36Sopenharmony_ci .msg = "PASID: [Negative] Execute LAM, PASID, SVA in sequence\n", 114462306a36Sopenharmony_ci }, 114562306a36Sopenharmony_ci { 114662306a36Sopenharmony_ci .expected = 0, 114762306a36Sopenharmony_ci .cmd = PAS_CMD(LAM_CMD_BIT, SVA_CMD_BIT, PAS_CMD_BIT), 114862306a36Sopenharmony_ci .test_func = handle_pasid, 114962306a36Sopenharmony_ci .msg = "PASID: Execute LAM, SVA, PASID in sequence\n", 115062306a36Sopenharmony_ci }, 115162306a36Sopenharmony_ci { 115262306a36Sopenharmony_ci .expected = 1, 115362306a36Sopenharmony_ci .cmd = PAS_CMD(PAS_CMD_BIT, LAM_CMD_BIT, SVA_CMD_BIT), 115462306a36Sopenharmony_ci .test_func = handle_pasid, 115562306a36Sopenharmony_ci .msg = "PASID: [Negative] Execute PASID, LAM, SVA in sequence\n", 115662306a36Sopenharmony_ci }, 115762306a36Sopenharmony_ci { 115862306a36Sopenharmony_ci .expected = 0, 115962306a36Sopenharmony_ci .cmd = PAS_CMD(PAS_CMD_BIT, SVA_CMD_BIT, LAM_CMD_BIT), 116062306a36Sopenharmony_ci .test_func = handle_pasid, 116162306a36Sopenharmony_ci .msg = "PASID: Execute PASID, SVA, LAM in sequence\n", 116262306a36Sopenharmony_ci }, 116362306a36Sopenharmony_ci { 116462306a36Sopenharmony_ci .expected = 0, 116562306a36Sopenharmony_ci .cmd = PAS_CMD(SVA_CMD_BIT, LAM_CMD_BIT, PAS_CMD_BIT), 116662306a36Sopenharmony_ci .test_func = handle_pasid, 116762306a36Sopenharmony_ci .msg = "PASID: Execute SVA, LAM, PASID in sequence\n", 116862306a36Sopenharmony_ci }, 116962306a36Sopenharmony_ci { 117062306a36Sopenharmony_ci .expected = 0, 117162306a36Sopenharmony_ci .cmd = PAS_CMD(SVA_CMD_BIT, PAS_CMD_BIT, LAM_CMD_BIT), 117262306a36Sopenharmony_ci .test_func = handle_pasid, 117362306a36Sopenharmony_ci .msg = "PASID: Execute SVA, PASID, LAM in sequence\n", 117462306a36Sopenharmony_ci }, 117562306a36Sopenharmony_ci}; 117662306a36Sopenharmony_ci 117762306a36Sopenharmony_ciint main(int argc, char **argv) 117862306a36Sopenharmony_ci{ 117962306a36Sopenharmony_ci int c = 0; 118062306a36Sopenharmony_ci unsigned int tests = TEST_MASK; 118162306a36Sopenharmony_ci 118262306a36Sopenharmony_ci tests_cnt = 0; 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci if (!cpu_has_lam()) { 118562306a36Sopenharmony_ci ksft_print_msg("Unsupported LAM feature!\n"); 118662306a36Sopenharmony_ci return -1; 118762306a36Sopenharmony_ci } 118862306a36Sopenharmony_ci 118962306a36Sopenharmony_ci while ((c = getopt(argc, argv, "ht:")) != -1) { 119062306a36Sopenharmony_ci switch (c) { 119162306a36Sopenharmony_ci case 't': 119262306a36Sopenharmony_ci tests = strtoul(optarg, NULL, 16); 119362306a36Sopenharmony_ci if (tests && !(tests & TEST_MASK)) { 119462306a36Sopenharmony_ci ksft_print_msg("Invalid argument!\n"); 119562306a36Sopenharmony_ci return -1; 119662306a36Sopenharmony_ci } 119762306a36Sopenharmony_ci break; 119862306a36Sopenharmony_ci case 'h': 119962306a36Sopenharmony_ci cmd_help(); 120062306a36Sopenharmony_ci return 0; 120162306a36Sopenharmony_ci default: 120262306a36Sopenharmony_ci ksft_print_msg("Invalid argument\n"); 120362306a36Sopenharmony_ci return -1; 120462306a36Sopenharmony_ci } 120562306a36Sopenharmony_ci } 120662306a36Sopenharmony_ci 120762306a36Sopenharmony_ci /* 120862306a36Sopenharmony_ci * When tests is 0, it is not a real test case; 120962306a36Sopenharmony_ci * the option used by test case(execve) to check the lam mode in 121062306a36Sopenharmony_ci * process generated by execve, the process read back lam mode and 121162306a36Sopenharmony_ci * check with lam mode in parent process. 121262306a36Sopenharmony_ci */ 121362306a36Sopenharmony_ci if (!tests) 121462306a36Sopenharmony_ci return (get_lam()); 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci /* Run test cases */ 121762306a36Sopenharmony_ci if (tests & FUNC_MALLOC) 121862306a36Sopenharmony_ci run_test(malloc_cases, ARRAY_SIZE(malloc_cases)); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci if (tests & FUNC_BITS) 122162306a36Sopenharmony_ci run_test(bits_cases, ARRAY_SIZE(bits_cases)); 122262306a36Sopenharmony_ci 122362306a36Sopenharmony_ci if (tests & FUNC_MMAP) 122462306a36Sopenharmony_ci run_test(mmap_cases, ARRAY_SIZE(mmap_cases)); 122562306a36Sopenharmony_ci 122662306a36Sopenharmony_ci if (tests & FUNC_SYSCALL) 122762306a36Sopenharmony_ci run_test(syscall_cases, ARRAY_SIZE(syscall_cases)); 122862306a36Sopenharmony_ci 122962306a36Sopenharmony_ci if (tests & FUNC_URING) 123062306a36Sopenharmony_ci run_test(uring_cases, ARRAY_SIZE(uring_cases)); 123162306a36Sopenharmony_ci 123262306a36Sopenharmony_ci if (tests & FUNC_INHERITE) 123362306a36Sopenharmony_ci run_test(inheritance_cases, ARRAY_SIZE(inheritance_cases)); 123462306a36Sopenharmony_ci 123562306a36Sopenharmony_ci if (tests & FUNC_PASID) 123662306a36Sopenharmony_ci run_test(pasid_cases, ARRAY_SIZE(pasid_cases)); 123762306a36Sopenharmony_ci 123862306a36Sopenharmony_ci ksft_set_plan(tests_cnt); 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci return ksft_exit_pass(); 124162306a36Sopenharmony_ci} 1242