1 /*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #ifndef BLOCKAWARE_H
16 #define BLOCKAWARE_H
17
18 #include <securec.h>
19 #include <cstdio>
20 #include <cstring>
21 #include <sys/prctl.h>
22 #include <cerrno>
23
24 #ifdef __cplusplus
25 extern "C" {
26 #endif
27
28 #define BLOCKAWARE_DOMAIN_ID_MAX 15
29 #define HM_PR_SILK_BLOCKAWARE_OPS 0x534b4241
30 #define BLOCKAWARE_SUBOPS_INIT 0x1
31 #define BLOCKAWARE_SUBOPS_REG 0x2
32 #define BLOCKAWARE_SUBOPS_UNREG 0x3
33 #define BLOCKAWARE_SUBOPS_WAIT 0x4
34 #define BLOCKAWARE_SUBOPS_WAKE 0x5
35 #define BLOCKAWARE_SUBOPS_MONITORFD 0x6
36
37 struct BlockawareDomainInfo {
38 unsigned int nrRunning;
39 unsigned int nrSleeping;
40 unsigned int nrBlocked;
41 };
42 struct BlockawareDomainInfoArea {
43 struct BlockawareDomainInfo localinfo[BLOCKAWARE_DOMAIN_ID_MAX + 1];
44 struct BlockawareDomainInfo globalinfo;
45 };
46 struct BlockawareWatermark {
47 unsigned int low;
48 unsigned int high;
49 };
50 struct BlockawareWakeupCond {
51 struct BlockawareWatermark local[BLOCKAWARE_DOMAIN_ID_MAX + 1];
52 struct BlockawareWatermark global;
53 bool check_ahead;
54 };
55 struct BlockawareKinfoPageS {
56 uint32_t seq;
57 struct BlockawareDomainInfoArea infoArea;
58 };
59
60 static inline int BlockawareInit(unsigned long *keyPtr);
61 static inline int BlockawareRegister(unsigned int domain);
62 static inline int BlockawareUnregister(void);
63 static inline int BlockawareLoadSnapshot(unsigned long key, struct BlockawareDomainInfoArea *infoArea);
64 static inline int BlockawareEnterSleeping(void);
65 static inline int BlockawareLeaveSleeping(void);
66 static inline int BlockawareWaitCond(struct BlockawareWakeupCond *cond);
67 static inline int BlockawareWake(void);
68 static inline int BlockawareMonitorfd(int fd, struct BlockawareWakeupCond *cond);
69
70 #ifdef __aarch64__
CpuRelax(void)71 static inline void CpuRelax(void)
72 {
73 asm volatile("yield" ::: "memory");
74 }
75
SmpRmb(void)76 static inline void SmpRmb(void)
77 {
78 asm volatile("dmb ishld" ::: "memory");
79 }
80
GetTlsPtr(void)81 static inline unsigned long GetTlsPtr(void)
82 {
83 unsigned long tls = 0;
84 asm volatile ("mrs %0, tpidr_el0\n" : "=r" (tls));
85 return tls;
86 }
87
curr_thread_tls_blockaware_slot_of(void)88 static inline unsigned long *curr_thread_tls_blockaware_slot_of(void)
89 {
90 unsigned long tls = GetTlsPtr();
91 unsigned long slot_addr = tls - sizeof (unsigned long) * (2UL + 5UL);
92 return reinterpret_cast<unsigned long *>(slot_addr);
93 }
94
BlockawareEnterSleeping(void)95 static inline int BlockawareEnterSleeping(void)
96 {
97 unsigned long *slot_ptr = curr_thread_tls_blockaware_slot_of();
98 *slot_ptr += 1;
99 return 0;
100 }
101
BlockawareLeaveSleeping(void)102 static inline int BlockawareLeaveSleeping(void)
103 {
104 unsigned long *slot_ptr = curr_thread_tls_blockaware_slot_of();
105 int err = 0;
106
107 if (*slot_ptr == 0) {
108 err = -EINVAL;
109 } else {
110 *slot_ptr -= 1;
111 }
112
113 return err;
114 }
115 #elif defined(__arm__)
116
CpuRelax(void)117 static inline void CpuRelax(void)
118 {
119 asm volatile("yield" ::: "memory");
120 }
121
SmpRmb(void)122 static inline void SmpRmb(void)
123 {
124 asm volatile("dmb ish" ::: "memory");
125 }
126
GetTlsPtr(void)127 static inline unsigned long GetTlsPtr(void)
128 {
129 unsigned long tpid = 0;
130 asm volatile("mrc p15, 0, %0, c13, c0, 3" : "=r"(tpid));
131 return tpid;
132 }
133
curr_thread_tls_blockaware_slot_of(void)134 static inline unsigned long *curr_thread_tls_blockaware_slot_of(void)
135 {
136 unsigned long tls = GetTlsPtr();
137 unsigned long slot_addr = tls - sizeof (unsigned long) * (2UL + 5UL);
138 return (unsigned long *)slot_addr;
139 }
140
BlockawareEnterSleeping(void)141 static inline int BlockawareEnterSleeping(void)
142 {
143 unsigned long *slot_ptr = curr_thread_tls_blockaware_slot_of();
144 *slot_ptr += 1;
145 return 0;
146 }
147
BlockawareLeaveSleeping(void)148 static inline int BlockawareLeaveSleeping(void)
149 {
150 unsigned long *slot_ptr = curr_thread_tls_blockaware_slot_of();
151 int err = 0;
152
153 if (*slot_ptr == 0) {
154 err = -EINVAL;
155 } else {
156 *slot_ptr -= 1;
157 }
158
159 return err;
160 }
161 #else
CpuRelax(void)162 static inline void CpuRelax(void)
163 {
164 }
165
SmpRmb(void)166 static inline void SmpRmb(void)
167 {
168 }
169
GetTlsPtr(void)170 static inline unsigned long GetTlsPtr(void)
171 {
172 return 0;
173 }
174
BlockawareEnterSleeping(void)175 static inline int BlockawareEnterSleeping(void)
176 {
177 return 0;
178 }
179
BlockawareLeaveSleeping(void)180 static inline int BlockawareLeaveSleeping(void)
181 {
182 return 0;
183 }
184 #endif
185
BlockawareInit(unsigned long * keyPtr)186 static inline int BlockawareInit(unsigned long *keyPtr)
187 {
188 int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_INIT, reinterpret_cast<unsigned long>(keyPtr));
189 return (rc == 0) ? 0 : errno;
190 }
191
BlockawareRegister(unsigned int domain)192 static inline int BlockawareRegister(unsigned int domain)
193 {
194 /* Mention that it is kernel's responsibility to init tls slot to 0 */
195 int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_REG, static_cast<unsigned long>(domain));
196 return (rc == 0) ? 0 : errno;
197 }
198
BlockawareUnregister(void)199 static inline int BlockawareUnregister(void)
200 {
201 /* Mention that it is kernel's responsibility to reset tls slot to 0 */
202 int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_UNREG);
203 return (rc == 0) ? 0 : errno;
204 }
205
seqlock_start_read(const uint32_t * seq_ptr)206 static inline uint32_t seqlock_start_read(const uint32_t *seq_ptr)
207 {
208 uint32_t seq;
209 do {
210 seq = *reinterpret_cast<const volatile uint32_t *>(seq_ptr);
211 if ((seq & 1U) == 0U) {
212 break;
213 }
214 CpuRelax();
215 } while (true);
216 SmpRmb();
217 return seq;
218 }
219
seqlock_check(const uint32_t * seq_ptr,uint32_t seq_prev)220 static inline bool seqlock_check(const uint32_t *seq_ptr, uint32_t seq_prev)
221 {
222 SmpRmb();
223 return (*seq_ptr == seq_prev);
224 }
225
BlockawareLoadSnapshot(unsigned long key,struct BlockawareDomainInfoArea * infoArea)226 static inline int BlockawareLoadSnapshot(unsigned long key, struct BlockawareDomainInfoArea *infoArea)
227 {
228 struct BlockawareKinfoPageS *kinfoPage = reinterpret_cast<struct BlockawareKinfoPageS *>(key);
229 uint32_t seq;
230 do {
231 seq = seqlock_start_read(&kinfoPage->seq);
232 memcpy_s(infoArea, sizeof(BlockawareDomainInfoArea), &kinfoPage->infoArea, sizeof(BlockawareDomainInfoArea));
233 } while (!seqlock_check(&kinfoPage->seq, seq));
234 return 0;
235 }
236
BlockawareWaitCond(struct BlockawareWakeupCond * cond)237 static inline int BlockawareWaitCond(struct BlockawareWakeupCond *cond)
238 {
239 int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_WAIT, reinterpret_cast<unsigned long>(cond));
240 return (rc == 0) ? 0 : errno;
241 }
242
BlockawareWake(void)243 static inline int BlockawareWake(void)
244 {
245 int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_WAKE);
246 return (rc == 0) ? 0 : errno;
247 }
248
BlockawareMonitorfd(int fd,struct BlockawareWakeupCond * cond)249 static inline int BlockawareMonitorfd(int fd, struct BlockawareWakeupCond *cond)
250 {
251 int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_MONITORFD,
252 static_cast<unsigned long>(fd), reinterpret_cast<unsigned long>(cond));
253 return (rc == 0) ? rc : -errno;
254 }
255
256
257 #ifdef __cplusplus
258 }
259 #endif
260 #endif /* BLOCKAWARE_H */