1484543d1Sopenharmony_ci/*
2484543d1Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
3484543d1Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
4484543d1Sopenharmony_ci * you may not use this file except in compliance with the License.
5484543d1Sopenharmony_ci * You may obtain a copy of the License at
6484543d1Sopenharmony_ci *
7484543d1Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
8484543d1Sopenharmony_ci *
9484543d1Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
10484543d1Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
11484543d1Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12484543d1Sopenharmony_ci * See the License for the specific language governing permissions and
13484543d1Sopenharmony_ci * limitations under the License.
14484543d1Sopenharmony_ci */
15484543d1Sopenharmony_ci#ifndef BLOCKAWARE_H
16484543d1Sopenharmony_ci#define BLOCKAWARE_H
17484543d1Sopenharmony_ci
18484543d1Sopenharmony_ci#include <securec.h>
19484543d1Sopenharmony_ci#include <cstdio>
20484543d1Sopenharmony_ci#include <cstring>
21484543d1Sopenharmony_ci#include <sys/prctl.h>
22484543d1Sopenharmony_ci#include <cerrno>
23484543d1Sopenharmony_ci
24484543d1Sopenharmony_ci#ifdef __cplusplus
25484543d1Sopenharmony_ciextern "C" {
26484543d1Sopenharmony_ci#endif
27484543d1Sopenharmony_ci
28484543d1Sopenharmony_ci#define BLOCKAWARE_DOMAIN_ID_MAX     15
29484543d1Sopenharmony_ci#define HM_PR_SILK_BLOCKAWARE_OPS    0x534b4241
30484543d1Sopenharmony_ci#define BLOCKAWARE_SUBOPS_INIT       0x1
31484543d1Sopenharmony_ci#define BLOCKAWARE_SUBOPS_REG        0x2
32484543d1Sopenharmony_ci#define BLOCKAWARE_SUBOPS_UNREG      0x3
33484543d1Sopenharmony_ci#define BLOCKAWARE_SUBOPS_WAIT       0x4
34484543d1Sopenharmony_ci#define BLOCKAWARE_SUBOPS_WAKE       0x5
35484543d1Sopenharmony_ci#define BLOCKAWARE_SUBOPS_MONITORFD  0X6
36484543d1Sopenharmony_ci
37484543d1Sopenharmony_cistruct BlockawareDomainInfo {
38484543d1Sopenharmony_ci    unsigned int nrRunning;
39484543d1Sopenharmony_ci    unsigned int nrSleeping;
40484543d1Sopenharmony_ci    unsigned int nrBlocked;
41484543d1Sopenharmony_ci};
42484543d1Sopenharmony_cistruct BlockawareDomainInfoArea {
43484543d1Sopenharmony_ci    struct BlockawareDomainInfo localinfo[BLOCKAWARE_DOMAIN_ID_MAX + 1];
44484543d1Sopenharmony_ci    struct BlockawareDomainInfo globalinfo;
45484543d1Sopenharmony_ci};
46484543d1Sopenharmony_cistruct BlockawareWatermark {
47484543d1Sopenharmony_ci    unsigned int low;
48484543d1Sopenharmony_ci    unsigned int high;
49484543d1Sopenharmony_ci};
50484543d1Sopenharmony_cistruct BlockawareWakeupCond {
51484543d1Sopenharmony_ci    struct BlockawareWatermark local[BLOCKAWARE_DOMAIN_ID_MAX + 1];
52484543d1Sopenharmony_ci    struct BlockawareWatermark global;
53484543d1Sopenharmony_ci    bool check_ahead;
54484543d1Sopenharmony_ci};
55484543d1Sopenharmony_cistruct BlockawareKinfoPageS {
56484543d1Sopenharmony_ci    uint32_t seq;
57484543d1Sopenharmony_ci    struct BlockawareDomainInfoArea infoArea;
58484543d1Sopenharmony_ci};
59484543d1Sopenharmony_ci
60484543d1Sopenharmony_cistatic inline int BlockawareInit(unsigned long *keyPtr);
61484543d1Sopenharmony_cistatic inline int BlockawareRegister(unsigned int domain);
62484543d1Sopenharmony_cistatic inline int BlockawareUnregister(void);
63484543d1Sopenharmony_cistatic inline int BlockawareLoadSnapshot(unsigned long key, struct BlockawareDomainInfoArea *infoArea);
64484543d1Sopenharmony_cistatic inline int BlockawareEnterSleeping(void);
65484543d1Sopenharmony_cistatic inline int BlockawareLeaveSleeping(void);
66484543d1Sopenharmony_cistatic inline int BlockawareWaitCond(struct BlockawareWakeupCond *cond);
67484543d1Sopenharmony_cistatic inline int BlockawareWake(void);
68484543d1Sopenharmony_cistatic inline int BlockawareMonitorfd(int fd, struct BlockawareWakeupCond *cond);
69484543d1Sopenharmony_ci
70484543d1Sopenharmony_ci#ifdef __aarch64__
71484543d1Sopenharmony_cistatic inline void CpuRelax(void)
72484543d1Sopenharmony_ci{
73484543d1Sopenharmony_ci    asm volatile("yield" ::: "memory");
74484543d1Sopenharmony_ci}
75484543d1Sopenharmony_ci
76484543d1Sopenharmony_cistatic inline void SmpRmb(void)
77484543d1Sopenharmony_ci{
78484543d1Sopenharmony_ci    asm volatile("dmb ishld" ::: "memory");
79484543d1Sopenharmony_ci}
80484543d1Sopenharmony_ci
81484543d1Sopenharmony_cistatic inline unsigned long GetTlsPtr(void)
82484543d1Sopenharmony_ci{
83484543d1Sopenharmony_ci    unsigned long tls = 0;
84484543d1Sopenharmony_ci    asm volatile ("mrs %0, tpidr_el0\n" : "=r" (tls));
85484543d1Sopenharmony_ci    return tls;
86484543d1Sopenharmony_ci}
87484543d1Sopenharmony_ci
88484543d1Sopenharmony_cistatic inline unsigned long *curr_thread_tls_blockaware_slot_of(void)
89484543d1Sopenharmony_ci{
90484543d1Sopenharmony_ci    unsigned long tls = GetTlsPtr();
91484543d1Sopenharmony_ci    unsigned long slot_addr = tls - sizeof (unsigned long) * (2UL + 5UL);
92484543d1Sopenharmony_ci    return reinterpret_cast<unsigned long *>(slot_addr);
93484543d1Sopenharmony_ci}
94484543d1Sopenharmony_ci
95484543d1Sopenharmony_cistatic inline int BlockawareEnterSleeping(void)
96484543d1Sopenharmony_ci{
97484543d1Sopenharmony_ci    unsigned long *slot_ptr = curr_thread_tls_blockaware_slot_of();
98484543d1Sopenharmony_ci    *slot_ptr += 1;
99484543d1Sopenharmony_ci    return 0;
100484543d1Sopenharmony_ci}
101484543d1Sopenharmony_ci
102484543d1Sopenharmony_cistatic inline int BlockawareLeaveSleeping(void)
103484543d1Sopenharmony_ci{
104484543d1Sopenharmony_ci    unsigned long *slot_ptr = curr_thread_tls_blockaware_slot_of();
105484543d1Sopenharmony_ci    int err = 0;
106484543d1Sopenharmony_ci
107484543d1Sopenharmony_ci    if (*slot_ptr == 0) {
108484543d1Sopenharmony_ci        err = -EINVAL;
109484543d1Sopenharmony_ci    } else {
110484543d1Sopenharmony_ci        *slot_ptr -= 1;
111484543d1Sopenharmony_ci    }
112484543d1Sopenharmony_ci
113484543d1Sopenharmony_ci    return err;
114484543d1Sopenharmony_ci}
115484543d1Sopenharmony_ci#elif defined(__arm__)
116484543d1Sopenharmony_ci
117484543d1Sopenharmony_cistatic inline void CpuRelax(void)
118484543d1Sopenharmony_ci{
119484543d1Sopenharmony_ci    asm volatile("yield" ::: "memory");
120484543d1Sopenharmony_ci}
121484543d1Sopenharmony_ci
122484543d1Sopenharmony_cistatic inline void SmpRmb(void)
123484543d1Sopenharmony_ci{
124484543d1Sopenharmony_ci    asm volatile("dmb ish" ::: "memory");
125484543d1Sopenharmony_ci}
126484543d1Sopenharmony_ci
127484543d1Sopenharmony_cistatic inline unsigned long GetTlsPtr(void)
128484543d1Sopenharmony_ci{
129484543d1Sopenharmony_ci    unsigned long tpid = 0;
130484543d1Sopenharmony_ci    asm volatile("mrc p15, 0, %0, c13, c0, 3" : "=r"(tpid));
131484543d1Sopenharmony_ci    return tpid;
132484543d1Sopenharmony_ci}
133484543d1Sopenharmony_ci
134484543d1Sopenharmony_cistatic inline unsigned long *curr_thread_tls_blockaware_slot_of(void)
135484543d1Sopenharmony_ci{
136484543d1Sopenharmony_ci    unsigned long tls = GetTlsPtr();
137484543d1Sopenharmony_ci    unsigned long slot_addr = tls - sizeof (unsigned long) * (2UL + 5UL);
138484543d1Sopenharmony_ci    return (unsigned long *)slot_addr;
139484543d1Sopenharmony_ci}
140484543d1Sopenharmony_ci
141484543d1Sopenharmony_cistatic inline int BlockawareEnterSleeping(void)
142484543d1Sopenharmony_ci{
143484543d1Sopenharmony_ci    unsigned long *slot_ptr = curr_thread_tls_blockaware_slot_of();
144484543d1Sopenharmony_ci    *slot_ptr += 1;
145484543d1Sopenharmony_ci    return 0;
146484543d1Sopenharmony_ci}
147484543d1Sopenharmony_ci
148484543d1Sopenharmony_cistatic inline int BlockawareLeaveSleeping(void)
149484543d1Sopenharmony_ci{
150484543d1Sopenharmony_ci    unsigned long *slot_ptr = curr_thread_tls_blockaware_slot_of();
151484543d1Sopenharmony_ci    int err = 0;
152484543d1Sopenharmony_ci
153484543d1Sopenharmony_ci    if (*slot_ptr == 0) {
154484543d1Sopenharmony_ci        err = -EINVAL;
155484543d1Sopenharmony_ci    } else {
156484543d1Sopenharmony_ci        *slot_ptr -= 1;
157484543d1Sopenharmony_ci    }
158484543d1Sopenharmony_ci
159484543d1Sopenharmony_ci    return err;
160484543d1Sopenharmony_ci}
161484543d1Sopenharmony_ci#else
162484543d1Sopenharmony_cistatic inline void CpuRelax(void)
163484543d1Sopenharmony_ci{
164484543d1Sopenharmony_ci}
165484543d1Sopenharmony_ci
166484543d1Sopenharmony_cistatic inline void SmpRmb(void)
167484543d1Sopenharmony_ci{
168484543d1Sopenharmony_ci}
169484543d1Sopenharmony_ci
170484543d1Sopenharmony_cistatic inline unsigned long GetTlsPtr(void)
171484543d1Sopenharmony_ci{
172484543d1Sopenharmony_ci    return 0;
173484543d1Sopenharmony_ci}
174484543d1Sopenharmony_ci
175484543d1Sopenharmony_cistatic inline int BlockawareEnterSleeping(void)
176484543d1Sopenharmony_ci{
177484543d1Sopenharmony_ci    return 0;
178484543d1Sopenharmony_ci}
179484543d1Sopenharmony_ci
180484543d1Sopenharmony_cistatic inline int BlockawareLeaveSleeping(void)
181484543d1Sopenharmony_ci{
182484543d1Sopenharmony_ci    return 0;
183484543d1Sopenharmony_ci}
184484543d1Sopenharmony_ci#endif
185484543d1Sopenharmony_ci
186484543d1Sopenharmony_cistatic inline int BlockawareInit(unsigned long *keyPtr)
187484543d1Sopenharmony_ci{
188484543d1Sopenharmony_ci    int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_INIT, reinterpret_cast<unsigned long>(keyPtr));
189484543d1Sopenharmony_ci    return (rc == 0) ? 0 : errno;
190484543d1Sopenharmony_ci}
191484543d1Sopenharmony_ci
192484543d1Sopenharmony_cistatic inline int BlockawareRegister(unsigned int domain)
193484543d1Sopenharmony_ci{
194484543d1Sopenharmony_ci    /* Mention that it is kernel's responsibility to init tls slot to 0 */
195484543d1Sopenharmony_ci    int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_REG, static_cast<unsigned long>(domain));
196484543d1Sopenharmony_ci    return (rc == 0) ? 0 : errno;
197484543d1Sopenharmony_ci}
198484543d1Sopenharmony_ci
199484543d1Sopenharmony_cistatic inline int BlockawareUnregister(void)
200484543d1Sopenharmony_ci{
201484543d1Sopenharmony_ci    /* Mention that it is kernel's responsibility to reset tls slot to 0 */
202484543d1Sopenharmony_ci    int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_UNREG);
203484543d1Sopenharmony_ci    return (rc == 0) ? 0 : errno;
204484543d1Sopenharmony_ci}
205484543d1Sopenharmony_ci
206484543d1Sopenharmony_cistatic inline uint32_t seqlock_start_read(const uint32_t *seq_ptr)
207484543d1Sopenharmony_ci{
208484543d1Sopenharmony_ci    uint32_t seq;
209484543d1Sopenharmony_ci    do {
210484543d1Sopenharmony_ci        seq = *reinterpret_cast<const volatile uint32_t *>(seq_ptr);
211484543d1Sopenharmony_ci        if ((seq & 1U) == 0U) {
212484543d1Sopenharmony_ci            break;
213484543d1Sopenharmony_ci        }
214484543d1Sopenharmony_ci        CpuRelax();
215484543d1Sopenharmony_ci    } while (true);
216484543d1Sopenharmony_ci    SmpRmb();
217484543d1Sopenharmony_ci    return seq;
218484543d1Sopenharmony_ci}
219484543d1Sopenharmony_ci
220484543d1Sopenharmony_cistatic inline bool seqlock_check(const uint32_t *seq_ptr, uint32_t seq_prev)
221484543d1Sopenharmony_ci{
222484543d1Sopenharmony_ci    SmpRmb();
223484543d1Sopenharmony_ci    return (*seq_ptr == seq_prev);
224484543d1Sopenharmony_ci}
225484543d1Sopenharmony_ci
226484543d1Sopenharmony_cistatic inline int BlockawareLoadSnapshot(unsigned long key, struct BlockawareDomainInfoArea *infoArea)
227484543d1Sopenharmony_ci{
228484543d1Sopenharmony_ci    struct BlockawareKinfoPageS *kinfoPage = reinterpret_cast<struct BlockawareKinfoPageS *>(key);
229484543d1Sopenharmony_ci    uint32_t seq;
230484543d1Sopenharmony_ci    do {
231484543d1Sopenharmony_ci        seq = seqlock_start_read(&kinfoPage->seq);
232484543d1Sopenharmony_ci        memcpy_s(infoArea, sizeof(BlockawareDomainInfoArea), &kinfoPage->infoArea, sizeof(BlockawareDomainInfoArea));
233484543d1Sopenharmony_ci    } while (!seqlock_check(&kinfoPage->seq, seq));
234484543d1Sopenharmony_ci    return 0;
235484543d1Sopenharmony_ci}
236484543d1Sopenharmony_ci
237484543d1Sopenharmony_cistatic inline int BlockawareWaitCond(struct BlockawareWakeupCond *cond)
238484543d1Sopenharmony_ci{
239484543d1Sopenharmony_ci    int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_WAIT, reinterpret_cast<unsigned long>(cond));
240484543d1Sopenharmony_ci    return (rc == 0) ? 0 : errno;
241484543d1Sopenharmony_ci}
242484543d1Sopenharmony_ci
243484543d1Sopenharmony_cistatic inline int BlockawareWake(void)
244484543d1Sopenharmony_ci{
245484543d1Sopenharmony_ci    int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_WAKE);
246484543d1Sopenharmony_ci    return (rc == 0) ? 0 : errno;
247484543d1Sopenharmony_ci}
248484543d1Sopenharmony_ci
249484543d1Sopenharmony_cistatic inline int BlockawareMonitorfd(int fd, struct BlockawareWakeupCond *cond)
250484543d1Sopenharmony_ci{
251484543d1Sopenharmony_ci    int rc = prctl(HM_PR_SILK_BLOCKAWARE_OPS, BLOCKAWARE_SUBOPS_MONITORFD,
252484543d1Sopenharmony_ci        static_cast<unsigned long>(fd), reinterpret_cast<unsigned long>(cond));
253484543d1Sopenharmony_ci    return (rc >= 0) ? rc : -errno;
254484543d1Sopenharmony_ci}
255484543d1Sopenharmony_ci
256484543d1Sopenharmony_ci#ifdef __cplusplus
257484543d1Sopenharmony_ci}
258484543d1Sopenharmony_ci#endif
259484543d1Sopenharmony_ci#endif /* BLOCKAWARE_H */