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 */