diff mbox series

[8/8] KVM: selftests: Add a selftest for guest prints and formatted asserts

Message ID 20230301053425.3880773-9-aaronlewis@google.com (mailing list archive)
State New, archived
Headers show
Series Add printf and formatted asserts in the guest | expand

Commit Message

Aaron Lewis March 1, 2023, 5:34 a.m. UTC
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
diff mbox series

Patch

diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index ce577b564616..8f7238da6b84 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -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
diff --git a/tools/testing/selftests/kvm/x86_64/guest_print_test.c b/tools/testing/selftests/kvm/x86_64/guest_print_test.c
new file mode 100644
index 000000000000..2ee16a9b3ebf
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/guest_print_test.c
@@ -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;
+}