// SPDX-License-Identifier: GPL-2.0
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <time.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/mman.h>
#include <sys/utsname.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <inttypes.h>
#include <sched.h>
#include <sys/uio.h>
#include <linux/io_uring.h>
#include "../kselftest.h"
#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_SVA 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 TEST_MASK 0x7f
#define LOW_ADDR (0x1UL << 30)
#define HIGH_ADDR (0x3UL << 48)
#define MALLOC_LEN 32
#define PAGE_SIZE (4 << 10)
#define STACK_SIZE 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 SVA_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;
jmp_buf segv_env;
static void segv_handler(int sig)
{
ksft_print_msg("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(