From patchwork Wed May 31 12:39:25 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Hildenbrand X-Patchwork-Id: 9756821 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 4C72A60390 for ; Wed, 31 May 2017 12:39:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3B15A283BA for ; Wed, 31 May 2017 12:39:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 2FCE0283D1; Wed, 31 May 2017 12:39:47 +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 6686D283C9 for ; Wed, 31 May 2017 12:39:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751196AbdEaMjj (ORCPT ); Wed, 31 May 2017 08:39:39 -0400 Received: from mx1.redhat.com ([209.132.183.28]:55420 "EHLO mx1.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751028AbdEaMji (ORCPT ); Wed, 31 May 2017 08:39:38 -0400 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 13644C049D57; Wed, 31 May 2017 12:39:38 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 13644C049D57 Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx07.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=david@redhat.com DKIM-Filter: OpenDKIM Filter v2.11.0 mx1.redhat.com 13644C049D57 Received: from t460s.redhat.com (ovpn-116-76.ams2.redhat.com [10.36.116.76]) by smtp.corp.redhat.com (Postfix) with ESMTP id 7ED9651973; Wed, 31 May 2017 12:39:34 +0000 (UTC) From: David Hildenbrand To: kvm@vger.kernel.org Cc: Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , Thomas Huth , david@redhat.com, Christian Borntraeger Subject: [kvm-unit-tests PATCH v2 2/2] s390x: pgm interrupt handler and a way to test them Date: Wed, 31 May 2017 14:39:25 +0200 Message-Id: <20170531123925.4547-3-david@redhat.com> In-Reply-To: <20170531123925.4547-1-david@redhat.com> References: <20170531123925.4547-1-david@redhat.com> X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.31]); Wed, 31 May 2017 12:39:38 +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 The program interrupt handler will detect unexpected program interrupts and allow to expect + verify program interrupts for testing purposes. We need "-fno-delete-null-pointer-checks", otherwise trying to access the lowcore at address 0 makes GCC generate very weird code. Add two tests to test for simple operation and addressing exceptions. Signed-off-by: David Hildenbrand Reviewed-by: Thomas Huth --- lib/s390x/asm-offsets.c | 3 ++ lib/s390x/asm/arch_def.h | 61 ++++++++++++++++++++++++++++++++++- lib/s390x/asm/interrupt.h | 18 +++++++++++ lib/s390x/interrupt.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++ s390x/Makefile | 2 ++ s390x/cstart64.S | 55 +++++++++++++++++++++++++++++++ s390x/selftest.c | 13 ++++++++ 7 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 lib/s390x/asm/interrupt.h create mode 100644 lib/s390x/interrupt.c diff --git a/lib/s390x/asm-offsets.c b/lib/s390x/asm-offsets.c index 1e8d5ce..f1012c6 100644 --- a/lib/s390x/asm-offsets.c +++ b/lib/s390x/asm-offsets.c @@ -54,6 +54,9 @@ int main(void) OFFSET(GEN_LC_PGM_NEW_PSW, lowcore, pgm_new_psw); OFFSET(GEN_LC_MCCK_NEW_PSW, lowcore, mcck_new_psw); OFFSET(GEN_LC_IO_NEW_PSW, lowcore, io_new_psw); + OFFSET(GEN_LC_SW_INT_GRS, lowcore, sw_int_grs); + OFFSET(GEN_LC_SW_INT_FPRS, lowcore, sw_int_fprs); + OFFSET(GEN_LC_SW_INT_FPC, lowcore, sw_int_fpc); OFFSET(GEN_LC_MCCK_EXT_SA_ADDR, lowcore, mcck_ext_sa_addr); OFFSET(GEN_LC_FPRS_SA, lowcore, fprs_sa); OFFSET(GEN_LC_GRS_SA, lowcore, grs_sa); diff --git a/lib/s390x/asm/arch_def.h b/lib/s390x/asm/arch_def.h index efa7f12..07d467e 100644 --- a/lib/s390x/asm/arch_def.h +++ b/lib/s390x/asm/arch_def.h @@ -64,7 +64,11 @@ struct lowcore { struct psw pgm_new_psw; /* 0x01d0 */ struct psw mcck_new_psw; /* 0x01e0 */ struct psw io_new_psw; /* 0x01f0 */ - uint8_t pad_0x0200[0x11b0 - 0x0200]; /* 0x0200 */ + /* sw definition: save area for registers in interrupt handlers */ + uint64_t sw_int_grs[16]; /* 0x0200 */ + uint64_t sw_int_fprs[16]; /* 0x0280 */ + uint32_t sw_int_fpc; /* 0x0300 */ + uint8_t pad_0x0304[0x11b0 - 0x0304]; /* 0x0304 */ uint64_t mcck_ext_sa_addr; /* 0x11b0 */ uint8_t pad_0x11b8[0x1200 - 0x11b8]; /* 0x11b8 */ uint64_t fprs_sa[16]; /* 0x1200 */ @@ -84,4 +88,59 @@ struct lowcore { uint8_t pgm_int_tdb[0x1900 - 0x1800]; /* 0x1800 */ } __attribute__ ((__packed__)); +#define PGM_INT_CODE_OPERATION 0x01 +#define PGM_INT_CODE_PRIVILEGED_OPERATION 0x02 +#define PGM_INT_CODE_EXECUTE 0x03 +#define PGM_INT_CODE_PROTECTION 0x04 +#define PGM_INT_CODE_ADDRESSING 0x05 +#define PGM_INT_CODE_SPECIFICATION 0x06 +#define PGM_INT_CODE_DATA 0x07 +#define PGM_INT_CODE_FIXED_POINT_OVERFLOW 0x08 +#define PGM_INT_CODE_FIXED_POINT_DIVIDE 0x09 +#define PGM_INT_CODE_DECIMAL_OVERFLOW 0x0a +#define PGM_INT_CODE_DECIMAL_DIVIDE 0x0b +#define PGM_INT_CODE_HFP_EXPONENT_OVERFLOW 0x0c +#define PGM_INT_CODE_HFP_EXPONENT_UNDERFLOW 0x0d +#define PGM_INT_CODE_HFP_SIGNIFICANCE 0x0e +#define PGM_INT_CODE_HFP_DIVIDE 0x0f +#define PGM_INT_CODE_SEGMENT_TRANSLATION 0x10 +#define PGM_INT_CODE_PAGE_TRANSLATION 0x11 +#define PGM_INT_CODE_TRANSLATION_SPEC 0x12 +#define PGM_INT_CODE_SPECIAL_OPERATION 0x13 +#define PGM_INT_CODE_OPERAND 0x15 +#define PGM_INT_CODE_TRACE_TABLE 0x16 +#define PGM_INT_CODE_VECTOR_PROCESSING 0x1b +#define PGM_INT_CODE_SPACE_SWITCH_EVENT 0x1c +#define PGM_INT_CODE_HFP_SQUARE_ROOT 0x1d +#define PGM_INT_CODE_PC_TRANSLATION_SPEC 0x1f +#define PGM_INT_CODE_AFX_TRANSLATION 0x20 +#define PGM_INT_CODE_ASX_TRANSLATION 0x21 +#define PGM_INT_CODE_LX_TRANSLATION 0x22 +#define PGM_INT_CODE_EX_TRANSLATION 0x23 +#define PGM_INT_CODE_PRIMARY_AUTHORITY 0x24 +#define PGM_INT_CODE_SECONDARY_AUTHORITY 0x25 +#define PGM_INT_CODE_LFX_TRANSLATION 0x26 +#define PGM_INT_CODE_LSX_TRANSLATION 0x27 +#define PGM_INT_CODE_ALET_SPECIFICATION 0x28 +#define PGM_INT_CODE_ALEN_TRANSLATION 0x29 +#define PGM_INT_CODE_ALE_SEQUENCE 0x2a +#define PGM_INT_CODE_ASTE_VALIDITY 0x2b +#define PGM_INT_CODE_ASTE_SEQUENCE 0x2c +#define PGM_INT_CODE_EXTENDED_AUTHORITY 0x2d +#define PGM_INT_CODE_LSTE_SEQUENCE 0x2e +#define PGM_INT_CODE_ASTE_INSTANCE 0x2f +#define PGM_INT_CODE_STACK_FULL 0x30 +#define PGM_INT_CODE_STACK_EMPTY 0x31 +#define PGM_INT_CODE_STACK_SPECIFICATION 0x32 +#define PGM_INT_CODE_STACK_TYPE 0x33 +#define PGM_INT_CODE_STACK_OPERATION 0x34 +#define PGM_INT_CODE_ASCE_TYPE 0x38 +#define PGM_INT_CODE_REGION_FIRST_TRANS 0x39 +#define PGM_INT_CODE_REGION_SECOND_TRANS 0x3a +#define PGM_INT_CODE_REGION_THIRD_TRANS 0x3b +#define PGM_INT_CODE_MONITOR_EVENT 0x40 +#define PGM_INT_CODE_PER 0x80 +#define PGM_INT_CODE_CRYPTO_OPERATION 0x119 +#define PGM_INT_CODE_TX_ABORTED_EVENT 0x200 + #endif diff --git a/lib/s390x/asm/interrupt.h b/lib/s390x/asm/interrupt.h new file mode 100644 index 0000000..383d312 --- /dev/null +++ b/lib/s390x/asm/interrupt.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2017 Red Hat Inc + * + * Authors: + * David Hildenbrand + * + * 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. + */ +#ifndef _ASMS390X_IRQ_H_ +#define _ASMS390X_IRQ_H_ +#include + +void handle_pgm_int(void); +void expect_pgm_int(void); +void check_pgm_int_code(uint16_t code); + +#endif diff --git a/lib/s390x/interrupt.c b/lib/s390x/interrupt.c new file mode 100644 index 0000000..8d861a2 --- /dev/null +++ b/lib/s390x/interrupt.c @@ -0,0 +1,82 @@ +/* + * s390x interrupt handling + * + * Copyright (c) 2017 Red Hat Inc + * + * Authors: + * David Hildenbrand + * + * 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 + +static bool pgm_int_expected; +static struct lowcore *lc; + +void expect_pgm_int(void) +{ + pgm_int_expected = true; + lc->pgm_int_code = 0; + mb(); +} + +void check_pgm_int_code(uint16_t code) +{ + mb(); + report("Program interrupt: expected(%d) == received(%d)", + code == lc->pgm_int_code, code, lc->pgm_int_code); +} + +static void fixup_pgm_int(void) +{ + switch (lc->pgm_int_code) { + case PGM_INT_CODE_SEGMENT_TRANSLATION: + case PGM_INT_CODE_PAGE_TRANSLATION: + case PGM_INT_CODE_TRACE_TABLE: + case PGM_INT_CODE_AFX_TRANSLATION: + case PGM_INT_CODE_ASX_TRANSLATION: + case PGM_INT_CODE_LX_TRANSLATION: + case PGM_INT_CODE_EX_TRANSLATION: + case PGM_INT_CODE_PRIMARY_AUTHORITY: + case PGM_INT_CODE_SECONDARY_AUTHORITY: + case PGM_INT_CODE_LFX_TRANSLATION: + case PGM_INT_CODE_LSX_TRANSLATION: + case PGM_INT_CODE_ALEN_TRANSLATION: + case PGM_INT_CODE_ALE_SEQUENCE: + case PGM_INT_CODE_ASTE_VALIDITY: + case PGM_INT_CODE_ASTE_SEQUENCE: + case PGM_INT_CODE_EXTENDED_AUTHORITY: + case PGM_INT_CODE_LSTE_SEQUENCE: + case PGM_INT_CODE_ASTE_INSTANCE: + case PGM_INT_CODE_STACK_FULL: + case PGM_INT_CODE_STACK_EMPTY: + case PGM_INT_CODE_STACK_SPECIFICATION: + case PGM_INT_CODE_STACK_TYPE: + case PGM_INT_CODE_STACK_OPERATION: + case PGM_INT_CODE_ASCE_TYPE: + case PGM_INT_CODE_REGION_FIRST_TRANS: + case PGM_INT_CODE_REGION_SECOND_TRANS: + case PGM_INT_CODE_REGION_THIRD_TRANS: + case PGM_INT_CODE_PER: + case PGM_INT_CODE_CRYPTO_OPERATION: + /* The interrupt was nullified, the old PSW points at the + * responsible instruction. Forward the PSW so we don't loop. + */ + lc->pgm_old_psw.addr += lc->pgm_int_id; + } + /* suppressed/terminated/completed point already at the next address */ +} + +void handle_pgm_int(void) +{ + if (!pgm_int_expected) + report_abort("Unexpected program interrupt: %d at %#lx, ilen %d\n", + lc->pgm_int_code, lc->pgm_old_psw.addr, + lc->pgm_int_id); + + pgm_int_expected = false; + fixup_pgm_int(); +} diff --git a/s390x/Makefile b/s390x/Makefile index 4e4b94a..b48f8ab 100644 --- a/s390x/Makefile +++ b/s390x/Makefile @@ -10,6 +10,7 @@ CFLAGS += -Wextra CFLAGS += -I $(SRCDIR)/lib CFLAGS += -O2 CFLAGS += -march=z900 +CFLAGS += -fno-delete-null-pointer-checks LDFLAGS += -nostdlib # We want to keep intermediate files @@ -23,6 +24,7 @@ cflatobjs += lib/alloc.o cflatobjs += lib/s390x/io.o cflatobjs += lib/s390x/stack.o cflatobjs += lib/s390x/sclp-ascii.o +cflatobjs += lib/s390x/interrupt.o OBJDIRS += lib/s390x diff --git a/s390x/cstart64.S b/s390x/cstart64.S index 28cd59d..4d0c877 100644 --- a/s390x/cstart64.S +++ b/s390x/cstart64.S @@ -10,6 +10,8 @@ * 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 + .section .init /* entry point - for KVM + TCG we directly start in 64 bit mode */ @@ -21,6 +23,10 @@ start: larl %r1, initital_psw lpswe 0(%r1) init_psw_cont: + /* setup pgm interrupt handler */ + larl %r1, pgm_int_psw + mvc GEN_LC_PGM_NEW_PSW(16), 0(%r1) + /* setup cr0, enabling e.g. AFP-register control */ larl %r1, initital_cr0 lctlg %c0, %c0, 0(%r1) /* call setup() */ @@ -36,9 +42,58 @@ init_psw_cont: /* call exit() */ j exit +pgm_int: + /* save grs 0-15 */ + stmg %r0, %r15, GEN_LC_SW_INT_GRS + /* save fprs 0-15 + fpc */ + larl %r1, GEN_LC_SW_INT_FPRS + std %f0, 0(%r1) + std %f1, 8(%r1) + std %f2, 16(%r1) + std %f3, 24(%r1) + std %f4, 32(%r1) + std %f5, 40(%r1) + std %f6, 48(%r1) + std %f7, 56(%r1) + std %f8, 64(%r1) + std %f9, 72(%r1) + std %f10, 80(%r1) + std %f11, 88(%r1) + std %f12, 96(%r1) + std %f13, 104(%r1) + std %f14, 112(%r1) + std %f15, 120(%r1) + stfpc GEN_LC_SW_INT_FPC + /* call our c handler */ + brasl %r14, handle_pgm_int + /* restore fprs 0-15 + fpc */ + larl %r1, GEN_LC_SW_INT_FPRS + ld %f0, 0(%r1) + ld %f1, 8(%r1) + ld %f2, 16(%r1) + ld %f3, 24(%r1) + ld %f4, 32(%r1) + ld %f5, 40(%r1) + ld %f6, 48(%r1) + ld %f7, 56(%r1) + ld %f8, 64(%r1) + ld %f9, 72(%r1) + ld %f10, 80(%r1) + ld %f11, 88(%r1) + ld %f12, 96(%r1) + ld %f13, 104(%r1) + ld %f14, 112(%r1) + ld %f15, 120(%r1) + lfpc GEN_LC_SW_INT_FPC + /* restore grs 0-15 */ + lmg %r0, %r15, GEN_LC_SW_INT_GRS + lpswe GEN_LC_PGM_OLD_PSW + .align 8 initital_psw: .quad 0x0000000180000000, init_psw_cont +pgm_int_psw: + .quad 0x0000000180000000, pgm_int initital_cr0: /* enable AFP-register control, so FP regs (+BFP instr) can be used */ .quad 0x0000000000040000 diff --git a/s390x/selftest.c b/s390x/selftest.c index 4558e47..ca94158 100644 --- a/s390x/selftest.c +++ b/s390x/selftest.c @@ -10,6 +10,7 @@ */ #include #include +#include static void test_fp(void) { @@ -25,6 +26,17 @@ static void test_fp(void) report("3.0/2.0 == 1.5", c == 1.5); } +static void test_pgm_int(void) +{ + expect_pgm_int(); + asm volatile(" .insn e,0x0001"); /* used for SW breakpoints in QEMU */ + check_pgm_int_code(PGM_INT_CODE_OPERATION); + + expect_pgm_int(); + *((unsigned int*)-1) = 1; + check_pgm_int_code(PGM_INT_CODE_ADDRESSING); +} + int main(int argc, char**argv) { report_prefix_push("selftest"); @@ -36,6 +48,7 @@ int main(int argc, char**argv) report("argv[2] == 123", !strcmp(argv[2], "123")); test_fp(); + test_pgm_int(); return report_summary(); }