mirror of
https://github.com/checkpoint-restore/criu
synced 2025-08-30 05:48:05 +00:00
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 <schwidefsky@de.ibm.com> Signed-off-by: Alice Frosi <alice@linux.vnet.ibm.com> Reviewed-by: Michael Holzheu <holzheu@linux.vnet.ibm.com> Signed-off-by: Andrei Vagin <avagin@virtuozzo.com>
This commit is contained in:
parent
16474786cb
commit
581f731ba6
@ -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
|
||||
|
||||
|
187
test/zdtm/static/s390x_gs_threads.c
Normal file
187
test/zdtm/static/s390x_gs_threads.c
Normal file
@ -0,0 +1,187 @@
|
||||
#include <linux/types.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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 <schwidefsky@de.ibm.com> */
|
||||
const char *test_author = "Alice Frosi <alice@linux.vnet.ibm.com>";
|
||||
|
||||
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;
|
||||
}
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user