From 581f731ba61420ee9b66d8ad1b4f65f35c9b2bc7 Mon Sep 17 00:00:00 2001 From: Alice Frosi Date: Thu, 5 Oct 2017 15:50:42 +0200 Subject: [PATCH] s390: Add test case for GS - Add new test "s390x_gs_threads" for GS with broadcast command for the s390_guarded_storage() system call. - Add GS control blocks in test s390x_regs_check.c The original test case for GS has been provided by Martin Schwidefsky Signed-off-by: Alice Frosi Reviewed-by: Michael Holzheu Signed-off-by: Andrei Vagin --- test/zdtm/static/Makefile | 4 +- test/zdtm/static/s390x_gs_threads.c | 187 ++++++++++++++++++++++++++++ test/zdtm/static/s390x_regs_check.c | 47 +++++++ 3 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 test/zdtm/static/s390x_gs_threads.c diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile index a35b81443..3a20f0f1a 100644 --- a/test/zdtm/static/Makefile +++ b/test/zdtm/static/Makefile @@ -187,7 +187,8 @@ endif endif ifeq ($(SRCARCH),s390) - TST_NOFILE += s390x_regs_check + TST_NOFILE += s390x_regs_check \ + s390x_gs_threads endif TST_FILE = \ @@ -471,6 +472,7 @@ pty-console: CFLAGS += -D ZDTM_DEV_CONSOLE shm-unaligned: CFLAGS += -DZDTM_SHM_UNALIGNED s390x_regs_check: LDFLAGS += -pthread +s390x_gs_threads: LDFLAGS += -pthread thread_different_uid_gid: LDLIBS += -pthread -lcap diff --git a/test/zdtm/static/s390x_gs_threads.c b/test/zdtm/static/s390x_gs_threads.c new file mode 100644 index 000000000..486b32087 --- /dev/null +++ b/test/zdtm/static/s390x_gs_threads.c @@ -0,0 +1,187 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lock.h" +#include "zdtmtst.h" + +#define NR_THREADS 4 +#define GS_ENABLE 0 +#define GS_SET_BC_CB 2 +#define GS_BROADCAST 4 + +#ifndef __NR_guarded_storage +#define __NR_guarded_storage 378 +#endif + +const char *test_doc = "Check the guarded storage broadcast"; +/* Original test provided by Martin Schwidefsky */ +const char *test_author = "Alice Frosi "; + +static unsigned long main_thread_tid; + +/* + * This test case executes the following procedure: + * + * 1) The parent thread creates NR_THREADS child threads + * + * 2) For each thread (including the parent thread): + * - Enable guarded-storage + * - Set the guarded-storage broadcast control block and + * specify gs_handler as Guarded-Storage-Event Parameter-List + * address + * + * 3) Dump and restore + * + * 4) Guarded-storage broadcast event + * - Child threads: Wait until main thread does GS broadcast + * - Parent thread: Trigger GS broadcast + * + * 5) Verify that all GS works as expected and all threads have been + * executed the gs_handler + */ + +struct gs_cb { + __u64 reserved; + __u64 gsd; + __u64 gssm; + __u64 gs_epl_a; +}; + +static futex_t futex; +static futex_t futex2; + +/* + * Load guarded-storage + */ +void load_guarded(unsigned long *mem); +asm( + ".global load_guarded\n" + "load_guarded:\n" + " .insn rxy,0xe3000000004c,%r2,0(%r2)\n" + " br %r14\n" + " .size load_guarded,.-load_guarded\n"); + +/* + * Inline assembly to deal with interrupted context to the call of + * the GS handler. Load guarded can be turned into a branch to this + * function. + */ +void gs_handler_asm(void); +asm( + ".globl gs_handler_asm\n" + "gs_handler_asm:\n" + " lgr %r14,%r15\n" + " aghi %r15,-320\n" + " stmg %r0,%r14,192(%r15)\n" + " stg %r14,312(%r14)\n" + " la %r2,160(%r15)\n" + " .insn rxy,0xe30000000049,0,160(%r15)\n" + " lg %r14,24(%r2)\n" + " lg %r14,40(%r14)\n" + " la %r14,6(%r14)\n" + " stg %r14,304(%r15)\n" + " brasl %r14,gs_handler\n" + " lmg %r0,%r15,192(%r15)\n" + " br %r14\n" + " .size gs_handler_asm,.-gs_handler_asm\n"); + +/* + * GS handler called when GS event occurs + */ +void gs_handler(struct gs_cb *this_cb) +{ + unsigned long tid = syscall(SYS_gettid); + test_msg("gs_handler for thread %016lx\n", tid); + futex_dec_and_wake(&futex2); +} + +/* + * Entry point for threads + */ +static void *thread_run(void *param) +{ + unsigned long test = 0x1234000000; + unsigned long *gs_epl; + struct gs_cb *gs_cb; + + /* Enable guarded-storage */ + if (syscall(__NR_guarded_storage, GS_ENABLE) != 0) { + fail("Unable to enable guarded storage"); + exit(1); + } + gs_epl = malloc(sizeof(unsigned long) * 6); + gs_cb = malloc(sizeof(*gs_cb)); + if (gs_epl == NULL || gs_cb == NULL) { + fail("Error allocating memory\n"); + exit(1); + } + gs_cb->gsd = 0x1234000000UL | 26; + gs_cb->gssm = -1UL; + gs_cb->gs_epl_a = (unsigned long) gs_epl; + gs_epl[1] = (unsigned long) gs_handler_asm; + /* Set the GS broadcast control block */ + syscall(__NR_guarded_storage, GS_SET_BC_CB, gs_cb); + futex_dec_and_wake(&futex); + /* Wait for all threads to set the GS broadcast control block */ + futex_wait_until(&futex, 0); + test_msg("Thread %016lx staring loop\n", syscall(SYS_gettid)); + /* + * Designate a guarded-storage section until the main task + * performs the GS_BROADCAST action and the following load_guarded + * will provoke the switch to the gs handler + */ + while (1) + load_guarded(&test); +} + +int main(int argc, char *argv[]) +{ + pthread_t tids[NR_THREADS]; + int i; + + main_thread_tid = syscall(SYS_gettid); + test_init(argc, argv); + /* Enable guarded-storage */ + if (syscall(__NR_guarded_storage, GS_ENABLE) != 0) { + if (errno == ENOSYS) { + test_daemon(); + test_waitsig(); + skip("No guarded storage support"); + pass(); + return 0; + } + fail("Unable to enable guarded storage"); + return 1; + } + + futex_set(&futex, NR_THREADS); + + for (i = 0; i < NR_THREADS; i++) + pthread_create(tids + i, NULL, thread_run, NULL); + + test_msg("Waiting for thread startup\n"); + /* Wait for all threads to set the GS broadcast control block */ + futex_wait_until(&futex, 0); + + test_daemon(); + test_waitsig(); + + test_msg("Doing broadcast\n"); + futex_set(&futex2, NR_THREADS); + /* + * Triggers a GS event and force all the threads to execute + * the gs handler + */ + syscall(__NR_guarded_storage, GS_BROADCAST); + + test_msg("Waiting for thread completion\n"); + futex_wait_until(&futex2, 0); + pass(); + return 0; +} diff --git a/test/zdtm/static/s390x_regs_check.c b/test/zdtm/static/s390x_regs_check.c index b8f9d862c..ab9d7d139 100644 --- a/test/zdtm/static/s390x_regs_check.c +++ b/test/zdtm/static/s390x_regs_check.c @@ -182,6 +182,50 @@ struct reg_set reg_set_vxrs_high = { .optional = true, }; +/* + * s390 guarded-storage registers + */ +#define NT_S390_GS_CB 0x30b +#define NT_S390_GS_BC 0x30c + +struct gs_cb { + uint64_t regs[4]; +}; + +struct gs_cb gs_cb_data = { + .regs = { + 0x0000000000000000, + 0x000000123400001a, + 0x5555555555555555, + 0x000000014b58a010, + } +}; + +struct reg_set reg_set_gs_cb = { + .name = "GS_CB", + .nr = NT_S390_GS_CB, + .data = &gs_cb_data, + .len = sizeof(gs_cb_data), + .optional = true, +}; + +struct gs_cb gs_bc_data = { + .regs = { + 0x0000000000000000, + 0x000000123400001a, + 0xffffffffffffffff, + 0x0000000aaaaaaaaa, + } +}; + +struct reg_set reg_set_gs_bc = { + .name = "GS_BC_CB", + .nr = NT_S390_GS_BC, + .data = &gs_bc_data, + .len = sizeof(gs_bc_data), + .optional = true, +}; + /* * Vector with all regsets */ @@ -189,6 +233,8 @@ struct reg_set *reg_set_vec[] = { ®_set_prfpreg, ®_set_vxrs_low, ®_set_vxrs_high, + ®_set_gs_cb, + ®_set_gs_bc, NULL, }; @@ -246,6 +292,7 @@ static int set_regset(pid_t pid, struct reg_set *reg_set) } if (reg_set->optional) { switch (errno) { + case EOPNOTSUPP: case ENODEV: test_msg(" REGSET: %12s -> not supported by machine\n", reg_set->name);