s390x: add a pgm irq handler and a way to expect them
PATCH 1/1 s390x: add a pgm irq handler and a way to expect them
The pgm irq handler will detect unexpected pgm irqs and allows to expect pgm irqs + verify that the pgm irq was triggered.
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 exception.
---
Note: This will require TCG patch "target/s390x: addressing exceptions are suppressing" in order to pass.
Patch "[kvm-unit-tests PATCH v1] s390x: generate asm offsets for the lowcore" is requires as a prerequisite.
lib/s390x/asm-offsets.c | 1 + lib/s390x/asm/arch_def.h | 59 +++++++++++++++++++++++++++++++- lib/s390x/asm/irq.h | 18 ++++++++++ lib/s390x/irq.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ s390x/Makefile | 2 ++ s390x/cstart64.S | 16 +++++++++ s390x/selftest.c | 14 ++++++++ 7 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 lib/s390x/asm/irq.h create mode 100644 lib/s390x/irq.c
lib/s390x/asm-offsets.c +1 -0
@@ -54,6 +54,7 @@ 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_IRQ_AREA , lowcore, sw_irq_area);OFFSET (GEN_LC_FPRS_SA , lowcore, fprs_sa);OFFSET (GEN_LC_GRS_SA , lowcore, grs_sa);OFFSET (GEN_LC_PSW_SA , lowcore, psw_sa);
lib/s390x/asm/arch_def.h +58 -1
69 lines not on this page · raw message
lib/s390x/asm/irq.h new file +18 -0
@@ -0,0 +1,18 @@ +/* +* Copyright (c) 2017 Red Hat Inc +* +* Authors: +* David Hildenbrand <[email protected]> +* +* 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 <asm/arch_def.h> + +void handle_pgm_irq (void ); +void expect_pgm_irq (void ); +uint16_t received_pgm_irq (void ); + +#endif
lib/s390x/irq.c new file +89 -0
89 lines not on this page · raw message
s390x/Makefile +2 -0
@@ -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/irq.o OBJDIRS += lib/s390x
s390x/cstart64.S +16 -0
@@ -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 <asm/asm-offsets.h> + .section .init /* entry point - for KVM + TCG we directly start in 64 bit mode */
@@ -21,6 +23,12 @@ start: larl %r1, initital_psw lpswe 0(%r1) init_psw_cont: + /* setup pgm irq handler */ + larl %r1, pgm_irq_mask + stg %r1, GEN_LC_PGM_NEW_PSW + larl %r1, pgm_irq + stg %r1, GEN_LC_PGM_NEW_PSW + 8 + /* setup the initital PSW and enable 64bit addressing */ larl %r1, initital_cr0 lctlg %c0, %c0, 0(%r1) /* call setup() */
@@ -36,9 +44,17 @@ init_psw_cont: /* call exit() */ j exit +pgm_irq: + stmg %r0, %r15, GEN_LC_SW_IRQ_AREA + brasl %r14, handle_pgm_irq + lmg %r0, %r15, GEN_LC_SW_IRQ_AREA + lpswe GEN_LC_PGM_OLD_PSW + .align 8 initital_psw: .quad 0x0000000180000000, init_psw_cont +pgm_irq_mask: + .quad 0x0000000180000000 initital_cr0: /* enable AFP-register control, so FP regs (+BFP instr) can be used */ .quad 0x0000000000040000
s390x/selftest.c +14 -0
@@ -10,6 +10,7 @@*/ #include <libcflat.h> #include <util.h> +#include <asm/irq.h> static void test_fp (void ) {
@@ -25,6 +26,18 @@ static void test_fp(void)report ("3.0/2.0 == 1.5" , c ==1.5 ); } +static void test_pgm_irq (void ) +{ +expect_pgm_irq (); + asmvolatile ( +" .insn e,0x0001" ); +report ("OPERATION pgm irq" ,received_pgm_irq () ==PGM_CODE_OPERATION ); + +expect_pgm_irq (); + *((unsigned int *)-1 ) =1 ; +report ("ADDRESSING pgm irq" ,received_pgm_irq () ==PGM_CODE_ADDRESSING ); +} +int main (int argc,char **argv) {report_prefix_push ("selftest" );
@@ -36,6 +49,7 @@ int main(int argc, char**argv)report ("argv[2] == 123" , !strcmp (argv[2 ],"123" ));test_fp (); +test_pgm_irq ();return report_summary (); }
Signature · 1 line
2.9.3
Quoted 267 lines · David Hildenbrand
The pgm irq handler will detect unexpected pgm irqs and allows to expect pgm irqs + verify that the pgm irq was triggered.
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 exception.
Signed-off-by David Hildenbrand <[email protected]>---
Note: This will require TCG patch "target/s390x: addressing exceptions are suppressing" in order to pass.Patch "[kvm-unit-tests PATCH v1] s390x: generate asm offsets for the lowcore" is requires as a prerequisite.
lib/s390x/asm-offsets.c | 1 + lib/s390x/asm/arch_def.h | 59 +++++++++++++++++++++++++++++++- lib/s390x/asm/irq.h | 18 ++++++++++ lib/s390x/irq.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ s390x/Makefile | 2 ++ s390x/cstart64.S | 16 +++++++++ s390x/selftest.c | 14 ++++++++ 7 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 lib/s390x/asm/irq.h create mode 100644 lib/s390x/irq.clib/s390x/asm-offsets.c +1
-0@@ -54,6 +54,7 @@ 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_IRQ_AREA , lowcore, sw_irq_area);OFFSET (GEN_LC_FPRS_SA , lowcore, fprs_sa);OFFSET (GEN_LC_GRS_SA , lowcore, grs_sa);OFFSET (GEN_LC_PSW_SA , lowcore, psw_sa);lib/s390x/asm/arch_def.h +58
-1@@ -64,7 +64,9 @@ struct lowcore {struct psw pgm_new_psw;/* 0x01d0 */ struct psw mcck_new_psw;/* 0x01e0 */ struct psw io_new_psw;/* 0x01f0 */ -uint8_t pad_0x0200[0x1200 -0x0200 ];/* 0x0200 */ +/* sw definition: large enough to save all grs in irq handlers */ +uint8_t sw_irq_area[0x280 -0x0200 ];/* 0x0200 */ +uint8_t pad_0x0280[0x1200 -0x0280 ];/* 0x0280 */ uint64_t fprs_sa[16 ];/* 0x1200 */ uint64_t grs_sa[16 ];/* 0x1280 */ struct psw psw_sa;/* 0x1300 */ @@ -82,4 +84,59 @@ struct lowcore {uint8_t pgm_int_tdb[0x1900 -0x1800 ];/* 0x1800 */ } __attribute__ ((__packed__)); +#define PGM_CODE_OPERATION 0x01 +#define PGM_CODE_PRIVILEGED_OPERATION 0x02 +#define PGM_CODE_EXECUTE 0x03 +#define PGM_CODE_PROTECTION 0x04 +#define PGM_CODE_ADDRESSING 0x05 +#define PGM_CODE_SPECIFICATION 0x06 +#define PGM_CODE_DATA 0x07 +#define PGM_CODE_FIXED_POINT_OVERFLOW 0x08 +#define PGM_CODE_FIXED_POINT_DIVIDE 0x09 +#define PGM_CODE_DECIMAL_OVERFLOW 0x0a +#define PGM_CODE_DECIMAL_DIVIDE 0x0b +#define PGM_CODE_HFP_EXPONENT_OVERFLOW 0x0c +#define PGM_CODE_HFP_EXPONENT_UNDERFLOW 0x0d +#define PGM_CODE_HFP_SIGNIFICANCE 0x0e +#define PGM_CODE_HFP_DIVIDE 0x0f +#define PGM_CODE_SEGMENT_TRANSLATION 0x10 +#define PGM_CODE_PAGE_TRANSLATION 0x11 +#define PGM_CODE_TRANSLATION_SPEC 0x12 +#define PGM_CODE_SPECIAL_OPERATION 0x13 +#define PGM_CODE_OPERAND 0x15 +#define PGM_CODE_TRACE_TABLE 0x16 +#define PGM_CODE_VECTOR_PROCESSING 0x1b +#define PGM_CODE_SPACE_SWITCH_EVENT 0x1c +#define PGM_CODE_HFP_SQUARE_ROOT 0x1d +#define PGM_CODE_PC_TRANSLATION_SPEC 0x1f +#define PGM_CODE_AFX_TRANSLATION 0x20 +#define PGM_CODE_ASX_TRANSLATION 0x21 +#define PGM_CODE_LX_TRANSLATION 0x22 +#define PGM_CODE_EX_TRANSLATION 0x23 +#define PGM_CODE_PRIMARY_AUTHORITY 0x24 +#define PGM_CODE_SECONDARY_AUTHORITY 0x25 +#define PGM_CODE_LFX_TRANSLATION 0x26 +#define PGM_CODE_LSX_TRANSLATION 0x27 +#define PGM_CODE_ALET_SPECIFICATION 0x28 +#define PGM_CODE_ALEN_TRANSLATION 0x29 +#define PGM_CODE_ALE_SEQUENCE 0x2a +#define PGM_CODE_ASTE_VALIDITY 0x2b +#define PGM_CODE_ASTE_SEQUENCE 0x2c +#define PGM_CODE_EXTENDED_AUTHORITY 0x2d +#define PGM_CODE_LSTE_SEQUENCE 0x2e +#define PGM_CODE_ASTE_INSTANCE 0x2f +#define PGM_CODE_STACK_FULL 0x30 +#define PGM_CODE_STACK_EMPTY 0x31 +#define PGM_CODE_STACK_SPECIFICATION 0x32 +#define PGM_CODE_STACK_TYPE 0x33 +#define PGM_CODE_STACK_OPERATION 0x34 +#define PGM_CODE_ASCE_TYPE 0x38 +#define PGM_CODE_REGION_FIRST_TRANS 0x39 +#define PGM_CODE_REGION_SECOND_TRANS 0x3a +#define PGM_CODE_REGION_THIRD_TRANS 0x3b +#define PGM_CODE_MONITOR_EVENT 0x40 +#define PGM_CODE_PER 0x80 +#define PGM_CODE_CRYPTO_OPERATION 0x119 +#define PGM_CODE_TX_ABORTED_EVENT 0x200 +#endif lib/s390x/asm/irq.h new file +18
-0@@ -0,0 +1,18 @@ +/* +* Copyright (c) 2017 Red Hat Inc +* +* Authors: +* David Hildenbrand <[email protected]> +* +* 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 <asm/arch_def.h> + +void handle_pgm_irq (void ); +void expect_pgm_irq (void ); +uint16_t received_pgm_irq (void ); + +#endif lib/s390x/irq.c new file +89
-0@@ -0,0 +1,89 @@ +/* +* s390x irq handling +* +* Copyright (c) 2017 Red Hat Inc +* +* Authors: +* Thomas Huth <[email protected]> +* David Hildenbrand <[email protected]> +* +* 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/irq.h> +#include <asm/barrier.h> + +static bool pgm_irq_expected; + +void expect_pgm_irq (void ) +{ +struct lowcore *lc = (void * )0 ; + + pgm_irq_expected = true; + lc->pgm_int_code =0 ; +mb (); +} + +uint16_t received_pgm_irq (void ) +{ +struct lowcore *lc = (void * )0 ; + +mb (); +return lc->pgm_int_code; +} + +static void fixup_pgm_irq (void ) +{ +struct lowcore *lc = (void * )0 ; + +switch (lc->pgm_int_code) { +case PGM_CODE_SEGMENT_TRANSLATION : +case PGM_CODE_PAGE_TRANSLATION : +case PGM_CODE_TRACE_TABLE : +case PGM_CODE_AFX_TRANSLATION : +case PGM_CODE_ASX_TRANSLATION : +case PGM_CODE_LX_TRANSLATION : +case PGM_CODE_EX_TRANSLATION : +case PGM_CODE_PRIMARY_AUTHORITY : +case PGM_CODE_SECONDARY_AUTHORITY : +case PGM_CODE_LFX_TRANSLATION : +case PGM_CODE_LSX_TRANSLATION : +case PGM_CODE_ALEN_TRANSLATION : +case PGM_CODE_ALE_SEQUENCE : +case PGM_CODE_ASTE_VALIDITY : +case PGM_CODE_ASTE_SEQUENCE : +case PGM_CODE_EXTENDED_AUTHORITY : +case PGM_CODE_LSTE_SEQUENCE : +case PGM_CODE_ASTE_INSTANCE : +case PGM_CODE_STACK_FULL : +case PGM_CODE_STACK_EMPTY : +case PGM_CODE_STACK_SPECIFICATION : +case PGM_CODE_STACK_TYPE : +case PGM_CODE_STACK_OPERATION : +case PGM_CODE_ASCE_TYPE : +case PGM_CODE_REGION_FIRST_TRANS : +case PGM_CODE_REGION_SECOND_TRANS : +case PGM_CODE_REGION_THIRD_TRANS : +case PGM_CODE_PER : +case PGM_CODE_CRYPTO_OPERATION : +/* The irq 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_irq (void ) +{ +struct lowcore *lc = (void *)0 ; + +if (!pgm_irq_expected) +report_abort ("Unexpected pgm irq %d at %#lx, ilen %d\n" , + lc->pgm_int_code, lc->pgm_old_psw.addr, + lc->pgm_int_id); + + pgm_irq_expected = false; +fixup_pgm_irq (); +}s390x/Makefile +2
-0@@ -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/irq.o OBJDIRS += lib/s390xs390x/cstart64.S +2
-0@@ -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 <asm/asm-offsets.h> + .section .init /* entry point - for KVM + TCG we directly start in 64 bit mode */
s390x/cstart64.S start: · line 27
Quoted 5 lines
s390x/cstart64.S +2
-0@@ -21,6 +23,12 @@ start: larl %r1, initital_psw lpswe 0(%r1) init_psw_cont: + /* setup pgm irq handler */ + larl %r1, pgm_irq_mask
So, apparently, TCG does not check for specification exceptions.
Here, a
lg %r1, 0(%r1)
is missing.
Quoted 65 lines
s390x/cstart64.S +12
-0+ stg %r1, GEN_LC_PGM_NEW_PSW + larl %r1, pgm_irq + stg %r1, GEN_LC_PGM_NEW_PSW + 8 + /* setup the initital PSW and enable 64bit addressing */ larl %r1, initital_cr0 lctlg %c0, %c0, 0(%r1) /* call setup() */@@ -36,9 +44,17 @@ init_psw_cont: /* call exit() */ j exit +pgm_irq: + stmg %r0, %r15, GEN_LC_SW_IRQ_AREA + brasl %r14, handle_pgm_irq + lmg %r0, %r15, GEN_LC_SW_IRQ_AREA + lpswe GEN_LC_PGM_OLD_PSW + .align 8 initital_psw: .quad 0x0000000180000000, init_psw_cont +pgm_irq_mask: + .quad 0x0000000180000000 initital_cr0: /* enable AFP-register control, so FP regs (+BFP instr) can be used */ .quad 0x0000000000040000s390x/selftest.c +14
-0@@ -10,6 +10,7 @@*/ #include <libcflat.h> #include <util.h> +#include <asm/irq.h> static void test_fp (void ) {@@ -25,6 +26,18 @@ static void test_fp(void)report ("3.0/2.0 == 1.5" , c ==1.5 ); } +static void test_pgm_irq (void ) +{ +expect_pgm_irq (); + asmvolatile ( +" .insn e,0x0001" ); +report ("OPERATION pgm irq" ,received_pgm_irq () ==PGM_CODE_OPERATION ); + +expect_pgm_irq (); + *((unsigned int *)-1 ) =1 ; +report ("ADDRESSING pgm irq" ,received_pgm_irq () ==PGM_CODE_ADDRESSING ); +} +int main (int argc,char **argv) {report_prefix_push ("selftest" );@@ -36,6 +49,7 @@ int main(int argc, char**argv)report ("argv[2] == 123" , !strcmp (argv[2 ],"123" ));test_fp (); +test_pgm_irq ();return report_summary (); }
Signature · 3 lines
Thanks, David
Quoted 5 lines · David Hildenbrand
The pgm irq handler will detect unexpected pgm irqs and allows to expect pgm irqs + verify that the pgm irq was triggered.
We need "-fno-delete-null-pointer-checks", otherwise trying to access the lowcore at address 0 makes GCC generate very weird code.
I wonder whether you could get rid of that by using a global variable for lc instead?
Quoted 9 lines
Add two tests to test for simple operation and addressing exception.
Signed-off-by David Hildenbrand <[email protected]>---
Note: This will require TCG patch "target/s390x: addressing exceptions are suppressing" in order to pass.Patch "[kvm-unit-tests PATCH v1] s390x: generate asm offsets for the lowcore" is requires as a prerequisite.
Maybe send them together as a series next time?
Quoted 28 lines
lib/s390x/asm-offsets.c | 1 + lib/s390x/asm/arch_def.h | 59 +++++++++++++++++++++++++++++++- lib/s390x/asm/irq.h | 18 ++++++++++ lib/s390x/irq.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ s390x/Makefile | 2 ++ s390x/cstart64.S | 16 +++++++++ s390x/selftest.c | 14 ++++++++ 7 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 lib/s390x/asm/irq.h create mode 100644 lib/s390x/irq.clib/s390x/asm-offsets.c +1
-0@@ -54,6 +54,7 @@ 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_IRQ_AREA , lowcore, sw_irq_area);OFFSET (GEN_LC_FPRS_SA , lowcore, fprs_sa);OFFSET (GEN_LC_GRS_SA , lowcore, grs_sa);OFFSET (GEN_LC_PSW_SA , lowcore, psw_sa);lib/s390x/asm/arch_def.h +0
-0
lib/s390x/asm/arch_def.h struct lowcore { · line 68
Quoted 6 lines
lib/s390x/asm/arch_def.h +2
-1@@ -64,7 +64,9 @@ struct lowcore {struct psw pgm_new_psw;/* 0x01d0 */ struct psw mcck_new_psw;/* 0x01e0 */ struct psw io_new_psw;/* 0x01f0 */ -uint8_t pad_0x0200[0x1200 -0x0200 ];/* 0x0200 */ +/* sw definition: large enough to save all grs in irq handlers */ +uint8_t sw_irq_area[0x280 -0x0200 ];/* 0x0200 */
Since you're saving 64-bit registers into this array, I'd suggest to make it an array of uint64_t values instead of uint8_t.
Quoted 118 lines
lib/s390x/asm/arch_def.h +56
-0+uint8_t pad_0x0280[0x1200 -0x0280 ];/* 0x0280 */ uint64_t fprs_sa[16 ];/* 0x1200 */ uint64_t grs_sa[16 ];/* 0x1280 */ struct psw psw_sa;/* 0x1300 */ @@ -82,4 +84,59 @@ struct lowcore {uint8_t pgm_int_tdb[0x1900 -0x1800 ];/* 0x1800 */ } __attribute__ ((__packed__)); +#define PGM_CODE_OPERATION 0x01 +#define PGM_CODE_PRIVILEGED_OPERATION 0x02 +#define PGM_CODE_EXECUTE 0x03 +#define PGM_CODE_PROTECTION 0x04 +#define PGM_CODE_ADDRESSING 0x05 +#define PGM_CODE_SPECIFICATION 0x06 +#define PGM_CODE_DATA 0x07 +#define PGM_CODE_FIXED_POINT_OVERFLOW 0x08 +#define PGM_CODE_FIXED_POINT_DIVIDE 0x09 +#define PGM_CODE_DECIMAL_OVERFLOW 0x0a +#define PGM_CODE_DECIMAL_DIVIDE 0x0b +#define PGM_CODE_HFP_EXPONENT_OVERFLOW 0x0c +#define PGM_CODE_HFP_EXPONENT_UNDERFLOW 0x0d +#define PGM_CODE_HFP_SIGNIFICANCE 0x0e +#define PGM_CODE_HFP_DIVIDE 0x0f +#define PGM_CODE_SEGMENT_TRANSLATION 0x10 +#define PGM_CODE_PAGE_TRANSLATION 0x11 +#define PGM_CODE_TRANSLATION_SPEC 0x12 +#define PGM_CODE_SPECIAL_OPERATION 0x13 +#define PGM_CODE_OPERAND 0x15 +#define PGM_CODE_TRACE_TABLE 0x16 +#define PGM_CODE_VECTOR_PROCESSING 0x1b +#define PGM_CODE_SPACE_SWITCH_EVENT 0x1c +#define PGM_CODE_HFP_SQUARE_ROOT 0x1d +#define PGM_CODE_PC_TRANSLATION_SPEC 0x1f +#define PGM_CODE_AFX_TRANSLATION 0x20 +#define PGM_CODE_ASX_TRANSLATION 0x21 +#define PGM_CODE_LX_TRANSLATION 0x22 +#define PGM_CODE_EX_TRANSLATION 0x23 +#define PGM_CODE_PRIMARY_AUTHORITY 0x24 +#define PGM_CODE_SECONDARY_AUTHORITY 0x25 +#define PGM_CODE_LFX_TRANSLATION 0x26 +#define PGM_CODE_LSX_TRANSLATION 0x27 +#define PGM_CODE_ALET_SPECIFICATION 0x28 +#define PGM_CODE_ALEN_TRANSLATION 0x29 +#define PGM_CODE_ALE_SEQUENCE 0x2a +#define PGM_CODE_ASTE_VALIDITY 0x2b +#define PGM_CODE_ASTE_SEQUENCE 0x2c +#define PGM_CODE_EXTENDED_AUTHORITY 0x2d +#define PGM_CODE_LSTE_SEQUENCE 0x2e +#define PGM_CODE_ASTE_INSTANCE 0x2f +#define PGM_CODE_STACK_FULL 0x30 +#define PGM_CODE_STACK_EMPTY 0x31 +#define PGM_CODE_STACK_SPECIFICATION 0x32 +#define PGM_CODE_STACK_TYPE 0x33 +#define PGM_CODE_STACK_OPERATION 0x34 +#define PGM_CODE_ASCE_TYPE 0x38 +#define PGM_CODE_REGION_FIRST_TRANS 0x39 +#define PGM_CODE_REGION_SECOND_TRANS 0x3a +#define PGM_CODE_REGION_THIRD_TRANS 0x3b +#define PGM_CODE_MONITOR_EVENT 0x40 +#define PGM_CODE_PER 0x80 +#define PGM_CODE_CRYPTO_OPERATION 0x119 +#define PGM_CODE_TX_ABORTED_EVENT 0x200 +#endif lib/s390x/asm/irq.h new file +18
-0@@ -0,0 +1,18 @@ +/* +* Copyright (c) 2017 Red Hat Inc +* +* Authors: +* David Hildenbrand <[email protected]> +* +* 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 <asm/arch_def.h> + +void handle_pgm_irq (void ); +void expect_pgm_irq (void ); +uint16_t received_pgm_irq (void ); + +#endif lib/s390x/irq.c new file +24
-0@@ -0,0 +1,89 @@ +/* +* s390x irq handling +* +* Copyright (c) 2017 Red Hat Inc +* +* Authors: +* Thomas Huth <[email protected]> +* David Hildenbrand <[email protected]> +* +* 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/irq.h> +#include <asm/barrier.h> + +static bool pgm_irq_expected; + +void expect_pgm_irq (void ) +{ +struct lowcore *lc = (void * )0 ; + + pgm_irq_expected = true; + lc->pgm_int_code =0 ;
lib/s390x/irq.c line 34
Quoted 10 lines
lib/s390x/irq.c new file +10
-0+mb (); +} + +uint16_t received_pgm_irq (void ) +{ +struct lowcore *lc = (void * )0 ; + +mb (); +return lc->pgm_int_code; +}
I'd maybe name this "get_pgm_int_code()" instead (but that's just a matter of taste)
Quoted 88 lines
lib/s390x/irq.c new file +54
-0+static void fixup_pgm_irq (void ) +{ +struct lowcore *lc = (void * )0 ; + +switch (lc->pgm_int_code) { +case PGM_CODE_SEGMENT_TRANSLATION : +case PGM_CODE_PAGE_TRANSLATION : +case PGM_CODE_TRACE_TABLE : +case PGM_CODE_AFX_TRANSLATION : +case PGM_CODE_ASX_TRANSLATION : +case PGM_CODE_LX_TRANSLATION : +case PGM_CODE_EX_TRANSLATION : +case PGM_CODE_PRIMARY_AUTHORITY : +case PGM_CODE_SECONDARY_AUTHORITY : +case PGM_CODE_LFX_TRANSLATION : +case PGM_CODE_LSX_TRANSLATION : +case PGM_CODE_ALEN_TRANSLATION : +case PGM_CODE_ALE_SEQUENCE : +case PGM_CODE_ASTE_VALIDITY : +case PGM_CODE_ASTE_SEQUENCE : +case PGM_CODE_EXTENDED_AUTHORITY : +case PGM_CODE_LSTE_SEQUENCE : +case PGM_CODE_ASTE_INSTANCE : +case PGM_CODE_STACK_FULL : +case PGM_CODE_STACK_EMPTY : +case PGM_CODE_STACK_SPECIFICATION : +case PGM_CODE_STACK_TYPE : +case PGM_CODE_STACK_OPERATION : +case PGM_CODE_ASCE_TYPE : +case PGM_CODE_REGION_FIRST_TRANS : +case PGM_CODE_REGION_SECOND_TRANS : +case PGM_CODE_REGION_THIRD_TRANS : +case PGM_CODE_PER : +case PGM_CODE_CRYPTO_OPERATION : +/* The irq 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_irq (void ) +{ +struct lowcore *lc = (void *)0 ; + +if (!pgm_irq_expected) +report_abort ("Unexpected pgm irq %d at %#lx, ilen %d\n" , + lc->pgm_int_code, lc->pgm_old_psw.addr, + lc->pgm_int_id); + + pgm_irq_expected = false; +fixup_pgm_irq (); +}s390x/Makefile +2
-0@@ -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/irq.o OBJDIRS += lib/s390xs390x/cstart64.S +2
-0@@ -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 <asm/asm-offsets.h> + .section .init /* entry point - for KVM + TCG we directly start in 64 bit mode */
s390x/cstart64.S start: · line 30
Quoted 8 lines
s390x/cstart64.S +5
-0@@ -21,6 +23,12 @@ start: larl %r1, initital_psw lpswe 0(%r1) init_psw_cont: + /* setup pgm irq handler */ + larl %r1, pgm_irq_mask + stg %r1, GEN_LC_PGM_NEW_PSW + larl %r1, pgm_irq + stg %r1, GEN_LC_PGM_NEW_PSW + 8
Not sure whether it's better/nicer, but I think you could also do:
lmg %r0, %r1, pgm_irq_psw stmg %r0, %r1, GEN_LC_PGM_NEW_PSW ... pgm_irq_psw: .quad 0x0000000180000000, pgm_irq
s390x/cstart64.S start: · line 31
Quoted 1 line
s390x/cstart64.S +1
-0+ /* setup the initital PSW and enable 64bit addressing */
That comment does not really match the code below?
s390x/cstart64.S init_psw_cont: · line 51
Quoted 12 lines
s390x/cstart64.S +5
-0larl %r1, initital_cr0 lctlg %c0, %c0, 0(%r1) /* call setup() */@@ -36,9 +44,17 @@ init_psw_cont: /* call exit() */ j exit +pgm_irq: + stmg %r0, %r15, GEN_LC_SW_IRQ_AREA + brasl %r14, handle_pgm_irq + lmg %r0, %r15, GEN_LC_SW_IRQ_AREA + lpswe GEN_LC_PGM_OLD_PSW
Use a TAB instead of space after lpswe ?
I also wonder whether you've got to save the floating point registers here, too, in case the compiler emits some floating point code in the interrupt handlers (since we're not using -msoftfloat anymore)?
Quoted 21 lines
s390x/cstart64.S +2
-0.align 8 initital_psw: .quad 0x0000000180000000, init_psw_cont +pgm_irq_mask: + .quad 0x0000000180000000 initital_cr0: /* enable AFP-register control, so FP regs (+BFP instr) can be used */ .quad 0x0000000000040000s390x/selftest.c +1
-0@@ -10,6 +10,7 @@*/ #include <libcflat.h> #include <util.h> +#include <asm/irq.h> static void test_fp (void ) {
s390x/selftest.c static void test_fp(void) · line 33
Quoted 8 lines
s390x/selftest.c +5
-0@@ -25,6 +26,18 @@ static void test_fp(void)report ("3.0/2.0 == 1.5" , c ==1.5 ); } +static void test_pgm_irq (void ) +{ +expect_pgm_irq (); + asmvolatile ( +" .insn e,0x0001" );
I'd put that into one line. And please add a comment - not everybody knows what opcode 0x0001 is good for.
Quoted 12 lines
s390x/selftest.c +7
-0+report ("OPERATION pgm irq" ,received_pgm_irq () ==PGM_CODE_OPERATION ); + +expect_pgm_irq (); + *((unsigned int *)-1 ) =1 ; +report ("ADDRESSING pgm irq" ,received_pgm_irq () ==PGM_CODE_ADDRESSING ); +} +int main (int argc,char **argv) {report_prefix_push ("selftest" );
s390x/selftest.c int main(int argc, char**argv) · line 55
Quoted 7 lines
s390x/selftest.c +1
-0@@ -36,6 +49,7 @@ int main(int argc, char**argv)report ("argv[2] == 123" , !strcmp (argv[2 ],"123" ));test_fp (); +test_pgm_irq ();return report_summary (); }
Thomas
Quoted 9 lines · Thomas Huth
Quoted 5 lines · David Hildenbrand
The pgm irq handler will detect unexpected pgm irqs and allows to expect pgm irqs + verify that the pgm irq was triggered.
We need "-fno-delete-null-pointer-checks", otherwise trying to access the lowcore at address 0 makes GCC generate very weird code.
I wonder whether you could get rid of that by using a global variable for lc instead?
As far as I remember, I tried that and it didn't change a thing. Will do a quick test.
Quoted 8 lines
Quoted 8 lines
Add two tests to test for simple operation and addressing exception.
Signed-off-by David Hildenbrand <[email protected]>---
Note: This will require TCG patch "target/s390x: addressing exceptions are suppressing" in order to pass.
Quoted 4 lines
Quoted 2 lines
Patch "[kvm-unit-tests PATCH v1] s390x: generate asm offsets for the lowcore" is requires as a prerequisite.
Maybe send them together as a series next time?
Yes, will send them out in one series for the next round.
Quoted 30 lines
Quoted 30 lines
lib/s390x/asm-offsets.c | 1 + lib/s390x/asm/arch_def.h | 59 +++++++++++++++++++++++++++++++- lib/s390x/asm/irq.h | 18 ++++++++++ lib/s390x/irq.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++++ s390x/Makefile | 2 ++ s390x/cstart64.S | 16 +++++++++ s390x/selftest.c | 14 ++++++++ 7 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 lib/s390x/asm/irq.h create mode 100644 lib/s390x/irq.clib/s390x/asm-offsets.c +1
-0@@ -54,6 +54,7 @@ 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_IRQ_AREA , lowcore, sw_irq_area);OFFSET (GEN_LC_FPRS_SA , lowcore, fprs_sa);OFFSET (GEN_LC_GRS_SA , lowcore, grs_sa);OFFSET (GEN_LC_PSW_SA , lowcore, psw_sa);lib/s390x/asm/arch_def.h +0
-0@@ -64,7 +64,9 @@ struct lowcore {struct psw pgm_new_psw;/* 0x01d0 */
Quoted 8 lines
lib/s390x/asm/arch_def.h struct lowcore { · line 68
Quoted 5 lines
lib/s390x/asm/arch_def.h +2
-1struct psw mcck_new_psw;/* 0x01e0 */ struct psw io_new_psw;/* 0x01f0 */ -uint8_t pad_0x0200[0x1200 -0x0200 ];/* 0x0200 */ +/* sw definition: large enough to save all grs in irq handlers */ +uint8_t sw_irq_area[0x280 -0x0200 ];/* 0x0200 */ Since you're saving 64-bit registers into this array, I'd suggest to make it an array of
uint64_tvalues instead ofuint8_t.
Ack. Also added save areas for fpc + fprs.
[...]>> /* entry point - for KVM + TCG we directly start in 64 bit mode */
Quoted 11 lines
lib/s390x/asm/arch_def.h start: · line 30
Quoted 9 lines
lib/s390x/asm/arch_def.h +5
-0@@ -21,6 +23,12 @@ start: larl %r1, initital_psw lpswe 0(%r1) init_psw_cont: +/* setup pgm irq handler */ + larl %r1, pgm_irq_mask + stg %r1, GEN_LC_PGM_NEW_PSW + larl %r1, pgm_irq + stg %r1, GEN_LC_PGM_NEW_PSW + 8Not sure whether it's better/nicer, but I think you could also do:
I now do
larl %r1, pgm_irq_psw
mvc GEN_LC_PGM_NEW_PSW(16), 0(%r1)
Quoted 10 lines
lmg %r0, %r1, pgm_irq_psw stmg %r0, %r1, GEN_LC_PGM_NEW_PSW ... pgm_irq_psw: .quad 0x0000000180000000, pgm_irqlib/s390x/asm/arch_def.h start: · line 31
Quoted 1 line
lib/s390x/asm/arch_def.h +1
-0+/* setup the initital PSW and enable 64bit addressing */ That comment does not really match the code below?
Yes, wonder how that slipped in.
/* setup cr0, enabling e.g. AFP-register control */
Quoted 8 lines
Quoted 8 lines
lib/s390x/asm/arch_def.h +0
-0larl %r1, initital_cr0 lctlg %c0, %c0, 0(%r1)/* call setup() */ @@ -36,9 +44,17 @@ init_psw_cont:/* call exit() */ j exit
Quoted 7 lines
lib/s390x/asm/arch_def.h init_psw_cont: · line 51
Quoted 5 lines
lib/s390x/asm/arch_def.h +5
-0+pgm_irq: + stmg %r0, %r15, GEN_LC_SW_IRQ_AREA + brasl %r14, handle_pgm_irq + lmg %r0, %r15, GEN_LC_SW_IRQ_AREA +lpswe GEN_LC_PGM_OLD_PSW Use a TAB instead of space after lpswe ?
Ack.
Quoted 4 lines
I also wonder whether you've got to save the floating point registers here, too, in case the compiler emits some floating point code in the interrupt handlers (since we're not using -msoftfloat anymore)?
Yes you're right. Saving/restoring fprs + fpc now. Unfortunately these can't be saved/loaded in one shot like grs. For vector registers, there is again an instruction to save/restore them in one shot.
Quoted 25 lines
Quoted 25 lines
lib/s390x/asm/arch_def.h +2
-0.align 8 initital_psw: .quad 0x0000000180000000, init_psw_cont +pgm_irq_mask: + .quad 0x0000000180000000 initital_cr0:/* enable AFP-register control, so FP regs (+BFP instr) can be used */ .quad 0x0000000000040000s390x/selftest.c +1
-0@@ -10,6 +10,7 @@*/ #include <libcflat.h> #include <util.h> +#include <asm/irq.h> static void test_fp (void ) {@@ -25,6 +26,18 @@ static void test_fp(void)report ("3.0/2.0 == 1.5" , c ==1.5 ); }
Quoted 8 lines
s390x/selftest.c static void test_fp(void) · line 33
Quoted 5 lines
s390x/selftest.c +5
-0+static void test_pgm_irq (void ) +{ +expect_pgm_irq (); + asmvolatile ( +" .insn e,0x0001" );I'd put that into one line. And please add a comment - not everybody knows what opcode
0x0001is good for.
Makes sense!
Quoted 14 lines
Quoted 14 lines
s390x/selftest.c +7
-0+report ("OPERATION pgm irq" ,received_pgm_irq () ==PGM_CODE_OPERATION ); + +expect_pgm_irq (); + *((unsigned int *)-1 ) =1 ; +report ("ADDRESSING pgm irq" ,received_pgm_irq () ==PGM_CODE_ADDRESSING ); +} +int main (int argc,char **argv) {report_prefix_push ("selftest" );@@ -36,6 +49,7 @@ int main(int argc, char**argv)report ("argv[2] == 123" , !strcmp (argv[2 ],"123" ));
Quoted 9 lines
s390x/selftest.c int main(int argc, char**argv) · line 55
Quoted 6 lines
s390x/selftest.c +1
-0test_fp (); +test_pgm_irq ();return report_summary (); }Thomas
Thanks a lot Thomas!
Signature · 3 lines
Thanks, David
Quoted 5 lines · David Hildenbrand
Quoted 4 lines · Thomas Huth
Quoted 3 lines · David Hildenbrand
The pgm irq handler will detect unexpected pgm irqs and allows to expect pgm irqs + verify that the pgm irq was triggered.
Quoted 8 lines
Quoted 5 lines
Quoted 2 lines
We need "-fno-delete-null-pointer-checks", otherwise trying to access the lowcore at address 0 makes GCC generate very weird code.
I wonder whether you could get rid of that by using a global variable for lc instead?
As far as I remember, I tried that and it didn't change a thing. Will do a quick test.
It works as long as that global variable is not static, because then GCC must assume that any other code could set it to !0.
Signature · 3 lines
Thanks, David
Paolo Bonzini
maintainerQuoted 7 lines · David Hildenbrand
Quoted 4 lines
Quoted 2 lines
We need "-fno-delete-null-pointer-checks", otherwise trying to access the lowcore at address 0 makes GCC generate very weird code.
I wonder whether you could get rid of that by using a global variable for lc instead?
As far as I remember, I tried that and it didn't change a thing. Will do a quick test.
-fno-delete-null-pointer-checks is the right thing to do, trying to hide undefined behavior from the compiler leads to misery. :)
Paolo