diff options
Diffstat (limited to 'tools/testing')
33 files changed, 759 insertions, 241 deletions
| diff --git a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c index bb143de68875..e27d66b75fb1 100644 --- a/tools/testing/selftests/bpf/prog_tests/arg_parsing.c +++ b/tools/testing/selftests/bpf/prog_tests/arg_parsing.c @@ -144,11 +144,17 @@ static void test_parse_test_list_file(void)  	if (!ASSERT_OK(ferror(fp), "prepare tmp"))  		goto out_fclose; +	if (!ASSERT_OK(fsync(fileno(fp)), "fsync tmp")) +		goto out_fclose; +  	init_test_filter_set(&set); -	ASSERT_OK(parse_test_list_file(tmpfile, &set, true), "parse file"); +	if (!ASSERT_OK(parse_test_list_file(tmpfile, &set, true), "parse file")) +		goto out_fclose; + +	if (!ASSERT_EQ(set.cnt, 4, "test  count")) +		goto out_free_set; -	ASSERT_EQ(set.cnt, 4, "test  count");  	ASSERT_OK(strcmp("test_with_spaces", set.tests[0].name), "test 0 name");  	ASSERT_EQ(set.tests[0].subtest_cnt, 0, "test 0 subtest count");  	ASSERT_OK(strcmp("testA", set.tests[1].name), "test 1 name"); @@ -158,8 +164,8 @@ static void test_parse_test_list_file(void)  	ASSERT_OK(strcmp("testB", set.tests[2].name), "test 2 name");  	ASSERT_OK(strcmp("testC_no_eof_newline", set.tests[3].name), "test 3 name"); +out_free_set:  	free_test_filter_set(&set); -  out_fclose:  	fclose(fp);  out_remove: diff --git a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c index 6630a92b1b47..1204fbc58178 100644 --- a/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c +++ b/tools/testing/selftests/bpf/progs/verifier_global_ptr_args.c @@ -225,7 +225,7 @@ int trusted_to_untrusted(void *ctx)  }  char mem[16]; -u32 off; +u32 offset;  SEC("tp_btf/sys_enter")  __success @@ -240,9 +240,9 @@ int anything_to_untrusted(void *ctx)  	/* scalar to untrusted */  	subprog_untrusted(0);  	/* variable offset to untrusted (map) */ -	subprog_untrusted((void *)mem + off); +	subprog_untrusted((void *)mem + offset);  	/* variable offset to untrusted (trusted) */ -	subprog_untrusted((void *)bpf_get_current_task_btf() + off); +	subprog_untrusted((void *)bpf_get_current_task_btf() + offset);  	return 0;  } @@ -298,12 +298,12 @@ int anything_to_untrusted_mem(void *ctx)  	/* scalar to untrusted mem */  	subprog_void_untrusted(0);  	/* variable offset to untrusted mem (map) */ -	subprog_void_untrusted((void *)mem + off); +	subprog_void_untrusted((void *)mem + offset);  	/* variable offset to untrusted mem (trusted) */ -	subprog_void_untrusted(bpf_get_current_task_btf() + off); +	subprog_void_untrusted(bpf_get_current_task_btf() + offset);  	/* variable offset to untrusted char/enum (map) */ -	subprog_char_untrusted(mem + off); -	subprog_enum_untrusted((void *)mem + off); +	subprog_char_untrusted(mem + offset); +	subprog_enum_untrusted((void *)mem + offset);  	return 0;  } diff --git a/tools/testing/selftests/cgroup/lib/include/cgroup_util.h b/tools/testing/selftests/cgroup/lib/include/cgroup_util.h index 9dc90a1b386d..7ab2824ed7b5 100644 --- a/tools/testing/selftests/cgroup/lib/include/cgroup_util.h +++ b/tools/testing/selftests/cgroup/lib/include/cgroup_util.h @@ -25,6 +25,26 @@ static inline int values_close(long a, long b, int err)  	return labs(a - b) <= (a + b) / 100 * err;  } +/* + * Checks if two given values differ by less than err% of their sum and assert + * with detailed debug info if not. + */ +static inline int values_close_report(long a, long b, int err) +{ +	long diff  = labs(a - b); +	long limit = (a + b) / 100 * err; +	double actual_err = (a + b) ? (100.0 * diff / (a + b)) : 0.0; +	int close = diff <= limit; + +	if (!close) +		fprintf(stderr, +			"[FAIL] actual=%ld expected=%ld | diff=%ld | limit=%ld | " +			"tolerance=%d%% | actual_error=%.2f%%\n", +			a, b, diff, limit, err, actual_err); + +	return close; +} +  extern ssize_t read_text(const char *path, char *buf, size_t max_len);  extern ssize_t write_text(const char *path, char *buf, ssize_t len); diff --git a/tools/testing/selftests/cgroup/test_cpu.c b/tools/testing/selftests/cgroup/test_cpu.c index 2a60e6c41940..d54e2317efff 100644 --- a/tools/testing/selftests/cgroup/test_cpu.c +++ b/tools/testing/selftests/cgroup/test_cpu.c @@ -219,7 +219,7 @@ static int test_cpucg_stats(const char *root)  	if (user_usec <= 0)  		goto cleanup; -	if (!values_close(usage_usec, expected_usage_usec, 1)) +	if (!values_close_report(usage_usec, expected_usage_usec, 1))  		goto cleanup;  	ret = KSFT_PASS; @@ -291,7 +291,7 @@ static int test_cpucg_nice(const char *root)  		user_usec = cg_read_key_long(cpucg, "cpu.stat", "user_usec");  		nice_usec = cg_read_key_long(cpucg, "cpu.stat", "nice_usec"); -		if (!values_close(nice_usec, expected_nice_usec, 1)) +		if (!values_close_report(nice_usec, expected_nice_usec, 1))  			goto cleanup;  		ret = KSFT_PASS; @@ -404,7 +404,7 @@ overprovision_validate(const struct cpu_hogger *children, int num_children)  			goto cleanup;  		delta = children[i + 1].usage - children[i].usage; -		if (!values_close(delta, children[0].usage, 35)) +		if (!values_close_report(delta, children[0].usage, 35))  			goto cleanup;  	} @@ -444,7 +444,7 @@ underprovision_validate(const struct cpu_hogger *children, int num_children)  	int ret = KSFT_FAIL, i;  	for (i = 0; i < num_children - 1; i++) { -		if (!values_close(children[i + 1].usage, children[0].usage, 15)) +		if (!values_close_report(children[i + 1].usage, children[0].usage, 15))  			goto cleanup;  	} @@ -573,16 +573,16 @@ run_cpucg_nested_weight_test(const char *root, bool overprovisioned)  	nested_leaf_usage = leaf[1].usage + leaf[2].usage;  	if (overprovisioned) { -		if (!values_close(leaf[0].usage, nested_leaf_usage, 15)) +		if (!values_close_report(leaf[0].usage, nested_leaf_usage, 15))  			goto cleanup; -	} else if (!values_close(leaf[0].usage * 2, nested_leaf_usage, 15)) +	} else if (!values_close_report(leaf[0].usage * 2, nested_leaf_usage, 15))  		goto cleanup;  	child_usage = cg_read_key_long(child, "cpu.stat", "usage_usec");  	if (child_usage <= 0)  		goto cleanup; -	if (!values_close(child_usage, nested_leaf_usage, 1)) +	if (!values_close_report(child_usage, nested_leaf_usage, 1))  		goto cleanup;  	ret = KSFT_PASS; @@ -691,7 +691,7 @@ static int test_cpucg_max(const char *root)  	expected_usage_usec  		= n_periods * quota_usec + MIN(remainder_usec, quota_usec); -	if (!values_close(usage_usec, expected_usage_usec, 10)) +	if (!values_close_report(usage_usec, expected_usage_usec, 10))  		goto cleanup;  	ret = KSFT_PASS; @@ -762,7 +762,7 @@ static int test_cpucg_max_nested(const char *root)  	expected_usage_usec  		= n_periods * quota_usec + MIN(remainder_usec, quota_usec); -	if (!values_close(usage_usec, expected_usage_usec, 10)) +	if (!values_close_report(usage_usec, expected_usage_usec, 10))  		goto cleanup;  	ret = KSFT_PASS; diff --git a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py index 0ceb297e7757..fb010a48a5a1 100644 --- a/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py +++ b/tools/testing/selftests/drivers/net/hw/lib/py/__init__.py @@ -1,5 +1,13 @@  # SPDX-License-Identifier: GPL-2.0 +""" +Driver test environment (hardware-only tests). +NetDrvEnv and NetDrvEpEnv are the main environment classes. +Former is for local host only tests, latter creates / connects +to a remote endpoint. See NIPA wiki for more information about +running and writing driver tests. +""" +  import sys  from pathlib import Path @@ -8,26 +16,36 @@ KSFT_DIR = (Path(__file__).parent / "../../../../..").resolve()  try:      sys.path.append(KSFT_DIR.as_posix()) -    from net.lib.py import * -    from drivers.net.lib.py import * -      # Import one by one to avoid pylint false positives +    from net.lib.py import NetNS, NetNSEnter, NetdevSimDev      from net.lib.py import EthtoolFamily, NetdevFamily, NetshaperFamily, \          NlError, RtnlFamily, DevlinkFamily, PSPFamily      from net.lib.py import CmdExitFailure -    from net.lib.py import bkg, cmd, defer, ethtool, fd_read_timeout, ip, \ -        rand_port, tool, wait_port_listen -    from net.lib.py import fd_read_timeout +    from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \ +        fd_read_timeout, ip, rand_port, wait_port_listen, wait_file      from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx      from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \          ksft_setup      from net.lib.py import ksft_eq, ksft_ge, ksft_in, ksft_is, ksft_lt, \          ksft_ne, ksft_not_in, ksft_raises, ksft_true, ksft_gt, ksft_not_none -    from net.lib.py import NetNSEnter -    from drivers.net.lib.py import GenerateTraffic +    from drivers.net.lib.py import GenerateTraffic, Remote      from drivers.net.lib.py import NetDrvEnv, NetDrvEpEnv + +    __all__ = ["NetNS", "NetNSEnter", "NetdevSimDev", +               "EthtoolFamily", "NetdevFamily", "NetshaperFamily", +               "NlError", "RtnlFamily", "DevlinkFamily", "PSPFamily", +               "CmdExitFailure", +               "bkg", "cmd", "bpftool", "bpftrace", "defer", "ethtool", +               "fd_read_timeout", "ip", "rand_port", +               "wait_port_listen", "wait_file", +               "KsftSkipEx", "KsftFailEx", "KsftXfailEx", +               "ksft_disruptive", "ksft_exit", "ksft_pr", "ksft_run", +               "ksft_setup", +               "ksft_eq", "ksft_ge", "ksft_in", "ksft_is", "ksft_lt", +               "ksft_ne", "ksft_not_in", "ksft_raises", "ksft_true", "ksft_gt", +               "ksft_not_none", "ksft_not_none", +               "NetDrvEnv", "NetDrvEpEnv", "GenerateTraffic", "Remote"]  except ModuleNotFoundError as e: -    ksft_pr("Failed importing `net` library from kernel sources") -    ksft_pr(str(e)) -    ktap_result(True, comment="SKIP") +    print("Failed importing `net` library from kernel sources") +    print(str(e))      sys.exit(4) diff --git a/tools/testing/selftests/drivers/net/lib/py/__init__.py b/tools/testing/selftests/drivers/net/lib/py/__init__.py index e6c070f32f51..b0c6300150fb 100644 --- a/tools/testing/selftests/drivers/net/lib/py/__init__.py +++ b/tools/testing/selftests/drivers/net/lib/py/__init__.py @@ -22,7 +22,7 @@ try:          NlError, RtnlFamily, DevlinkFamily, PSPFamily      from net.lib.py import CmdExitFailure      from net.lib.py import bkg, cmd, bpftool, bpftrace, defer, ethtool, \ -        fd_read_timeout, ip, rand_port, tool, wait_port_listen, wait_file +        fd_read_timeout, ip, rand_port, wait_port_listen, wait_file      from net.lib.py import KsftSkipEx, KsftFailEx, KsftXfailEx      from net.lib.py import ksft_disruptive, ksft_exit, ksft_pr, ksft_run, \          ksft_setup @@ -34,7 +34,7 @@ try:                 "NlError", "RtnlFamily", "DevlinkFamily", "PSPFamily",                 "CmdExitFailure",                 "bkg", "cmd", "bpftool", "bpftrace", "defer", "ethtool", -               "fd_read_timeout", "ip", "rand_port", "tool", +               "fd_read_timeout", "ip", "rand_port",                 "wait_port_listen", "wait_file",                 "KsftSkipEx", "KsftFailEx", "KsftXfailEx",                 "ksft_disruptive", "ksft_exit", "ksft_pr", "ksft_run", diff --git a/tools/testing/selftests/hid/tests/test_multitouch.py b/tools/testing/selftests/hid/tests/test_multitouch.py index 5d2ffa3d5977..ece0ba8e7d34 100644 --- a/tools/testing/selftests/hid/tests/test_multitouch.py +++ b/tools/testing/selftests/hid/tests/test_multitouch.py @@ -1752,6 +1752,52 @@ class TestWin8TSConfidence(BaseTest.TestWin8Multitouch):          assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1 +    @pytest.mark.skip_if_uhdev( +        lambda uhdev: "Confidence" not in uhdev.fields, +        "Device not compatible, missing Confidence usage", +    ) +    def test_mt_confidence_bad_multi_release(self): +        """Check for the sticky finger being properly detected. + +        We first inject 3 fingers, then release only the second. +        After 100 ms, we should receive a generated event about the +        2 missing fingers being released. +        """ +        uhdev = self.uhdev +        evdev = uhdev.get_evdev() + +        # send 3 touches +        t0 = Touch(1, 50, 10) +        t1 = Touch(2, 150, 100) +        t2 = Touch(3, 250, 200) +        r = uhdev.event([t0, t1, t2]) +        events = uhdev.next_sync_events() +        self.debug_reports(r, uhdev, events) + +        # release the second +        t1.tipswitch = False +        r = uhdev.event([t1]) +        events = uhdev.next_sync_events() +        self.debug_reports(r, uhdev, events) + +        # only the second is released +        assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] != -1 +        assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1 +        assert evdev.slots[2][libevdev.EV_ABS.ABS_MT_TRACKING_ID] != -1 + +        # wait for the timer to kick in +        time.sleep(0.2) + +        events = uhdev.next_sync_events() +        self.debug_reports([], uhdev, events) + +        # now all 3 fingers are released +        assert libevdev.InputEvent(libevdev.EV_KEY.BTN_TOUCH, 0) in events +        assert evdev.slots[0][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1 +        assert evdev.slots[1][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1 +        assert evdev.slots[2][libevdev.EV_ABS.ABS_MT_TRACKING_ID] == -1 + +  class TestElanXPS9360(BaseTest.TestWin8Multitouch):      def create_device(self):          return Digitizer( @@ -2086,3 +2132,12 @@ class Testsynaptics_06cb_ce08(BaseTest.TestPTP):              input_info=(BusType.I2C, 0x06CB, 0xCE08),              rdesc="05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 75 01 95 02 81 02 95 06 81 01 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0 05 01 09 02 a1 01 85 18 09 01 a1 00 05 09 19 01 29 03 46 00 00 15 00 25 01 75 01 95 03 81 02 95 05 81 01 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0 06 00 ff 09 02 a1 01 85 20 09 01 a1 00 09 03 15 00 26 ff 00 35 00 46 ff 00 75 08 95 05 81 02 c0 c0 05 0d 09 05 a1 01 85 03 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 f8 04 75 10 55 0e 65 11 09 30 35 00 46 24 04 95 01 81 02 46 30 02 26 a0 02 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 f8 04 75 10 55 0e 65 11 09 30 35 00 46 24 04 95 01 81 02 46 30 02 26 a0 02 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 f8 04 75 10 55 0e 65 11 09 30 35 00 46 24 04 95 01 81 02 46 30 02 26 a0 02 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 f8 04 75 10 55 0e 65 11 09 30 35 00 46 24 04 95 01 81 02 46 30 02 26 a0 02 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 f8 04 75 10 55 0e 65 11 09 30 35 00 46 24 04 95 01 81 02 46 30 02 26 a0 02 09 31 81 02 c0 05 0d 55 0c 66 01 10 47 ff ff 00 00 27 ff ff 00 00 75 10 95 01 09 56 81 02 09 54 25 7f 95 01 75 08 81 02 05 09 09 01 25 01 75 01 95 01 81 02 95 07 81 03 05 0d 85 08 09 55 09 59 75 04 95 02 25 0f b1 02 85 0d 09 60 75 01 95 01 15 00 25 01 b1 02 95 07 b1 03 85 07 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 0d 09 0e a1 01 85 04 09 22 a1 02 09 52 15 00 25 0a 75 08 95 01 b1 02 c0 09 22 a1 00 85 06 09 57 09 58 75 01 95 02 25 01 b1 02 95 06 b1 03 c0 c0 06 00 ff 09 01 a1 01 85 09 09 02 15 00 26 ff 00 75 08 95 14 91 02 85 0a 09 03 15 00 26 ff 00 75 08 95 14 91 02 85 0b 09 04 15 00 26 ff 00 75 08 95 45 81 02 85 0c 09 05 15 00 26 ff 00 75 08 95 45 81 02 85 0f 09 06 15 00 26 ff 00 75 08 95 03 b1 02 85 0e 09 07 15 00 26 ff 00 75 08 95 01 b1 02 c0",          ) + +class Testsynaptics_06cb_ce26(TestWin8TSConfidence): +    def create_device(self): +        return PTP( +            "uhid test synaptics_06cb_ce26", +            max_contacts=5, +            input_info=(BusType.I2C, 0x06CB, 0xCE26), +            rdesc="05 01 09 02 a1 01 85 02 09 01 a1 00 05 09 19 01 29 02 15 00 25 01 75 01 95 02 81 02 95 06 81 01 05 01 09 30 09 31 15 81 25 7f 75 08 95 02 81 06 c0 c0 05 0d 09 05 a1 01 85 03 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 45 05 75 10 55 0e 65 11 09 30 35 00 46 64 04 95 01 81 02 46 a2 02 26 29 03 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 45 05 75 10 55 0e 65 11 09 30 35 00 46 64 04 95 01 81 02 46 a2 02 26 29 03 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 45 05 75 10 55 0e 65 11 09 30 35 00 46 64 04 95 01 81 02 46 a2 02 26 29 03 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 45 05 75 10 55 0e 65 11 09 30 35 00 46 64 04 95 01 81 02 46 a2 02 26 29 03 09 31 81 02 c0 05 0d 09 22 a1 02 15 00 25 01 09 47 09 42 95 02 75 01 81 02 95 01 75 03 25 05 09 51 81 02 75 01 95 03 81 03 05 01 15 00 26 45 05 75 10 55 0e 65 11 09 30 35 00 46 64 04 95 01 81 02 46 a2 02 26 29 03 09 31 81 02 c0 05 0d 55 0c 66 01 10 47 ff ff 00 00 27 ff ff 00 00 75 10 95 01 09 56 81 02 09 54 25 7f 95 01 75 08 81 02 05 09 09 01 25 01 75 01 95 01 81 02 95 07 81 03 05 0d 85 08 09 55 09 59 75 04 95 02 25 0f b1 02 85 0d 09 60 75 01 95 01 15 00 25 01 b1 02 95 07 b1 03 85 07 06 00 ff 09 c5 15 00 26 ff 00 75 08 96 00 01 b1 02 c0 05 0d 09 0e a1 01 85 04 09 22 a1 02 09 52 15 00 25 0a 75 08 95 01 b1 02 c0 09 22 a1 00 85 06 09 57 09 58 75 01 95 02 25 01 b1 02 95 06 b1 03 c0 c0 06 00 ff 09 01 a1 01 85 09 09 02 15 00 26 ff 00 75 08 95 14 91 02 85 0a 09 03 15 00 26 ff 00 75 08 95 14 91 02 85 0b 09 04 15 00 26 ff 00 75 08 95 3d 81 02 85 0c 09 05 15 00 26 ff 00 75 08 95 3d 81 02 85 0f 09 06 15 00 26 ff 00 75 08 95 03 b1 02 85 0e 09 07 15 00 26 ff 00 75 08 95 01 b1 02 c0", +        ) diff --git a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c index 91906414a474..993c9e38e729 100644 --- a/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c +++ b/tools/testing/selftests/kvm/arm64/arch_timer_edge_cases.c @@ -1020,7 +1020,7 @@ static void set_counter_defaults(void)  {  	const uint64_t MIN_ROLLOVER_SECS = 40ULL * 365 * 24 * 3600;  	uint64_t freq = read_sysreg(CNTFRQ_EL0); -	uint64_t width = ilog2(MIN_ROLLOVER_SECS * freq); +	int width = ilog2(MIN_ROLLOVER_SECS * freq);  	width = clamp(width, 56, 64);  	CVAL_MAX = GENMASK_ULL(width - 1, 0); diff --git a/tools/testing/selftests/kvm/arm64/external_aborts.c b/tools/testing/selftests/kvm/arm64/external_aborts.c index 592b26ded779..d8fe17a6cc59 100644 --- a/tools/testing/selftests/kvm/arm64/external_aborts.c +++ b/tools/testing/selftests/kvm/arm64/external_aborts.c @@ -359,6 +359,44 @@ static void test_mmio_ease(void)  	kvm_vm_free(vm);  } +static void test_serror_amo_guest(void) +{ +	/* +	 * The ISB is entirely unnecessary (and highlights how FEAT_NV2 is borked) +	 * since the write is redirected to memory. But don't write (intentionally) +	 * broken code! +	 */ +	sysreg_clear_set(hcr_el2, HCR_EL2_AMO | HCR_EL2_TGE, 0); +	isb(); + +	GUEST_SYNC(0); +	GUEST_ASSERT(read_sysreg(isr_el1) & ISR_EL1_A); + +	/* +	 * KVM treats the effective value of AMO as 1 when +	 * HCR_EL2.{E2H,TGE} = {1, 0}, meaning the SError will be taken when +	 * unmasked. +	 */ +	local_serror_enable(); +	isb(); +	local_serror_disable(); + +	GUEST_FAIL("Should've taken pending SError exception"); +} + +static void test_serror_amo(void) +{ +	struct kvm_vcpu *vcpu; +	struct kvm_vm *vm = vm_create_with_dabt_handler(&vcpu, test_serror_amo_guest, +							unexpected_dabt_handler); + +	vm_install_exception_handler(vm, VECTOR_ERROR_CURRENT, expect_serror_handler); +	vcpu_run_expect_sync(vcpu); +	vcpu_inject_serror(vcpu); +	vcpu_run_expect_done(vcpu); +	kvm_vm_free(vm); +} +  int main(void)  {  	test_mmio_abort(); @@ -369,4 +407,9 @@ int main(void)  	test_serror_emulated();  	test_mmio_ease();  	test_s1ptw_abort(); + +	if (!test_supports_el2()) +		return 0; + +	test_serror_amo();  } diff --git a/tools/testing/selftests/kvm/arm64/get-reg-list.c b/tools/testing/selftests/kvm/arm64/get-reg-list.c index 011fad95dd02..c9b84eeaab6b 100644 --- a/tools/testing/selftests/kvm/arm64/get-reg-list.c +++ b/tools/testing/selftests/kvm/arm64/get-reg-list.c @@ -65,6 +65,9 @@ static struct feature_id_reg feat_id_regs[] = {  	REG_FEAT(SCTLR2_EL1,	ID_AA64MMFR3_EL1, SCTLRX, IMP),  	REG_FEAT(VDISR_EL2,	ID_AA64PFR0_EL1, RAS, IMP),  	REG_FEAT(VSESR_EL2,	ID_AA64PFR0_EL1, RAS, IMP), +	REG_FEAT(VNCR_EL2,	ID_AA64MMFR4_EL1, NV_frac, NV2_ONLY), +	REG_FEAT(CNTHV_CTL_EL2, ID_AA64MMFR1_EL1, VH, IMP), +	REG_FEAT(CNTHV_CVAL_EL2,ID_AA64MMFR1_EL1, VH, IMP),  };  bool filter_reg(__u64 reg) @@ -345,9 +348,20 @@ static __u64 base_regs[] = {  	KVM_REG_ARM_FW_FEAT_BMAP_REG(1),	/* KVM_REG_ARM_STD_HYP_BMAP */  	KVM_REG_ARM_FW_FEAT_BMAP_REG(2),	/* KVM_REG_ARM_VENDOR_HYP_BMAP */  	KVM_REG_ARM_FW_FEAT_BMAP_REG(3),	/* KVM_REG_ARM_VENDOR_HYP_BMAP_2 */ -	ARM64_SYS_REG(3, 3, 14, 3, 1),	/* CNTV_CTL_EL0 */ -	ARM64_SYS_REG(3, 3, 14, 3, 2),	/* CNTV_CVAL_EL0 */ -	ARM64_SYS_REG(3, 3, 14, 0, 2), + +	/* +	 * EL0 Virtual Timer Registers +	 * +	 * WARNING: +	 * KVM_REG_ARM_TIMER_CVAL and KVM_REG_ARM_TIMER_CNT are not defined +	 * with the appropriate register encodings.  Their values have been +	 * accidentally swapped.  As this is set API, the definitions here +	 * must be used, rather than ones derived from the encodings. +	 */ +	KVM_ARM64_SYS_REG(SYS_CNTV_CTL_EL0), +	KVM_REG_ARM_TIMER_CVAL, +	KVM_REG_ARM_TIMER_CNT, +  	ARM64_SYS_REG(3, 0, 0, 0, 0),	/* MIDR_EL1 */  	ARM64_SYS_REG(3, 0, 0, 0, 6),	/* REVIDR_EL1 */  	ARM64_SYS_REG(3, 1, 0, 0, 1),	/* CLIDR_EL1 */ @@ -755,6 +769,10 @@ static __u64 el2_regs[] = {  	SYS_REG(VSESR_EL2),  }; +static __u64 el2_e2h0_regs[] = { +	/* Empty */ +}; +  #define BASE_SUBLIST \  	{ "base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), }  #define VREGS_SUBLIST \ @@ -789,6 +807,15 @@ static __u64 el2_regs[] = {  		.regs		= el2_regs,			\  		.regs_n		= ARRAY_SIZE(el2_regs),		\  	} +#define EL2_E2H0_SUBLIST					\ +	EL2_SUBLIST,						\ +	{							\ +		.name 		= "EL2 E2H0",			\ +		.capability	= KVM_CAP_ARM_EL2_E2H0,		\ +		.feature	= KVM_ARM_VCPU_HAS_EL2_E2H0,	\ +		.regs		= el2_e2h0_regs,		\ +		.regs_n		= ARRAY_SIZE(el2_e2h0_regs),	\ +	}  static struct vcpu_reg_list vregs_config = {  	.sublists = { @@ -897,6 +924,65 @@ static struct vcpu_reg_list el2_pauth_pmu_config = {  	},  }; +static struct vcpu_reg_list el2_e2h0_vregs_config = { +	.sublists = { +	BASE_SUBLIST, +	EL2_E2H0_SUBLIST, +	VREGS_SUBLIST, +	{0}, +	}, +}; + +static struct vcpu_reg_list el2_e2h0_vregs_pmu_config = { +	.sublists = { +	BASE_SUBLIST, +	EL2_E2H0_SUBLIST, +	VREGS_SUBLIST, +	PMU_SUBLIST, +	{0}, +	}, +}; + +static struct vcpu_reg_list el2_e2h0_sve_config = { +	.sublists = { +	BASE_SUBLIST, +	EL2_E2H0_SUBLIST, +	SVE_SUBLIST, +	{0}, +	}, +}; + +static struct vcpu_reg_list el2_e2h0_sve_pmu_config = { +	.sublists = { +	BASE_SUBLIST, +	EL2_E2H0_SUBLIST, +	SVE_SUBLIST, +	PMU_SUBLIST, +	{0}, +	}, +}; + +static struct vcpu_reg_list el2_e2h0_pauth_config = { +	.sublists = { +	BASE_SUBLIST, +	EL2_E2H0_SUBLIST, +	VREGS_SUBLIST, +	PAUTH_SUBLIST, +	{0}, +	}, +}; + +static struct vcpu_reg_list el2_e2h0_pauth_pmu_config = { +	.sublists = { +	BASE_SUBLIST, +	EL2_E2H0_SUBLIST, +	VREGS_SUBLIST, +	PAUTH_SUBLIST, +	PMU_SUBLIST, +	{0}, +	}, +}; +  struct vcpu_reg_list *vcpu_configs[] = {  	&vregs_config,  	&vregs_pmu_config, @@ -911,5 +997,12 @@ struct vcpu_reg_list *vcpu_configs[] = {  	&el2_sve_pmu_config,  	&el2_pauth_config,  	&el2_pauth_pmu_config, + +	&el2_e2h0_vregs_config, +	&el2_e2h0_vregs_pmu_config, +	&el2_e2h0_sve_config, +	&el2_e2h0_sve_pmu_config, +	&el2_e2h0_pauth_config, +	&el2_e2h0_pauth_pmu_config,  };  int vcpu_configs_n = ARRAY_SIZE(vcpu_configs); diff --git a/tools/testing/selftests/kvm/arm64/set_id_regs.c b/tools/testing/selftests/kvm/arm64/set_id_regs.c index 8ff1e853f7f8..5e24f77868b5 100644 --- a/tools/testing/selftests/kvm/arm64/set_id_regs.c +++ b/tools/testing/selftests/kvm/arm64/set_id_regs.c @@ -249,11 +249,14 @@ static void guest_code(void)  	GUEST_REG_SYNC(SYS_ID_AA64ISAR2_EL1);  	GUEST_REG_SYNC(SYS_ID_AA64ISAR3_EL1);  	GUEST_REG_SYNC(SYS_ID_AA64PFR0_EL1); +	GUEST_REG_SYNC(SYS_ID_AA64PFR1_EL1);  	GUEST_REG_SYNC(SYS_ID_AA64MMFR0_EL1);  	GUEST_REG_SYNC(SYS_ID_AA64MMFR1_EL1);  	GUEST_REG_SYNC(SYS_ID_AA64MMFR2_EL1);  	GUEST_REG_SYNC(SYS_ID_AA64MMFR3_EL1);  	GUEST_REG_SYNC(SYS_ID_AA64ZFR0_EL1); +	GUEST_REG_SYNC(SYS_MPIDR_EL1); +	GUEST_REG_SYNC(SYS_CLIDR_EL1);  	GUEST_REG_SYNC(SYS_CTR_EL0);  	GUEST_REG_SYNC(SYS_MIDR_EL1);  	GUEST_REG_SYNC(SYS_REVIDR_EL1); diff --git a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c index 87922a89b134..687d04463983 100644 --- a/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c +++ b/tools/testing/selftests/kvm/arm64/vgic_lpi_stress.c @@ -123,6 +123,7 @@ static void guest_setup_gic(void)  static void guest_code(size_t nr_lpis)  {  	guest_setup_gic(); +	local_irq_enable();  	GUEST_SYNC(0); @@ -331,7 +332,7 @@ static void setup_vm(void)  {  	int i; -	vcpus = malloc(test_data.nr_cpus * sizeof(struct kvm_vcpu)); +	vcpus = malloc(test_data.nr_cpus * sizeof(struct kvm_vcpu *));  	TEST_ASSERT(vcpus, "Failed to allocate vCPU array");  	vm = vm_create_with_vcpus(test_data.nr_cpus, guest_code, vcpus); diff --git a/tools/testing/selftests/kvm/guest_memfd_test.c b/tools/testing/selftests/kvm/guest_memfd_test.c index b3ca6737f304..e7d9aeb418d3 100644 --- a/tools/testing/selftests/kvm/guest_memfd_test.c +++ b/tools/testing/selftests/kvm/guest_memfd_test.c @@ -14,8 +14,6 @@  #include <linux/bitmap.h>  #include <linux/falloc.h>  #include <linux/sizes.h> -#include <setjmp.h> -#include <signal.h>  #include <sys/mman.h>  #include <sys/types.h>  #include <sys/stat.h> @@ -24,7 +22,9 @@  #include "test_util.h"  #include "ucall_common.h" -static void test_file_read_write(int fd) +static size_t page_size; + +static void test_file_read_write(int fd, size_t total_size)  {  	char buf[64]; @@ -38,18 +38,22 @@ static void test_file_read_write(int fd)  		    "pwrite on a guest_mem fd should fail");  } -static void test_mmap_supported(int fd, size_t page_size, size_t total_size) +static void test_mmap_cow(int fd, size_t size) +{ +	void *mem; + +	mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); +	TEST_ASSERT(mem == MAP_FAILED, "Copy-on-write not allowed by guest_memfd."); +} + +static void test_mmap_supported(int fd, size_t total_size)  {  	const char val = 0xaa;  	char *mem;  	size_t i;  	int ret; -	mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0); -	TEST_ASSERT(mem == MAP_FAILED, "Copy-on-write not allowed by guest_memfd."); - -	mem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -	TEST_ASSERT(mem != MAP_FAILED, "mmap() for guest_memfd should succeed."); +	mem = kvm_mmap(total_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);  	memset(mem, val, total_size);  	for (i = 0; i < total_size; i++) @@ -68,45 +72,37 @@ static void test_mmap_supported(int fd, size_t page_size, size_t total_size)  	for (i = 0; i < total_size; i++)  		TEST_ASSERT_EQ(READ_ONCE(mem[i]), val); -	ret = munmap(mem, total_size); -	TEST_ASSERT(!ret, "munmap() should succeed."); -} - -static sigjmp_buf jmpbuf; -void fault_sigbus_handler(int signum) -{ -	siglongjmp(jmpbuf, 1); +	kvm_munmap(mem, total_size);  } -static void test_fault_overflow(int fd, size_t page_size, size_t total_size) +static void test_fault_sigbus(int fd, size_t accessible_size, size_t map_size)  { -	struct sigaction sa_old, sa_new = { -		.sa_handler = fault_sigbus_handler, -	}; -	size_t map_size = total_size * 4;  	const char val = 0xaa;  	char *mem;  	size_t i; -	int ret; -	mem = mmap(NULL, map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -	TEST_ASSERT(mem != MAP_FAILED, "mmap() for guest_memfd should succeed."); +	mem = kvm_mmap(map_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd); -	sigaction(SIGBUS, &sa_new, &sa_old); -	if (sigsetjmp(jmpbuf, 1) == 0) { -		memset(mem, 0xaa, map_size); -		TEST_ASSERT(false, "memset() should have triggered SIGBUS."); -	} -	sigaction(SIGBUS, &sa_old, NULL); +	TEST_EXPECT_SIGBUS(memset(mem, val, map_size)); +	TEST_EXPECT_SIGBUS((void)READ_ONCE(mem[accessible_size])); -	for (i = 0; i < total_size; i++) +	for (i = 0; i < accessible_size; i++)  		TEST_ASSERT_EQ(READ_ONCE(mem[i]), val); -	ret = munmap(mem, map_size); -	TEST_ASSERT(!ret, "munmap() should succeed."); +	kvm_munmap(mem, map_size); +} + +static void test_fault_overflow(int fd, size_t total_size) +{ +	test_fault_sigbus(fd, total_size, total_size * 4); +} + +static void test_fault_private(int fd, size_t total_size) +{ +	test_fault_sigbus(fd, 0, total_size);  } -static void test_mmap_not_supported(int fd, size_t page_size, size_t total_size) +static void test_mmap_not_supported(int fd, size_t total_size)  {  	char *mem; @@ -117,7 +113,7 @@ static void test_mmap_not_supported(int fd, size_t page_size, size_t total_size)  	TEST_ASSERT_EQ(mem, MAP_FAILED);  } -static void test_file_size(int fd, size_t page_size, size_t total_size) +static void test_file_size(int fd, size_t total_size)  {  	struct stat sb;  	int ret; @@ -128,7 +124,7 @@ static void test_file_size(int fd, size_t page_size, size_t total_size)  	TEST_ASSERT_EQ(sb.st_blksize, page_size);  } -static void test_fallocate(int fd, size_t page_size, size_t total_size) +static void test_fallocate(int fd, size_t total_size)  {  	int ret; @@ -165,7 +161,7 @@ static void test_fallocate(int fd, size_t page_size, size_t total_size)  	TEST_ASSERT(!ret, "fallocate to restore punched hole should succeed");  } -static void test_invalid_punch_hole(int fd, size_t page_size, size_t total_size) +static void test_invalid_punch_hole(int fd, size_t total_size)  {  	struct {  		off_t offset; @@ -196,8 +192,7 @@ static void test_invalid_punch_hole(int fd, size_t page_size, size_t total_size)  }  static void test_create_guest_memfd_invalid_sizes(struct kvm_vm *vm, -						  uint64_t guest_memfd_flags, -						  size_t page_size) +						  uint64_t guest_memfd_flags)  {  	size_t size;  	int fd; @@ -214,7 +209,6 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm)  {  	int fd1, fd2, ret;  	struct stat st1, st2; -	size_t page_size = getpagesize();  	fd1 = __vm_create_guest_memfd(vm, page_size, 0);  	TEST_ASSERT(fd1 != -1, "memfd creation should succeed"); @@ -239,9 +233,9 @@ static void test_create_guest_memfd_multiple(struct kvm_vm *vm)  	close(fd1);  } -static void test_guest_memfd_flags(struct kvm_vm *vm, uint64_t valid_flags) +static void test_guest_memfd_flags(struct kvm_vm *vm)  { -	size_t page_size = getpagesize(); +	uint64_t valid_flags = vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS);  	uint64_t flag;  	int fd; @@ -260,43 +254,57 @@ static void test_guest_memfd_flags(struct kvm_vm *vm, uint64_t valid_flags)  	}  } -static void test_guest_memfd(unsigned long vm_type) +#define gmem_test(__test, __vm, __flags)				\ +do {									\ +	int fd = vm_create_guest_memfd(__vm, page_size * 4, __flags);	\ +									\ +	test_##__test(fd, page_size * 4);				\ +	close(fd);							\ +} while (0) + +static void __test_guest_memfd(struct kvm_vm *vm, uint64_t flags)  { -	uint64_t flags = 0; -	struct kvm_vm *vm; -	size_t total_size; -	size_t page_size; -	int fd; +	test_create_guest_memfd_multiple(vm); +	test_create_guest_memfd_invalid_sizes(vm, flags); -	page_size = getpagesize(); -	total_size = page_size * 4; +	gmem_test(file_read_write, vm, flags); -	vm = vm_create_barebones_type(vm_type); +	if (flags & GUEST_MEMFD_FLAG_MMAP) { +		if (flags & GUEST_MEMFD_FLAG_INIT_SHARED) { +			gmem_test(mmap_supported, vm, flags); +			gmem_test(fault_overflow, vm, flags); +		} else { +			gmem_test(fault_private, vm, flags); +		} -	if (vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_MMAP)) -		flags |= GUEST_MEMFD_FLAG_MMAP; +		gmem_test(mmap_cow, vm, flags); +	} else { +		gmem_test(mmap_not_supported, vm, flags); +	} -	test_create_guest_memfd_multiple(vm); -	test_create_guest_memfd_invalid_sizes(vm, flags, page_size); +	gmem_test(file_size, vm, flags); +	gmem_test(fallocate, vm, flags); +	gmem_test(invalid_punch_hole, vm, flags); +} -	fd = vm_create_guest_memfd(vm, total_size, flags); +static void test_guest_memfd(unsigned long vm_type) +{ +	struct kvm_vm *vm = vm_create_barebones_type(vm_type); +	uint64_t flags; -	test_file_read_write(fd); +	test_guest_memfd_flags(vm); -	if (flags & GUEST_MEMFD_FLAG_MMAP) { -		test_mmap_supported(fd, page_size, total_size); -		test_fault_overflow(fd, page_size, total_size); -	} else { -		test_mmap_not_supported(fd, page_size, total_size); -	} +	__test_guest_memfd(vm, 0); -	test_file_size(fd, page_size, total_size); -	test_fallocate(fd, page_size, total_size); -	test_invalid_punch_hole(fd, page_size, total_size); +	flags = vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS); +	if (flags & GUEST_MEMFD_FLAG_MMAP) +		__test_guest_memfd(vm, GUEST_MEMFD_FLAG_MMAP); -	test_guest_memfd_flags(vm, flags); +	/* MMAP should always be supported if INIT_SHARED is supported. */ +	if (flags & GUEST_MEMFD_FLAG_INIT_SHARED) +		__test_guest_memfd(vm, GUEST_MEMFD_FLAG_MMAP | +				       GUEST_MEMFD_FLAG_INIT_SHARED); -	close(fd);  	kvm_vm_free(vm);  } @@ -328,22 +336,26 @@ static void test_guest_memfd_guest(void)  	size_t size;  	int fd, i; -	if (!kvm_has_cap(KVM_CAP_GUEST_MEMFD_MMAP)) +	if (!kvm_check_cap(KVM_CAP_GUEST_MEMFD_FLAGS))  		return;  	vm = __vm_create_shape_with_one_vcpu(VM_SHAPE_DEFAULT, &vcpu, 1, guest_code); -	TEST_ASSERT(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_MMAP), -		    "Default VM type should always support guest_memfd mmap()"); +	TEST_ASSERT(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS) & GUEST_MEMFD_FLAG_MMAP, +		    "Default VM type should support MMAP, supported flags = 0x%x", +		    vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS)); +	TEST_ASSERT(vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS) & GUEST_MEMFD_FLAG_INIT_SHARED, +		    "Default VM type should support INIT_SHARED, supported flags = 0x%x", +		    vm_check_cap(vm, KVM_CAP_GUEST_MEMFD_FLAGS));  	size = vm->page_size; -	fd = vm_create_guest_memfd(vm, size, GUEST_MEMFD_FLAG_MMAP); +	fd = vm_create_guest_memfd(vm, size, GUEST_MEMFD_FLAG_MMAP | +					     GUEST_MEMFD_FLAG_INIT_SHARED);  	vm_set_user_memory_region2(vm, slot, KVM_MEM_GUEST_MEMFD, gpa, size, NULL, fd, 0); -	mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -	TEST_ASSERT(mem != MAP_FAILED, "mmap() on guest_memfd failed"); +	mem = kvm_mmap(size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);  	memset(mem, 0xaa, size); -	munmap(mem, size); +	kvm_munmap(mem, size);  	virt_pg_map(vm, gpa, gpa);  	vcpu_args_set(vcpu, 2, gpa, size); @@ -351,8 +363,7 @@ static void test_guest_memfd_guest(void)  	TEST_ASSERT_EQ(get_ucall(vcpu, NULL), UCALL_DONE); -	mem = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -	TEST_ASSERT(mem != MAP_FAILED, "mmap() on guest_memfd failed"); +	mem = kvm_mmap(size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);  	for (i = 0; i < size; i++)  		TEST_ASSERT_EQ(mem[i], 0xff); @@ -366,6 +377,8 @@ int main(int argc, char *argv[])  	TEST_REQUIRE(kvm_has_cap(KVM_CAP_GUEST_MEMFD)); +	page_size = getpagesize(); +  	/*  	 * Not all architectures support KVM_CAP_VM_TYPES. However, those that  	 * support guest_memfd have that support for the default VM type. diff --git a/tools/testing/selftests/kvm/include/arm64/processor.h b/tools/testing/selftests/kvm/include/arm64/processor.h index 6f481475c135..ff928716574d 100644 --- a/tools/testing/selftests/kvm/include/arm64/processor.h +++ b/tools/testing/selftests/kvm/include/arm64/processor.h @@ -305,7 +305,17 @@ void test_wants_mte(void);  void test_disable_default_vgic(void);  bool vm_supports_el2(struct kvm_vm *vm); -static bool vcpu_has_el2(struct kvm_vcpu *vcpu) + +static inline bool test_supports_el2(void) +{ +	struct kvm_vm *vm = vm_create(1); +	bool supported = vm_supports_el2(vm); + +	kvm_vm_free(vm); +	return supported; +} + +static inline bool vcpu_has_el2(struct kvm_vcpu *vcpu)  {  	return vcpu->init.features[0] & BIT(KVM_ARM_VCPU_HAS_EL2);  } diff --git a/tools/testing/selftests/kvm/include/kvm_util.h b/tools/testing/selftests/kvm/include/kvm_util.h index 26cc30290e76..d3f3e455c031 100644 --- a/tools/testing/selftests/kvm/include/kvm_util.h +++ b/tools/testing/selftests/kvm/include/kvm_util.h @@ -286,6 +286,31 @@ static inline bool kvm_has_cap(long cap)  #define __KVM_SYSCALL_ERROR(_name, _ret) \  	"%s failed, rc: %i errno: %i (%s)", (_name), (_ret), errno, strerror(errno) +static inline void *__kvm_mmap(size_t size, int prot, int flags, int fd, +			       off_t offset) +{ +	void *mem; + +	mem = mmap(NULL, size, prot, flags, fd, offset); +	TEST_ASSERT(mem != MAP_FAILED, __KVM_SYSCALL_ERROR("mmap()", +		    (int)(unsigned long)MAP_FAILED)); + +	return mem; +} + +static inline void *kvm_mmap(size_t size, int prot, int flags, int fd) +{ +	return __kvm_mmap(size, prot, flags, fd, 0); +} + +static inline void kvm_munmap(void *mem, size_t size) +{ +	int ret; + +	ret = munmap(mem, size); +	TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); +} +  /*   * Use the "inner", double-underscore macro when reporting errors from within   * other macros so that the name of ioctl() and not its literal numeric value @@ -1273,4 +1298,6 @@ bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr);  uint32_t guest_get_vcpuid(void); +bool kvm_arch_has_default_irqchip(void); +  #endif /* SELFTEST_KVM_UTIL_H */ diff --git a/tools/testing/selftests/kvm/include/test_util.h b/tools/testing/selftests/kvm/include/test_util.h index c6ef895fbd9a..b4872ba8ed12 100644 --- a/tools/testing/selftests/kvm/include/test_util.h +++ b/tools/testing/selftests/kvm/include/test_util.h @@ -8,6 +8,8 @@  #ifndef SELFTEST_KVM_TEST_UTIL_H  #define SELFTEST_KVM_TEST_UTIL_H +#include <setjmp.h> +#include <signal.h>  #include <stdlib.h>  #include <stdarg.h>  #include <stdbool.h> @@ -78,6 +80,23 @@ do {									\  	__builtin_unreachable(); \  } while (0) +extern sigjmp_buf expect_sigbus_jmpbuf; +void expect_sigbus_handler(int signum); + +#define TEST_EXPECT_SIGBUS(action)						\ +do {										\ +	struct sigaction sa_old, sa_new = {					\ +		.sa_handler = expect_sigbus_handler,				\ +	};									\ +										\ +	sigaction(SIGBUS, &sa_new, &sa_old);					\ +	if (sigsetjmp(expect_sigbus_jmpbuf, 1) == 0) {				\ +		action;								\ +		TEST_FAIL("'%s' should have triggered SIGBUS", #action);	\ +	}									\ +	sigaction(SIGBUS, &sa_old, NULL);					\ +} while (0) +  size_t parse_size(const char *size);  int64_t timespec_to_ns(struct timespec ts); diff --git a/tools/testing/selftests/kvm/irqfd_test.c b/tools/testing/selftests/kvm/irqfd_test.c index 7c301b4c7005..5d7590d01868 100644 --- a/tools/testing/selftests/kvm/irqfd_test.c +++ b/tools/testing/selftests/kvm/irqfd_test.c @@ -89,11 +89,19 @@ static void juggle_eventfd_primary(struct kvm_vm *vm, int eventfd)  int main(int argc, char *argv[])  {  	pthread_t racing_thread; +	struct kvm_vcpu *unused;  	int r, i; -	/* Create "full" VMs, as KVM_IRQFD requires an in-kernel IRQ chip. */ -	vm1 = vm_create(1); -	vm2 = vm_create(1); +	TEST_REQUIRE(kvm_arch_has_default_irqchip()); + +	/* +	 * Create "full" VMs, as KVM_IRQFD requires an in-kernel IRQ chip. Also +	 * create an unused vCPU as certain architectures (like arm64) need to +	 * complete IRQ chip initialization after all possible vCPUs for a VM +	 * have been created. +	 */ +	vm1 = vm_create_with_one_vcpu(&unused, NULL); +	vm2 = vm_create_with_one_vcpu(&unused, NULL);  	WRITE_ONCE(__eventfd, kvm_new_eventfd()); diff --git a/tools/testing/selftests/kvm/lib/arm64/processor.c b/tools/testing/selftests/kvm/lib/arm64/processor.c index 369a4c87dd8f..54f6d17c78f7 100644 --- a/tools/testing/selftests/kvm/lib/arm64/processor.c +++ b/tools/testing/selftests/kvm/lib/arm64/processor.c @@ -725,3 +725,8 @@ void kvm_arch_vm_release(struct kvm_vm *vm)  	if (vm->arch.has_gic)  		close(vm->arch.gic_fd);  } + +bool kvm_arch_has_default_irqchip(void) +{ +	return request_vgic && kvm_supports_vgic_v3(); +} diff --git a/tools/testing/selftests/kvm/lib/kvm_util.c b/tools/testing/selftests/kvm/lib/kvm_util.c index 6743fbd9bd67..1a93d6361671 100644 --- a/tools/testing/selftests/kvm/lib/kvm_util.c +++ b/tools/testing/selftests/kvm/lib/kvm_util.c @@ -741,13 +741,11 @@ static void vm_vcpu_rm(struct kvm_vm *vm, struct kvm_vcpu *vcpu)  	int ret;  	if (vcpu->dirty_gfns) { -		ret = munmap(vcpu->dirty_gfns, vm->dirty_ring_size); -		TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); +		kvm_munmap(vcpu->dirty_gfns, vm->dirty_ring_size);  		vcpu->dirty_gfns = NULL;  	} -	ret = munmap(vcpu->run, vcpu_mmap_sz()); -	TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); +	kvm_munmap(vcpu->run, vcpu_mmap_sz());  	ret = close(vcpu->fd);  	TEST_ASSERT(!ret,  __KVM_SYSCALL_ERROR("close()", ret)); @@ -783,20 +781,16 @@ void kvm_vm_release(struct kvm_vm *vmp)  static void __vm_mem_region_delete(struct kvm_vm *vm,  				   struct userspace_mem_region *region)  { -	int ret; -  	rb_erase(®ion->gpa_node, &vm->regions.gpa_tree);  	rb_erase(®ion->hva_node, &vm->regions.hva_tree);  	hash_del(®ion->slot_node);  	sparsebit_free(®ion->unused_phy_pages);  	sparsebit_free(®ion->protected_phy_pages); -	ret = munmap(region->mmap_start, region->mmap_size); -	TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); +	kvm_munmap(region->mmap_start, region->mmap_size);  	if (region->fd >= 0) {  		/* There's an extra map when using shared memory. */ -		ret = munmap(region->mmap_alias, region->mmap_size); -		TEST_ASSERT(!ret, __KVM_SYSCALL_ERROR("munmap()", ret)); +		kvm_munmap(region->mmap_alias, region->mmap_size);  		close(region->fd);  	}  	if (region->region.guest_memfd >= 0) @@ -1053,12 +1047,9 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,  		region->fd = kvm_memfd_alloc(region->mmap_size,  					     src_type == VM_MEM_SRC_SHARED_HUGETLB); -	region->mmap_start = mmap(NULL, region->mmap_size, -				  PROT_READ | PROT_WRITE, -				  vm_mem_backing_src_alias(src_type)->flag, -				  region->fd, 0); -	TEST_ASSERT(region->mmap_start != MAP_FAILED, -		    __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED)); +	region->mmap_start = kvm_mmap(region->mmap_size, PROT_READ | PROT_WRITE, +				      vm_mem_backing_src_alias(src_type)->flag, +				      region->fd);  	TEST_ASSERT(!is_backing_src_hugetlb(src_type) ||  		    region->mmap_start == align_ptr_up(region->mmap_start, backing_src_pagesz), @@ -1129,12 +1120,10 @@ void vm_mem_add(struct kvm_vm *vm, enum vm_mem_backing_src_type src_type,  	/* If shared memory, create an alias. */  	if (region->fd >= 0) { -		region->mmap_alias = mmap(NULL, region->mmap_size, -					  PROT_READ | PROT_WRITE, -					  vm_mem_backing_src_alias(src_type)->flag, -					  region->fd, 0); -		TEST_ASSERT(region->mmap_alias != MAP_FAILED, -			    __KVM_SYSCALL_ERROR("mmap()",  (int)(unsigned long)MAP_FAILED)); +		region->mmap_alias = kvm_mmap(region->mmap_size, +					      PROT_READ | PROT_WRITE, +					      vm_mem_backing_src_alias(src_type)->flag, +					      region->fd);  		/* Align host alias address */  		region->host_alias = align_ptr_up(region->mmap_alias, alignment); @@ -1344,10 +1333,8 @@ struct kvm_vcpu *__vm_vcpu_add(struct kvm_vm *vm, uint32_t vcpu_id)  	TEST_ASSERT(vcpu_mmap_sz() >= sizeof(*vcpu->run), "vcpu mmap size "  		"smaller than expected, vcpu_mmap_sz: %zi expected_min: %zi",  		vcpu_mmap_sz(), sizeof(*vcpu->run)); -	vcpu->run = (struct kvm_run *) mmap(NULL, vcpu_mmap_sz(), -		PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, 0); -	TEST_ASSERT(vcpu->run != MAP_FAILED, -		    __KVM_SYSCALL_ERROR("mmap()", (int)(unsigned long)MAP_FAILED)); +	vcpu->run = kvm_mmap(vcpu_mmap_sz(), PROT_READ | PROT_WRITE, +			     MAP_SHARED, vcpu->fd);  	if (kvm_has_cap(KVM_CAP_BINARY_STATS_FD))  		vcpu->stats.fd = vcpu_get_stats_fd(vcpu); @@ -1794,9 +1781,8 @@ void *vcpu_map_dirty_ring(struct kvm_vcpu *vcpu)  			    page_size * KVM_DIRTY_LOG_PAGE_OFFSET);  		TEST_ASSERT(addr == MAP_FAILED, "Dirty ring mapped exec"); -		addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, -			    page_size * KVM_DIRTY_LOG_PAGE_OFFSET); -		TEST_ASSERT(addr != MAP_FAILED, "Dirty ring map failed"); +		addr = __kvm_mmap(size, PROT_READ | PROT_WRITE, MAP_SHARED, vcpu->fd, +				  page_size * KVM_DIRTY_LOG_PAGE_OFFSET);  		vcpu->dirty_gfns = addr;  		vcpu->dirty_gfns_count = size / sizeof(struct kvm_dirty_gfn); @@ -2344,3 +2330,8 @@ bool vm_is_gpa_protected(struct kvm_vm *vm, vm_paddr_t paddr)  	pg = paddr >> vm->page_shift;  	return sparsebit_is_set(region->protected_phy_pages, pg);  } + +__weak bool kvm_arch_has_default_irqchip(void) +{ +	return false; +} diff --git a/tools/testing/selftests/kvm/lib/s390/processor.c b/tools/testing/selftests/kvm/lib/s390/processor.c index 20cfe970e3e3..8ceeb17c819a 100644 --- a/tools/testing/selftests/kvm/lib/s390/processor.c +++ b/tools/testing/selftests/kvm/lib/s390/processor.c @@ -221,3 +221,8 @@ void vcpu_arch_dump(FILE *stream, struct kvm_vcpu *vcpu, uint8_t indent)  void assert_on_unhandled_exception(struct kvm_vcpu *vcpu)  {  } + +bool kvm_arch_has_default_irqchip(void) +{ +	return true; +} diff --git a/tools/testing/selftests/kvm/lib/test_util.c b/tools/testing/selftests/kvm/lib/test_util.c index 03eb99af9b8d..8a1848586a85 100644 --- a/tools/testing/selftests/kvm/lib/test_util.c +++ b/tools/testing/selftests/kvm/lib/test_util.c @@ -18,6 +18,13 @@  #include "test_util.h" +sigjmp_buf expect_sigbus_jmpbuf; + +void __attribute__((used)) expect_sigbus_handler(int signum) +{ +	siglongjmp(expect_sigbus_jmpbuf, 1); +} +  /*   * Random number generator that is usable from guest code. This is the   * Park-Miller LCG using standard constants. diff --git a/tools/testing/selftests/kvm/lib/x86/processor.c b/tools/testing/selftests/kvm/lib/x86/processor.c index c748cd9b2eef..b418502c5ecc 100644 --- a/tools/testing/selftests/kvm/lib/x86/processor.c +++ b/tools/testing/selftests/kvm/lib/x86/processor.c @@ -1318,3 +1318,8 @@ bool sys_clocksource_is_based_on_tsc(void)  	return ret;  } + +bool kvm_arch_has_default_irqchip(void) +{ +	return true; +} diff --git a/tools/testing/selftests/kvm/mmu_stress_test.c b/tools/testing/selftests/kvm/mmu_stress_test.c index 6a437d2be9fa..37b7e6524533 100644 --- a/tools/testing/selftests/kvm/mmu_stress_test.c +++ b/tools/testing/selftests/kvm/mmu_stress_test.c @@ -339,8 +339,7 @@ int main(int argc, char *argv[])  	TEST_ASSERT(max_gpa > (4 * slot_size), "MAXPHYADDR <4gb ");  	fd = kvm_memfd_alloc(slot_size, hugepages); -	mem = mmap(NULL, slot_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); -	TEST_ASSERT(mem != MAP_FAILED, "mmap() failed"); +	mem = kvm_mmap(slot_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd);  	TEST_ASSERT(!madvise(mem, slot_size, MADV_NOHUGEPAGE), "madvise() failed"); @@ -413,7 +412,7 @@ int main(int argc, char *argv[])  	for (slot = (slot - 1) & ~1ull; slot >= first_slot; slot -= 2)  		vm_set_user_memory_region(vm, slot, 0, 0, 0, NULL); -	munmap(mem, slot_size / 2); +	kvm_munmap(mem, slot_size / 2);  	/* Sanity check that the vCPUs actually ran. */  	for (i = 0; i < nr_vcpus; i++) diff --git a/tools/testing/selftests/kvm/pre_fault_memory_test.c b/tools/testing/selftests/kvm/pre_fault_memory_test.c index 0350a8896a2f..f04768c1d2e4 100644 --- a/tools/testing/selftests/kvm/pre_fault_memory_test.c +++ b/tools/testing/selftests/kvm/pre_fault_memory_test.c @@ -10,6 +10,7 @@  #include <test_util.h>  #include <kvm_util.h>  #include <processor.h> +#include <pthread.h>  /* Arbitrarily chosen values */  #define TEST_SIZE		(SZ_2M + PAGE_SIZE) @@ -30,18 +31,66 @@ static void guest_code(uint64_t base_gpa)  	GUEST_DONE();  } -static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 gpa, u64 size, -			     u64 left) +struct slot_worker_data { +	struct kvm_vm *vm; +	u64 gpa; +	uint32_t flags; +	bool worker_ready; +	bool prefault_ready; +	bool recreate_slot; +}; + +static void *delete_slot_worker(void *__data) +{ +	struct slot_worker_data *data = __data; +	struct kvm_vm *vm = data->vm; + +	WRITE_ONCE(data->worker_ready, true); + +	while (!READ_ONCE(data->prefault_ready)) +		cpu_relax(); + +	vm_mem_region_delete(vm, TEST_SLOT); + +	while (!READ_ONCE(data->recreate_slot)) +		cpu_relax(); + +	vm_userspace_mem_region_add(vm, VM_MEM_SRC_ANONYMOUS, data->gpa, +				    TEST_SLOT, TEST_NPAGES, data->flags); + +	return NULL; +} + +static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 base_gpa, u64 offset, +			     u64 size, u64 expected_left, bool private)  {  	struct kvm_pre_fault_memory range = { -		.gpa = gpa, +		.gpa = base_gpa + offset,  		.size = size,  		.flags = 0,  	}; -	u64 prev; +	struct slot_worker_data data = { +		.vm = vcpu->vm, +		.gpa = base_gpa, +		.flags = private ? KVM_MEM_GUEST_MEMFD : 0, +	}; +	bool slot_recreated = false; +	pthread_t slot_worker;  	int ret, save_errno; +	u64 prev; + +	/* +	 * Concurrently delete (and recreate) the slot to test KVM's handling +	 * of a racing memslot deletion with prefaulting. +	 */ +	pthread_create(&slot_worker, NULL, delete_slot_worker, &data); -	do { +	while (!READ_ONCE(data.worker_ready)) +		cpu_relax(); + +	WRITE_ONCE(data.prefault_ready, true); + +	for (;;) {  		prev = range.size;  		ret = __vcpu_ioctl(vcpu, KVM_PRE_FAULT_MEMORY, &range);  		save_errno = errno; @@ -49,18 +98,65 @@ static void pre_fault_memory(struct kvm_vcpu *vcpu, u64 gpa, u64 size,  			    "%sexpecting range.size to change on %s",  			    ret < 0 ? "not " : "",  			    ret < 0 ? "failure" : "success"); -	} while (ret >= 0 ? range.size : save_errno == EINTR); -	TEST_ASSERT(range.size == left, -		    "Completed with %lld bytes left, expected %" PRId64, -		    range.size, left); +		/* +		 * Immediately retry prefaulting if KVM was interrupted by an +		 * unrelated signal/event. +		 */ +		if (ret < 0 && save_errno == EINTR) +			continue; + +		/* +		 * Tell the worker to recreate the slot in order to complete +		 * prefaulting (if prefault didn't already succeed before the +		 * slot was deleted) and/or to prepare for the next testcase. +		 * Wait for the worker to exit so that the next invocation of +		 * prefaulting is guaranteed to complete (assuming no KVM bugs). +		 */ +		if (!slot_recreated) { +			WRITE_ONCE(data.recreate_slot, true); +			pthread_join(slot_worker, NULL); +			slot_recreated = true; + +			/* +			 * Retry prefaulting to get a stable result, i.e. to +			 * avoid seeing random EAGAIN failures.  Don't retry if +			 * prefaulting already succeeded, as KVM disallows +			 * prefaulting with size=0, i.e. blindly retrying would +			 * result in test failures due to EINVAL.  KVM should +			 * always return success if all bytes are prefaulted, +			 * i.e. there is no need to guard against EAGAIN being +			 * returned. +			 */ +			if (range.size) +				continue; +		} + +		/* +		 * All done if there are no remaining bytes to prefault, or if +		 * prefaulting failed (EINTR was handled above, and EAGAIN due +		 * to prefaulting a memslot that's being actively deleted should +		 * be impossible since the memslot has already been recreated). +		 */ +		if (!range.size || ret < 0) +			break; +	} -	if (left == 0) -		__TEST_ASSERT_VM_VCPU_IOCTL(!ret, "KVM_PRE_FAULT_MEMORY", ret, vcpu->vm); +	TEST_ASSERT(range.size == expected_left, +		    "Completed with %llu bytes left, expected %lu", +		    range.size, expected_left); + +	/* +	 * Assert success if prefaulting the entire range should succeed, i.e. +	 * complete with no bytes remaining.  Otherwise prefaulting should have +	 * failed due to ENOENT (due to RET_PF_EMULATE for emulated MMIO when +	 * no memslot exists). +	 */ +	if (!expected_left) +		TEST_ASSERT_VM_VCPU_IOCTL(!ret, KVM_PRE_FAULT_MEMORY, ret, vcpu->vm);  	else -		/* No memory slot causes RET_PF_EMULATE. it results in -ENOENT. */ -		__TEST_ASSERT_VM_VCPU_IOCTL(ret && save_errno == ENOENT, -					    "KVM_PRE_FAULT_MEMORY", ret, vcpu->vm); +		TEST_ASSERT_VM_VCPU_IOCTL(ret && save_errno == ENOENT, +					  KVM_PRE_FAULT_MEMORY, ret, vcpu->vm);  }  static void __test_pre_fault_memory(unsigned long vm_type, bool private) @@ -97,9 +193,10 @@ static void __test_pre_fault_memory(unsigned long vm_type, bool private)  	if (private)  		vm_mem_set_private(vm, guest_test_phys_mem, TEST_SIZE); -	pre_fault_memory(vcpu, guest_test_phys_mem, SZ_2M, 0); -	pre_fault_memory(vcpu, guest_test_phys_mem + SZ_2M, PAGE_SIZE * 2, PAGE_SIZE); -	pre_fault_memory(vcpu, guest_test_phys_mem + TEST_SIZE, PAGE_SIZE, PAGE_SIZE); + +	pre_fault_memory(vcpu, guest_test_phys_mem, 0, SZ_2M, 0, private); +	pre_fault_memory(vcpu, guest_test_phys_mem, SZ_2M, PAGE_SIZE * 2, PAGE_SIZE, private); +	pre_fault_memory(vcpu, guest_test_phys_mem, TEST_SIZE, PAGE_SIZE, PAGE_SIZE, private);  	vcpu_args_set(vcpu, 1, guest_test_virt_mem);  	vcpu_run(vcpu); diff --git a/tools/testing/selftests/kvm/s390/ucontrol_test.c b/tools/testing/selftests/kvm/s390/ucontrol_test.c index d265b34c54be..50bc1c38225a 100644 --- a/tools/testing/selftests/kvm/s390/ucontrol_test.c +++ b/tools/testing/selftests/kvm/s390/ucontrol_test.c @@ -142,19 +142,17 @@ FIXTURE_SETUP(uc_kvm)  	self->kvm_run_size = ioctl(self->kvm_fd, KVM_GET_VCPU_MMAP_SIZE, NULL);  	ASSERT_GE(self->kvm_run_size, sizeof(struct kvm_run))  		  TH_LOG(KVM_IOCTL_ERROR(KVM_GET_VCPU_MMAP_SIZE, self->kvm_run_size)); -	self->run = (struct kvm_run *)mmap(NULL, self->kvm_run_size, -		    PROT_READ | PROT_WRITE, MAP_SHARED, self->vcpu_fd, 0); -	ASSERT_NE(self->run, MAP_FAILED); +	self->run = kvm_mmap(self->kvm_run_size, PROT_READ | PROT_WRITE, +			     MAP_SHARED, self->vcpu_fd);  	/**  	 * For virtual cpus that have been created with S390 user controlled  	 * virtual machines, the resulting vcpu fd can be memory mapped at page  	 * offset KVM_S390_SIE_PAGE_OFFSET in order to obtain a memory map of  	 * the virtual cpu's hardware control block.  	 */ -	self->sie_block = (struct kvm_s390_sie_block *)mmap(NULL, PAGE_SIZE, -			  PROT_READ | PROT_WRITE, MAP_SHARED, -			  self->vcpu_fd, KVM_S390_SIE_PAGE_OFFSET << PAGE_SHIFT); -	ASSERT_NE(self->sie_block, MAP_FAILED); +	self->sie_block = __kvm_mmap(PAGE_SIZE, PROT_READ | PROT_WRITE, +				     MAP_SHARED, self->vcpu_fd, +				     KVM_S390_SIE_PAGE_OFFSET << PAGE_SHIFT);  	TH_LOG("VM created %p %p", self->run, self->sie_block); @@ -186,8 +184,8 @@ FIXTURE_SETUP(uc_kvm)  FIXTURE_TEARDOWN(uc_kvm)  { -	munmap(self->sie_block, PAGE_SIZE); -	munmap(self->run, self->kvm_run_size); +	kvm_munmap(self->sie_block, PAGE_SIZE); +	kvm_munmap(self->run, self->kvm_run_size);  	close(self->vcpu_fd);  	close(self->vm_fd);  	close(self->kvm_fd); diff --git a/tools/testing/selftests/kvm/set_memory_region_test.c b/tools/testing/selftests/kvm/set_memory_region_test.c index ce3ac0fd6dfb..7fe427ff9b38 100644 --- a/tools/testing/selftests/kvm/set_memory_region_test.c +++ b/tools/testing/selftests/kvm/set_memory_region_test.c @@ -433,10 +433,10 @@ static void test_add_max_memory_regions(void)  	pr_info("Adding slots 0..%i, each memory region with %dK size\n",  		(max_mem_slots - 1), MEM_REGION_SIZE >> 10); -	mem = mmap(NULL, (size_t)max_mem_slots * MEM_REGION_SIZE + alignment, -		   PROT_READ | PROT_WRITE, -		   MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0); -	TEST_ASSERT(mem != MAP_FAILED, "Failed to mmap() host"); + +	mem = kvm_mmap((size_t)max_mem_slots * MEM_REGION_SIZE + alignment, +		       PROT_READ | PROT_WRITE, +		       MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1);  	mem_aligned = (void *)(((size_t) mem + alignment - 1) & ~(alignment - 1));  	for (slot = 0; slot < max_mem_slots; slot++) @@ -446,9 +446,8 @@ static void test_add_max_memory_regions(void)  					  mem_aligned + (uint64_t)slot * MEM_REGION_SIZE);  	/* Check it cannot be added memory slots beyond the limit */ -	mem_extra = mmap(NULL, MEM_REGION_SIZE, PROT_READ | PROT_WRITE, -			 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); -	TEST_ASSERT(mem_extra != MAP_FAILED, "Failed to mmap() host"); +	mem_extra = kvm_mmap(MEM_REGION_SIZE, PROT_READ | PROT_WRITE, +			     MAP_PRIVATE | MAP_ANONYMOUS, -1);  	ret = __vm_set_user_memory_region(vm, max_mem_slots, 0,  					  (uint64_t)max_mem_slots * MEM_REGION_SIZE, @@ -456,8 +455,8 @@ static void test_add_max_memory_regions(void)  	TEST_ASSERT(ret == -1 && errno == EINVAL,  		    "Adding one more memory slot should fail with EINVAL"); -	munmap(mem, (size_t)max_mem_slots * MEM_REGION_SIZE + alignment); -	munmap(mem_extra, MEM_REGION_SIZE); +	kvm_munmap(mem, (size_t)max_mem_slots * MEM_REGION_SIZE + alignment); +	kvm_munmap(mem_extra, MEM_REGION_SIZE);  	kvm_vm_free(vm);  } diff --git a/tools/testing/selftests/net/lib/py/__init__.py b/tools/testing/selftests/net/lib/py/__init__.py index 997b85cc216a..97b7cf2b20eb 100644 --- a/tools/testing/selftests/net/lib/py/__init__.py +++ b/tools/testing/selftests/net/lib/py/__init__.py @@ -1,9 +1,32 @@  # SPDX-License-Identifier: GPL-2.0 +""" +Python selftest helpers for netdev. +""" +  from .consts import KSRC -from .ksft import * +from .ksft import KsftFailEx, KsftSkipEx, KsftXfailEx, ksft_pr, ksft_eq, \ +    ksft_ne, ksft_true, ksft_not_none, ksft_in, ksft_not_in, ksft_is, \ +    ksft_ge, ksft_gt, ksft_lt, ksft_raises, ksft_busy_wait, \ +    ktap_result, ksft_disruptive, ksft_setup, ksft_run, ksft_exit  from .netns import NetNS, NetNSEnter -from .nsim import * -from .utils import * +from .nsim import NetdevSim, NetdevSimDev +from .utils import CmdExitFailure, fd_read_timeout, cmd, bkg, defer, \ +    bpftool, ip, ethtool, bpftrace, rand_port, wait_port_listen, wait_file  from .ynl import NlError, YnlFamily, EthtoolFamily, NetdevFamily, RtnlFamily, RtnlAddrFamily  from .ynl import NetshaperFamily, DevlinkFamily, PSPFamily + +__all__ = ["KSRC", +           "KsftFailEx", "KsftSkipEx", "KsftXfailEx", "ksft_pr", "ksft_eq", +           "ksft_ne", "ksft_true", "ksft_not_none", "ksft_in", "ksft_not_in", +           "ksft_is", "ksft_ge", "ksft_gt", "ksft_lt", "ksft_raises", +           "ksft_busy_wait", "ktap_result", "ksft_disruptive", "ksft_setup", +           "ksft_run", "ksft_exit", +           "NetNS", "NetNSEnter", +           "CmdExitFailure", "fd_read_timeout", "cmd", "bkg", "defer", +           "bpftool", "ip", "ethtool", "bpftrace", "rand_port", +           "wait_port_listen", "wait_file", +           "NetdevSim", "NetdevSimDev", +           "NetshaperFamily", "DevlinkFamily", "PSPFamily", "NlError", +           "YnlFamily", "EthtoolFamily", "NetdevFamily", "RtnlFamily", +           "RtnlAddrFamily"] diff --git a/tools/testing/selftests/net/mptcp/mptcp_join.sh b/tools/testing/selftests/net/mptcp/mptcp_join.sh index c90d8e8b95cb..78a1aa4ecff2 100755 --- a/tools/testing/selftests/net/mptcp/mptcp_join.sh +++ b/tools/testing/selftests/net/mptcp/mptcp_join.sh @@ -2324,7 +2324,7 @@ laminar_endp_tests()  {  	# no laminar endpoints: routing rules are used  	if reset_with_tcp_filter "without a laminar endpoint" ns1 10.0.2.2 REJECT && -	   mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then +	   continue_if mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then  		pm_nl_set_limits $ns1 0 2  		pm_nl_set_limits $ns2 2 2  		pm_nl_add_endpoint $ns1 10.0.2.1 flags signal @@ -2336,7 +2336,7 @@ laminar_endp_tests()  	# laminar endpoints: this endpoint is used  	if reset_with_tcp_filter "with a laminar endpoint" ns1 10.0.2.2 REJECT && -	   mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then +	   continue_if mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then  		pm_nl_set_limits $ns1 0 2  		pm_nl_set_limits $ns2 2 2  		pm_nl_add_endpoint $ns1 10.0.2.1 flags signal @@ -2348,7 +2348,7 @@ laminar_endp_tests()  	# laminar endpoints: these endpoints are used  	if reset_with_tcp_filter "with multiple laminar endpoints" ns1 10.0.2.2 REJECT && -	   mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then +	   continue_if mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then  		pm_nl_set_limits $ns1 0 2  		pm_nl_set_limits $ns2 2 2  		pm_nl_add_endpoint $ns1 10.0.2.1 flags signal @@ -2363,7 +2363,7 @@ laminar_endp_tests()  	# laminar endpoints: only one endpoint is used  	if reset_with_tcp_filter "single laminar endpoint" ns1 10.0.2.2 REJECT && -	   mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then +	   continue_if mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then  		pm_nl_set_limits $ns1 0 2  		pm_nl_set_limits $ns2 2 2  		pm_nl_add_endpoint $ns1 10.0.2.1 flags signal @@ -2376,7 +2376,7 @@ laminar_endp_tests()  	# laminar endpoints: subflow and laminar flags  	if reset_with_tcp_filter "sublow + laminar endpoints" ns1 10.0.2.2 REJECT && -	   mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then +	   continue_if mptcp_lib_kallsyms_has "mptcp_pm_get_endp_laminar_max$"; then  		pm_nl_set_limits $ns1 0 4  		pm_nl_set_limits $ns2 2 4  		pm_nl_add_endpoint $ns1 10.0.2.1 flags signal @@ -3939,7 +3939,7 @@ endpoint_tests()  	# subflow_rebuild_header is needed to support the implicit flag  	# userspace pm type prevents add_addr  	if reset "implicit EP" && -	   mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then +	   continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then  		pm_nl_set_limits $ns1 2 2  		pm_nl_set_limits $ns2 2 2  		pm_nl_add_endpoint $ns1 10.0.2.1 flags signal @@ -3964,7 +3964,7 @@ endpoint_tests()  	fi  	if reset_with_tcp_filter "delete and re-add" ns2 10.0.3.2 REJECT OUTPUT && -	   mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then +	   continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then  		start_events  		pm_nl_set_limits $ns1 0 3  		pm_nl_set_limits $ns2 0 3 @@ -4040,7 +4040,7 @@ endpoint_tests()  	# remove and re-add  	if reset_with_events "delete re-add signal" && -	   mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then +	   continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then  		ip netns exec $ns1 sysctl -q net.mptcp.add_addr_timeout=0  		pm_nl_set_limits $ns1 0 3  		pm_nl_set_limits $ns2 3 3 @@ -4115,7 +4115,7 @@ endpoint_tests()  	# flush and re-add  	if reset_with_tcp_filter "flush re-add" ns2 10.0.3.2 REJECT OUTPUT && -	   mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then +	   continue_if mptcp_lib_kallsyms_has "subflow_rebuild_header$"; then  		pm_nl_set_limits $ns1 0 2  		pm_nl_set_limits $ns2 1 2  		# broadcast IP: no packet for this address will be received on ns1 diff --git a/tools/testing/selftests/net/rtnetlink.sh b/tools/testing/selftests/net/rtnetlink.sh index dbf77513f617..163a084d525d 100755 --- a/tools/testing/selftests/net/rtnetlink.sh +++ b/tools/testing/selftests/net/rtnetlink.sh @@ -1466,6 +1466,8 @@ usage: ${0##*/} OPTS  EOF  } +require_command jq +  #check for needed privileges  if [ "$(id -u)" -ne 0 ];then  	end_test "SKIP: Need root privileges" diff --git a/tools/testing/selftests/net/sctp_hello.c b/tools/testing/selftests/net/sctp_hello.c index f02f1f95d227..a04dac0b8027 100644 --- a/tools/testing/selftests/net/sctp_hello.c +++ b/tools/testing/selftests/net/sctp_hello.c @@ -29,7 +29,6 @@ static void set_addr(struct sockaddr_storage *ss, char *ip, char *port, int *len  static int do_client(int argc, char *argv[])  {  	struct sockaddr_storage ss; -	char buf[] = "hello";  	int csk, ret, len;  	if (argc < 5) { @@ -56,16 +55,10 @@ static int do_client(int argc, char *argv[])  	set_addr(&ss, argv[3], argv[4], &len);  	ret = connect(csk, (struct sockaddr *)&ss, len); -	if (ret < 0) { -		printf("failed to connect to peer\n"); +	if (ret < 0)  		return -1; -	} -	ret = send(csk, buf, strlen(buf) + 1, 0); -	if (ret < 0) { -		printf("failed to send msg %d\n", ret); -		return -1; -	} +	recv(csk, NULL, 0, 0);  	close(csk);  	return 0; @@ -75,7 +68,6 @@ int main(int argc, char *argv[])  {  	struct sockaddr_storage ss;  	int lsk, csk, ret, len; -	char buf[20];  	if (argc < 2 || (strcmp(argv[1], "server") && strcmp(argv[1], "client"))) {  		printf("%s server|client ...\n", argv[0]); @@ -125,11 +117,6 @@ int main(int argc, char *argv[])  		return -1;  	} -	ret = recv(csk, buf, sizeof(buf), 0); -	if (ret <= 0) { -		printf("failed to recv msg %d\n", ret); -		return -1; -	}  	close(csk);  	close(lsk); diff --git a/tools/testing/selftests/net/sctp_vrf.sh b/tools/testing/selftests/net/sctp_vrf.sh index c854034b6aa1..667b211aa8a1 100755 --- a/tools/testing/selftests/net/sctp_vrf.sh +++ b/tools/testing/selftests/net/sctp_vrf.sh @@ -20,9 +20,9 @@ setup() {  	modprobe sctp_diag  	setup_ns CLIENT_NS1 CLIENT_NS2 SERVER_NS -	ip net exec $CLIENT_NS1 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null -	ip net exec $CLIENT_NS2 sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null -	ip net exec $SERVER_NS sysctl -w net.ipv6.conf.default.accept_dad=0 2>&1 >/dev/null +	ip net exec $CLIENT_NS1 sysctl -wq net.ipv6.conf.default.accept_dad=0 +	ip net exec $CLIENT_NS2 sysctl -wq net.ipv6.conf.default.accept_dad=0 +	ip net exec $SERVER_NS sysctl -wq net.ipv6.conf.default.accept_dad=0  	ip -n $SERVER_NS link add veth1 type veth peer name veth1 netns $CLIENT_NS1  	ip -n $SERVER_NS link add veth2 type veth peer name veth1 netns $CLIENT_NS2 @@ -62,17 +62,40 @@ setup() {  }  cleanup() { -	ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null +	wait_client $CLIENT_NS1 +	wait_client $CLIENT_NS2 +	stop_server  	cleanup_ns $CLIENT_NS1 $CLIENT_NS2 $SERVER_NS  } -wait_server() { +start_server() {  	local IFACE=$1  	local CNT=0 -	until ip netns exec $SERVER_NS ss -lS src $SERVER_IP:$SERVER_PORT | \ -		grep LISTEN | grep "$IFACE" 2>&1 >/dev/null; do -		[ $((CNT++)) = "20" ] && { RET=3; return $RET; } +	ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP $SERVER_PORT $IFACE & +	disown +	until ip netns exec $SERVER_NS ss -SlH | grep -q "$IFACE"; do +		[ $((CNT++)) -eq 30 ] && { RET=3; return $RET; } +		sleep 0.1 +	done +} + +stop_server() { +	local CNT=0 + +	ip netns exec $SERVER_NS pkill sctp_hello +	while ip netns exec $SERVER_NS ss -SaH | grep -q .; do +		[ $((CNT++)) -eq 30 ] && break +		sleep 0.1 +	done +} + +wait_client() { +	local CLIENT_NS=$1 +	local CNT=0 + +	while ip netns exec $CLIENT_NS ss -SaH | grep -q .; do +		[ $((CNT++)) -eq 30 ] && break  		sleep 0.1  	done  } @@ -81,14 +104,12 @@ do_test() {  	local CLIENT_NS=$1  	local IFACE=$2 -	ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null -	ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \ -		$SERVER_PORT $IFACE 2>&1 >/dev/null & -	disown -	wait_server $IFACE || return $RET +	start_server $IFACE || return $RET  	timeout 3 ip netns exec $CLIENT_NS ./sctp_hello client $AF \ -		$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null +		$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT  	RET=$? +	wait_client $CLIENT_NS +	stop_server  	return $RET  } @@ -96,25 +117,21 @@ do_testx() {  	local IFACE1=$1  	local IFACE2=$2 -	ip netns exec $SERVER_NS pkill sctp_hello 2>&1 >/dev/null -	ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \ -		$SERVER_PORT $IFACE1 2>&1 >/dev/null & -	disown -	wait_server $IFACE1 || return $RET -	ip netns exec $SERVER_NS ./sctp_hello server $AF $SERVER_IP \ -		$SERVER_PORT $IFACE2 2>&1 >/dev/null & -	disown -	wait_server $IFACE2 || return $RET +	start_server $IFACE1 || return $RET +	start_server $IFACE2 || return $RET  	timeout 3 ip netns exec $CLIENT_NS1 ./sctp_hello client $AF \ -		$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null && \ +		$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT && \  	timeout 3 ip netns exec $CLIENT_NS2 ./sctp_hello client $AF \ -		$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT 2>&1 >/dev/null +		$SERVER_IP $SERVER_PORT $CLIENT_IP $CLIENT_PORT  	RET=$? +	wait_client $CLIENT_NS1 +	wait_client $CLIENT_NS2 +	stop_server  	return $RET  }  testup() { -	ip netns exec $SERVER_NS sysctl -w net.sctp.l3mdev_accept=1 2>&1 >/dev/null +	ip netns exec $SERVER_NS sysctl -wq net.sctp.l3mdev_accept=1  	echo -n "TEST 01: nobind, connect from client 1, l3mdev_accept=1, Y "  	do_test $CLIENT_NS1 || { echo "[FAIL]"; return $RET; }  	echo "[PASS]" @@ -123,7 +140,7 @@ testup() {  	do_test $CLIENT_NS2 && { echo "[FAIL]"; return $RET; }  	echo "[PASS]" -	ip netns exec $SERVER_NS sysctl -w net.sctp.l3mdev_accept=0 2>&1 >/dev/null +	ip netns exec $SERVER_NS sysctl -wq net.sctp.l3mdev_accept=0  	echo -n "TEST 03: nobind, connect from client 1, l3mdev_accept=0, N "  	do_test $CLIENT_NS1 && { echo "[FAIL]"; return $RET; }  	echo "[PASS]" @@ -160,7 +177,7 @@ testup() {  	do_testx vrf-1 vrf-2 || { echo "[FAIL]"; return $RET; }  	echo "[PASS]" -	echo -n "TEST 12: bind vrf-2 & 1 in server, connect from client 1 & 2, N " +	echo -n "TEST 12: bind vrf-2 & 1 in server, connect from client 1 & 2, Y "  	do_testx vrf-2 vrf-1 || { echo "[FAIL]"; return $RET; }  	echo "[PASS]"  } diff --git a/tools/testing/selftests/net/tls.c b/tools/testing/selftests/net/tls.c index e788b84551ca..5c6d8215021c 100644 --- a/tools/testing/selftests/net/tls.c +++ b/tools/testing/selftests/net/tls.c @@ -564,6 +564,40 @@ TEST_F(tls, msg_more)  	EXPECT_EQ(memcmp(buf, test_str, send_len), 0);  } +TEST_F(tls, cmsg_msg_more) +{ +	char *test_str =  "test_read"; +	char record_type = 100; +	int send_len = 10; + +	/* we don't allow MSG_MORE with non-DATA records */ +	EXPECT_EQ(tls_send_cmsg(self->fd, record_type, test_str, send_len, +				MSG_MORE), -1); +	EXPECT_EQ(errno, EINVAL); +} + +TEST_F(tls, msg_more_then_cmsg) +{ +	char *test_str = "test_read"; +	char record_type = 100; +	int send_len = 10; +	char buf[10 * 2]; +	int ret; + +	EXPECT_EQ(send(self->fd, test_str, send_len, MSG_MORE), send_len); +	EXPECT_EQ(recv(self->cfd, buf, send_len, MSG_DONTWAIT), -1); + +	ret = tls_send_cmsg(self->fd, record_type, test_str, send_len, 0); +	EXPECT_EQ(ret, send_len); + +	/* initial DATA record didn't get merged with the non-DATA record */ +	EXPECT_EQ(recv(self->cfd, buf, send_len * 2, 0), send_len); + +	EXPECT_EQ(tls_recv_cmsg(_metadata, self->cfd, record_type, +				buf, sizeof(buf), MSG_WAITALL), +		  send_len); +} +  TEST_F(tls, msg_more_unsent)  {  	char const *test_str = "test_read"; @@ -912,6 +946,37 @@ TEST_F(tls, peek_and_splice)  	EXPECT_EQ(memcmp(mem_send, mem_recv, send_len), 0);  } +#define MAX_FRAGS 48 +TEST_F(tls, splice_short) +{ +	struct iovec sendchar_iov; +	char read_buf[0x10000]; +	char sendbuf[0x100]; +	char sendchar = 'S'; +	int pipefds[2]; +	int i; + +	sendchar_iov.iov_base = &sendchar; +	sendchar_iov.iov_len = 1; + +	memset(sendbuf, 's', sizeof(sendbuf)); + +	ASSERT_GE(pipe2(pipefds, O_NONBLOCK), 0); +	ASSERT_GE(fcntl(pipefds[0], F_SETPIPE_SZ, (MAX_FRAGS + 1) * 0x1000), 0); + +	for (i = 0; i < MAX_FRAGS; i++) +		ASSERT_GE(vmsplice(pipefds[1], &sendchar_iov, 1, 0), 0); + +	ASSERT_EQ(write(pipefds[1], sendbuf, sizeof(sendbuf)), sizeof(sendbuf)); + +	EXPECT_EQ(splice(pipefds[0], NULL, self->fd, NULL, MAX_FRAGS + 0x1000, 0), +		  MAX_FRAGS + sizeof(sendbuf)); +	EXPECT_EQ(recv(self->cfd, read_buf, sizeof(read_buf), 0), MAX_FRAGS + sizeof(sendbuf)); +	EXPECT_EQ(recv(self->cfd, read_buf, sizeof(read_buf), MSG_DONTWAIT), -1); +	EXPECT_EQ(errno, EAGAIN); +} +#undef MAX_FRAGS +  TEST_F(tls, recvmsg_single)  {  	char const *test_str = "test_recvmsg_single"; diff --git a/tools/testing/selftests/net/vlan_bridge_binding.sh b/tools/testing/selftests/net/vlan_bridge_binding.sh index db481af9b6b3..e8c02c64e03a 100755 --- a/tools/testing/selftests/net/vlan_bridge_binding.sh +++ b/tools/testing/selftests/net/vlan_bridge_binding.sh @@ -249,6 +249,8 @@ test_binding_toggle_off_when_upper_down()  	do_test_binding_off : "on->off when upper down"  } +require_command jq +  trap defer_scopes_cleanup EXIT  setup_prepare  tests_run | 
