Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/checkpoint-restore/criu.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>2022-02-21 15:45:40 +0300
committerAndrei Vagin <avagin@gmail.com>2022-04-29 03:53:52 +0300
commit064e9925a0516737dc2ae7cc025cd667992de79d (patch)
tree3437d553c8e315e1dbe8b664cc6940d88f4ad59b
parent2d3354e7b63ea6f9566f0ff3b17e7cb9f282be9e (diff)
zdtm: add transition/rseq01 test for amd64
Signed-off-by: Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>
-rw-r--r--test/zdtm/transition/Makefile1
-rw-r--r--test/zdtm/transition/rseq01.c225
-rw-r--r--test/zdtm/transition/rseq01.desc1
3 files changed, 227 insertions, 0 deletions
diff --git a/test/zdtm/transition/Makefile b/test/zdtm/transition/Makefile
index 9388157e8..fae4e27b3 100644
--- a/test/zdtm/transition/Makefile
+++ b/test/zdtm/transition/Makefile
@@ -23,6 +23,7 @@ TST_NOFILE = \
lazy-thp \
pid_reuse \
pidfd_store_sk \
+ rseq01 \
TST_FILE = \
diff --git a/test/zdtm/transition/rseq01.c b/test/zdtm/transition/rseq01.c
new file mode 100644
index 000000000..7a22854a3
--- /dev/null
+++ b/test/zdtm/transition/rseq01.c
@@ -0,0 +1,225 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <syscall.h>
+
+#include "zdtmtst.h"
+
+#ifdef __has_include
+#if __has_include("sys/rseq.h")
+#include <sys/rseq.h>
+#endif
+#endif
+
+#if defined(__x86_64__)
+
+#if defined(__x86_64__) && defined(RSEQ_SIG)
+static inline void *thread_pointer(void)
+{
+ void *result;
+ asm("mov %%fs:0, %0" : "=r"(result));
+ return result;
+}
+
+static inline void unregister_old_rseq(void)
+{
+ /* unregister rseq */
+ syscall(__NR_rseq, (void *)((char *)thread_pointer() + __rseq_offset), __rseq_size, 1, RSEQ_SIG);
+}
+#else
+static inline void unregister_old_rseq(void)
+{
+}
+#endif
+
+const char *test_doc = "rseq() transition test";
+const char *test_author = "Alexander Mikhalitsyn <alexander.mikhalitsyn@virtuozzo.com>";
+/*
+ * Thanks to Mathieu Desnoyers <mathieu.desnoyers@efficios.com> (rseq author)
+ * who helped me with review and debugging the problem on the Alpine Linux.
+ *
+ * parts of code borrowed from
+ * https://www.efficios.com/blog/2019/02/08/linux-restartable-sequences/
+ */
+
+/* some useful definitions from kernel uapi */
+#ifndef RSEQ_SIG
+
+enum rseq_flags {
+ RSEQ_FLAG_UNREGISTER = (1 << 0),
+};
+
+struct rseq {
+ uint32_t cpu_id_start;
+ uint32_t cpu_id;
+ uint64_t rseq_cs;
+ uint32_t flags;
+} __attribute__((aligned(4 * sizeof(uint64_t))));
+
+#define RSEQ_SIG 0x53053053
+
+#endif
+
+#ifndef __NR_rseq
+#define __NR_rseq 334
+#endif
+/* EOF */
+
+static volatile struct rseq *rseq_ptr;
+static __thread volatile struct rseq __rseq_abi;
+
+static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, int flags, uint32_t sig)
+{
+ return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
+}
+
+static void register_thread(void)
+{
+ int rc;
+ unregister_old_rseq();
+ rc = sys_rseq(rseq_ptr, sizeof(struct rseq), 0, RSEQ_SIG);
+ if (rc) {
+ fail("Failed to register rseq");
+ exit(1);
+ }
+}
+
+static void check_thread(void)
+{
+ int rc;
+ rc = sys_rseq(rseq_ptr, sizeof(struct rseq), 0, RSEQ_SIG);
+ if (!(rc && errno == EBUSY)) {
+ fail("Failed to check rseq %d", rc);
+ exit(1);
+ }
+}
+
+#define RSEQ_ACCESS_ONCE(x) (*(__volatile__ __typeof__(x) *)&(x))
+
+#define rseq_after_asm_goto() asm volatile("" : : : "memory")
+
+static int rseq_addv(intptr_t *v, intptr_t count, int cpu)
+{
+ double a = 10000000000000000.0;
+ double b = -1;
+
+ /* clang-format off */
+ __asm__ __volatile__ goto(
+ ".pushsection __rseq_table, \"aw\"\n\t"
+ ".balign 32\n\t"
+ "cs_obj:\n\t"
+ /* version, flags */
+ ".long 0, 0\n\t"
+ /* start_ip, post_commit_offset, abort_ip */
+ ".quad 1f, (2f-1f), 4f\n\t"
+ ".popsection\n\t"
+ "fldl %[x]\n\t" /* we have st clobbered */
+ "leaq cs_obj(%%rip), %%rax\n\t"
+ "1:\n\t"
+ "movq %%rax, %[rseq_cs]\n\t"
+ "cmpl %[cpu_id], %[current_cpu_id]\n\t"
+ "jnz 4f\n\t"
+ "addq %[count], %[v]\n\t" /* final store */
+ "mov $10000000, %%rcx\n\t"
+ "5:\n\t"
+ "fsqrt\n\t" /* heavy instruction */
+ "dec %%rcx\n\t"
+ "jnz 5b\n\t"
+ "fstpl %[y]\n\t"
+ "2:\n\t"
+ ".pushsection __rseq_failure, \"ax\"\n\t"
+ /* Disassembler-friendly signature: nopl <sig>(%rip). */
+ ".byte 0x0f, 0xb9, 0x3d\n\t"
+ ".long 0x53053053\n\t" /* RSEQ_FLAGS */
+ "4:\n\t"
+ "fstpl %[y]\n\t"
+ "jmp %l[abort]\n\t"
+ /*"jmp 1b\n\t"*/
+ ".popsection\n\t"
+ : /* gcc asm goto does not allow outputs */
+ : [cpu_id] "r" (cpu),
+ [current_cpu_id] "m" (rseq_ptr->cpu_id),
+ [rseq_cs] "m" (rseq_ptr->rseq_cs),
+ /* final store input */
+ [v] "m" (*v),
+ [count] "er" (count),
+ [x] "m" (a),
+ [y] "m" (b)
+ : "memory", "cc", "rax", "rcx", "st"
+ : abort
+ );
+ /* clang-format on */
+ rseq_after_asm_goto();
+ return 0;
+abort:
+ rseq_after_asm_goto();
+ return -1;
+}
+
+int main(int argc, char *argv[])
+{
+ int cpu = 0;
+ int ret;
+ intptr_t *cpu_data;
+ long nr_cpus;
+
+ rseq_ptr = &__rseq_abi;
+ memset((void *)rseq_ptr, 0, sizeof(struct rseq));
+
+ test_init(argc, argv);
+ nr_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+
+ cpu_data = calloc(nr_cpus, sizeof(*cpu_data));
+ if (!cpu_data) {
+ fail("calloc");
+ exit(EXIT_FAILURE);
+ }
+ register_thread();
+
+ test_daemon();
+
+ while (test_go()) {
+ cpu = RSEQ_ACCESS_ONCE(rseq_ptr->cpu_id_start);
+ ret = rseq_addv(&cpu_data[cpu], 2, cpu);
+
+ /* just ignore abort */
+ ret = 0;
+
+ if (ret)
+ break;
+ }
+
+ test_waitsig();
+
+ check_thread();
+
+ if (ret)
+ fail();
+ else
+ pass();
+
+ return 0;
+}
+
+#else /* #if defined(__x86_64__) */
+
+int main(int argc, char *argv[])
+{
+ test_init(argc, argv);
+ skip("Unsupported arch");
+ test_daemon();
+ test_waitsig();
+ pass();
+ return 0;
+}
+
+#endif /* #if defined(__x86_64__) */
diff --git a/test/zdtm/transition/rseq01.desc b/test/zdtm/transition/rseq01.desc
new file mode 100644
index 000000000..0324fa39c
--- /dev/null
+++ b/test/zdtm/transition/rseq01.desc
@@ -0,0 +1 @@
+{'flavor': 'h', 'arch': 'x86_64', 'feature': 'get_rseq_conf'}