1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test that KVM_GET_MSR_INDEX_LIST and
4  * KVM_GET_MSR_FEATURE_INDEX_LIST work as intended
5  *
6  * Copyright (C) 2020, Red Hat, Inc.
7  */
8 #include <fcntl.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/ioctl.h>
13 
14 #include "test_util.h"
15 #include "kvm_util.h"
16 #include "processor.h"
17 
18 static int kvm_num_index_msrs(int kvm_fd, int nmsrs)
19 {
20 	struct kvm_msr_list *list;
21 	int r;
22 
23 	list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0]));
24 	list->nmsrs = nmsrs;
25 	r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list);
26 	TEST_ASSERT(r == -1 && errno == E2BIG,
27 				"Unexpected result from KVM_GET_MSR_INDEX_LIST probe, r: %i",
28 				r);
29 
30 	r = list->nmsrs;
31 	free(list);
32 	return r;
33 }
34 
35 static void test_get_msr_index(void)
36 {
37 	int old_res, res, kvm_fd, r;
38 	struct kvm_msr_list *list;
39 
40 	kvm_fd = open(KVM_DEV_PATH, O_RDONLY);
41 	if (kvm_fd < 0)
42 		exit(KSFT_SKIP);
43 
44 	old_res = kvm_num_index_msrs(kvm_fd, 0);
45 	TEST_ASSERT(old_res != 0, "Expecting nmsrs to be > 0");
46 
47 	if (old_res != 1) {
48 		res = kvm_num_index_msrs(kvm_fd, 1);
49 		TEST_ASSERT(res > 1, "Expecting nmsrs to be > 1");
50 		TEST_ASSERT(res == old_res, "Expecting nmsrs to be identical");
51 	}
52 
53 	list = malloc(sizeof(*list) + old_res * sizeof(list->indices[0]));
54 	list->nmsrs = old_res;
55 	r = ioctl(kvm_fd, KVM_GET_MSR_INDEX_LIST, list);
56 
57 	TEST_ASSERT(r == 0,
58 		    "Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST, r: %i",
59 		    r);
60 	TEST_ASSERT(list->nmsrs == old_res, "Expecting nmsrs to be identical");
61 	free(list);
62 
63 	close(kvm_fd);
64 }
65 
66 static int kvm_num_feature_msrs(int kvm_fd, int nmsrs)
67 {
68 	struct kvm_msr_list *list;
69 	int r;
70 
71 	list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0]));
72 	list->nmsrs = nmsrs;
73 	r = ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list);
74 	TEST_ASSERT(r == -1 && errno == E2BIG,
75 		"Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST probe, r: %i",
76 				r);
77 
78 	r = list->nmsrs;
79 	free(list);
80 	return r;
81 }
82 
83 struct kvm_msr_list *kvm_get_msr_feature_list(int kvm_fd, int nmsrs)
84 {
85 	struct kvm_msr_list *list;
86 	int r;
87 
88 	list = malloc(sizeof(*list) + nmsrs * sizeof(list->indices[0]));
89 	list->nmsrs = nmsrs;
90 	r = ioctl(kvm_fd, KVM_GET_MSR_FEATURE_INDEX_LIST, list);
91 
92 	TEST_ASSERT(r == 0,
93 		"Unexpected result from KVM_GET_MSR_FEATURE_INDEX_LIST, r: %i",
94 		r);
95 
96 	return list;
97 }
98 
99 static void test_get_msr_feature(void)
100 {
101 	int res, old_res, i, kvm_fd;
102 	struct kvm_msr_list *feature_list;
103 
104 	kvm_fd = open(KVM_DEV_PATH, O_RDONLY);
105 	if (kvm_fd < 0)
106 		exit(KSFT_SKIP);
107 
108 	old_res = kvm_num_feature_msrs(kvm_fd, 0);
109 	TEST_ASSERT(old_res != 0, "Expecting nmsrs to be > 0");
110 
111 	if (old_res != 1) {
112 		res = kvm_num_feature_msrs(kvm_fd, 1);
113 		TEST_ASSERT(res > 1, "Expecting nmsrs to be > 1");
114 		TEST_ASSERT(res == old_res, "Expecting nmsrs to be identical");
115 	}
116 
117 	feature_list = kvm_get_msr_feature_list(kvm_fd, old_res);
118 	TEST_ASSERT(old_res == feature_list->nmsrs,
119 				"Unmatching number of msr indexes");
120 
121 	for (i = 0; i < feature_list->nmsrs; i++)
122 		kvm_get_feature_msr(feature_list->indices[i]);
123 
124 	free(feature_list);
125 	close(kvm_fd);
126 }
127 
128 int main(int argc, char *argv[])
129 {
130 	if (kvm_check_cap(KVM_CAP_GET_MSR_FEATURES))
131 		test_get_msr_feature();
132 
133 	test_get_msr_index();
134 }
135