forked from ~ljy/RK356X_SDK_RELEASE

hc
2024-12-19 9370bb92b2d16684ee45cf24e879c93c509162da
kernel/tools/testing/selftests/rseq/rseq.c
....@@ -25,83 +25,134 @@
2525 #include <syscall.h>
2626 #include <assert.h>
2727 #include <signal.h>
28
+#include <limits.h>
29
+#include <dlfcn.h>
30
+#include <stddef.h>
2831
32
+#include <linux/compiler.h>
33
+
34
+#include "../kselftest.h"
2935 #include "rseq.h"
3036
31
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
37
+/*
38
+ * Define weak versions to play nice with binaries that are statically linked
39
+ * against a libc that doesn't support registering its own rseq.
40
+ */
41
+__weak ptrdiff_t __rseq_offset;
42
+__weak unsigned int __rseq_size;
43
+__weak unsigned int __rseq_flags;
3244
33
-__attribute__((tls_model("initial-exec"))) __thread
34
-volatile struct rseq __rseq_abi = {
35
- .cpu_id = RSEQ_CPU_ID_UNINITIALIZED,
45
+static const ptrdiff_t *libc_rseq_offset_p = &__rseq_offset;
46
+static const unsigned int *libc_rseq_size_p = &__rseq_size;
47
+static const unsigned int *libc_rseq_flags_p = &__rseq_flags;
48
+
49
+/* Offset from the thread pointer to the rseq area. */
50
+ptrdiff_t rseq_offset;
51
+
52
+/* Size of the registered rseq area. 0 if the registration was
53
+ unsuccessful. */
54
+unsigned int rseq_size = -1U;
55
+
56
+/* Flags used during rseq registration. */
57
+unsigned int rseq_flags;
58
+
59
+static int rseq_ownership;
60
+
61
+static
62
+__thread struct rseq_abi __rseq_abi __attribute__((tls_model("initial-exec"))) = {
63
+ .cpu_id = RSEQ_ABI_CPU_ID_UNINITIALIZED,
3664 };
3765
38
-static __attribute__((tls_model("initial-exec"))) __thread
39
-volatile int refcount;
40
-
41
-static void signal_off_save(sigset_t *oldset)
42
-{
43
- sigset_t set;
44
- int ret;
45
-
46
- sigfillset(&set);
47
- ret = pthread_sigmask(SIG_BLOCK, &set, oldset);
48
- if (ret)
49
- abort();
50
-}
51
-
52
-static void signal_restore(sigset_t oldset)
53
-{
54
- int ret;
55
-
56
- ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL);
57
- if (ret)
58
- abort();
59
-}
60
-
61
-static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len,
66
+static int sys_rseq(struct rseq_abi *rseq_abi, uint32_t rseq_len,
6267 int flags, uint32_t sig)
6368 {
6469 return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
6570 }
6671
72
+int rseq_available(void)
73
+{
74
+ int rc;
75
+
76
+ rc = sys_rseq(NULL, 0, 0, 0);
77
+ if (rc != -1)
78
+ abort();
79
+ switch (errno) {
80
+ case ENOSYS:
81
+ return 0;
82
+ case EINVAL:
83
+ return 1;
84
+ default:
85
+ abort();
86
+ }
87
+}
88
+
6789 int rseq_register_current_thread(void)
6890 {
69
- int rc, ret = 0;
70
- sigset_t oldset;
91
+ int rc;
7192
72
- signal_off_save(&oldset);
73
- if (refcount++)
74
- goto end;
75
- rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG);
76
- if (!rc) {
77
- assert(rseq_current_cpu_raw() >= 0);
78
- goto end;
93
+ if (!rseq_ownership) {
94
+ /* Treat libc's ownership as a successful registration. */
95
+ return 0;
7996 }
80
- if (errno != EBUSY)
81
- __rseq_abi.cpu_id = -2;
82
- ret = -1;
83
- refcount--;
84
-end:
85
- signal_restore(oldset);
86
- return ret;
97
+ rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), 0, RSEQ_SIG);
98
+ if (rc)
99
+ return -1;
100
+ assert(rseq_current_cpu_raw() >= 0);
101
+ return 0;
87102 }
88103
89104 int rseq_unregister_current_thread(void)
90105 {
91
- int rc, ret = 0;
92
- sigset_t oldset;
106
+ int rc;
93107
94
- signal_off_save(&oldset);
95
- if (--refcount)
96
- goto end;
97
- rc = sys_rseq(&__rseq_abi, sizeof(struct rseq),
98
- RSEQ_FLAG_UNREGISTER, RSEQ_SIG);
99
- if (!rc)
100
- goto end;
101
- ret = -1;
102
-end:
103
- signal_restore(oldset);
104
- return ret;
108
+ if (!rseq_ownership) {
109
+ /* Treat libc's ownership as a successful unregistration. */
110
+ return 0;
111
+ }
112
+ rc = sys_rseq(&__rseq_abi, sizeof(struct rseq_abi), RSEQ_ABI_FLAG_UNREGISTER, RSEQ_SIG);
113
+ if (rc)
114
+ return -1;
115
+ return 0;
116
+}
117
+
118
+static __attribute__((constructor))
119
+void rseq_init(void)
120
+{
121
+ /*
122
+ * If the libc's registered rseq size isn't already valid, it may be
123
+ * because the binary is dynamically linked and not necessarily due to
124
+ * libc not having registered a restartable sequence. Try to find the
125
+ * symbols if that's the case.
126
+ */
127
+ if (!*libc_rseq_size_p) {
128
+ libc_rseq_offset_p = dlsym(RTLD_NEXT, "__rseq_offset");
129
+ libc_rseq_size_p = dlsym(RTLD_NEXT, "__rseq_size");
130
+ libc_rseq_flags_p = dlsym(RTLD_NEXT, "__rseq_flags");
131
+ }
132
+ if (libc_rseq_size_p && libc_rseq_offset_p && libc_rseq_flags_p &&
133
+ *libc_rseq_size_p != 0) {
134
+ /* rseq registration owned by glibc */
135
+ rseq_offset = *libc_rseq_offset_p;
136
+ rseq_size = *libc_rseq_size_p;
137
+ rseq_flags = *libc_rseq_flags_p;
138
+ return;
139
+ }
140
+ if (!rseq_available())
141
+ return;
142
+ rseq_ownership = 1;
143
+ rseq_offset = (void *)&__rseq_abi - rseq_thread_pointer();
144
+ rseq_size = sizeof(struct rseq_abi);
145
+ rseq_flags = 0;
146
+}
147
+
148
+static __attribute__((destructor))
149
+void rseq_exit(void)
150
+{
151
+ if (!rseq_ownership)
152
+ return;
153
+ rseq_offset = 0;
154
+ rseq_size = -1U;
155
+ rseq_ownership = 0;
105156 }
106157
107158 int32_t rseq_fallback_current_cpu(void)