~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/kvm/guest_print_test.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 18 struct guest_vals {
 19         uint64_t a;
 20         uint64_t b;
 21         uint64_t type;
 22 };
 23 
 24 static struct guest_vals vals;
 25 
 26 /* GUEST_PRINTF()/GUEST_ASSERT_FMT() does not support float or double. */
 27 #define TYPE_LIST                                       \
 28 TYPE(test_type_i64,  I64,  "%ld",   int64_t)            \
 29 TYPE(test_type_u64,  U64u, "%lu",   uint64_t)           \
 30 TYPE(test_type_x64,  U64x, "0x%lx", uint64_t)           \
 31 TYPE(test_type_X64,  U64X, "0x%lX", uint64_t)           \
 32 TYPE(test_type_u32,  U32u, "%u",    uint32_t)           \
 33 TYPE(test_type_x32,  U32x, "0x%x",  uint32_t)           \
 34 TYPE(test_type_X32,  U32X, "0x%X",  uint32_t)           \
 35 TYPE(test_type_int,  INT,  "%d",    int)                \
 36 TYPE(test_type_char, CHAR, "%c",    char)               \
 37 TYPE(test_type_str,  STR,  "'%s'",  const char *)       \
 38 TYPE(test_type_ptr,  PTR,  "%p",    uintptr_t)
 39 
 40 enum args_type {
 41 #define TYPE(fn, ext, fmt_t, T) TYPE_##ext,
 42         TYPE_LIST
 43 #undef TYPE
 44 };
 45 
 46 static 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)                     \
 50 const char *PRINTF_FMT_##ext = "Got params a = " fmt_t " and b = " fmt_t;    \
 51 const char *ASSERT_FMT_##ext = "Expected " fmt_t ", got " fmt_t " instead";  \
 52 static 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 
 69 static 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  */
 95 static 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 static void run_test(struct kvm_vcpu *vcpu, const char *expected_printf,
111                      const char *expected_assert)
112 {
113         struct kvm_run *run = vcpu->run;
114         struct ucall uc;
115 
116         while (1) {
117                 vcpu_run(vcpu);
118 
119                 TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
120                             "Unexpected exit reason: %u (%s),",
121                             run->exit_reason, exit_reason_str(run->exit_reason));
122 
123                 switch (get_ucall(vcpu, &uc)) {
124                 case UCALL_SYNC:
125                         TEST_FAIL("Unknown 'args_type' = %lu", uc.args[1]);
126                         break;
127                 case UCALL_PRINTF:
128                         TEST_ASSERT(strcmp(uc.buffer, expected_printf) == 0,
129                                     "Unexpected mismatch. Expected: '%s', got: '%s'",
130                                     expected_printf, uc.buffer);
131                         break;
132                 case UCALL_ABORT:
133                         ucall_abort(uc.buffer, expected_assert);
134                         break;
135                 case UCALL_DONE:
136                         return;
137                 default:
138                         TEST_FAIL("Unknown ucall %lu", uc.cmd);
139                 }
140         }
141 }
142 
143 static void guest_code_limits(void)
144 {
145         char test_str[UCALL_BUFFER_LEN + 10];
146 
147         memset(test_str, 'a', sizeof(test_str));
148         test_str[sizeof(test_str) - 1] = 0;
149 
150         GUEST_PRINTF("%s", test_str);
151 }
152 
153 static void test_limits(void)
154 {
155         struct kvm_vcpu *vcpu;
156         struct kvm_run *run;
157         struct kvm_vm *vm;
158         struct ucall uc;
159 
160         vm = vm_create_with_one_vcpu(&vcpu, guest_code_limits);
161         run = vcpu->run;
162         vcpu_run(vcpu);
163 
164         TEST_ASSERT(run->exit_reason == UCALL_EXIT_REASON,
165                     "Unexpected exit reason: %u (%s),",
166                     run->exit_reason, exit_reason_str(run->exit_reason));
167 
168         TEST_ASSERT(get_ucall(vcpu, &uc) == UCALL_ABORT,
169                     "Unexpected ucall command: %lu,  Expected: %u (UCALL_ABORT)",
170                     uc.cmd, UCALL_ABORT);
171 
172         kvm_vm_free(vm);
173 }
174 
175 int main(int argc, char *argv[])
176 {
177         struct kvm_vcpu *vcpu;
178         struct kvm_vm *vm;
179 
180         vm = vm_create_with_one_vcpu(&vcpu, guest_code);
181 
182         test_type_i64(vcpu, -1, -1);
183         test_type_i64(vcpu, -1,  1);
184         test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
185         test_type_i64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
186 
187         test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
188         test_type_u64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
189         test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
190         test_type_x64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
191         test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
192         test_type_X64(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
193 
194         test_type_u32(vcpu, 0x90abcdef, 0x90abcdef);
195         test_type_u32(vcpu, 0x90abcdef, 0x90abcdee);
196         test_type_x32(vcpu, 0x90abcdef, 0x90abcdef);
197         test_type_x32(vcpu, 0x90abcdef, 0x90abcdee);
198         test_type_X32(vcpu, 0x90abcdef, 0x90abcdef);
199         test_type_X32(vcpu, 0x90abcdef, 0x90abcdee);
200 
201         test_type_int(vcpu, -1, -1);
202         test_type_int(vcpu, -1,  1);
203         test_type_int(vcpu,  1,  1);
204 
205         test_type_char(vcpu, 'a', 'a');
206         test_type_char(vcpu, 'a', 'A');
207         test_type_char(vcpu, 'a', 'b');
208 
209         test_type_str(vcpu, "foo", "foo");
210         test_type_str(vcpu, "foo", "bar");
211 
212         test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdef);
213         test_type_ptr(vcpu, 0x1234567890abcdef, 0x1234567890abcdee);
214 
215         kvm_vm_free(vm);
216 
217         test_limits();
218 
219         return 0;
220 }
221 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php