s390x: Add a test for the diagnose 0x308 hypercall
PATCH v2 1/1 s390x: Add a test for the diagnose 0x308 hypercall
The original idea for this test is to have an easy way to check for a problem that has been fixed in QEMU recently: QEMU simply aborted if this diagnose call was called with an unsupported subcode (e.g. 2). The problem has been fixed in QEMU commit 37dbd1f4d4805edcd18d94eb202bb3461b3cd52d ("Return specification exception for unimplemented diag 308 subcodes"), and this test now should make sure that we do not regress here again. While we're at it, also check whether LOAD NORMAL via subcode 1 works correctly, whether the diagnose call is blocked correctly in problem state and whether subcodes 5 and 6 are generating specification exceptions for illegal parameters as expected.
---
v2: Use "epsw" in test_subcode1() to get the right upper bits of the PSW
s390x/Makefile | 1 + s390x/diag308.c | 130 ++++++++++++++++++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 + 3 files changed, 134 insertions(+) create mode 100644 s390x/diag308.c
s390x/Makefile +1 -0
@@ -5,6 +5,7 @@ tests += $(TEST_DIR)/sieve.elf tests += $(TEST_DIR)/sthyi.elf tests += $(TEST_DIR)/skey.elf tests += $(TEST_DIR)/diag10.elf +tests += $(TEST_DIR)/diag308.elf tests += $(TEST_DIR)/pfmf.elf tests += $(TEST_DIR)/cmm.elf tests += $(TEST_DIR)/vector.elf
s390x/diag308.c new file +130 -0
130 lines not on this page · raw message
s390x/unittests.cfg +3 -0
@@ -44,6 +44,9 @@ file = skey.elf [diag10] file = diag10.elf +[diag308] +file = diag308.elf + [pfmf] file = pfmf.elf
Signature · 1 line
2.21.0
Quoted 11 lines · Thomas Huth
The original idea for this test is to have an easy way to check for a problem that has been fixed in QEMU recently: QEMU simply aborted if this diagnose call was called with an unsupported subcode (e.g. 2). The problem has been fixed in QEMU commit
37dbd1f4d4805edcd18d94eb202bb3461b3cd52d("Return specification exception for unimplemented diag 308 subcodes"), and this test now should make sure that we do not regress here again. While we're at it, also check whether LOAD NORMAL via subcode 1 works correctly, whether the diagnose call is blocked correctly in problem state and whether subcodes 5 and 6 are generating specification exceptions for illegal parameters as expected.
Quoted 1 line
Signed-off-by Thomas Huth <[email protected]>
A sane thing to have.
Quoted 171 lines
---
v2: Use "epsw" intest_subcode1()to get the right upper bits of the PSWs390x/Makefile | 1 + s390x/diag308.c | 130 ++++++++++++++++++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 + 3 files changed, 134 insertions(+) create mode 100644 s390x/diag308.cs390x/Makefile +1
-0@@ -5,6 +5,7 @@ tests += $(TEST_DIR)/sieve.elf tests += $(TEST_DIR)/sthyi.elf tests += $(TEST_DIR)/skey.elf tests += $(TEST_DIR)/diag10.elf +tests += $(TEST_DIR)/diag308.elf tests += $(TEST_DIR)/pfmf.elf tests += $(TEST_DIR)/cmm.elf tests += $(TEST_DIR)/vector.elfs390x/diag308.c new file +130
-0@@ -0,0 +1,130 @@ +/* +* Diagnose 0x308 hypercall tests +* +* Copyright (c) 2019 Thomas Huth, Red Hat Inc. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2, or (at +* your option) any later version. +*/ + +#include <libcflat.h> +#include <asm/asm-offsets.h> +#include <asm/interrupt.h> + +/* The diagnose calls should be blocked in problem state */ +static void test_priv (void ) +{ +expect_pgm_int (); +enter_pstate (); + asmvolatile ("diag %0,%1,0x308" ::"a" (0 ),"a" (3 )); +check_pgm_int_code (PGM_INT_CODE_PRIVILEGED_OPERATION ); +} + +/* +* Check that diag308 with subcode 1 loads the PSW at address 0, i.e. +* that we can put a pointer into address 4 which then gets executed. +*/ +static void test_subcode1 (void ) +{ +uint64_t saved_psw = *(uint64_t *)0 ; +long subcode =1 ; +long ret, tmp; + + asmvolatile ( +" epsw %0,%1\n" +" st %0,0\n" +" larl %0,0f\n" +" oilh %0,0x8000\n" +" st %0,4\n" +" diag 0,%2,0x308\n" +" lghi %0,0\n" +" j 1f\n" +"0: lghi %0,1\n" +"1:" + :"=&a" (ret),"=&a" (tmp) :"a" (subcode) :"memory" ); + + *(uint64_t *)0 = saved_psw; + +report ("load normal reset done" , ret ==1 ); +} + +/* Expect a specification exception when using an uneven register */ +static void test_uneven_reg (unsigned int subcode) +{ + register unsigned long sc asm("6") = subcode; + register unsigned long r3 asm("9") = 0x2000; + +report_prefix_push ("uneven register" ); +expect_pgm_int (); + asmvolatile ("diag %0,%1,0x308" ::"a" (r3),"a" (sc)); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +/* Expect a specification exception when using an unaligned address */ +static void test_unaligned_address (unsigned int subcode) +{ + register unsigned long sc asm("6") = subcode; + register unsigned long addr asm("8") = 54321; + +report_prefix_push ("unaligned address" ); +expect_pgm_int (); + asmvolatile ("diag %0,%1,0x308" ::"a" (addr),"a" (sc)); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static void test_subcode5 (void ) +{ +test_uneven_reg (5 ); +test_unaligned_address (5 ); +} + +static void test_subcode6 (void ) +{ +test_uneven_reg (6 ); +test_unaligned_address (6 ); +} + +/* Unsupported subcodes should generate a specification exception */ +static void test_unsupported_subcode (void ) +{ +int subcodes[] = {2 ,0x101 ,0xffff ,0x10001 ,-1 }; +int idx; + +for (idx =0 ; idx <ARRAY_SIZE (subcodes); idx++) { +report_prefix_pushf ("0x%04x" , subcodes[idx]); +expect_pgm_int (); + asmvolatile ("diag %0,%1,0x308" ::"a" (0 ),"a" (subcodes[idx])); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); + } +} + +static struct { +const char *name; +void (*func)(void ); +} tests[] = { + {"privileged" , test_priv }, + {"subcode 1" , test_subcode1 }, + {"subcode 5" , test_subcode5 }, + {"subcode 6" , test_subcode6 }, + {"unsupported" , test_unsupported_subcode }, + {NULL ,NULL } +}; + +int main (int argc,char **argv) +{ +int i; + +report_prefix_push ("diag308" ); +for (i =0 ; tests[i].name; i++) { +report_prefix_push (tests[i].name); + tests[i].func (); +report_prefix_pop (); + } +report_prefix_pop (); + +return report_summary (); +}s390x/unittests.cfg +3
-0@@ -44,6 +44,9 @@ file = skey.elf [diag10] file = diag10.elf +[diag308] +file = diag308.elf + [pfmf] file = pfmf.elf
Quoted 175 lines · Thomas Huth
The original idea for this test is to have an easy way to check for a problem that has been fixed in QEMU recently: QEMU simply aborted if this diagnose call was called with an unsupported subcode (e.g. 2). The problem has been fixed in QEMU commit
37dbd1f4d4805edcd18d94eb202bb3461b3cd52d("Return specification exception for unimplemented diag 308 subcodes"), and this test now should make sure that we do not regress here again. While we're at it, also check whether LOAD NORMAL via subcode 1 works correctly, whether the diagnose call is blocked correctly in problem state and whether subcodes 5 and 6 are generating specification exceptions for illegal parameters as expected.Signed-off-by Thomas Huth <[email protected]>---
v2: Use "epsw" intest_subcode1()to get the right upper bits of the PSWs390x/Makefile | 1 + s390x/diag308.c | 130 ++++++++++++++++++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 + 3 files changed, 134 insertions(+) create mode 100644 s390x/diag308.cs390x/Makefile +1
-0@@ -5,6 +5,7 @@ tests += $(TEST_DIR)/sieve.elf tests += $(TEST_DIR)/sthyi.elf tests += $(TEST_DIR)/skey.elf tests += $(TEST_DIR)/diag10.elf +tests += $(TEST_DIR)/diag308.elf tests += $(TEST_DIR)/pfmf.elf tests += $(TEST_DIR)/cmm.elf tests += $(TEST_DIR)/vector.elfs390x/diag308.c new file +130
-0@@ -0,0 +1,130 @@ +/* +* Diagnose 0x308 hypercall tests +* +* Copyright (c) 2019 Thomas Huth, Red Hat Inc. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2, or (at +* your option) any later version. +*/ + +#include <libcflat.h> +#include <asm/asm-offsets.h> +#include <asm/interrupt.h> + +/* The diagnose calls should be blocked in problem state */ +static void test_priv (void ) +{ +expect_pgm_int (); +enter_pstate (); + asmvolatile ("diag %0,%1,0x308" ::"a" (0 ),"a" (3 )); +check_pgm_int_code (PGM_INT_CODE_PRIVILEGED_OPERATION ); +} + +/* +* Check that diag308 with subcode 1 loads the PSW at address 0, i.e. +* that we can put a pointer into address 4 which then gets executed. +*/ +static void test_subcode1 (void ) +{ +uint64_t saved_psw = *(uint64_t *)0 ; +long subcode =1 ; +long ret, tmp; + + asmvolatile ( +" epsw %0,%1\n" +" st %0,0\n" +" larl %0,0f\n" +" oilh %0,0x8000\n" +" st %0,4\n" +" diag 0,%2,0x308\n" +" lghi %0,0\n" +" j 1f\n" +"0: lghi %0,1\n" +"1:" + :"=&a" (ret),"=&a" (tmp) :"a" (subcode) :"memory" ); + + *(uint64_t *)0 = saved_psw; + +report ("load normal reset done" , ret ==1 ); +} + +/* Expect a specification exception when using an uneven register */ +static void test_uneven_reg (unsigned int subcode) +{ + register unsigned long sc asm("6") = subcode; + register unsigned long r3 asm("9") = 0x2000; + +report_prefix_push ("uneven register" ); +expect_pgm_int (); + asmvolatile ("diag %0,%1,0x308" ::"a" (r3),"a" (sc)); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +/* Expect a specification exception when using an unaligned address */ +static void test_unaligned_address (unsigned int subcode) +{ + register unsigned long sc asm("6") = subcode; + register unsigned long addr asm("8") = 54321; + +report_prefix_push ("unaligned address" ); +expect_pgm_int (); + asmvolatile ("diag %0,%1,0x308" ::"a" (addr),"a" (sc)); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); +} + +static void test_subcode5 (void ) +{ +test_uneven_reg (5 ); +test_unaligned_address (5 ); +} + +static void test_subcode6 (void ) +{ +test_uneven_reg (6 ); +test_unaligned_address (6 ); +} + +/* Unsupported subcodes should generate a specification exception */ +static void test_unsupported_subcode (void ) +{ +int subcodes[] = {2 ,0x101 ,0xffff ,0x10001 ,-1 }; +int idx; + +for (idx =0 ; idx <ARRAY_SIZE (subcodes); idx++) { +report_prefix_pushf ("0x%04x" , subcodes[idx]); +expect_pgm_int (); + asmvolatile ("diag %0,%1,0x308" ::"a" (0 ),"a" (subcodes[idx])); +check_pgm_int_code (PGM_INT_CODE_SPECIFICATION ); +report_prefix_pop (); + } +} + +static struct { +const char *name; +void (*func)(void ); +} tests[] = { + {"privileged" , test_priv }, + {"subcode 1" , test_subcode1 }, + {"subcode 5" , test_subcode5 }, + {"subcode 6" , test_subcode6 }, + {"unsupported" , test_unsupported_subcode }, + {NULL ,NULL } +}; + +int main (int argc,char **argv) +{ +int i; + +report_prefix_push ("diag308" ); +for (i =0 ; tests[i].name; i++) { +report_prefix_push (tests[i].name); + tests[i].func (); +report_prefix_pop (); + } +report_prefix_pop (); + +return report_summary (); +}s390x/unittests.cfg +0
-0
s390x/unittests.cfg file = skey.elf · line 52
Quoted 9 lines
s390x/unittests.cfg +3
-0@@ -44,6 +44,9 @@ file = skey.elf [diag10] file = diag10.elf +[diag308] +file = diag308.elf + [pfmf] file = pfmf.elf
You might want to use "g" instead of "a", as we are not dealing with address registers (base/index). Apart from that, nothing major jumped at me.
Signature · 3 lines
Thanks, David / dhildenb
Quoted 62 lines · David Hildenbrand
Quoted 61 lines · Thomas Huth
The original idea for this test is to have an easy way to check for a problem that has been fixed in QEMU recently: QEMU simply aborted if this diagnose call was called with an unsupported subcode (e.g. 2). The problem has been fixed in QEMU commit
37dbd1f4d4805edcd18d94eb202bb3461b3cd52d("Return specification exception for unimplemented diag 308 subcodes"), and this test now should make sure that we do not regress here again. While we're at it, also check whether LOAD NORMAL via subcode 1 works correctly, whether the diagnose call is blocked correctly in problem state and whether subcodes 5 and 6 are generating specification exceptions for illegal parameters as expected.Signed-off-by Thomas Huth <[email protected]>---
v2: Use "epsw" intest_subcode1()to get the right upper bits of the PSWs390x/Makefile | 1 + s390x/diag308.c | 130 ++++++++++++++++++++++++++++++++++++++++++++ s390x/unittests.cfg | 3 + 3 files changed, 134 insertions(+) create mode 100644 s390x/diag308.cs390x/Makefile +1
-0@@ -5,6 +5,7 @@ tests += $(TEST_DIR)/sieve.elf tests += $(TEST_DIR)/sthyi.elf tests += $(TEST_DIR)/skey.elf tests += $(TEST_DIR)/diag10.elf +tests += $(TEST_DIR)/diag308.elf tests += $(TEST_DIR)/pfmf.elf tests += $(TEST_DIR)/cmm.elf tests += $(TEST_DIR)/vector.elfs390x/diag308.c new file +22
-0@@ -0,0 +1,130 @@ +/* +* Diagnose 0x308 hypercall tests +* +* Copyright (c) 2019 Thomas Huth, Red Hat Inc. +* +* This code is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License version 2, or (at +* your option) any later version. +*/ + +#include <libcflat.h> +#include <asm/asm-offsets.h> +#include <asm/interrupt.h> + +/* The diagnose calls should be blocked in problem state */ +static void test_priv (void ) +{ +expect_pgm_int (); +enter_pstate (); + asmvolatile ("diag %0,%1,0x308" ::"a" (0 ),"a" (3 )); +check_pgm_int_code (PGM_INT_CODE_PRIVILEGED_OPERATION ); +}
[...]
Quoted 4 lines
You might want to use "g" instead of "a", as we are not dealing with address registers (base/index). Apart from that, nothing major jumped at me.
Copy-n-past "bug" from diag10.c ;-)
I'll switch it to "d" which is should be the right thing on s390x.
Thanks,
Thomas