All of lore.kernel.org
 help / color / mirror / Atom feed
From: Thomas Huth <thuth@redhat.com>
To: David Hildenbrand <david@redhat.com>, kvm@vger.kernel.org
Cc: "Paolo Bonzini" <pbonzini@redhat.com>,
	"Radim Krčmář" <rkrcmar@redhat.com>
Subject: [kvm-unit-tests PATCH v3] s390x: Interception tests
Date: Wed,  7 Jun 2017 15:41:31 +0200	[thread overview]
Message-ID: <1496842891-18011-1-git-send-email-thuth@redhat.com> (raw)

Certain CPU instructions will cause an exit of the virtual
machine. Run some of these instructions to check whether
they are emulated right by KVM (or QEMU).

Signed-off-by: Thomas Huth <thuth@redhat.com>
---
 v3:
 - Split the prefix tests into spx and stpx tests, so checking the
   exception with check_pgm_int_code() is now possible with the right
   report_prefix_push()
 - Move low_prot enable/disable code into interrupt.h
 - Added -i and -t parameters for running the tests more than once

 lib/s390x/asm/interrupt.h |  20 ++++
 s390x/Makefile            |   1 +
 s390x/intercept.c         | 227 ++++++++++++++++++++++++++++++++++++++++++++++
 s390x/unittests.cfg       |   3 +
 4 files changed, 251 insertions(+)
 create mode 100644 s390x/intercept.c

diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h
index 383d312..e4bde6c 100644
--- a/lib/s390x/asm/interrupt.h
+++ b/lib/s390x/asm/interrupt.h
@@ -15,4 +15,24 @@ void handle_pgm_int(void);
 void expect_pgm_int(void);
 void check_pgm_int_code(uint16_t code);
 
+/* Activate low-address protection */
+static inline void low_prot_enable(void)
+{
+	uint64_t cr0;
+
+	asm volatile (" stctg %%c0,%%c0,%0 " : : "Q"(cr0) : "memory");
+	cr0 |= 1ULL << (63-35);
+	asm volatile (" lctlg 0,0,%0 " : : "Q"(cr0));
+}
+
+/* Disable low-address protection */
+static inline void low_prot_disable(void)
+{
+	uint64_t cr0;
+
+	asm volatile (" stctg %%c0,%%c0,%0 " : : "Q"(cr0) : "memory");
+	cr0 &= ~(1ULL << (63-35));
+	asm volatile (" lctlg 0,0,%0 " : : "Q"(cr0));
+}
+
 #endif
diff --git a/s390x/Makefile b/s390x/Makefile
index b48f8ab..a61e163 100644
--- a/s390x/Makefile
+++ b/s390x/Makefile
@@ -1,4 +1,5 @@
 tests = $(TEST_DIR)/selftest.elf
+tests += $(TEST_DIR)/intercept.elf
 
 all: directories test_cases
 
