1 // SPDX-License-Identifier: GPL-2.0
3 * A test for GUEST_PRINTF
5 * Copyright 2022, Google, Inc. and/or its affiliates.
11 #include <sys/ioctl.h>
13 #include "test_util.h"
15 #include "processor.h"
23 static struct guest_vals vals;
25 /* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */
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)
40 #define TYPE(fn, ext, fmt_t, T) TYPE_##ext,
45 static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
46 const char *expected_assert);
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) \
53 char expected_printf[UCALL_BUFFER_LEN]; \
54 char expected_assert[UCALL_BUFFER_LEN]; \
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); \
63 #define TYPE(fn, ext, fmt_t, T) \
64 BUILD_TYPE_STRINGS_AND_HELPER(fn, ext, fmt_t, T)
68 static void guest_code(void)
72 #define TYPE(fn, ext, fmt_t, T) \
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); \
81 GUEST_SYNC(vals.type);
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
94 static void ucall_abort(const char *assert_msg, const char *expected_assert_msg)
96 int len_str = strlen(assert_msg);
97 int len_substr = strlen(expected_assert_msg);
98 int offset = len_str - len_substr;
100 TEST_ASSERT(len_substr <= len_str,
101 "Expected '%s' to be a substring of '%s'",
102 assert_msg, expected_assert_msg);
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]);
109 static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
110 const char *expected_assert)
112 struct kvm_run *run = vcpu->run;
118 TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
119 "Unexpected exit reason: %u (%s),",
120 run->exit_reason, exit_reason_str(run->exit_reason));
122 switch (get_ucall(vcpu, &uc)) {
124 TEST_FAIL("Unknown 'args_type' = %lu", uc.args[1]);
127 TEST_ASSERT(strcmp(uc.buffer, expected_printf) == 0,
128 "Unexpected mismatch. Expected: '%s', got: '%s'",
129 expected_printf, uc.buffer);
132 ucall_abort(uc.buffer, expected_assert);
137 TEST_FAIL("Unknown ucall %lu", uc.cmd);
142 static void guest_code_limits(void)
144 char test_str[UCALL_BUFFER_LEN + 10];
146 memset(test_str, 'a', sizeof(test_str));
147 test_str[sizeof(test_str) - 1] = 0;
149 GUEST_PRINTF("%s", test_str);
152 static void test_limits(void)
154 struct kvm_vcpu *vcpu;
159 vm = vm_create_with_one_vcpu(&vcpu, guest_code_limits);
163 TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
164 "Unexpected exit reason: %u (%s),",
165 run->exit_reason, exit_reason_str(run->exit_reason));
167 TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT,
168 "Unexpected ucall command: %lu, Expected: %u (UCALL_ABORT)",
169 uc.cmd, UCALL_ABORT);
174 int main(int argc, char *argv[])
176 struct kvm_vcpu *vcpu;
179 vm = vm_create_with_one_vcpu(&vcpu, guest_code);
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);
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);
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);
200 test_type_int(vcpu, -1, -1);
201 test_type_int(vcpu, -1, 1);
202 test_type_int(vcpu, 1, 1);
204 test_type_char(vcpu, 'a', 'a');
205 test_type_char(vcpu, 'a', 'A');
206 test_type_char(vcpu, 'a', 'b');
208 test_type_str(vcpu, "foo", "foo");
209 test_type_str(vcpu, "foo", "bar");
211 test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
212 test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);