File Index
Files and directories
Sign in
FILE

guest_print_test.c

File preview with syntax highlighting.

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