| // SPDX-License-Identifier: GPL-2.0-only |
| #include <sys/prctl.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <sys/wait.h> |
| #include <sys/types.h> |
| #include <stdlib.h> |
| |
| #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 |