1 /*
2  * Copyright (c) 2021 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 
16 #include "cache_manager.h"
17 
18 #include "ace_log.h"
19 #include "securec.h"
20 
21 namespace OHOS {
22 namespace ACELite {
23 /**
24  * This table will decide the cache usage distribution. If one module want to use cache functionality,
25  * it must config here first. The cache manager will assign buffer according to the actual whole
26  * buffer rang, if the buffer supplement is rich, every cache user might be assigned one buffer
27  * rang bigger than its lowest requirement.
28  *
29  * NOTE: the user must not be duplicated in this list
30  */
31 const CacheUnit CacheManager::DEFAULT_CONFIG_TABLE[] = {
32     {USER_LOCALIZATION, 16}, // localization key-value cache, lowest 16KB
33 };
34 
CacheManager()35 CacheManager::CacheManager() : cacheState_(STATE_NORMAL)
36 {
37     configTable_ = DEFAULT_CONFIG_TABLE;
38     configTableLen_ = sizeof(DEFAULT_CONFIG_TABLE) / sizeof(CacheUnit);
39     ResetDistributedInfo();
40 }
41 
GetInstance()42 CacheManager &CacheManager::GetInstance()
43 {
44     static CacheManager cacheManager;
45     return cacheManager;
46 }
47 
ResetDistributedInfo()48 void CacheManager::ResetDistributedInfo()
49 {
50     wholeCacheMemInfo_.cacheStartAddr = 0;
51     wholeCacheMemInfo_.cacheLength = 0;
52     auto ret = memset_s(cacheUnitInfo_, sizeof(CacheMemInfo) * USER_MAX_COUNT,
53         0, sizeof(CacheMemInfo) * USER_MAX_COUNT);
54     if (ret != EOK) {
55         HILOG_ERROR(HILOG_MODULE_ACE, "reset cache info failed");
56     }
57 }
58 
SetConfigTable(const CacheUnit * table,size_t count)59 void CacheManager::SetConfigTable(const CacheUnit *table, size_t count)
60 {
61     if (cacheState_ == STATE_SUCCESS) {
62         // reset
63         cacheState_ = STATE_NORMAL;
64         ResetDistributedInfo();
65     }
66     configTable_ = table;
67     configTableLen_ = count;
68 }
69 
SetupCacheMemInfo(uintptr_t startAddr,size_t length)70 void CacheManager::SetupCacheMemInfo(uintptr_t startAddr, size_t length)
71 {
72     // only can be setup once
73     if (cacheState_ == STATE_SUCCESS) {
74         return;
75     }
76     // try to distribute the whole buffer, and if the buffer length can not meet the lowest requirement, just give up
77     cacheState_ = DistributeCacheRange(startAddr, length);
78     if (cacheState_ != STATE_SUCCESS) {
79         return;
80     }
81     wholeCacheMemInfo_.cacheStartAddr = startAddr;
82     wholeCacheMemInfo_.cacheLength = length;
83 }
84 
PrecheckStatus(uintptr_t startAddr,size_t totalBytes) const85 CacheSetupState CacheManager::PrecheckStatus(uintptr_t startAddr, size_t totalBytes) const
86 {
87     // check basic info
88     if (configTableLen_ == 0 || configTable_ == nullptr) {
89         // no user, return normal as no one cares
90         return STATE_NORMAL;
91     }
92     if (configTableLen_ > CACHE_USER_MAX_COUNT) {
93         HILOG_ERROR(HILOG_MODULE_ACE, "too many user!");
94         return STATE_FAILURE;
95     }
96     if (startAddr == 0 || totalBytes == 0) {
97         HILOG_ERROR(HILOG_MODULE_ACE, "error cache buffer rang!");
98         return STATE_FAILURE;
99     }
100 
101     // calculate the lowest requirement
102     size_t lowestRequiredKBs = 0;
103     size_t index = 0;
104     while (index < configTableLen_) {
105         lowestRequiredKBs = lowestRequiredKBs + configTable_[index].minLength_;
106         index++;
107     }
108     if (lowestRequiredKBs > CACHE_REQUIREMENT_MAX_KBS) {
109         HILOG_ERROR(HILOG_MODULE_ACE, "the requirement KBs is too much!");
110         return STATE_FAILURE;
111     }
112 
113     constexpr uint16_t bytesOneKB = 1024;
114     // convert the required KBs to bytes
115     size_t totalRequiredBytes = lowestRequiredKBs * bytesOneKB;
116     // consider the magic number length for each unit
117     totalRequiredBytes += (configTableLen_ * MAGIC_NUMBER_TOTAL_LENGTH_FOR_EACH);
118     if (totalRequiredBytes > totalBytes) {
119         // the given buffer is less than the lowest requirement
120         HILOG_ERROR(HILOG_MODULE_ACE, "the cache buffer length can not meet the lowest requirement!");
121         return STATE_FAILURE;
122     }
123     return STATE_SUCCESS;
124 }
125 
DistributeCacheRange(uintptr_t startAddr,size_t totalBytes)126 CacheSetupState CacheManager::DistributeCacheRange(uintptr_t startAddr, size_t totalBytes)
127 {
128     CacheSetupState setupResult = PrecheckStatus(startAddr, totalBytes);
129     if (setupResult != STATE_SUCCESS) {
130         return setupResult;
131     }
132 
133     size_t index = 0;
134     constexpr uint16_t bytesOneKB = 1024;
135     size_t offset = 0;
136     while (index < configTableLen_) {
137         size_t requestBytes = (configTable_[index].minLength_ * bytesOneKB) + MAGIC_NUMBER_TOTAL_LENGTH_FOR_EACH;
138         uintptr_t startPos = startAddr + offset;
139         cacheUnitInfo_[configTable_[index].cacheUser_].cacheStartAddr = startPos;
140         cacheUnitInfo_[configTable_[index].cacheUser_].cacheLength = requestBytes;
141         // set magic number
142         *(reinterpret_cast<uint32_t *>(startPos)) = CACHE_MEM_MAGIC_NUMBER;
143         *(reinterpret_cast<uint32_t *>(startPos + requestBytes - MAGIC_NUMBER_LENGTH)) = CACHE_MEM_MAGIC_NUMBER;
144         offset = offset + requestBytes;
145         index++;
146     }
147     return STATE_SUCCESS;
148 }
149 
IsEnvReady(CacheUser user) const150 bool CacheManager::IsEnvReady(CacheUser user) const
151 {
152     if (cacheState_ != STATE_SUCCESS) {
153         return false;
154     }
155     return ((user < USER_MAX_COUNT) && (cacheUnitInfo_[user].cacheStartAddr != 0));
156 }
157 
GetCacheBufAddress(CacheUser user) const158 uintptr_t CacheManager::GetCacheBufAddress(CacheUser user) const
159 {
160     if (!IsEnvReady(user)) {
161         return 0;
162     }
163     return cacheUnitInfo_[user].cacheStartAddr + MAGIC_NUMBER_LENGTH;
164 }
165 
GetCacheBufLength(CacheUser user) const166 size_t CacheManager::GetCacheBufLength(CacheUser user) const
167 {
168     if (!IsEnvReady(user)) {
169         return 0;
170     }
171     return cacheUnitInfo_[user].cacheLength - MAGIC_NUMBER_TOTAL_LENGTH_FOR_EACH;
172 }
173 
IsCacheOverflow(CacheUser user) const174 bool CacheManager::IsCacheOverflow(CacheUser user) const
175 {
176     if (!IsEnvReady(user)) {
177         return false;
178     }
179     // get head and tail magic number
180     uint32_t *bufferHead = reinterpret_cast<uint32_t *>(cacheUnitInfo_[user].cacheStartAddr);
181     uint32_t headMagicNumber = reinterpret_cast<uint32_t>(*(bufferHead));
182     uint32_t *bufferTail = reinterpret_cast<uint32_t *>(cacheUnitInfo_[user].cacheStartAddr +
183                                                         cacheUnitInfo_[user].cacheLength - MAGIC_NUMBER_LENGTH);
184     uint32_t tailMagicNumber = reinterpret_cast<uint32_t>(*(bufferTail));
185     // if the head magic number was over write, it means someone else overflow this area
186     if (headMagicNumber != CACHE_MEM_MAGIC_NUMBER) {
187         HILOG_ERROR(HILOG_MODULE_ACE, "the cache buffer[%{public}d] was overflown by someone else?", user);
188         return true;
189     }
190     // if the tail magic number was over write, it means the user itself overflow this area
191     if (tailMagicNumber != CACHE_MEM_MAGIC_NUMBER) {
192         HILOG_ERROR(HILOG_MODULE_ACE, "the cache buffer[%{public}d] was overflown by self?", user);
193         return true;
194     }
195     return false;
196 }
197 
IsWholeCacheHealthy() const198 bool CacheManager::IsWholeCacheHealthy() const
199 {
200     if (cacheState_ != STATE_SUCCESS) {
201         return false;
202     }
203     for (int i = 0; i < USER_MAX_COUNT; i++) {
204         if (IsCacheOverflow(CacheUser(i))) {
205             return false;
206         }
207     }
208     return true;
209 }
210 } // namespace ACELite
211 } // namespace OHOS
212