From c2792fb2a69665d27628815cb2f598e1bd50d5a0 Mon Sep 17 00:00:00 2001 From: Xuelian Guo Date: Wed, 11 Sep 2024 16:19:29 +0800 Subject: [PATCH] add LAM basic test cases on SRF platform Signed-off-by: Xuelian Guo --- BM/lam/Makefile | 12 + BM/lam/README.md | 28 + BM/lam/lam | Bin 0 -> 30408 bytes BM/lam/lam.c | 1316 ++++++++++++++++++++++++++++++++++++++++++++++ BM/lam/tests | 9 + 5 files changed, 1365 insertions(+) create mode 100644 BM/lam/Makefile create mode 100644 BM/lam/README.md create mode 100755 BM/lam/lam create mode 100755 BM/lam/lam.c create mode 100644 BM/lam/tests diff --git a/BM/lam/Makefile b/BM/lam/Makefile new file mode 100644 index 0000000..f89d5d5 --- /dev/null +++ b/BM/lam/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Copyright (c) 2024 Intel Corporation. + +CC = gcc +CFLAGS = -D_GNU_SOURCE -lpthread -m64 -O2 +TARGET = lam + +$(TARGET): lam.c + $(CC) $(CFLAGS) -o $@ $< + +clean: + rm -f $(TARGET) diff --git a/BM/lam/README.md b/BM/lam/README.md new file mode 100644 index 0000000..0ae3b16 --- /dev/null +++ b/BM/lam/README.md @@ -0,0 +1,28 @@ +# LAM + +## Description +Linear Address Masking (LAM) is a new feature in the latest Intel platform Sierra Forest. +LAM modifies the checking that is applied to 64-bit linear addresses, allowing software +to use of the untranslated address bits for metadata. +This test suite provides basic functional check to ensure LAM works properly. + +## Usage +``` +make +# To run a specific case +./lam -t +(for example, cpuid) ./lam -t 0x80 +``` +Test results (PASS or FAIL) will be printed out. + +## Testcase ID +| Case ID | Case Name | +| ------ | ---------------------------- | +| 0x1 | malloc | +| 0x2 | max_bits | +| 0x4 | mmap | +| 0x8 | syscall | +| 0x10 | io_uring | +| 0x20 | inherit | +| 0x40 | pasid | +| 0x80 | cpuid | diff --git a/BM/lam/lam b/BM/lam/lam new file mode 100755 index 0000000000000000000000000000000000000000..b2f5501293a50e059df2c1dcff9dd1671a6aa38c GIT binary patch literal 30408 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) // mainline has no this line + +#ifndef __x86_64__ +# error This test is 64-bit only +#endif + +/* LAM modes, these definitions were copied from kernel code */ +#define LAM_NONE 0 +#define LAM_U57_BITS 6 + +#define LAM_U57_MASK (0x3fULL << 57) + +/* arch prctl for LAM */ +#define ARCH_GET_UNTAG_MASK 0x4001 +#define ARCH_ENABLE_TAGGED_ADDR 0x4002 +#define ARCH_GET_MAX_TAG_BITS 0x4003 +#define ARCH_FORCE_TAGGED_SVM 0x4004 + +/* Specified test function bits */ +#define FUNC_MALLOC 0x1 +#define FUNC_BITS 0x2 +#define FUNC_MMAP 0x4 +#define FUNC_SYSCALL 0x8 +#define FUNC_URING 0x10 +#define FUNC_INHERITE 0x20 +#define FUNC_PASID 0x40 +#define FUNC_CPUID 0x80 + +#define TEST_MASK 0xff + +#define LOW_ADDR (0x1UL << 30) +#define HIGH_ADDR (0x3UL << 48) + +#define MALLOC_LEN 32 + +#define PAGE_SIZE (4 << 10) + +#define STACK_SIZE (4 << 10) //mainline 65536 + +#define barrier() ({ \ + __asm__ __volatile__("" : : : "memory"); \ +}) + +#define URING_QUEUE_SZ 1 +#define URING_BLOCK_SZ 2048 + +/* Pasid test define */ +#define LAM_CMD_BIT 0x1 +#define PAS_CMD_BIT 0x2 +#define SVM_CMD_BIT 0x4 + +#define PAS_CMD(cmd1, cmd2, cmd3) (((cmd3) << 8) | ((cmd2) << 4) | ((cmd1) << 0)) + +struct testcases { + unsigned int later; + int expected; /* 2: SIGSEGV Error; 1: other errors */ + unsigned long lam; + uint64_t addr; + uint64_t cmd; + int (*test_func)(struct testcases *test); + const char *msg; +}; + +/* Used by CQ of uring, source file handler and file's size */ +struct file_io { + int file_fd; + off_t file_sz; + struct iovec iovecs[]; +}; + +struct io_uring_queue { + unsigned int *head; + unsigned int *tail; + unsigned int *ring_mask; + unsigned int *ring_entries; + unsigned int *flags; + unsigned int *array; + union { + struct io_uring_cqe *cqes; + struct io_uring_sqe *sqes; + } queue; + size_t ring_sz; +}; + +struct io_ring { + int ring_fd; + struct io_uring_queue sq_ring; + struct io_uring_queue cq_ring; +}; + +int tests_cnt; +int tests_pass; +jmp_buf segv_env; + +static void segv_handler(int sig) +{ + printf("Get segmentation fault(%d).", sig); + + siglongjmp(segv_env, 1); +} + +static inline int cpu_has_lam(void) +{ + unsigned int cpuinfo[4]; + + __cpuid_count(0x7, 1, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); + + return (cpuinfo[0] & (1 << 26)); +} + +/* Check 5-level page table feature in CPUID.(EAX=07H, ECX=00H):ECX.[bit 16] */ +static inline int cpu_has_la57(void) +{ + unsigned int cpuinfo[4]; + + __cpuid_count(0x7, 0, cpuinfo[0], cpuinfo[1], cpuinfo[2], cpuinfo[3]); + + return (cpuinfo[2] & (1 << 16)); +} + +/* + * Set tagged address and read back untag mask. + * check if the untagged mask is expected. + * + * @return: + * 0: Set LAM mode successfully + * others: failed to set LAM + */ +static int set_lam(unsigned long lam) +{ + int ret = 0; + uint64_t ptr = 0; + + if (lam != LAM_U57_BITS && lam != LAM_NONE) + return -1; + + /* Skip check return */ + syscall(SYS_arch_prctl, ARCH_ENABLE_TAGGED_ADDR, lam); + + /* Get untagged mask */ + syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr); + + /* Check mask returned is expected */ + if (lam == LAM_U57_BITS) + ret = (ptr != ~(LAM_U57_MASK)); + else if (lam == LAM_NONE) + ret = (ptr != -1ULL); + + return ret; +} + +static unsigned long get_default_tag_bits(void) +{ + pid_t pid; + int lam = LAM_NONE; + int ret = 0; + + pid = fork(); + if (pid < 0) { + perror("Fork failed."); + } else if (pid == 0) { + /* Set LAM mode in child process */ + if (set_lam(LAM_U57_BITS) == 0) + lam = LAM_U57_BITS; + else + lam = LAM_NONE; + exit(lam); + } else { + wait(&ret); + lam = WEXITSTATUS(ret); + } + + return lam; +} + +/* + * Set tagged address and read back untag mask. + * check if the untag mask is expected. + */ +static int get_lam(void) +{ + uint64_t ptr = 0; + int ret = -1; + /* Get untagged mask */ + if (syscall(SYS_arch_prctl, ARCH_GET_UNTAG_MASK, &ptr) == -1) + return -1; + + /* Check mask returned is expected */ + if (ptr == ~(LAM_U57_MASK)) + ret = LAM_U57_BITS; + else if (ptr == -1ULL) + ret = LAM_NONE; + + return ret; +} + +/* According to LAM mode, set metadata in high bits */ +static uint64_t set_metadata(uint64_t src, unsigned long lam) +{ + uint64_t metadata; + + srand(time(NULL)); + /* Get a random value as metadata */ + metadata = rand(); + + switch (lam) { + case LAM_U57_BITS: /* Set metadata in bits 62:57 */ + /* Get a random non-zero value as metadata */ + metadata = (rand() % ((1UL << LAM_U57_BITS) - 1) + 1) << 57; + metadata |= (src & ~(LAM_U57_MASK)); + /* ddt old way*/ + //metadata = (src & ~(LAM_U57_MASK)) | ((metadata & 0x3f) << 57); + break; + default: + metadata = src; + break; + } + + return metadata; +} + +/* + * Set metadata in user pointer, compare new pointer with original pointer. + * both pointers should point to the same address. + * + * @return: + * 0: value on the pointer with metadate and value on original are same + * 1: not same. + */ +static int handle_lam_test(void *src, unsigned int lam) +{ + char *ptr; + + strcpy((char *)src, "USER POINTER"); + + ptr = (char *)set_metadata((uint64_t)src, lam); + if (src == ptr) + return 0; + + /* Copy a string into the pointer with metadata */ + strcpy((char *)ptr, "METADATA POINTER"); + + return (!!strcmp((char *)src, (char *)ptr)); +} + + +int handle_max_bits(struct testcases *test) +{ + void *ptr; + unsigned int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; + unsigned long exp_bits = get_default_tag_bits(); + unsigned long bits = 0; + + if (exp_bits != LAM_NONE) + exp_bits = LAM_U57_BITS; + + ptr = mmap((void *)test->addr, PAGE_SIZE, PROT_READ | PROT_WRITE, + flags, -1, 0); + if (ptr == MAP_FAILED) { + if (test->addr == HIGH_ADDR) + if (!cpu_has_la57()) { + return 3; /* unsupport LA57 */ + } + return 1; + } + + /* Get LAM max tag bits */ + if (syscall(SYS_arch_prctl, ARCH_GET_MAX_TAG_BITS, &bits) == -1) + return 1; + + return (exp_bits != bits); +} + +/* + * Test lam feature through dereference pointer get from malloc. + * @return 0: Pass test. 1: Get failure during test 2: Get SIGSEGV + */ +static int handle_malloc(struct testcases *test) +{ + char *ptr = NULL; + int ret = 0; + + if (test->later == 0 && test->lam != 0) + if (set_lam(test->lam) == -1) + return 1; + + ptr = (char *)malloc(MALLOC_LEN); + if (ptr == NULL) { + perror("malloc() failure\n"); + return 1; + } + + /* Set signal handler */ + if (sigsetjmp(segv_env, 1) == 0) { + signal(SIGSEGV, segv_handler); + ret = handle_lam_test(ptr, test->lam); + } else { + ret = 2; + } + + if (test->later != 0 && test->lam != 0) + if (set_lam(test->lam) == -1 && ret == 0) + ret = 1; + + free(ptr); + + return ret; +} + +static int handle_mmap(struct testcases *test) +{ + void *ptr; + unsigned int flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED; + int ret = 0; + + if (test->later == 0 && test->lam != 0) + if (set_lam(test->lam) != 0) + return 1; + + ptr = mmap((void *)test->addr, PAGE_SIZE, PROT_READ | PROT_WRITE, + flags, -1, 0); + if (ptr == MAP_FAILED) { + if (test->addr == HIGH_ADDR) { + if (!cpu_has_la57()) + { + return 3; /* unsupport LA57 */ + } else { + return 1; /* support LA57 */ + } + } else { + + return 1; + } + } + + if (test->later != 0 && test->lam != 0) + if (set_lam(test->lam) != 0) + ret = 1; + + if (ret == 0) { + if (sigsetjmp(segv_env, 1) == 0) { + signal(SIGSEGV, segv_handler); + ret = handle_lam_test(ptr, test->lam); + } else { + ret = 2; + } + } + + munmap(ptr, PAGE_SIZE); + return ret; +} + +static int handle_syscall(struct testcases *test) +{ + struct utsname unme, *pu; + int ret = 0; + + if (test->later == 0 && test->lam != 0) + if (set_lam(test->lam) != 0) + return 1; + + if (sigsetjmp(segv_env, 1) == 0) { + signal(SIGSEGV, segv_handler); + pu = (struct utsname *)set_metadata((uint64_t)&unme, test->lam); + ret = uname(pu); + if (ret < 0) + ret = 1; + } else { + ret = 2; + } + + if (test->later != 0 && test->lam != 0) + if (set_lam(test->lam) != -1 && ret == 0) + ret = 1; + + return ret; +} + +int sys_uring_setup(unsigned int entries, struct io_uring_params *p) +{ + return (int)syscall(__NR_io_uring_setup, entries, p); +} + +int sys_uring_enter(int fd, unsigned int to, unsigned int min, unsigned int flags) +{ + return (int)syscall(__NR_io_uring_enter, fd, to, min, flags, NULL, 0); +} + +/* Init submission queue and completion queue */ +int mmap_io_uring(struct io_uring_params p, struct io_ring *s) +{ + struct io_uring_queue *sring = &s->sq_ring; + struct io_uring_queue *cring = &s->cq_ring; + + sring->ring_sz = p.sq_off.array + p.sq_entries * sizeof(unsigned int); + cring->ring_sz = p.cq_off.cqes + p.cq_entries * sizeof(struct io_uring_cqe); + + if (p.features & IORING_FEAT_SINGLE_MMAP) { + if (cring->ring_sz > sring->ring_sz) + sring->ring_sz = cring->ring_sz; + + cring->ring_sz = sring->ring_sz; + } + + void *sq_ptr = mmap(0, sring->ring_sz, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_POPULATE, s->ring_fd, + IORING_OFF_SQ_RING); + + if (sq_ptr == MAP_FAILED) { + perror("sub-queue!"); + return 1; + } + + void *cq_ptr = sq_ptr; + + if (!(p.features & IORING_FEAT_SINGLE_MMAP)) { + cq_ptr = mmap(0, cring->ring_sz, PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_POPULATE, s->ring_fd, + IORING_OFF_CQ_RING); + if (cq_ptr == MAP_FAILED) { + perror("cpl-queue!"); + munmap(sq_ptr, sring->ring_sz); + return 1; + } + } + + sring->head = sq_ptr + p.sq_off.head; + sring->tail = sq_ptr + p.sq_off.tail; + sring->ring_mask = sq_ptr + p.sq_off.ring_mask; + sring->ring_entries = sq_ptr + p.sq_off.ring_entries; + sring->flags = sq_ptr + p.sq_off.flags; + sring->array = sq_ptr + p.sq_off.array; + + /* Map a queue as mem map */ + s->sq_ring.queue.sqes = mmap(0, p.sq_entries * sizeof(struct io_uring_sqe), + PROT_READ | PROT_WRITE, MAP_SHARED | MAP_POPULATE, + s->ring_fd, IORING_OFF_SQES); + if (s->sq_ring.queue.sqes == MAP_FAILED) { + munmap(sq_ptr, sring->ring_sz); + if (sq_ptr != cq_ptr) { + printf("failed to mmap uring queue!"); + munmap(cq_ptr, cring->ring_sz); + return 1; + } + } + + cring->head = cq_ptr + p.cq_off.head; + cring->tail = cq_ptr + p.cq_off.tail; + cring->ring_mask = cq_ptr + p.cq_off.ring_mask; + cring->ring_entries = cq_ptr + p.cq_off.ring_entries; + cring->queue.cqes = cq_ptr + p.cq_off.cqes; + + return 0; +} + +/* Init io_uring queues */ +int setup_io_uring(struct io_ring *s) +{ + struct io_uring_params para; + + memset(¶, 0, sizeof(para)); + s->ring_fd = sys_uring_setup(URING_QUEUE_SZ, ¶); + if (s->ring_fd < 0) + return 1; + + return mmap_io_uring(para, s); +} + +/* + * Get data from completion queue. the data buffer saved the file data + * return 0: success; others: error; + */ +int handle_uring_cq(struct io_ring *s) +{ + struct file_io *fi = NULL; + struct io_uring_queue *cring = &s->cq_ring; + struct io_uring_cqe *cqe; + unsigned int head; + off_t len = 0; + + head = *cring->head; + + do { + barrier(); + if (head == *cring->tail) + break; + /* Get the entry */ + cqe = &cring->queue.cqes[head & *s->cq_ring.ring_mask]; + fi = (struct file_io *)cqe->user_data; + if (cqe->res < 0) + break; + + int blocks = (int)(fi->file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ; + + for (int i = 0; i < blocks; i++) + len += fi->iovecs[i].iov_len; + + head++; + } while (1); + + *cring->head = head; + barrier(); + + return (len != fi->file_sz); +} + +/* + * Submit squeue. specify via IORING_OP_READV. + * the buffer need to be set metadata according to LAM mode + */ +int handle_uring_sq(struct io_ring *ring, struct file_io *fi, unsigned long lam) +{ + int file_fd = fi->file_fd; + struct io_uring_queue *sring = &ring->sq_ring; + unsigned int index = 0, cur_block = 0, tail = 0, next_tail = 0; + struct io_uring_sqe *sqe; + + off_t remain = fi->file_sz; + int blocks = (int)(remain + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ; + + while (remain) { + off_t bytes = remain; + void *buf; + + if (bytes > URING_BLOCK_SZ) + bytes = URING_BLOCK_SZ; + + fi->iovecs[cur_block].iov_len = bytes; + + if (posix_memalign(&buf, URING_BLOCK_SZ, URING_BLOCK_SZ)) + return 1; + + fi->iovecs[cur_block].iov_base = (void *)set_metadata((uint64_t)buf, lam); + remain -= bytes; + cur_block++; + } + + next_tail = *sring->tail; + tail = next_tail; + next_tail++; + + barrier(); + + index = tail & *ring->sq_ring.ring_mask; + + sqe = &ring->sq_ring.queue.sqes[index]; + sqe->fd = file_fd; + sqe->flags = 0; + sqe->opcode = IORING_OP_READV; + sqe->addr = (unsigned long)fi->iovecs; + sqe->len = blocks; + sqe->off = 0; + sqe->user_data = (uint64_t)fi; + + sring->array[index] = index; + tail = next_tail; + + if (*sring->tail != tail) { + *sring->tail = tail; + barrier(); + } + + if (sys_uring_enter(ring->ring_fd, 1, 1, IORING_ENTER_GETEVENTS) < 0) + return 1; + + return 0; +} + +/* + * Test LAM in async I/O and io_uring, read current binery through io_uring + * Set metadata in pointers to iovecs buffer. + */ +int do_uring(unsigned long lam) +{ + struct io_ring *ring; + struct file_io *fi; + struct stat st; + int ret = 1; + char path[PATH_MAX] = {0}; + + /* get current process path */ + if (readlink("/proc/self/exe", path, PATH_MAX) <= 0) + return 1; + + int file_fd = open(path, O_RDONLY); + + if (file_fd < 0) + return 1; + + if (fstat(file_fd, &st) < 0) + return 1; + + off_t file_sz = st.st_size; + + int blocks = (int)(file_sz + URING_BLOCK_SZ - 1) / URING_BLOCK_SZ; + + fi = malloc(sizeof(*fi) + sizeof(struct iovec) * blocks); + if (!fi) + return 1; + + fi->file_sz = file_sz; + fi->file_fd = file_fd; + + ring = malloc(sizeof(*ring)); + if (!ring) + return 1; + + memset(ring, 0, sizeof(struct io_ring)); + + if (setup_io_uring(ring)) + goto out; + + if (handle_uring_sq(ring, fi, lam)) + goto out; + + ret = handle_uring_cq(ring); + +out: + free(ring); + + for (int i = 0; i < blocks; i++) { + if (fi->iovecs[i].iov_base) { + uint64_t addr = ((uint64_t)fi->iovecs[i].iov_base); + + switch (lam) { + case LAM_U57_BITS: /* Clear bits 62:57 */ + addr = (addr & ~(LAM_U57_MASK)); + break; + } + free((void *)addr); + fi->iovecs[i].iov_base = NULL; + } + } + + free(fi); + + return ret; +} + +int handle_uring(struct testcases *test) +{ + int ret = 0; + + if (test->later == 0 && test->lam != 0) + if (set_lam(test->lam) != 0) + return 1; + + if (sigsetjmp(segv_env, 1) == 0) { + signal(SIGSEGV, segv_handler); + ret = do_uring(test->lam); + } else { + ret = 2; + } + + return ret; +} + +static int fork_test(struct testcases *test) +{ + int ret, child_ret; + pid_t pid; + + pid = fork(); + if (pid < 0) { + perror("Fork failed."); + ret = 1; + } else if (pid == 0) { + ret = test->test_func(test); + exit(ret); + } else { + wait(&child_ret); + ret = WEXITSTATUS(child_ret); + } + + return ret; +} + +static int handle_execve(struct testcases *test) +{ + int ret, child_ret; + int lam = test->lam; + pid_t pid; + + pid = fork(); + if (pid < 0) { + perror("Fork failed."); + ret = 1; + } else if (pid == 0) { + char path[PATH_MAX] = {0}; + + /* Set LAM mode in parent process */ + if (set_lam(lam) != 0) + return 1; + + /* Get current binary's path and the binary was run by execve */ + if (readlink("/proc/self/exe", path, PATH_MAX) <= 0) + exit(-1); + + /* run binary to get LAM mode and return to parent process */ + printf("%s\n", path); + if (execlp(path, path, "-t 0x0", NULL) < 0) { + perror("error on exec"); + exit(-1); + } + } else { + wait(&child_ret); + ret = WEXITSTATUS(child_ret); + if (ret != LAM_NONE) + return 1; + } + + return 0; +} + +static int handle_inheritance(struct testcases *test) +{ + int ret, child_ret; + int lam = test->lam; + pid_t pid; + + /* Set LAM mode in parent process */ + if (set_lam(lam) != 0) + return 1; + + pid = fork(); + if (pid < 0) { + perror("Fork failed."); + return 1; + } else if (pid == 0) { + /* Set LAM mode in parent process */ + int child_lam = get_lam(); + + exit(child_lam); + } else { + wait(&child_ret); + ret = WEXITSTATUS(child_ret); + + if (lam != ret) + return 1; + } + + return 0; +} + +static int thread_fn_get_lam(void *arg) +{ + return get_lam(); +} + +static int thread_fn_set_lam(void *arg) +{ + struct testcases *test = arg; + + return set_lam(test->lam); +} + + +static int handle_thread(struct testcases *test) +{ + char stack[STACK_SIZE]; + int ret, child_ret; + int lam = 0; + pid_t pid; + + /* Set LAM mode in parent process */ + if (!test->later) { + lam = test->lam; + if (set_lam(lam) != 0) + return 1; + } + + pid = clone(thread_fn_get_lam, stack + STACK_SIZE, + SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, NULL); + if (pid < 0) { + perror("Clone failed."); + return 1; + } + + waitpid(pid, &child_ret, 0); + ret = WEXITSTATUS(child_ret); + + if (lam != ret) + return 1; + + if (test->later) { + if (set_lam(test->lam) != 0) + return 1; + } + + return 0; +} + + +static int handle_thread_enable(struct testcases *test) +{ + char stack[STACK_SIZE]; + int ret, child_ret; + int lam = test->lam; + pid_t pid; + + pid = clone(thread_fn_set_lam, stack + STACK_SIZE, + SIGCHLD | CLONE_FILES | CLONE_FS | CLONE_VM, test); + if (pid < 0) { + perror("Clone failed."); + return 1; + } + + waitpid(pid, &child_ret, 0); + ret = WEXITSTATUS(child_ret); + + if (lam != ret) + return 1; + + return 0; +} + +int handle_cpuid(struct testcases *test) +{ + int ret=0; + + if (cpu_has_lam()) { + ret = 0; /* LAM CPUID is supported */ + } else { + ret = 1; /* LAM CPUID is not supported */ + } + + return ret; +} + +static void run_test(struct testcases *test, int count) +{ + int i, ret = 0; + + for (i = 0; i < count; i++) { + struct testcases *t = test + i; + + /* fork a process to run test case */ + tests_cnt++; + ret = fork_test(t); + + /* return 3 is not support LA57, the case should be skipped */ + if (ret == 3) { + tests_pass++; + printf("[SKIP] No:%d %s", tests_cnt, t->msg); + continue; + } + + if (ret != 0) + ret = (t->expected == ret); + else + ret = !(t->expected); + + + if (ret == 1) { + tests_pass++; + printf("[PASS] No:%d %s", tests_cnt, t->msg); + } else { + printf("[FAIL] No:%d %s", tests_cnt, t->msg); + } + } +} + +static struct testcases uring_cases[] = { + { + .later = 0, + .lam = LAM_U57_BITS, + .test_func = handle_uring, + .msg = "URING: LAM_U57. Dereferencing pointer with metadata\n", + }, + { + .later = 1, + .expected = 1, + .lam = LAM_U57_BITS, + .test_func = handle_uring, + .msg = "URING:[Negative] Disable LAM. Dereferencing pointer with metadata.\n", + }, +}; + +static struct testcases malloc_cases[] = { + { + .later = 0, + .lam = LAM_U57_BITS, + .test_func = handle_malloc, + .msg = "MALLOC: LAM_U57. Dereferencing pointer with metadata\n", + }, + { + .later = 1, + .expected = 2, + .lam = LAM_U57_BITS, + .test_func = handle_malloc, + .msg = "MALLOC:[Negative] Disable LAM. Dereferencing pointer with metadata.\n", + }, +}; + +static struct testcases bits_cases[] = { + { + .test_func = handle_max_bits, + .msg = "BITS: Check default tag bits\n", + }, +}; + +static struct testcases syscall_cases[] = { + { + .later = 0, + .lam = LAM_U57_BITS, + .test_func = handle_syscall, + .msg = "SYSCALL: LAM_U57. syscall with metadata\n", + }, + { + .later = 1, + .expected = 1, + .lam = LAM_U57_BITS, + .test_func = handle_syscall, + .msg = "SYSCALL:[Negative] Disable LAM. Dereferencing pointer with metadata.\n", + }, +}; + +static struct testcases mmap_cases[] = { + { + .later = 1, + .expected = 0, + .lam = LAM_U57_BITS, + .addr = HIGH_ADDR, + .test_func = handle_mmap, + .msg = "MMAP: First mmap high address, then set LAM_U57.\n", + }, + { + .later = 0, + .expected = 0, + .lam = LAM_U57_BITS, + .addr = HIGH_ADDR, + .test_func = handle_mmap, + .msg = "MMAP: First LAM_U57, then High address.\n", + }, + { + .later = 0, + .expected = 0, + .lam = LAM_U57_BITS, + .addr = LOW_ADDR, + .test_func = handle_mmap, + .msg = "MMAP: First LAM_U57, then Low address.\n", + }, +}; + +static struct testcases inheritance_cases[] = { + { + .expected = 0, + .lam = LAM_U57_BITS, + .test_func = handle_inheritance, + .msg = "FORK: LAM_U57, child process should get LAM mode same as parent\n", + }, + { + .expected = 0, + .lam = LAM_U57_BITS, + .test_func = handle_thread, + .msg = "THREAD: LAM_U57, child thread should get LAM mode same as parent\n", + }, + { + .expected = 1, + .lam = LAM_U57_BITS, + .test_func = handle_thread_enable, + .msg = "THREAD: [NEGATIVE] Enable LAM in child.\n", + }, + { + .expected = 1, + .later = 1, + .lam = LAM_U57_BITS, + .test_func = handle_thread, + .msg = "THREAD: [NEGATIVE] Enable LAM in parent after thread created.\n", + }, + { + .expected = 0, + .lam = LAM_U57_BITS, + .test_func = handle_execve, + .msg = "EXECVE: LAM_U57, child process should get disabled LAM mode\n", + }, +}; + +static void cmd_help(void) +{ + printf("usage: lam [-h] [-t test list]\n"); + printf("\t-t test list: run tests specified in the test list, default:0x%x\n", TEST_MASK); + printf("\t\t0x1:malloc;\n"); + printf("\t\t0x2:max_bits;\n"); + printf("\t\t0x4:mmap;\n"); + printf("\t\t0x8:syscall;\n"); + printf("\t\t0x10:io_uring;\n"); + printf("\t\t0x20:inherit;\n"); + printf("\t\t0x40:pasid;\n"); + printf("\t\t0x80:cpuid;\n"); + + printf("\t-h: help\n"); +} + + +/* Check for file existence */ +uint8_t file_Exists(const char *fileName) +{ + struct stat buffer; + + uint8_t ret = (stat(fileName, &buffer) == 0); + + return ret; +} + +/* Sysfs idxd files */ +const char *dsa_configs[] = { + "echo 1 > /sys/bus/dsa/devices/dsa0/wq0.1/group_id", + "echo shared > /sys/bus/dsa/devices/dsa0/wq0.1/mode", + "echo 10 > /sys/bus/dsa/devices/dsa0/wq0.1/priority", + "echo 16 > /sys/bus/dsa/devices/dsa0/wq0.1/size", + "echo 15 > /sys/bus/dsa/devices/dsa0/wq0.1/threshold", + "echo user > /sys/bus/dsa/devices/dsa0/wq0.1/type", + "echo MyApp1 > /sys/bus/dsa/devices/dsa0/wq0.1/name", + "echo 1 > /sys/bus/dsa/devices/dsa0/engine0.1/group_id", + "echo dsa0 > /sys/bus/dsa/drivers/idxd/bind", + /* bind files and devices, generated a device file in /dev */ + "echo wq0.1 > /sys/bus/dsa/drivers/user/bind", +}; + +/* DSA device file */ +const char *dsaDeviceFile = "/dev/dsa/wq0.1"; +/* file for io*/ +const char *dsaPasidEnable = "/sys/bus/dsa/devices/dsa0/pasid_enabled"; + +/* + * DSA depends on kernel cmdline "intel_iommu=on,sm_on" + * return pasid_enabled (0: disable 1:enable) + */ +int Check_DSA_Kernel_Setting(void) +{ + char command[256] = ""; + char buf[256] = ""; + char *ptr; + int rv = -1; + + snprintf(command, sizeof(command) - 1, "cat %s", dsaPasidEnable); + + FILE *cmd = popen(command, "r"); + + if (cmd) { + while (fgets(buf, sizeof(buf) - 1, cmd) != NULL); + + pclose(cmd); + rv = strtol(buf, &ptr, 16); + } + + return rv; +} + +/* + * Config DSA's sysfs files as shared DSA's WQ. + * Generated a device file /dev/dsa/wq0.1 + * Return: 0 OK; 1 Failed; 3 Skip(SVM disabled). + */ +int Dsa_Init_Sysfs(void) +{ + uint len = ARRAY_SIZE(dsa_configs); + const char **p = dsa_configs; + + if (file_Exists(dsaDeviceFile) == 1) + return 0; + + /* check the idxd driver */ + if (file_Exists(dsaPasidEnable) != 1) { + printf("Please make sure idxd driver was loaded\n"); + return 3; + } + + /* Check SVM feature */ + if (Check_DSA_Kernel_Setting() != 1) { + printf("Please enable SVA.(Add intel_iommu=on,sm_on in kernel cmdline)\n"); + return 3; + } + + /* Check the idxd device file on /dev/dsa/ */ + for (int i = 0; i < len; i++) { + if (system(p[i])) + return 1; + } + + /* After config, /dev/dsa/wq0.1 should be generated */ + return (file_Exists(dsaDeviceFile) != 1); +} + +/* + * Open DSA device file, triger API: iommu_sva_alloc_pasid + */ +void *allocate_dsa_pasid(void) +{ + int fd; + void *wq; + + fd = open(dsaDeviceFile, O_RDWR); + if (fd < 0) { + perror("open"); + return MAP_FAILED; + } + + wq = mmap(NULL, 0x1000, PROT_WRITE, + MAP_SHARED | MAP_POPULATE, fd, 0); + if (wq == MAP_FAILED) + perror("mmap"); + + return wq; +} + +int set_force_svm(void) +{ + int ret = 0; + + ret = syscall(SYS_arch_prctl, ARCH_FORCE_TAGGED_SVM); + + return ret; +} + +int handle_pasid(struct testcases *test) +{ + uint tmp = test->cmd; + uint runed = 0x0; + int ret = 0; + void *wq = NULL; + + ret = Dsa_Init_Sysfs(); + if (ret != 0) + return ret; + + for (int i = 0; i < 3; i++) { + int err = 0; + + if (tmp & 0x1) { + /* run set lam mode*/ + if ((runed & 0x1) == 0) { + err = set_lam(LAM_U57_BITS); + runed = runed | 0x1; + } else + err = 1; + } else if (tmp & 0x4) { + /* run force svm */ + if ((runed & 0x4) == 0) { + err = set_force_svm(); + runed = runed | 0x4; + } else + err = 1; + } else if (tmp & 0x2) { + /* run allocate pasid */ + if ((runed & 0x2) == 0) { + runed = runed | 0x2; + wq = allocate_dsa_pasid(); + if (wq == MAP_FAILED) + err = 1; + } else + err = 1; + } + + ret = ret + err; + if (ret > 0) + break; + + tmp = tmp >> 4; + } + + if (wq != MAP_FAILED && wq != NULL) + if (munmap(wq, 0x1000)) + perror("munmap failed:"); + + if (runed != 0x7) + ret = 1; + + return (ret != 0); +} + +/* + * Pasid test depends on idxd and SVM, kernel should enable iommu and sm. + * command line(intel_iommu=on,sm_on) + */ +static struct testcases pasid_cases[] = { + { + .expected = 1, + .cmd = PAS_CMD(LAM_CMD_BIT, PAS_CMD_BIT, SVM_CMD_BIT), + .test_func = handle_pasid, + .msg = "PASID: [Negative] Execute LAM, PASID, SVM in sequence\n", + }, + { + .expected = 0, + .cmd = PAS_CMD(LAM_CMD_BIT, SVM_CMD_BIT, PAS_CMD_BIT), + .test_func = handle_pasid, + .msg = "PASID: Execute LAM, SVM, PASID in sequence\n", + }, + { + .expected = 1, + .cmd = PAS_CMD(PAS_CMD_BIT, LAM_CMD_BIT, SVM_CMD_BIT), + .test_func = handle_pasid, + .msg = "PASID: [Negative] Execute PASID, LAM, SVM in sequence\n", + }, + { + .expected = 0, + .cmd = PAS_CMD(PAS_CMD_BIT, SVM_CMD_BIT, LAM_CMD_BIT), + .test_func = handle_pasid, + .msg = "PASID: Execute PASID, SVM, LAM in sequence\n", + }, + { + .expected = 0, + .cmd = PAS_CMD(SVM_CMD_BIT, LAM_CMD_BIT, PAS_CMD_BIT), + .test_func = handle_pasid, + .msg = "PASID: Execute SVM, LAM, PASID in sequence\n", + }, + { + .expected = 0, + .cmd = PAS_CMD(SVM_CMD_BIT, PAS_CMD_BIT, LAM_CMD_BIT), + .test_func = handle_pasid, + .msg = "PASID: Execute SVM, PASID, LAM in sequence\n", + }, +}; + +/* cpuid_cases + * cpuid of LAM checking. + */ +static struct testcases cpuid_cases[] = { + { + .expected = 0, + .test_func = handle_cpuid, + .msg = "CPUID: cpuid are supported\n", + }, +}; + +int main(int argc, char **argv) +{ + int c = 0; + unsigned int tests = TEST_MASK; + + tests_cnt = 0; + tests_pass = 0; + + if (!cpu_has_lam()) { + printf("Unsupported LAM feature!\n"); + return -1; + } + + while ((c = getopt(argc, argv, "ht:")) != -1) { + switch (c) { + case 't': + tests = strtoul(optarg, NULL, 16); + if (tests && !(tests & TEST_MASK)) { + printf("Invalid argument!\n"); + return -1; + } + break; + case 'h': + cmd_help(); + return -1; + default: + printf("Invalid argument\n"); + return -1; + } + } + + /* + * When tests is 0, it is not a real test case; + * the option used by test case(execve) to check the lam mode in + * process generated by execve, the process read back lam mode and + * check with lam mode in parent process. + */ + if (!tests) + return (get_lam()); + + /* Run test cases */ + if (tests & FUNC_MALLOC) + run_test(malloc_cases, ARRAY_SIZE(malloc_cases)); + + if (tests & FUNC_BITS) + run_test(bits_cases, ARRAY_SIZE(bits_cases)); + + if (tests & FUNC_MMAP) + run_test(mmap_cases, ARRAY_SIZE(mmap_cases)); + + if (tests & FUNC_SYSCALL) + run_test(syscall_cases, ARRAY_SIZE(syscall_cases)); + + if (tests & FUNC_URING) + run_test(uring_cases, ARRAY_SIZE(uring_cases)); + + if (tests & FUNC_INHERITE) + run_test(inheritance_cases, ARRAY_SIZE(inheritance_cases)); + + if (tests & FUNC_PASID) + run_test(pasid_cases, ARRAY_SIZE(pasid_cases)); + + if (tests & FUNC_CPUID) + run_test(cpuid_cases, ARRAY_SIZE(cpuid_cases)); + + printf("Total tests: %d; Pass:%d\n", tests_cnt, tests_pass); + + return (tests_cnt - tests_pass); +} diff --git a/BM/lam/tests b/BM/lam/tests new file mode 100644 index 0000000..59cc39c --- /dev/null +++ b/BM/lam/tests @@ -0,0 +1,9 @@ +# This file collects the LAM cases +lam -t 0x1 # malloc +lam -t 0x2 # max_bits +lam -t 0x4 # mmap +lam -t 0x8 # syscall +lam -t 0x10 # io_uring +lam -t 0x20 # inherit +lam -t 0x40 # pasid +lam -t 0x80 # cpuid