@@ -63,6 +63,7 @@ TEST_PROGS_x86_64 += x86_64/nx_huge_pages_test.sh
TEST_GEN_PROGS_x86_64 = x86_64/cpuid_test
TEST_GEN_PROGS_x86_64 += x86_64/cr4_cpuid_sync_test
TEST_GEN_PROGS_x86_64 += x86_64/get_msr_index_features
+TEST_GEN_PROGS_x86_64 += x86_64/guest_print_test
TEST_GEN_PROGS_x86_64 += x86_64/exit_on_emulation_failure_test
TEST_GEN_PROGS_x86_64 += x86_64/fix_hypercall_test
TEST_GEN_PROGS_x86_64 += x86_64/hyperv_clock
new file mode 100644
@@ -0,0 +1,100 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * A test for GUEST_PRINTF
+ *
+ * Copyright 2022, Google, Inc. and/or its affiliates.
+ */
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+
+#include "test_util.h"
+
+#include "kvm_util.h"
+#include "processor.h"
+
+static void guest_code(void)
+{
+ const char *s = "from the guest!";
+ uint64_t xcr0;
+
+ set_cr4(get_cr4() | X86_CR4_OSXSAVE);
+ xcr0 = xgetbv(0);
+
+ GUEST_PRINTF("XCR0 = 0x%lx\n", xcr0);
+
+ /*
+ * Assert that XCR0 is at RESET, and that AVX-512 is not enabled.
+ * LIBC loves to use AVX-512 instructions when doing string
+ * formatting, which would be a pain to require of the guest as
+ * a prerequisite of using print formatting functions.
+ */
+ GUEST_ASSERT_FMT(xcr0 == XFEATURE_MASK_FP,
+ "Expected an XCR0 value of 0x%lx, got 0x%lx instead.",
+ XFEATURE_MASK_FP, xcr0);
+
+ /*
+ * When %s is used in the string format the guest's version of printf
+ * uses strnlen(), which will use AVX-512 instructions if routed
+ * through the LIBC version. To prevent that from happening strnlen()
+ * has been added to the string_override functions.
+ */
+ GUEST_PRINTF("Hello %s\n", s);
+
+ GUEST_SYNC(0);
+
+ /* Demonstrate GUEST_ASSERT_FMT by invoking it. */
+ xsetbv(0, xcr0 | XFEATURE_MASK_SSE);
+ xcr0 = xgetbv(0);
+ GUEST_ASSERT_FMT(xcr0 == XFEATURE_MASK_FP,
+ "Expected an XCR0 value of 0x%lx, got 0x%lx instead.",
+ XFEATURE_MASK_FP, xcr0);
+
+ GUEST_DONE();
+}
+
+int main(int argc, char *argv[])
+{
+ struct kvm_vcpu *vcpu;
+ struct kvm_run *run;
+ struct kvm_vm *vm;
+ struct ucall uc;
+
+ /* Tell stdout not to buffer its content */
+ setbuf(stdout, NULL);
+
+ vm = vm_create_with_one_vcpu(&vcpu, guest_code);
+ run = vcpu->run;
+
+ while (1) {
+ vcpu_run(vcpu);
+
+ TEST_ASSERT(run->exit_reason == KVM_EXIT_IO,
+ "Unexpected exit reason: %u (%s),\n",
+ run->exit_reason,
+ exit_reason_str(run->exit_reason));
+
+ switch (get_ucall(vcpu, &uc)) {
+ case UCALL_SYNC:
+ printf("Hello from the host!\n");
+ break;
+ case UCALL_PRINTF:
+ printf("%s", uc.buffer);
+ break;
+ case UCALL_ABORT:
+ REPORT_GUEST_ASSERT_FMT(uc);
+ break;
+ case UCALL_DONE:
+ goto done;
+ default:
+ TEST_FAIL("Unknown ucall %lu", uc.cmd);
+ }
+ }
+
+done:
+ kvm_vm_free(vm);
+ return 0;
+}
Add a selftest to demonstrate the use of prints and formatted asserts in the guest through the ucall framework. This test isn't intended to be accepted upstream and intentionally asserts at the end to demonstrate GUEST_ASSERT_FMT(). Signed-off-by: Aaron Lewis <aaronlewis@google.com> --- tools/testing/selftests/kvm/Makefile | 1 + .../selftests/kvm/x86_64/guest_print_test.c | 100 ++++++++++++++++++ 2 files changed, 101 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/guest_print_test.c