// SPDX-License-Identifier: GPL-2.0-only #include #include #include #include #include #include #include "../../kselftest_harness.h" #include "v_helpers.h" #define NEXT_PROGRAM "./vstate_exec_nolibc" int test_and_compare_child(long provided, long expected, int inherit, int xtheadvector) { int rc; rc = prctl(PR_RISCV_V_SET_CONTROL, provided); if (rc != 0) { printf("prctl with provided arg %lx failed with code %d\n", provided, rc); return -1; } rc = launch_test(NEXT_PROGRAM, inherit, xtheadvector); if (rc != expected) { printf("Test failed, check %d != %ld\n", rc, expected); return -2; } return 0; } #define PR_RISCV_V_VSTATE_CTRL_CUR_SHIFT 0 #define PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT 2 TEST(get_control_no_v) { long rc; if (is_vector_supported() || is_xtheadvector_supported()) SKIP(return, "Test expects vector to be not supported"); rc = prctl(PR_RISCV_V_GET_CONTROL); EXPECT_EQ(-1, rc) TH_LOG("GET_CONTROL should fail on kernel/hw without ZVE32X"); EXPECT_EQ(EINVAL, errno) TH_LOG("GET_CONTROL should fail on kernel/hw without ZVE32X"); } TEST(set_control_no_v) { long rc; if (is_vector_supported() || is_xtheadvector_supported()) SKIP(return, "Test expects vector to be not supported"); rc = prctl(PR_RISCV_V_SET_CONTROL, PR_RISCV_V_VSTATE_CTRL_ON); EXPECT_EQ(-1, rc) TH_LOG("SET_CONTROL should fail on kernel/hw without ZVE32X"); EXPECT_EQ(EINVAL, errno) TH_LOG("SET_CONTROL should fail on kernel/hw without ZVE32X"); } TEST(vstate_on_current) { long flag; long rc; if (!is_vector_supported() && !is_xtheadvector_supported()) SKIP(return, "Vector not supported"); flag = PR_RISCV_V_VSTATE_CTRL_ON; rc = prctl(PR_RISCV_V_SET_CONTROL, flag); EXPECT_EQ(0, rc) TH_LOG("Enabling V for current should always succeed"); } TEST(vstate_off_eperm) { long flag; long rc; if (!is_vector_supported() && !is_xtheadvector_supported()) SKIP(return, "Vector not supported"); flag = PR_RISCV_V_VSTATE_CTRL_OFF; rc = prctl(PR_RISCV_V_SET_CONTROL, flag); EXPECT_EQ(EPERM, errno) TH_LOG("Disabling V in current thread with V enabled must fail with EPERM(%d)", errno); EXPECT_EQ(-1, rc) TH_LOG("Disabling V in current thread with V enabled must fail with EPERM(%d)", errno); } TEST(vstate_on_no_nesting) { long flag; int xtheadvector = 0; if (!is_vector_supported()) { if (is_xtheadvector_supported()) xtheadvector = 1; else SKIP(return, "Vector not supported"); } /* Turn on next's vector explicitly and test */ flag = PR_RISCV_V_VSTATE_CTRL_ON << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT; EXPECT_EQ(0, test_and_compare_child(flag, PR_RISCV_V_VSTATE_CTRL_ON, 0, xtheadvector)); } TEST(vstate_off_nesting) { long flag; int xtheadvector = 0; if (!is_vector_supported()) { if (is_xtheadvector_supported()) xtheadvector = 1; else SKIP(return, "Vector not supported"); } /* Turn off next's vector explicitly and test */ flag = PR_RISCV_V_VSTATE_CTRL_OFF << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT; EXPECT_EQ(0, test_and_compare_child(flag, PR_RISCV_V_VSTATE_CTRL_OFF, 1, xtheadvector)); } TEST(vstate_on_inherit_no_nesting) { long flag, expected; int xtheadvector = 0; if (!is_vector_supported()) { if (is_xtheadvector_supported()) xtheadvector = 1; else SKIP(return, "Vector not supported"); } /* Turn on next's vector explicitly and test no inherit */ flag = PR_RISCV_V_VSTATE_CTRL_ON << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT; flag |= PR_RISCV_V_VSTATE_CTRL_INHERIT; expected = flag | PR_RISCV_V_VSTATE_CTRL_ON; EXPECT_EQ(0, test_and_compare_child(flag, expected, 0, xtheadvector)); } TEST(vstate_on_inherit) { long flag, expected; int xtheadvector = 0; if (!is_vector_supported()) { if (is_xtheadvector_supported()) xtheadvector = 1; else SKIP(return, "Vector not supported"); } /* Turn on next's vector explicitly and test inherit */ flag = PR_RISCV_V_VSTATE_CTRL_ON << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT; flag |= PR_RISCV_V_VSTATE_CTRL_INHERIT; expected = flag | PR_RISCV_V_VSTATE_CTRL_ON; EXPECT_EQ(0, test_and_compare_child(flag, expected, 1, xtheadvector)); } TEST(vstate_off_inherit_no_nesting) { long flag, expected; int xtheadvector = 0; if (!is_vector_supported()) { if (is_xtheadvector_supported()) xtheadvector = 1; else SKIP(return, "Vector not supported"); } /* Turn off next's vector explicitly and test no inherit */ flag = PR_RISCV_V_VSTATE_CTRL_OFF << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT; flag |= PR_RISCV_V_VSTATE_CTRL_INHERIT; expected = flag | PR_RISCV_V_VSTATE_CTRL_OFF; EXPECT_EQ(0, test_and_compare_child(flag, expected, 0, xtheadvector)); } TEST(vstate_off_inherit) { long flag, expected; int xtheadvector = 0; if (!is_vector_supported()) { if (is_xtheadvector_supported()) xtheadvector = 1; else SKIP(return, "Vector not supported"); } /* Turn off next's vector explicitly and test inherit */ flag = PR_RISCV_V_VSTATE_CTRL_OFF << PR_RISCV_V_VSTATE_CTRL_NEXT_SHIFT; flag |= PR_RISCV_V_VSTATE_CTRL_INHERIT; expected = flag | PR_RISCV_V_VSTATE_CTRL_OFF; EXPECT_EQ(0, test_and_compare_child(flag, expected, 1, xtheadvector)); } /* arguments should fail with EINVAL */ TEST(inval_set_control_1) { int rc; if (!is_vector_supported() && !is_xtheadvector_supported()) SKIP(return, "Vector not supported"); rc = prctl(PR_RISCV_V_SET_CONTROL, 0xff0); EXPECT_EQ(-1, rc); EXPECT_EQ(EINVAL, errno); } /* arguments should fail with EINVAL */ TEST(inval_set_control_2) { int rc; if (!is_vector_supported() && !is_xtheadvector_supported()) SKIP(return, "Vector not supported"); rc = prctl(PR_RISCV_V_SET_CONTROL, 0x3); EXPECT_EQ(-1, rc); EXPECT_EQ(EINVAL, errno); } /* arguments should fail with EINVAL */ TEST(inval_set_control_3) { int rc; if (!is_vector_supported() && !is_xtheadvector_supported()) SKIP(return, "Vector not supported"); rc = prctl(PR_RISCV_V_SET_CONTROL, 0xc); EXPECT_EQ(-1, rc); EXPECT_EQ(EINVAL, errno); } TEST_HARNESS_MAIN