Merge v5.14-rc3 into usb-next
[linux-2.6-microblaze.git] / tools / testing / selftests / kvm / x86_64 / sync_regs_test.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Test for x86 KVM_CAP_SYNC_REGS
4  *
5  * Copyright (C) 2018, Google LLC.
6  *
7  * Verifies expected behavior of x86 KVM_CAP_SYNC_REGS functionality,
8  * including requesting an invalid register set, updates to/from values
9  * in kvm_run.s.regs when kvm_valid_regs and kvm_dirty_regs are toggled.
10  */
11
12 #define _GNU_SOURCE /* for program_invocation_short_name */
13 #include <fcntl.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/ioctl.h>
18
19 #include "test_util.h"
20 #include "kvm_util.h"
21 #include "processor.h"
22
23 #define VCPU_ID 5
24
25 #define UCALL_PIO_PORT ((uint16_t)0x1000)
26
27 struct ucall uc_none = {
28         .cmd = UCALL_NONE,
29 };
30
31 /*
32  * ucall is embedded here to protect against compiler reshuffling registers
33  * before calling a function. In this test we only need to get KVM_EXIT_IO
34  * vmexit and preserve RBX, no additional information is needed.
35  */
36 void guest_code(void)
37 {
38         asm volatile("1: in %[port], %%al\n"
39                      "add $0x1, %%rbx\n"
40                      "jmp 1b"
41                      : : [port] "d" (UCALL_PIO_PORT), "D" (&uc_none)
42                      : "rax", "rbx");
43 }
44
45 static void compare_regs(struct kvm_regs *left, struct kvm_regs *right)
46 {
47 #define REG_COMPARE(reg) \
48         TEST_ASSERT(left->reg == right->reg, \
49                     "Register " #reg \
50                     " values did not match: 0x%llx, 0x%llx\n", \
51                     left->reg, right->reg)
52         REG_COMPARE(rax);
53         REG_COMPARE(rbx);
54         REG_COMPARE(rcx);
55         REG_COMPARE(rdx);
56         REG_COMPARE(rsi);
57         REG_COMPARE(rdi);
58         REG_COMPARE(rsp);
59         REG_COMPARE(rbp);
60         REG_COMPARE(r8);
61         REG_COMPARE(r9);
62         REG_COMPARE(r10);
63         REG_COMPARE(r11);
64         REG_COMPARE(r12);
65         REG_COMPARE(r13);
66         REG_COMPARE(r14);
67         REG_COMPARE(r15);
68         REG_COMPARE(rip);
69         REG_COMPARE(rflags);
70 #undef REG_COMPARE
71 }
72
73 static void compare_sregs(struct kvm_sregs *left, struct kvm_sregs *right)
74 {
75 }
76
77 static void compare_vcpu_events(struct kvm_vcpu_events *left,
78                                 struct kvm_vcpu_events *right)
79 {
80 }
81
82 #define TEST_SYNC_FIELDS   (KVM_SYNC_X86_REGS|KVM_SYNC_X86_SREGS|KVM_SYNC_X86_EVENTS)
83 #define INVALID_SYNC_FIELD 0x80000000
84
85 int main(int argc, char *argv[])
86 {
87         struct kvm_vm *vm;
88         struct kvm_run *run;
89         struct kvm_regs regs;
90         struct kvm_sregs sregs;
91         struct kvm_vcpu_events events;
92         int rv, cap;
93
94         /* Tell stdout not to buffer its content */
95         setbuf(stdout, NULL);
96
97         cap = kvm_check_cap(KVM_CAP_SYNC_REGS);
98         if ((cap & TEST_SYNC_FIELDS) != TEST_SYNC_FIELDS) {
99                 print_skip("KVM_CAP_SYNC_REGS not supported");
100                 exit(KSFT_SKIP);
101         }
102         if ((cap & INVALID_SYNC_FIELD) != 0) {
103                 print_skip("The \"invalid\" field is not invalid");
104                 exit(KSFT_SKIP);
105         }
106
107         /* Create VM */
108         vm = vm_create_default(VCPU_ID, 0, guest_code);
109
110         run = vcpu_state(vm, VCPU_ID);
111
112         /* Request reading invalid register set from VCPU. */
113         run->kvm_valid_regs = INVALID_SYNC_FIELD;
114         rv = _vcpu_run(vm, VCPU_ID);
115         TEST_ASSERT(rv < 0 && errno == EINVAL,
116                     "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
117                     rv);
118         vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
119
120         run->kvm_valid_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
121         rv = _vcpu_run(vm, VCPU_ID);
122         TEST_ASSERT(rv < 0 && errno == EINVAL,
123                     "Invalid kvm_valid_regs did not cause expected KVM_RUN error: %d\n",
124                     rv);
125         vcpu_state(vm, VCPU_ID)->kvm_valid_regs = 0;
126
127         /* Request setting invalid register set into VCPU. */
128         run->kvm_dirty_regs = INVALID_SYNC_FIELD;
129         rv = _vcpu_run(vm, VCPU_ID);
130         TEST_ASSERT(rv < 0 && errno == EINVAL,
131                     "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
132                     rv);
133         vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
134
135         run->kvm_dirty_regs = INVALID_SYNC_FIELD | TEST_SYNC_FIELDS;
136         rv = _vcpu_run(vm, VCPU_ID);
137         TEST_ASSERT(rv < 0 && errno == EINVAL,
138                     "Invalid kvm_dirty_regs did not cause expected KVM_RUN error: %d\n",
139                     rv);
140         vcpu_state(vm, VCPU_ID)->kvm_dirty_regs = 0;
141
142         /* Request and verify all valid register sets. */
143         /* TODO: BUILD TIME CHECK: TEST_ASSERT(KVM_SYNC_X86_NUM_FIELDS != 3); */
144         run->kvm_valid_regs = TEST_SYNC_FIELDS;
145         rv = _vcpu_run(vm, VCPU_ID);
146         TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
147                     "Unexpected exit reason: %u (%s),\n",
148                     run->exit_reason,
149                     exit_reason_str(run->exit_reason));
150
151         vcpu_regs_get(vm, VCPU_ID, &regs);
152         compare_regs(&regs, &run->s.regs.regs);
153
154         vcpu_sregs_get(vm, VCPU_ID, &sregs);
155         compare_sregs(&sregs, &run->s.regs.sregs);
156
157         vcpu_events_get(vm, VCPU_ID, &events);
158         compare_vcpu_events(&events, &run->s.regs.events);
159
160         /* Set and verify various register values. */
161         run->s.regs.regs.rbx = 0xBAD1DEA;
162         run->s.regs.sregs.apic_base = 1 << 11;
163         /* TODO run->s.regs.events.XYZ = ABC; */
164
165         run->kvm_valid_regs = TEST_SYNC_FIELDS;
166         run->kvm_dirty_regs = KVM_SYNC_X86_REGS | KVM_SYNC_X86_SREGS;
167         rv = _vcpu_run(vm, VCPU_ID);
168         TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
169                     "Unexpected exit reason: %u (%s),\n",
170                     run->exit_reason,
171                     exit_reason_str(run->exit_reason));
172         TEST_ASSERT(run->s.regs.regs.rbx == 0xBAD1DEA + 1,
173                     "rbx sync regs value incorrect 0x%llx.",
174                     run->s.regs.regs.rbx);
175         TEST_ASSERT(run->s.regs.sregs.apic_base == 1 << 11,
176                     "apic_base sync regs value incorrect 0x%llx.",
177                     run->s.regs.sregs.apic_base);
178
179         vcpu_regs_get(vm, VCPU_ID, &regs);
180         compare_regs(&regs, &run->s.regs.regs);
181
182         vcpu_sregs_get(vm, VCPU_ID, &sregs);
183         compare_sregs(&sregs, &run->s.regs.sregs);
184
185         vcpu_events_get(vm, VCPU_ID, &events);
186         compare_vcpu_events(&events, &run->s.regs.events);
187
188         /* Clear kvm_dirty_regs bits, verify new s.regs values are
189          * overwritten with existing guest values.
190          */
191         run->kvm_valid_regs = TEST_SYNC_FIELDS;
192         run->kvm_dirty_regs = 0;
193         run->s.regs.regs.rbx = 0xDEADBEEF;
194         rv = _vcpu_run(vm, VCPU_ID);
195         TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
196                     "Unexpected exit reason: %u (%s),\n",
197                     run->exit_reason,
198                     exit_reason_str(run->exit_reason));
199         TEST_ASSERT(run->s.regs.regs.rbx != 0xDEADBEEF,
200                     "rbx sync regs value incorrect 0x%llx.",
201                     run->s.regs.regs.rbx);
202
203         /* Clear kvm_valid_regs bits and kvm_dirty_bits.
204          * Verify s.regs values are not overwritten with existing guest values
205          * and that guest values are not overwritten with kvm_sync_regs values.
206          */
207         run->kvm_valid_regs = 0;
208         run->kvm_dirty_regs = 0;
209         run->s.regs.regs.rbx = 0xAAAA;
210         regs.rbx = 0xBAC0;
211         vcpu_regs_set(vm, VCPU_ID, &regs);
212         rv = _vcpu_run(vm, VCPU_ID);
213         TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
214                     "Unexpected exit reason: %u (%s),\n",
215                     run->exit_reason,
216                     exit_reason_str(run->exit_reason));
217         TEST_ASSERT(run->s.regs.regs.rbx == 0xAAAA,
218                     "rbx sync regs value incorrect 0x%llx.",
219                     run->s.regs.regs.rbx);
220         vcpu_regs_get(vm, VCPU_ID, &regs);
221         TEST_ASSERT(regs.rbx == 0xBAC0 + 1,
222                     "rbx guest value incorrect 0x%llx.",
223                     regs.rbx);
224
225         /* Clear kvm_valid_regs bits. Verify s.regs values are not overwritten
226          * with existing guest values but that guest values are overwritten
227          * with kvm_sync_regs values.
228          */
229         run->kvm_valid_regs = 0;
230         run->kvm_dirty_regs = TEST_SYNC_FIELDS;
231         run->s.regs.regs.rbx = 0xBBBB;
232         rv = _vcpu_run(vm, VCPU_ID);
233         TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
234                     "Unexpected exit reason: %u (%s),\n",
235                     run->exit_reason,
236                     exit_reason_str(run->exit_reason));
237         TEST_ASSERT(run->s.regs.regs.rbx == 0xBBBB,
238                     "rbx sync regs value incorrect 0x%llx.",
239                     run->s.regs.regs.rbx);
240         vcpu_regs_get(vm, VCPU_ID, &regs);
241         TEST_ASSERT(regs.rbx == 0xBBBB + 1,
242                     "rbx guest value incorrect 0x%llx.",
243                     regs.rbx);
244
245         kvm_vm_free(vm);
246
247         return 0;
248 }