diff --git a/s390x/intercept.c b/s390x/intercept.c
new file mode 100644
index 0000000..639cb72
--- /dev/null
+++ b/s390x/intercept.c
@@ -0,0 +1,227 @@
+/*
+ * Interception tests - for s390x CPU instruction that cause a VM exit
+ *
+ * Copyright (c) 2017 Red Hat Inc
+ *
+ * Authors:
+ *  Thomas Huth <thuth@redhat.com>
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License version 2.
+ */
+#include <libcflat.h>
+#include <asm/asm-offsets.h>
+#include <asm/interrupt.h>
+#include <asm/page.h>
+
+static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE * 2)));
+
+static unsigned long nr_iterations;
+static unsigned long time_to_run;
+
+/* Test the STORE PREFIX instruction */
+static void test_stpx(void)
+{
+	uint32_t old_prefix = -1U, tst_prefix = -1U;
+	uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf;
+
+	/* Can we successfully change the prefix? */
+	asm volatile (
+		" stpx	%0\n"
+		" spx	%2\n"
+		" stpx	%1\n"
+		" spx	%0\n"
+		: "+Q"(old_prefix), "+Q"(tst_prefix)
+		: "Q"(new_prefix));
+	report("store prefix", old_prefix == 0 && tst_prefix == new_prefix);
+
+	expect_pgm_int();
+	low_prot_enable();
+	asm volatile(" stpx 0(%0) " : : "r"(8));
+	low_prot_disable();
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+
+	expect_pgm_int();
+	asm volatile(" stpx 0(%0) " : : "r"(1));
+	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
+
+	expect_pgm_int();
+	asm volatile(" stpx 0(%0) " : : "r"(-8));
+	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
+}
+
+/* Test the SET PREFIX instruction */
+static void test_spx(void)
+{
+	uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf;
+	uint32_t old_prefix;
+
+	memset(pagebuf, 0, PAGE_SIZE * 2);
+
+	/*
+	 * Temporarily change the prefix page to our buffer, and store
+	 * some facility bits there ... at least some of them should be
+	 * set in our buffer afterwards.
+	 */
+	asm volatile (
+		" stpx	%0\n"
+		" spx	%1\n"
+		" stfl	0\n"
+		" spx	%0\n"
+		: "+Q"(old_prefix)
+		: "Q"(new_prefix)
+		: "memory");
+	report("stfl to new prefix", pagebuf[GEN_LC_STFL] != 0);
+
+	expect_pgm_int();
+	asm volatile(" spx 0(%0) " : : "r"(1));
+	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
+
+	expect_pgm_int();
+	asm volatile(" spx 0(%0) " : : "r"(-8));
+	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
+}
+
+/* Test the STORE CPU ADDRESS instruction */
+static void test_stap(void)
+{
+	uint16_t cpuid = 0xffff;
+
+	asm volatile ("stap %0\n" : "+Q"(cpuid));
+	report("get cpu id", cpuid != 0xffff);
+
+	expect_pgm_int();
+	low_prot_enable();
+	asm volatile ("stap 0(%0)\n" : : "r"(8));
+	low_prot_disable();
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+
+	expect_pgm_int();
+	asm volatile ("stap 0(%0)\n" : : "r"(1));
+	check_pgm_int_code(PGM_INT_CODE_SPECIFICATION);
+
+	expect_pgm_int();
+	asm volatile ("stap 0(%0)\n" : : "r"(-8));
+	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
+}
+
+/* Test the TEST BLOCK instruction */
+static void test_testblock(void)
+{
+	int cc;
+
+	memset(pagebuf, 0xaa, PAGE_SIZE);
+
+	asm volatile (
+		" lghi	%%r0,0\n"
+		" tb	%1\n"
+		" ipm	%0\n"
+		" srl	%0,28\n"
+		: "=d" (cc)
+		: "a"(pagebuf + 0x123)
+		: "memory", "0", "cc");
+	report("page cleared",
+	       cc == 0 && pagebuf[0] == 0 &&  pagebuf[PAGE_SIZE - 1] == 0);
+
+	expect_pgm_int();
+	low_prot_enable();
+	asm volatile (" tb %0 " : : "r"(4096));
+	low_prot_disable();
+	check_pgm_int_code(PGM_INT_CODE_PROTECTION);
+
+	expect_pgm_int();
+	asm volatile (" tb %0 " : : "r"(-4096));
+	check_pgm_int_code(PGM_INT_CODE_ADDRESSING);
+}
+
+static uint64_t get_clock_ms(void)
+{
+	uint64_t clk;
+
+	asm volatile(" stck %0 " : : "Q"(clk) : "memory");
+
+	/* Bit 51 is incrememented each microsecond */
+	return (clk >> (63 - 51)) / 1000;
+}
+
+struct {
+	const char *name;
+	void (*func)(void);
+	bool run_it;
+} tests[] = {
+	{ "stpx", test_stpx, false },
+	{ "spx", test_spx, false },
+	{ "stap", test_stap, false },
+	{ "testblock", test_testblock, false },
+	{ NULL, NULL, false }
+};
+
+void parse_intercept_test_args(int argc, char **argv)
+{
+	int i, ti;
+	bool run_all = true;
+
+	for (i = 1; i < argc; i++) {
+		if (!strcmp("-i", argv[i])) {
+			i++;
+			if (i >= argc)
+				report_abort("-i needs a parameter");
+			nr_iterations = atol(argv[i]);
+		} else if (!strcmp("-t", argv[i])) {
+			i++;
+			if (i >= argc)
+				report_abort("-t needs a parameter");
+			time_to_run = atol(argv[i]);
+		} else for (ti = 0; tests[ti].name != NULL; ti++) {
+			if (!strcmp(tests[ti].name, argv[i])) {
+				run_all = false;
+				tests[ti].run_it = true;
+				break;
+			} else if (tests[ti + 1].name == NULL) {
+				report_abort("Unsupported parameter '%s'",
+					     argv[i]);
+			}
+		}
+	}
+
+	if (run_all) {
+		for (ti = 0; tests[ti].name != NULL; ti++)
+			tests[ti].run_it = true;
+	}
+}
+
+int main(int argc, char **argv)
+{
+	uint64_t startclk;
+	int ti;
+
+	parse_intercept_test_args(argc, argv);
+
+	if (nr_iterations == 0 && time_to_run == 0)
+		nr_iterations = 1;
+
+	report_prefix_push("intercept");
+
+	startclk = get_clock_ms();
+	for (;;) {
+		for (ti = 0; tests[ti].name != NULL; ti++) {
+			report_prefix_push(tests[ti].name);
+			if (tests[ti].run_it)
+				tests[ti].func();
+			report_prefix_pop();
+		}
+		if (nr_iterations) {
+			nr_iterations -= 1;
+			if (nr_iterations == 0)
+				break;
+		}
+		if (time_to_run) {
+			if (get_clock_ms() - startclk > time_to_run)
+				break;
+		}
+	}
+
+	report_prefix_pop();
+
+	return report_summary();
+}
diff --git a/s390x/unittests.cfg b/s390x/unittests.cfg
index 92e01ab..3b6b892 100644
--- a/s390x/unittests.cfg
+++ b/s390x/unittests.cfg
@@ -22,3 +22,6 @@
 file = selftest.elf
 groups = selftest
 extra_params = -append 'test 123'
+
+[intercept]
+file = intercept.elf
-- 
1.8.3.1

             reply	other threads:[~2017-06-07 13:41 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-06-07 13:41 Thomas Huth [this message]
2017-06-07 14:01 ` [kvm-unit-tests PATCH v3] s390x: Interception tests David Hildenbrand
2017-06-07 14:59   ` Thomas Huth

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1496842891-18011-1-git-send-email-thuth@redhat.com \
    --to=thuth@redhat.com \
    --cc=david@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=rkrcmar@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.