linux-user/riscv: Add syscall riscv_hwprobe

This patch adds the new syscall for the
"RISC-V Hardware Probing Interface"
(https://docs.kernel.org/riscv/hwprobe.html).

Reviewed-by: Palmer Dabbelt <palmer@rivosinc.com>
Signed-off-by: Robbin Ehn <rehn@rivosinc.com>
Message-Id: <06a4543df2aa6101ca9a48f21a3198064b4f1f87.camel@rivosinc.com>
Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
This commit is contained in:
Robbin Ehn 2023-06-19 10:24:03 +02:00 committed by Alistair Francis
parent c0716c81b2
commit 9e1c7d982d
3 changed files with 148 additions and 0 deletions

View File

@ -228,6 +228,7 @@
#define TARGET_NR_accept4 242
#define TARGET_NR_arch_specific_syscall 244
#define TARGET_NR_riscv_flush_icache (TARGET_NR_arch_specific_syscall + 15)
#define TARGET_NR_riscv_hwprobe (TARGET_NR_arch_specific_syscall + 14)
#define TARGET_NR_prlimit64 261
#define TARGET_NR_fanotify_init 262
#define TARGET_NR_fanotify_mark 263

View File

@ -251,6 +251,7 @@
#define TARGET_NR_recvmmsg 243
#define TARGET_NR_arch_specific_syscall 244
#define TARGET_NR_riscv_flush_icache (TARGET_NR_arch_specific_syscall + 15)
#define TARGET_NR_riscv_hwprobe (TARGET_NR_arch_specific_syscall + 14)
#define TARGET_NR_wait4 260
#define TARGET_NR_prlimit64 261
#define TARGET_NR_fanotify_init 262

View File

@ -8983,6 +8983,147 @@ static int do_getdents64(abi_long dirfd, abi_long arg2, abi_long count)
}
#endif /* TARGET_NR_getdents64 */
#if defined(TARGET_NR_riscv_hwprobe)
#define RISCV_HWPROBE_KEY_MVENDORID 0
#define RISCV_HWPROBE_KEY_MARCHID 1
#define RISCV_HWPROBE_KEY_MIMPID 2
#define RISCV_HWPROBE_KEY_BASE_BEHAVIOR 3
#define RISCV_HWPROBE_BASE_BEHAVIOR_IMA (1 << 0)
#define RISCV_HWPROBE_KEY_IMA_EXT_0 4
#define RISCV_HWPROBE_IMA_FD (1 << 0)
#define RISCV_HWPROBE_IMA_C (1 << 1)
#define RISCV_HWPROBE_KEY_CPUPERF_0 5
#define RISCV_HWPROBE_MISALIGNED_UNKNOWN (0 << 0)
#define RISCV_HWPROBE_MISALIGNED_EMULATED (1 << 0)
#define RISCV_HWPROBE_MISALIGNED_SLOW (2 << 0)
#define RISCV_HWPROBE_MISALIGNED_FAST (3 << 0)
#define RISCV_HWPROBE_MISALIGNED_UNSUPPORTED (4 << 0)
#define RISCV_HWPROBE_MISALIGNED_MASK (7 << 0)
struct riscv_hwprobe {
abi_llong key;
abi_ullong value;
};
static void risc_hwprobe_fill_pairs(CPURISCVState *env,
struct riscv_hwprobe *pair,
size_t pair_count)
{
const RISCVCPUConfig *cfg = riscv_cpu_cfg(env);
for (; pair_count > 0; pair_count--, pair++) {
abi_llong key;
abi_ullong value;
__put_user(0, &pair->value);
__get_user(key, &pair->key);
switch (key) {
case RISCV_HWPROBE_KEY_MVENDORID:
__put_user(cfg->mvendorid, &pair->value);
break;
case RISCV_HWPROBE_KEY_MARCHID:
__put_user(cfg->marchid, &pair->value);
break;
case RISCV_HWPROBE_KEY_MIMPID:
__put_user(cfg->mimpid, &pair->value);
break;
case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
value = riscv_has_ext(env, RVI) &&
riscv_has_ext(env, RVM) &&
riscv_has_ext(env, RVA) ?
RISCV_HWPROBE_BASE_BEHAVIOR_IMA : 0;
__put_user(value, &pair->value);
break;
case RISCV_HWPROBE_KEY_IMA_EXT_0:
value = riscv_has_ext(env, RVF) &&
riscv_has_ext(env, RVD) ?
RISCV_HWPROBE_IMA_FD : 0;
value |= riscv_has_ext(env, RVC) ?
RISCV_HWPROBE_IMA_C : pair->value;
__put_user(value, &pair->value);
break;
case RISCV_HWPROBE_KEY_CPUPERF_0:
__put_user(RISCV_HWPROBE_MISALIGNED_FAST, &pair->value);
break;
default:
__put_user(-1, &pair->key);
break;
}
}
}
static int cpu_set_valid(abi_long arg3, abi_long arg4)
{
int ret, i, tmp;
size_t host_mask_size, target_mask_size;
unsigned long *host_mask;
/*
* cpu_set_t represent CPU masks as bit masks of type unsigned long *.
* arg3 contains the cpu count.
*/
tmp = (8 * sizeof(abi_ulong));
target_mask_size = ((arg3 + tmp - 1) / tmp) * sizeof(abi_ulong);
host_mask_size = (target_mask_size + (sizeof(*host_mask) - 1)) &
~(sizeof(*host_mask) - 1);
host_mask = alloca(host_mask_size);
ret = target_to_host_cpu_mask(host_mask, host_mask_size,
arg4, target_mask_size);
if (ret != 0) {
return ret;
}
for (i = 0 ; i < host_mask_size / sizeof(*host_mask); i++) {
if (host_mask[i] != 0) {
return 0;
}
}
return -TARGET_EINVAL;
}
static abi_long do_riscv_hwprobe(CPUArchState *cpu_env, abi_long arg1,
abi_long arg2, abi_long arg3,
abi_long arg4, abi_long arg5)
{
int ret;
struct riscv_hwprobe *host_pairs;
/* flags must be 0 */
if (arg5 != 0) {
return -TARGET_EINVAL;
}
/* check cpu_set */
if (arg3 != 0) {
ret = cpu_set_valid(arg3, arg4);
if (ret != 0) {
return ret;
}
} else if (arg4 != 0) {
return -TARGET_EINVAL;
}
/* no pairs */
if (arg2 == 0) {
return 0;
}
host_pairs = lock_user(VERIFY_WRITE, arg1,
sizeof(*host_pairs) * (size_t)arg2, 0);
if (host_pairs == NULL) {
return -TARGET_EFAULT;
}
risc_hwprobe_fill_pairs(cpu_env, host_pairs, arg2);
unlock_user(host_pairs, arg1, sizeof(*host_pairs) * (size_t)arg2);
return 0;
}
#endif /* TARGET_NR_riscv_hwprobe */
#if defined(TARGET_NR_pivot_root) && defined(__NR_pivot_root)
_syscall2(int, pivot_root, const char *, new_root, const char *, put_old)
#endif
@ -13665,6 +13806,11 @@ static abi_long do_syscall1(CPUArchState *cpu_env, int num, abi_long arg1,
return ret;
#endif
#if defined(TARGET_NR_riscv_hwprobe)
case TARGET_NR_riscv_hwprobe:
return do_riscv_hwprobe(cpu_env, arg1, arg2, arg3, arg4, arg5);
#endif
default:
qemu_log_mask(LOG_UNIMP, "Unsupported syscall: %d\n", num);
return -TARGET_ENOSYS;