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 17 struct guest_vals { 18 uint64_t a; 19 uint64_t b; 20 uint64_t type; 21 }; 22 23 static struct guest_vals vals; 24 25 /* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */ 26 #define TYPE_LIST \ 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) 38 39 enum args_type { 40 #define TYPE(fn, ext, fmt_t, T) TYPE_##ext, 41 TYPE_LIST 42 #undef TYPE 43 }; 44 45 static 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) \ 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) \ 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 68 static 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 */ 94 static 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 109 static 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 142 static 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 152 static 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 174 int 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