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
17 struct guest_vals {
18 uint64_t a;
19 uint64_t b;
20 uint64_t type;
21 };
22
23 static struct guest_vals vals;
24
25 /* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */
26 #define TYPE_LIST \
27 TYPE(test_type_i64, I64, "%ld", int64_t) \
28 TYPE(test_type_u64, U64u, "%lu", uint64_t) \
29 TYPE(test_type_x64, U64x, "0x%lx", uint64_t) \
30 TYPE(test_type_X64, U64X, "0x%lX", uint64_t) \
31 TYPE(test_type_u32, U32u, "%u", uint32_t) \
32 TYPE(test_type_x32, U32x, "0x%x", uint32_t) \
33 TYPE(test_type_X32, U32X, "0x%X", uint32_t) \
34 TYPE(test_type_int, INT, "%d", int) \
35 TYPE(test_type_char, CHAR, "%c", char) \
36 TYPE(test_type_str, STR, "'%s'", const char *) \
37 TYPE(test_type_ptr, PTR, "%p", uintptr_t)
38
39 enum args_type {
40 #define TYPE(fn, ext, fmt_t, T) TYPE_##ext,
41 TYPE_LIST
42 #undef TYPE
43 };
44
45 static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
46 const char *expected_assert);
47
48 #define BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T) \
49 const char *PRINTF_FMT_##ext = "Got params a = " fmt_t " and b = " fmt_t; \
50 const char *ASSERT_FMT_##ext = "Expected " fmt_t ", got " fmt_t " instead"; \
51 static void fn(struct kvm_vcpu *vcpu, T a, T b) \
52 { \
53 char expected_printf[UCALL_BUFFER_LEN]; \
54 char expected_assert[UCALL_BUFFER_LEN]; \
55 \
56 snprintf(expected_printf, UCALL_BUFFER_LEN, PRINTF_FMT_##ext, a, b); \
57 snprintf(expected_assert, UCALL_BUFFER_LEN, ASSERT_FMT_##ext, a, b); \
58 vals = (struct guest_vals){ (uint64_t)a, (uint64_t)b, TYPE_##ext }; \
59 sync_global_to_guest(vcpu->vm, vals); \
60 run_test(vcpu, expected_printf, expected_assert); \
61 }
62
63 #define TYPE(fn, ext, fmt_t, T) \
64 BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T)
65 TYPE_LIST
66 #undef TYPE
67
guest_code(void)68 static void guest_code(void)
69 {
70 while (1) {
71 switch (vals.type) {
72 #define TYPE(fn, ext, fmt_t, T) \
73 case TYPE_##ext: \
74 GUEST_PRINTF(PRINTF_FMT_##ext, vals.a, vals.b); \
75 __GUEST_ASSERT(vals.a == vals.b, \
76 ASSERT_FMT_##ext, vals.a, vals.b); \
77 break;
78 TYPE_LIST
79 #undef TYPE
80 default:
81 GUEST_SYNC(vals.type);
82 }
83
84 GUEST_DONE();
85 }
86 }
87
88 /*
89 * Unfortunately this gets a little messy because 'assert_msg' doesn't
90 * just contains the matching string, it also contains additional assert
91 * info. Fortunately the part that matches should be at the very end of
92 * 'assert_msg'.
93 */
ucall_abort(const char * assert_msg,const char * expected_assert_msg)94 static void ucall_abort(const char *assert_msg, const char *expected_assert_msg)
95 {
96 int len_str = strlen(assert_msg);
97 int len_substr = strlen(expected_assert_msg);
98 int offset = len_str - len_substr;
99
100 TEST_ASSERT(len_substr <= len_str,
101 "Expected '%s' to be a substring of '%s'\n",
102 assert_msg, expected_assert_msg);
103
104 TEST_ASSERT(strcmp(&assert_msg[offset], expected_assert_msg) == 0,
105 "Unexpected mismatch. Expected: '%s', got: '%s'",
106 expected_assert_msg, &assert_msg[offset]);
107 }
108
run_test(struct kvm_vcpu * vcpu,const char * expected_printf,const char * expected_assert)109 static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
110 const char *expected_assert)
111 {
112 struct kvm_run *run = vcpu->run;
113 struct ucall uc;
114
115 while (1) {
116 vcpu_run(vcpu);
117
118 TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
119 "Unexpected exit reason: %u (%s),\n",
120 run->exit_reason, exit_reason_str(run->exit_reason));
121
122 switch (get_ucall(vcpu, &uc)) {
123 case UCALL_SYNC:
124 TEST_FAIL("Unknown 'args_type' = %lu", uc.args[1]);
125 break;
126 case UCALL_PRINTF:
127 TEST_ASSERT(strcmp(uc.buffer, expected_printf) == 0,
128 "Unexpected mismatch. Expected: '%s', got: '%s'",
129 expected_printf, uc.buffer);
130 break;
131 case UCALL_ABORT:
132 ucall_abort(uc.buffer, expected_assert);
133 break;
134 case UCALL_DONE:
135 return;
136 default:
137 TEST_FAIL("Unknown ucall %lu", uc.cmd);
138 }
139 }
140 }
141
guest_code_limits(void)142 static void guest_code_limits(void)
143 {
144 char test_str[UCALL_BUFFER_LEN + 10];
145
146 memset(test_str, 'a', sizeof(test_str));
147 test_str[sizeof(test_str) - 1] = 0;
148
149 GUEST_PRINTF("%s", test_str);
150 }
151
test_limits(void)152 static void test_limits(void)
153 {
154 struct kvm_vcpu *vcpu;
155 struct kvm_run *run;
156 struct kvm_vm *vm;
157 struct ucall uc;
158
159 vm = vm_create_with_one_vcpu(&vcpu, guest_code_limits);
160 run = vcpu->run;
161 vcpu_run(vcpu);
162
163 TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
164 "Unexpected exit reason: %u (%s),\n",
165 run->exit_reason, exit_reason_str(run->exit_reason));
166
167 TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT,
168 "Unexpected ucall command: %lu, Expected: %u (UCALL_ABORT)\n",
169 uc.cmd, UCALL_ABORT);
170
171 kvm_vm_free(vm);
172 }
173
main(int argc,char * argv[])174 int main(int argc, char *argv[])
175 {
176 struct kvm_vcpu *vcpu;
177 struct kvm_vm *vm;
178
179 vm = vm_create_with_one_vcpu(&vcpu, guest_code);
180
181 test_type_i64(vcpu, -1, -1);
182 test_type_i64(vcpu, -1, 1);
183 test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
184 test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
185
186 test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
187 test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
188 test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
189 test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
190 test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
191 test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
192
193 test_type_u32(vcpu, 0x90abcdef, 0x90abcdef);
194 test_type_u32(vcpu, 0x90abcdef, 0x90abcdee);
195 test_type_x32(vcpu, 0x90abcdef, 0x90abcdef);
196 test_type_x32(vcpu, 0x90abcdef, 0x90abcdee);
197 test_type_X32(vcpu, 0x90abcdef, 0x90abcdef);
198 test_type_X32(vcpu, 0x90abcdef, 0x90abcdee);
199
200 test_type_int(vcpu, -1, -1);
201 test_type_int(vcpu, -1, 1);
202 test_type_int(vcpu, 1, 1);
203
204 test_type_char(vcpu, 'a', 'a');
205 test_type_char(vcpu, 'a', 'A');
206 test_type_char(vcpu, 'a', 'b');
207
208 test_type_str(vcpu, "foo", "foo");
209 test_type_str(vcpu, "foo", "bar");
210
211 test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
212 test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
213
214 kvm_vm_free(vm);
215
216 test_limits();
217
218 return 0;
219 }
220