]> Git Repo - J-linux.git/blob - tools/testing/selftests/kvm/guest_print_test.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / tools / testing / selftests / kvm / guest_print_test.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * A test for GUEST_PRINTF
4  *
5  * Copyright 2022, Google, Inc. and/or its affiliates.
6  */
7 #include <fcntl.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <sys/ioctl.h>
12
13 #include "test_util.h"
14 #include "kvm_util.h"
15 #include "processor.h"
16 #include "ucall_common.h"
17
18 struct guest_vals {
19         uint64_t a;
20         uint64_t b;
21         uint64_t type;
22 };
23
24 static struct guest_vals vals;
25
26 /* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */
27 #define TYPE_LIST                                       \
28 TYPE(test_type_i64,  I64,  "%ld",   int64_t)            \
29 TYPE(test_type_u64,  U64u, "%lu",   uint64_t)           \
30 TYPE(test_type_x64,  U64x, "0x%lx", uint64_t)           \
31 TYPE(test_type_X64,  U64X, "0x%lX", uint64_t)           \
32 TYPE(test_type_u32,  U32u, "%u",    uint32_t)           \
33 TYPE(test_type_x32,  U32x, "0x%x",  uint32_t)           \
34 TYPE(test_type_X32,  U32X, "0x%X",  uint32_t)           \
35 TYPE(test_type_int,  INT,  "%d",    int)                \
36 TYPE(test_type_char, CHAR, "%c",    char)               \
37 TYPE(test_type_str,  STR,  "'%s'",  const char *)       \
38 TYPE(test_type_ptr,  PTR,  "%p",    uintptr_t)
39
40 enum args_type {
41 #define TYPE(fn, ext, fmt_t, T) TYPE_##ext,
42         TYPE_LIST
43 #undef TYPE
44 };
45
46 static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
47                      const char *expected_assert);
48
49 #define BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T)                     \
50 const char *PRINTF_FMT_##ext = "Got params a = " fmt_t " and b = " fmt_t;    \
51 const char *ASSERT_FMT_##ext = "Expected " fmt_t ", got " fmt_t " instead";  \
52 static void fn(struct kvm_vcpu *vcpu, T a, T b)                              \
53 {                                                                            \
54         char expected_printf[UCALL_BUFFER_LEN];                              \
55         char expected_assert[UCALL_BUFFER_LEN];                              \
56                                                                              \
57         snprintf(expected_printf, UCALL_BUFFER_LEN, PRINTF_FMT_##ext, a, b); \
58         snprintf(expected_assert, UCALL_BUFFER_LEN, ASSERT_FMT_##ext, a, b); \
59         vals = (struct guest_vals){ (uint64_t)a, (uint64_t)b, TYPE_##ext };  \
60         sync_global_to_guest(vcpu->vm, vals);                                \
61         run_test(vcpu, expected_printf, expected_assert);                    \
62 }
63
64 #define TYPE(fn, ext, fmt_t, T) \
65                 BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T)
66         TYPE_LIST
67 #undef TYPE
68
69 static void guest_code(void)
70 {
71         while (1) {
72                 switch (vals.type) {
73 #define TYPE(fn, ext, fmt_t, T)                                                 \
74                 case TYPE_##ext:                                                \
75                         GUEST_PRINTF(PRINTF_FMT_##ext, vals.a, vals.b);         \
76                         __GUEST_ASSERT(vals.a == vals.b,                        \
77                                        ASSERT_FMT_##ext, vals.a, vals.b);       \
78                         break;
79                 TYPE_LIST
80 #undef TYPE
81                 default:
82                         GUEST_SYNC(vals.type);
83                 }
84
85                 GUEST_DONE();
86         }
87 }
88
89 /*
90  * Unfortunately this gets a little messy because 'assert_msg' doesn't
91  * just contains the matching string, it also contains additional assert
92  * info.  Fortunately the part that matches should be at the very end of
93  * 'assert_msg'.
94  */
95 static void ucall_abort(const char *assert_msg, const char *expected_assert_msg)
96 {
97         int len_str = strlen(assert_msg);
98         int len_substr = strlen(expected_assert_msg);
99         int offset = len_str - len_substr;
100
101         TEST_ASSERT(len_substr <= len_str,
102                     "Expected '%s' to be a substring of '%s'",
103                     assert_msg, expected_assert_msg);
104
105         TEST_ASSERT(strcmp(&assert_msg[offset], expected_assert_msg) == 0,
106                     "Unexpected mismatch. Expected: '%s', got: '%s'",
107                     expected_assert_msg, &assert_msg[offset]);
108 }
109
110 /*
111  * Open code vcpu_run(), sans the UCALL_ABORT handling, so that intentional
112  * guest asserts guest can be verified instead of being reported as failures.
113  */
114 static void do_vcpu_run(struct kvm_vcpu *vcpu)
115 {
116         int r;
117
118         do {
119                 r = __vcpu_run(vcpu);
120         } while (r == -1 && errno == EINTR);
121
122         TEST_ASSERT(!r, KVM_IOCTL_ERROR(KVM_RUN, r));
123 }
124
125 static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
126                      const char *expected_assert)
127 {
128         struct kvm_run *run = vcpu->run;
129         struct ucall uc;
130
131         while (1) {
132                 do_vcpu_run(vcpu);
133
134                 TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
135                             "Unexpected exit reason: %u (%s),",
136                             run->exit_reason, exit_reason_str(run->exit_reason));
137
138                 switch (get_ucall(vcpu, &uc)) {
139                 case UCALL_SYNC:
140                         TEST_FAIL("Unknown 'args_type' = %lu", uc.args[1]);
141                         break;
142                 case UCALL_PRINTF:
143                         TEST_ASSERT(strcmp(uc.buffer, expected_printf) == 0,
144                                     "Unexpected mismatch. Expected: '%s', got: '%s'",
145                                     expected_printf, uc.buffer);
146                         break;
147                 case UCALL_ABORT:
148                         ucall_abort(uc.buffer, expected_assert);
149                         break;
150                 case UCALL_DONE:
151                         return;
152                 default:
153                         TEST_FAIL("Unknown ucall %lu", uc.cmd);
154                 }
155         }
156 }
157
158 static void guest_code_limits(void)
159 {
160         char test_str[UCALL_BUFFER_LEN + 10];
161
162         memset(test_str, 'a', sizeof(test_str));
163         test_str[sizeof(test_str) - 1] = 0;
164
165         GUEST_PRINTF("%s", test_str);
166 }
167
168 static void test_limits(void)
169 {
170         struct kvm_vcpu *vcpu;
171         struct kvm_run *run;
172         struct kvm_vm *vm;
173         struct ucall uc;
174
175         vm = vm_create_with_one_vcpu(&vcpu, guest_code_limits);
176         run = vcpu->run;
177         do_vcpu_run(vcpu);
178
179         TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
180                     "Unexpected exit reason: %u (%s),",
181                     run->exit_reason, exit_reason_str(run->exit_reason));
182
183         TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT,
184                     "Unexpected ucall command: %lu,  Expected: %u (UCALL_ABORT)",
185                     uc.cmd, UCALL_ABORT);
186
187         kvm_vm_free(vm);
188 }
189
190 int main(int argc, char *argv[])
191 {
192         struct kvm_vcpu *vcpu;
193         struct kvm_vm *vm;
194
195         vm = vm_create_with_one_vcpu(&vcpu, guest_code);
196
197         test_type_i64(vcpu, -1, -1);
198         test_type_i64(vcpu, -1,  1);
199         test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
200         test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
201
202         test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
203         test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
204         test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
205         test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
206         test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
207         test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
208
209         test_type_u32(vcpu, 0x90abcdef, 0x90abcdef);
210         test_type_u32(vcpu, 0x90abcdef, 0x90abcdee);
211         test_type_x32(vcpu, 0x90abcdef, 0x90abcdef);
212         test_type_x32(vcpu, 0x90abcdef, 0x90abcdee);
213         test_type_X32(vcpu, 0x90abcdef, 0x90abcdef);
214         test_type_X32(vcpu, 0x90abcdef, 0x90abcdee);
215
216         test_type_int(vcpu, -1, -1);
217         test_type_int(vcpu, -1,  1);
218         test_type_int(vcpu,  1,  1);
219
220         test_type_char(vcpu, 'a', 'a');
221         test_type_char(vcpu, 'a', 'A');
222         test_type_char(vcpu, 'a', 'b');
223
224         test_type_str(vcpu, "foo", "foo");
225         test_type_str(vcpu, "foo", "bar");
226
227         test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
228         test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
229
230         kvm_vm_free(vm);
231
232         test_limits();
233
234         return 0;
235 }
This page took 0.038186 seconds and 4 git commands to generate.