OSDN Git Service

Merge tag 'perf-urgent-2023-09-10' of git://git.kernel.org/pub/scm/linux/kernel/git...
[tomoyo/tomoyo-test1.git] / tools / testing / selftests / kvm / get-reg-list.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Check for KVM_GET_REG_LIST regressions.
4  *
5  * Copyright (C) 2020, Red Hat, Inc.
6  *
7  * When attempting to migrate from a host with an older kernel to a host
8  * with a newer kernel we allow the newer kernel on the destination to
9  * list new registers with get-reg-list. We assume they'll be unused, at
10  * least until the guest reboots, and so they're relatively harmless.
11  * However, if the destination host with the newer kernel is missing
12  * registers which the source host with the older kernel has, then that's
13  * a regression in get-reg-list. This test checks for that regression by
14  * checking the current list against a blessed list. We should never have
15  * missing registers, but if new ones appear then they can probably be
16  * added to the blessed list. A completely new blessed list can be created
17  * by running the test with the --list command line argument.
18  *
19  * The blessed list should be created from the oldest possible kernel.
20  */
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include "kvm_util.h"
28 #include "test_util.h"
29 #include "processor.h"
30
31 static struct kvm_reg_list *reg_list;
32 static __u64 *blessed_reg, blessed_n;
33
34 extern struct vcpu_reg_list *vcpu_configs[];
35 extern int vcpu_configs_n;
36
37 #define for_each_reg(i)                                                         \
38         for ((i) = 0; (i) < reg_list->n; ++(i))
39
40 #define for_each_reg_filtered(i)                                                \
41         for_each_reg(i)                                                         \
42                 if (!filter_reg(reg_list->reg[i]))
43
44 #define for_each_missing_reg(i)                                                 \
45         for ((i) = 0; (i) < blessed_n; ++(i))                                   \
46                 if (!find_reg(reg_list->reg, reg_list->n, blessed_reg[i]))      \
47                         if (check_supported_reg(vcpu, blessed_reg[i]))
48
49 #define for_each_new_reg(i)                                                     \
50         for_each_reg_filtered(i)                                                \
51                 if (!find_reg(blessed_reg, blessed_n, reg_list->reg[i]))
52
53 #define for_each_present_blessed_reg(i)                                         \
54         for_each_reg(i)                                                         \
55                 if (find_reg(blessed_reg, blessed_n, reg_list->reg[i]))
56
57 static const char *config_name(struct vcpu_reg_list *c)
58 {
59         struct vcpu_reg_sublist *s;
60         int len = 0;
61
62         if (c->name)
63                 return c->name;
64
65         for_each_sublist(c, s)
66                 len += strlen(s->name) + 1;
67
68         c->name = malloc(len);
69
70         len = 0;
71         for_each_sublist(c, s) {
72                 if (!strcmp(s->name, "base"))
73                         continue;
74                 strcat(c->name + len, s->name);
75                 len += strlen(s->name) + 1;
76                 c->name[len - 1] = '+';
77         }
78         c->name[len - 1] = '\0';
79
80         return c->name;
81 }
82
83 bool __weak check_supported_reg(struct kvm_vcpu *vcpu, __u64 reg)
84 {
85         return true;
86 }
87
88 bool __weak filter_reg(__u64 reg)
89 {
90         return false;
91 }
92
93 static bool find_reg(__u64 regs[], __u64 nr_regs, __u64 reg)
94 {
95         int i;
96
97         for (i = 0; i < nr_regs; ++i)
98                 if (reg == regs[i])
99                         return true;
100         return false;
101 }
102
103 void __weak print_reg(const char *prefix, __u64 id)
104 {
105         printf("\t0x%llx,\n", id);
106 }
107
108 bool __weak check_reject_set(int err)
109 {
110         return true;
111 }
112
113 void __weak finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
114 {
115 }
116
117 #ifdef __aarch64__
118 static void prepare_vcpu_init(struct vcpu_reg_list *c, struct kvm_vcpu_init *init)
119 {
120         struct vcpu_reg_sublist *s;
121
122         for_each_sublist(c, s)
123                 if (s->capability)
124                         init->features[s->feature / 32] |= 1 << (s->feature % 32);
125 }
126
127 static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm)
128 {
129         struct kvm_vcpu_init init = { .target = -1, };
130         struct kvm_vcpu *vcpu;
131
132         prepare_vcpu_init(c, &init);
133         vcpu = __vm_vcpu_add(vm, 0);
134         aarch64_vcpu_setup(vcpu, &init);
135
136         return vcpu;
137 }
138 #else
139 static struct kvm_vcpu *vcpu_config_get_vcpu(struct vcpu_reg_list *c, struct kvm_vm *vm)
140 {
141         return __vm_vcpu_add(vm, 0);
142 }
143 #endif
144
145 static void check_supported(struct vcpu_reg_list *c)
146 {
147         struct vcpu_reg_sublist *s;
148
149         for_each_sublist(c, s) {
150                 if (!s->capability)
151                         continue;
152
153                 __TEST_REQUIRE(kvm_has_cap(s->capability),
154                                "%s: %s not available, skipping tests\n",
155                                config_name(c), s->name);
156         }
157 }
158
159 static bool print_list;
160 static bool print_filtered;
161
162 static void run_test(struct vcpu_reg_list *c)
163 {
164         int new_regs = 0, missing_regs = 0, i, n;
165         int failed_get = 0, failed_set = 0, failed_reject = 0;
166         int skipped_set = 0;
167         struct kvm_vcpu *vcpu;
168         struct kvm_vm *vm;
169         struct vcpu_reg_sublist *s;
170
171         check_supported(c);
172
173         vm = vm_create_barebones();
174         vcpu = vcpu_config_get_vcpu(c, vm);
175         finalize_vcpu(vcpu, c);
176
177         reg_list = vcpu_get_reg_list(vcpu);
178
179         if (print_list || print_filtered) {
180                 putchar('\n');
181                 for_each_reg(i) {
182                         __u64 id = reg_list->reg[i];
183                         if ((print_list && !filter_reg(id)) ||
184                             (print_filtered && filter_reg(id)))
185                                 print_reg(config_name(c), id);
186                 }
187                 putchar('\n');
188                 return;
189         }
190
191         for_each_sublist(c, s)
192                 blessed_n += s->regs_n;
193         blessed_reg = calloc(blessed_n, sizeof(__u64));
194
195         n = 0;
196         for_each_sublist(c, s) {
197                 for (i = 0; i < s->regs_n; ++i)
198                         blessed_reg[n++] = s->regs[i];
199         }
200
201         /*
202          * We only test that we can get the register and then write back the
203          * same value. Some registers may allow other values to be written
204          * back, but others only allow some bits to be changed, and at least
205          * for ID registers set will fail if the value does not exactly match
206          * what was returned by get. If registers that allow other values to
207          * be written need to have the other values tested, then we should
208          * create a new set of tests for those in a new independent test
209          * executable.
210          *
211          * Only do the get/set tests on present, blessed list registers,
212          * since we don't know the capabilities of any new registers.
213          */
214         for_each_present_blessed_reg(i) {
215                 uint8_t addr[2048 / 8];
216                 struct kvm_one_reg reg = {
217                         .id = reg_list->reg[i],
218                         .addr = (__u64)&addr,
219                 };
220                 bool reject_reg = false, skip_reg = false;
221                 int ret;
222
223                 ret = __vcpu_get_reg(vcpu, reg_list->reg[i], &addr);
224                 if (ret) {
225                         printf("%s: Failed to get ", config_name(c));
226                         print_reg(config_name(c), reg.id);
227                         putchar('\n');
228                         ++failed_get;
229                 }
230
231                 for_each_sublist(c, s) {
232                         /* rejects_set registers are rejected for set operation */
233                         if (s->rejects_set && find_reg(s->rejects_set, s->rejects_set_n, reg.id)) {
234                                 reject_reg = true;
235                                 ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, &reg);
236                                 if (ret != -1 || !check_reject_set(errno)) {
237                                         printf("%s: Failed to reject (ret=%d, errno=%d) ", config_name(c), ret, errno);
238                                         print_reg(config_name(c), reg.id);
239                                         putchar('\n');
240                                         ++failed_reject;
241                                 }
242                                 break;
243                         }
244
245                         /* skips_set registers are skipped for set operation */
246                         if (s->skips_set && find_reg(s->skips_set, s->skips_set_n, reg.id)) {
247                                 skip_reg = true;
248                                 ++skipped_set;
249                                 break;
250                         }
251                 }
252
253                 if (!reject_reg && !skip_reg) {
254                         ret = __vcpu_ioctl(vcpu, KVM_SET_ONE_REG, &reg);
255                         if (ret) {
256                                 printf("%s: Failed to set ", config_name(c));
257                                 print_reg(config_name(c), reg.id);
258                                 putchar('\n');
259                                 ++failed_set;
260                         }
261                 }
262         }
263
264         for_each_new_reg(i)
265                 ++new_regs;
266
267         for_each_missing_reg(i)
268                 ++missing_regs;
269
270         if (new_regs || missing_regs) {
271                 n = 0;
272                 for_each_reg_filtered(i)
273                         ++n;
274
275                 printf("%s: Number blessed registers: %5lld\n", config_name(c), blessed_n);
276                 printf("%s: Number registers:         %5lld (includes %lld filtered registers)\n",
277                        config_name(c), reg_list->n, reg_list->n - n);
278         }
279
280         if (new_regs) {
281                 printf("\n%s: There are %d new registers.\n"
282                        "Consider adding them to the blessed reg "
283                        "list with the following lines:\n\n", config_name(c), new_regs);
284                 for_each_new_reg(i)
285                         print_reg(config_name(c), reg_list->reg[i]);
286                 putchar('\n');
287         }
288
289         if (missing_regs) {
290                 printf("\n%s: There are %d missing registers.\n"
291                        "The following lines are missing registers:\n\n", config_name(c), missing_regs);
292                 for_each_missing_reg(i)
293                         print_reg(config_name(c), blessed_reg[i]);
294                 putchar('\n');
295         }
296
297         TEST_ASSERT(!missing_regs && !failed_get && !failed_set && !failed_reject,
298                     "%s: There are %d missing registers; %d registers failed get; "
299                     "%d registers failed set; %d registers failed reject; %d registers skipped set",
300                     config_name(c), missing_regs, failed_get, failed_set, failed_reject, skipped_set);
301
302         pr_info("%s: PASS\n", config_name(c));
303         blessed_n = 0;
304         free(blessed_reg);
305         free(reg_list);
306         kvm_vm_free(vm);
307 }
308
309 static void help(void)
310 {
311         struct vcpu_reg_list *c;
312         int i;
313
314         printf(
315         "\n"
316         "usage: get-reg-list [--config=<selection>] [--list] [--list-filtered]\n\n"
317         " --config=<selection>        Used to select a specific vcpu configuration for the test/listing\n"
318         "                             '<selection>' may be\n");
319
320         for (i = 0; i < vcpu_configs_n; ++i) {
321                 c = vcpu_configs[i];
322                 printf(
323         "                               '%s'\n", config_name(c));
324         }
325
326         printf(
327         "\n"
328         " --list                      Print the register list rather than test it (requires --config)\n"
329         " --list-filtered             Print registers that would normally be filtered out (requires --config)\n"
330         "\n"
331         );
332 }
333
334 static struct vcpu_reg_list *parse_config(const char *config)
335 {
336         struct vcpu_reg_list *c = NULL;
337         int i;
338
339         if (config[8] != '=')
340                 help(), exit(1);
341
342         for (i = 0; i < vcpu_configs_n; ++i) {
343                 c = vcpu_configs[i];
344                 if (strcmp(config_name(c), &config[9]) == 0)
345                         break;
346         }
347
348         if (i == vcpu_configs_n)
349                 help(), exit(1);
350
351         return c;
352 }
353
354 int main(int ac, char **av)
355 {
356         struct vcpu_reg_list *c, *sel = NULL;
357         int i, ret = 0;
358         pid_t pid;
359
360         for (i = 1; i < ac; ++i) {
361                 if (strncmp(av[i], "--config", 8) == 0)
362                         sel = parse_config(av[i]);
363                 else if (strcmp(av[i], "--list") == 0)
364                         print_list = true;
365                 else if (strcmp(av[i], "--list-filtered") == 0)
366                         print_filtered = true;
367                 else if (strcmp(av[i], "--help") == 0 || strcmp(av[1], "-h") == 0)
368                         help(), exit(0);
369                 else
370                         help(), exit(1);
371         }
372
373         if (print_list || print_filtered) {
374                 /*
375                  * We only want to print the register list of a single config.
376                  */
377                 if (!sel)
378                         help(), exit(1);
379         }
380
381         for (i = 0; i < vcpu_configs_n; ++i) {
382                 c = vcpu_configs[i];
383                 if (sel && c != sel)
384                         continue;
385
386                 pid = fork();
387
388                 if (!pid) {
389                         run_test(c);
390                         exit(0);
391                 } else {
392                         int wstatus;
393                         pid_t wpid = wait(&wstatus);
394                         TEST_ASSERT(wpid == pid && WIFEXITED(wstatus), "wait: Unexpected return");
395                         if (WEXITSTATUS(wstatus) && WEXITSTATUS(wstatus) != KSFT_SKIP)
396                                 ret = KSFT_FAIL;
397                 }
398         }
399
400         return ret;
401 }