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
17struct guest_vals {
18	uint64_t a;
19	uint64_t b;
20	uint64_t type;
21};
22
23static struct guest_vals vals;
24
25/* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */
26#define TYPE_LIST					\
27TYPE(test_type_i64,  I64,  "%ld",   int64_t)		\
28TYPE(test_type_u64,  U64u, "%lu",   uint64_t)		\
29TYPE(test_type_x64,  U64x, "0x%lx", uint64_t)		\
30TYPE(test_type_X64,  U64X, "0x%lX", uint64_t)		\
31TYPE(test_type_u32,  U32u, "%u",    uint32_t)		\
32TYPE(test_type_x32,  U32x, "0x%x",  uint32_t)		\
33TYPE(test_type_X32,  U32X, "0x%X",  uint32_t)		\
34TYPE(test_type_int,  INT,  "%d",    int)		\
35TYPE(test_type_char, CHAR, "%c",    char)		\
36TYPE(test_type_str,  STR,  "'%s'",  const char *)	\
37TYPE(test_type_ptr,  PTR,  "%p",    uintptr_t)
38
39enum args_type {
40#define TYPE(fn, ext, fmt_t, T) TYPE_##ext,
41	TYPE_LIST
42#undef TYPE
43};
44
45static 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)		     \
49const char *PRINTF_FMT_##ext = "Got params a = " fmt_t " and b = " fmt_t;    \
50const char *ASSERT_FMT_##ext = "Expected " fmt_t ", got " fmt_t " instead";  \
51static 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
68static 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 */
94static 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
109static 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
142static 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
152static 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
174int 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