tools/testing/selftests/kvm/guest_print_test.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/kvm/guest_print_test.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/kvm/guest_print_test.c
Extension
.c
Size
6457 bytes
Lines
236
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct guest_vals {
	u64 a;
	u64 b;
	u64 type;
};

static struct guest_vals vals;

/* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */
#define TYPE_LIST					\
TYPE(test_type_i64,  I64,  "%ld",   s64)		\
TYPE(test_type_u64,  U64u, "%lu",   u64)		\
TYPE(test_type_x64,  U64x, "0x%lx", u64)		\
TYPE(test_type_X64,  U64X, "0x%lX", u64)		\
TYPE(test_type_u32,  U32u, "%u",    u32)		\
TYPE(test_type_x32,  U32x, "0x%x",  u32)		\
TYPE(test_type_X32,  U32X, "0x%X",  u32)		\
TYPE(test_type_int,  INT,  "%d",    int)		\
TYPE(test_type_char, CHAR, "%c",    char)		\
TYPE(test_type_str,  STR,  "'%s'",  const char *)	\
TYPE(test_type_ptr,  PTR,  "%p",    uintptr_t)

enum args_type {
#define TYPE(fn, ext, fmt_t, T) TYPE_##ext,
	TYPE_LIST
#undef TYPE
};

static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
		     const char *expected_assert);

#define BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T)		     \
const char *PRINTF_FMT_##ext = "Got params a = " fmt_t " and b = " fmt_t;    \
const char *ASSERT_FMT_##ext = "Expected " fmt_t ", got " fmt_t " instead";  \
static void fn(struct kvm_vcpu *vcpu, T a, T b)				     \
{									     \
	char expected_printf[UCALL_BUFFER_LEN];				     \
	char expected_assert[UCALL_BUFFER_LEN];				     \
									     \
	snprintf(expected_printf, UCALL_BUFFER_LEN, PRINTF_FMT_##ext, a, b); \
	snprintf(expected_assert, UCALL_BUFFER_LEN, ASSERT_FMT_##ext, a, b); \
	vals = (struct guest_vals){ (u64)a, (u64)b, TYPE_##ext };  \
	sync_global_to_guest(vcpu->vm, vals);				     \
	run_test(vcpu, expected_printf, expected_assert);		     \
}

#define TYPE(fn, ext, fmt_t, T) \
		BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T)
	TYPE_LIST
#undef TYPE

static void guest_code(void)
{
	while (1) {
		switch (vals.type) {
#define TYPE(fn, ext, fmt_t, T)							\
		case TYPE_##ext:						\
			GUEST_PRINTF(PRINTF_FMT_##ext, vals.a, vals.b);		\
			__GUEST_ASSERT(vals.a == vals.b,			\
				       ASSERT_FMT_##ext, vals.a, vals.b);	\
			break;
		TYPE_LIST
#undef TYPE
		default:
			GUEST_SYNC(vals.type);
		}

		GUEST_DONE();
	}
}

/*
 * Unfortunately this gets a little messy because 'assert_msg' doesn't
 * just contains the matching string, it also contains additional assert
 * info.  Fortunately the part that matches should be at the very end of
 * 'assert_msg'.
 */
static void ucall_abort(const char *assert_msg, const char *expected_assert_msg)
{
	int len_str = strlen(assert_msg);
	int len_substr = strlen(expected_assert_msg);
	int offset = len_str - len_substr;

	TEST_ASSERT(len_substr <= len_str,
		    "Expected '%s' to be a substring of '%s'",
		    assert_msg, expected_assert_msg);

	TEST_ASSERT(strcmp(&assert_msg[offset], expected_assert_msg) == 0,
		    "Unexpected mismatch. Expected: '%s', got: '%s'",
		    expected_assert_msg, &assert_msg[offset]);

Annotation

Implementation Notes