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