diff --git a/CMakeLists.txt b/CMakeLists.txt index 73748e181f1..fb9f9240df7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1450,6 +1450,7 @@ set(BASIC_TESTS sysinfo syslog arm/tagged_addr_ctrl + arm/sve_vl tgkill thread_yield timer diff --git a/src/kernel_supplement.h b/src/kernel_supplement.h index df1d677f17c..0c6f8eaaea8 100644 --- a/src/kernel_supplement.h +++ b/src/kernel_supplement.h @@ -520,6 +520,17 @@ enum { #define BLKGETNRZONES _IOR(0x12, 133, __u32) #endif +// New in the 4.15 kernel +#ifndef PR_SVE_SET_VL +#define PR_SVE_SET_VL 50 +#endif +#ifndef PR_SVE_GET_VL +#define PR_SVE_GET_VL 51 +#endif +#ifndef PR_SVE_VL_LEN_MASK +#define PR_SVE_VL_LEN_MASK 0xffff +#endif + // New in the 5.4 kernel #ifndef PR_SET_TAGGED_ADDR_CTRL #define PR_SET_TAGGED_ADDR_CTRL 55 diff --git a/src/record_syscall.cc b/src/record_syscall.cc index 6eccada9e98..738e069d613 100644 --- a/src/record_syscall.cc +++ b/src/record_syscall.cc @@ -4792,6 +4792,8 @@ static Switchable rec_prepare_syscall_arch(RecordTask* t, case PR_GET_SECUREBITS: case PR_GET_TAGGED_ADDR_CTRL: case PR_GET_MDWE: + case PR_SVE_GET_VL: + case PR_SVE_SET_VL: break; case PR_SET_TAGGED_ADDR_CTRL: diff --git a/src/replay_syscall.cc b/src/replay_syscall.cc index 1f98135b383..150e72f1034 100644 --- a/src/replay_syscall.cc +++ b/src/replay_syscall.cc @@ -1215,11 +1215,13 @@ static void rep_process_syscall_arch(ReplayTask* t, ReplayTraceStep* step, case Arch::prctl: { auto arg1 = t->regs().arg1(); if (sys == Arch::prctl && - (Arch::arch() != aarch64 || arg1 != PR_SET_SPECULATION_CTRL) && + (Arch::arch() != aarch64 || (arg1 != PR_SET_SPECULATION_CTRL && + arg1 != PR_SVE_SET_VL)) && ((unsigned long)t->regs().arg1() != PR_SET_VMA || trace_regs.syscall_result_signed() == -EINVAL)) { // On aarch64 PR_SET_SPECULATION_CTRL affects the pstate - // register during the system call, so we need to replay - // it, otherwise we'll get a mismatch there. + // register during the system call, and PR_SVE_SET_VL affects + // the SVE vector length, so we need to replay them, otherwise + // we'll get a mismatch. // We want to replay PR_SET_VMA as well, but not if it originally failed // with EINVAL because the recording kernel may not have supported it. return; diff --git a/src/test/arm/sve_vl.c b/src/test/arm/sve_vl.c new file mode 100644 index 00000000000..447dabe4644 --- /dev/null +++ b/src/test/arm/sve_vl.c @@ -0,0 +1,40 @@ +/* -*- Mode: C; tab-width: 8; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ + +#include "util.h" + +#include +#include + +#ifndef PR_SVE_SET_VL +#define PR_SVE_SET_VL 50 +#endif +#ifndef PR_SVE_GET_VL +#define PR_SVE_GET_VL 51 +#endif +#ifndef PR_SVE_VL_LEN_MASK +#define PR_SVE_VL_LEN_MASK 0xffff +#endif + +int main(void) { + int vl = prctl(PR_SVE_GET_VL); + /* Skip on hardware without SVE support. */ + if (vl == -1 && errno == EINVAL) { + atomic_puts("EXIT-SUCCESS"); + return 0; + } + test_assert(vl > 0); + int len = vl & PR_SVE_VL_LEN_MASK; + test_assert(len > 0); + + /* Set the same vector length we already have. */ + int ret = prctl(PR_SVE_SET_VL, len); + test_assert(ret >= 0); + test_assert((ret & PR_SVE_VL_LEN_MASK) == len); + + /* Confirm GET still returns the same value. */ + int vl2 = prctl(PR_SVE_GET_VL); + test_assert((vl2 & PR_SVE_VL_LEN_MASK) == len); + + atomic_puts("EXIT-SUCCESS"); + return 0; +}