From patchwork Fri Jun 2 12:44:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Thomas Huth X-Patchwork-Id: 9762465 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id C3DD3602F0 for ; Fri, 2 Jun 2017 12:44:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id B3E11205A4 for ; Fri, 2 Jun 2017 12:44:33 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id A821226E4E; Fri, 2 Jun 2017 12:44:33 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.9 required=2.0 tests=BAYES_00,RCVD_IN_DNSWL_HI autolearn=ham version=3.3.1 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 1D1C2205A4 for ; Fri, 2 Jun 2017 12:44:33 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751147AbdFBMob (ORCPT ); Fri, 2 Jun 2017 08:44:31 -0400 Received: from mx1.redhat.com ([209.132.183.28]:33892 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751125AbdFBMoa (ORCPT ); Fri, 2 Jun 2017 08:44:30 -0400 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8994841A5B; Fri, 2 Jun 2017 12:44:29 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 8994841A5B Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx06.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=thuth@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 8994841A5B Received: from thh440s.str.redhat.com (dhcp-192-189.str.redhat.com [10.33.192.189]) by smtp.corp.redhat.com (Postfix) with ESMTP id 57B81788E3; Fri, 2 Jun 2017 12:44:22 +0000 (UTC) From: Thomas Huth To: David Hildenbrand , kvm@vger.kernel.org Cc: Christian Borntraeger , Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= Subject: [kvm-unit-tests PATCH v2] s390x: Interception tests Date: Fri, 2 Jun 2017 14:44:21 +0200 Message-Id: <1496407461-31163-1-git-send-email-thuth@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.16 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.30]); Fri, 02 Jun 2017 12:44:29 +0000 (UTC) Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP 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 Reviewed-by: David Hildenbrand --- Note: Test have been verified to pass with KVM of a 4.11 kernel. Running the tests with QEMU TCG emulation does not work yet ... QEMU first requires a bunch of fixes before this can pass there. v2: - Added entry in s390x/unittests.cfg - Use low-core GEN_LC_STFL definition instead of hard-coded magic value - Added lots of exception tests (thanks to David's interrupt framework!) - Fixed constraints of inline assembler (I haven't added a timing/iteration infrastructure like Paolo suggested yet - will do that later once the basic tests have been accepted) lib/s390x/asm/interrupt.h | 1 + lib/s390x/interrupt.c | 5 ++ s390x/Makefile | 1 + s390x/intercept.c | 170 ++++++++++++++++++++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 + 5 files changed, 180 insertions(+) create mode 100644 s390x/intercept.c diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h index 383d312..926f858 100644 --- a/lib/s390x/asm/interrupt.h +++ b/lib/s390x/asm/interrupt.h @@ -14,5 +14,6 @@ void handle_pgm_int(void); void expect_pgm_int(void); void check_pgm_int_code(uint16_t code); +uint16_t get_pgm_int_code(void); #endif diff --git a/lib/s390x/interrupt.c b/lib/s390x/interrupt.c index 8d861a2..b5cc7ce 100644 --- a/lib/s390x/interrupt.c +++ b/lib/s390x/interrupt.c @@ -23,6 +23,11 @@ void expect_pgm_int(void) mb(); } +uint16_t get_pgm_int_code(void) +{ + return lc->pgm_int_code; +} + void check_pgm_int_code(uint16_t code) { mb(); 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..4e3fb57 --- /dev/null +++ b/s390x/intercept.c @@ -0,0 +1,170 @@ +/* + * Interception tests - for s390x CPU instruction that cause a VM exit + * + * Copyright (c) 2017 Red Hat Inc + * + * Authors: + * Thomas Huth + * + * 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 +#include +#include +#include + +static uint8_t pagebuf[PAGE_SIZE * 2] __attribute__((aligned(PAGE_SIZE))); + +/* Enable or disable low-address protection */ +static void set_low_prot(bool enable) +{ + uint64_t cr0; + + asm volatile (" stctg 0,0,%0 " : : "Q"(cr0)); + if (enable) + cr0 |= 1ULL << (63-35); + else + cr0 &= ~(1ULL << (63-35)); + asm volatile (" lctlg 0,0,%0 " : : "Q"(cr0)); +} + +/* Test the SET PREFIX and STORE PREFIX instructions */ +static void test_prefix(void) +{ + uint32_t old_prefix = -1U, tst_prefix = -1U; + uint32_t new_prefix = (uint32_t)(intptr_t)pagebuf; + + 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 %2\n" + " stfl 0\n" + " stpx %1\n" + " spx %0\n" + : "+Q"(old_prefix), "+Q"(tst_prefix) + : "Q"(new_prefix) + : "memory"); + report("spx + stfl", pagebuf[GEN_LC_STFL] != 0 && + old_prefix == 0 && tst_prefix == new_prefix); + + expect_pgm_int(); + asm volatile(" spx 0(%0) " : : "r"(1)); + report("spx alignment", + get_pgm_int_code() == PGM_INT_CODE_SPECIFICATION); + + expect_pgm_int(); + asm volatile(" spx 0(%0) " : : "r"(-8)); + report("spx addressing", + get_pgm_int_code() == PGM_INT_CODE_ADDRESSING); + + expect_pgm_int(); + set_low_prot(true); + asm volatile(" stpx 0(%0) " : : "r"(8)); + set_low_prot(false); + report("stpx low-address protection", + get_pgm_int_code() == PGM_INT_CODE_PROTECTION); + + expect_pgm_int(); + asm volatile(" stpx 0(%0) " : : "r"(1)); + report("stpx alignment", + get_pgm_int_code() == PGM_INT_CODE_SPECIFICATION); + + expect_pgm_int(); + asm volatile(" stpx 0(%0) " : : "r"(-8)); + report("stpx addressing", + get_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(); + set_low_prot(true); + asm volatile ("stap 0(%0)\n" : : "r"(8)); + set_low_prot(false); + report("low-address protection", + get_pgm_int_code() == PGM_INT_CODE_PROTECTION); + + expect_pgm_int(); + asm volatile ("stap 0(%0)\n" : : "r"(1)); + report("alignment", get_pgm_int_code() == PGM_INT_CODE_SPECIFICATION); + + expect_pgm_int(); + asm volatile ("stap 0(%0)\n" : : "r"(-8)); + report("addressing", get_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 0,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(); + set_low_prot(true); + asm volatile (" tb %0 " : : "r"(4096)); + set_low_prot(false); + report("low-address protection", + get_pgm_int_code() == PGM_INT_CODE_PROTECTION); + + expect_pgm_int(); + asm volatile (" tb %0 " : : "r"(-4096)); + report("addressing", get_pgm_int_code() == PGM_INT_CODE_ADDRESSING); +} + +struct { + const char *name; + void (*func)(void); +} tests[] = { + { "prefix", test_prefix }, + { "stap", test_stap }, + { "testblock", test_testblock }, + { NULL, NULL } +}; + +int main(int argc, char **argv) +{ + int all = 0; + int i; + + report_prefix_push("intercept"); + + if (argc < 2 || (argc == 2 && !strcmp(argv[1], "all"))) + all = 1; + + for (i = 0; tests[i].name != NULL; i++) { + report_prefix_push(tests[i].name); + if (all || strcmp(argv[1], tests[i].name) == 0) { + tests[i].func(); + } + report_prefix_pop(); + } + + 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