xref: /linux/tools/testing/selftests/kvm/guest_print_test.c (revision c5288cda69ee2d8607f5026bd599a5cebf0ee783)
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 static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
111 		     const char *expected_assert)
112 {
113 	struct kvm_run *run = vcpu->run;
114 	struct ucall uc;
115 
116 	while (1) {
117 		vcpu_run(vcpu);
118 
119 		TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
120 			    "Unexpected exit reason: %u (%s),",
121 			    run->exit_reason, exit_reason_str(run->exit_reason));
122 
123 		switch (get_ucall(vcpu, &uc)) {
124 		case UCALL_SYNC:
125 			TEST_FAIL("Unknown 'args_type' = %lu", uc.args[1]);
126 			break;
127 		case UCALL_PRINTF:
128 			TEST_ASSERT(strcmp(uc.buffer, expected_printf) == 0,
129 				    "Unexpected mismatch. Expected: '%s', got: '%s'",
130 				    expected_printf, uc.buffer);
131 			break;
132 		case UCALL_ABORT:
133 			ucall_abort(uc.buffer, expected_assert);
134 			break;
135 		case UCALL_DONE:
136 			return;
137 		default:
138 			TEST_FAIL("Unknown ucall %lu", uc.cmd);
139 		}
140 	}
141 }
142 
143 static void guest_code_limits(void)
144 {
145 	char test_str[UCALL_BUFFER_LEN + 10];
146 
147 	memset(test_str, 'a', sizeof(test_str));
148 	test_str[sizeof(test_str) - 1] = 0;
149 
150 	GUEST_PRINTF("%s", test_str);
151 }
152 
153 static void test_limits(void)
154 {
155 	struct kvm_vcpu *vcpu;
156 	struct kvm_run *run;
157 	struct kvm_vm *vm;
158 	struct ucall uc;
159 
160 	vm = vm_create_with_one_vcpu(&vcpu, guest_code_limits);
161 	run = vcpu->run;
162 	vcpu_run(vcpu);
163 
164 	TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
165 		    "Unexpected exit reason: %u (%s),",
166 		    run->exit_reason, exit_reason_str(run->exit_reason));
167 
168 	TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT,
169 		    "Unexpected ucall command: %lu,  Expected: %u (UCALL_ABORT)",
170 		    uc.cmd, UCALL_ABORT);
171 
172 	kvm_vm_free(vm);
173 }
174 
175 int main(int argc, char *argv[])
176 {
177 	struct kvm_vcpu *vcpu;
178 	struct kvm_vm *vm;
179 
180 	vm = vm_create_with_one_vcpu(&vcpu, guest_code);
181 
182 	test_type_i64(vcpu, -1, -1);
183 	test_type_i64(vcpu, -1,  1);
184 	test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
185 	test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
186 
187 	test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
188 	test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
189 	test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
190 	test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
191 	test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
192 	test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
193 
194 	test_type_u32(vcpu, 0x90abcdef, 0x90abcdef);
195 	test_type_u32(vcpu, 0x90abcdef, 0x90abcdee);
196 	test_type_x32(vcpu, 0x90abcdef, 0x90abcdef);
197 	test_type_x32(vcpu, 0x90abcdef, 0x90abcdee);
198 	test_type_X32(vcpu, 0x90abcdef, 0x90abcdef);
199 	test_type_X32(vcpu, 0x90abcdef, 0x90abcdee);
200 
201 	test_type_int(vcpu, -1, -1);
202 	test_type_int(vcpu, -1,  1);
203 	test_type_int(vcpu,  1,  1);
204 
205 	test_type_char(vcpu, 'a', 'a');
206 	test_type_char(vcpu, 'a', 'A');
207 	test_type_char(vcpu, 'a', 'b');
208 
209 	test_type_str(vcpu, "foo", "foo");
210 	test_type_str(vcpu, "foo", "bar");
211 
212 	test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
213 	test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
214 
215 	kvm_vm_free(vm);
216 
217 	test_limits();
218 
219 	return 0;
220 }
221