1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
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 * Description: offline log file saved to the storage
15 */
16
17 #include "log_file.h"
18 #include "errcode.h"
19 #include "securec.h"
20 #include "stdbool.h"
21 #include "soc_osal.h"
22 #include "common_def.h"
23 #include "dfx_adapt_layer.h"
24 #include "debug_print.h"
25 #include "log_file_common.h"
26 #include "log_file_flash.h"
27
28 #define INVAID_INDEX_ID 0xFFFFFFFF
29
30 #if (CONFIG_DFX_SUPPORT_OFFLINE_LOG_FILE == YES)
31 #if (CONFIG_DFX_SUPPORT_FILE_SYSTEM == DFX_NO)
32
logfile_get_flash_op_type(store_service_t type)33 STATIC dfx_flash_op_type_t logfile_get_flash_op_type(store_service_t type)
34 {
35 dfx_flash_op_type_t flash_op_type;
36 switch (type) {
37 case STORE_DIAG:
38 flash_op_type = FLASH_OP_TYPE_LOG_FILE;
39 break;
40 default:
41 flash_op_type = FLASH_OP_TYPE_MAX;
42 break;
43 }
44 return flash_op_type;
45 }
46
logfile_check_record_head_null(store_record_info_t * record_header,uint32_t start_pos)47 STATIC uint32_t logfile_check_record_head_null(store_record_info_t *record_header, uint32_t start_pos)
48 {
49 uint8_t i;
50 uint8_t* record_data = (uint8_t *)(uintptr_t)record_header;
51 for (i = 0; i < sizeof(store_record_info_t); i++) {
52 if (record_data[i] != 0xFF) {
53 break;
54 }
55 }
56
57 /* 如当前位置数据为全FF, 直接返回记录头长度 */
58 if (i == (uint8_t)sizeof(store_record_info_t)) {
59 return (uint32_t)sizeof(store_record_info_t);
60 }
61
62 uint32_t remain_len = FLASH_SECTOR_SIZE - (start_pos % FLASH_SECTOR_SIZE);
63
64 /* 剩余长度大于记录头长度,即当前位置不在flash页的结尾部分,则直接返回0 */
65 if (remain_len > sizeof(store_record_info_t)) {
66 return 0;
67 }
68
69 /* 当前位置在flash页的结尾部分,则计算从当前位置至flash页的结尾是否全FF,如果是则返回长度,否则返回0 */
70 for (i = 0; i < remain_len; i++) {
71 if (record_data[i] != 0xFF) {
72 break;
73 }
74 }
75
76 if (i == remain_len) {
77 return remain_len;
78 }
79 return 0;
80 }
81
flash_erase_older_records(const store_file_info_t * file_info,uint32_t data_len)82 STATIC errcode_t flash_erase_older_records(const store_file_info_t *file_info, uint32_t data_len)
83 {
84 uint32_t space_left = file_info->flash_cur_pos % FLASH_SECTOR_SIZE == 0 ? 0 :
85 FLASH_SECTOR_SIZE - file_info->flash_cur_pos % FLASH_SECTOR_SIZE;
86 uint32_t next_sector_pos = file_info->flash_cur_pos + space_left;
87
88 while (space_left < data_len) {
89 /* 获取下一个sector的位置 */
90 if (next_sector_pos == file_info->file_cfg.file_size) {
91 next_sector_pos = 0;
92 }
93 dfx_flash_erase(logfile_get_flash_op_type(file_info->type), next_sector_pos, FLASH_SECTOR_SIZE);
94
95 next_sector_pos += FLASH_SECTOR_SIZE;
96 space_left += FLASH_SECTOR_SIZE;
97 }
98
99 return ERRCODE_SUCC;
100 }
101
write_cache_to_flash(store_file_info_t * file_info,uint8_t * data,uint32_t data_len)102 STATIC errcode_t write_cache_to_flash(store_file_info_t *file_info, uint8_t *data, uint32_t data_len)
103 {
104 uint32_t flash_left = file_info->file_cfg.file_size - file_info->flash_cur_pos;
105 flash_erase_older_records(file_info, data_len);
106
107 dfx_flash_op_type_t flash_op_type = logfile_get_flash_op_type(file_info->type);
108 if (data_len > flash_left) {
109 uint32_t data_left_len = data_len - flash_left;
110 dfx_flash_write(flash_op_type, file_info->flash_cur_pos, data, flash_left, 0);
111 dfx_flash_write(flash_op_type, 0, (uint8_t *)&(file_info->file_head), sizeof(store_file_head_t), 0);
112 dfx_flash_write(flash_op_type, sizeof(store_file_head_t), data + flash_left, data_left_len, 0);
113 file_info->flash_cur_pos = (uint32_t)sizeof(store_file_head_t) + data_left_len;
114 } else {
115 dfx_flash_write(flash_op_type, file_info->flash_cur_pos, data, data_len, 0);
116 file_info->flash_cur_pos += data_len;
117 }
118
119 return ERRCODE_SUCC;
120 }
121
logfile_write_cache_to_flash(store_file_info_t * file_info)122 errcode_t logfile_write_cache_to_flash(store_file_info_t *file_info)
123 {
124 store_cache_t *cache = file_info->cache;
125 uint8_t *read_data;
126 int32_t read_len;
127 uint32_t tmp_pos = 0;
128
129 /* 读取 cache_write_pos 的瞬时值 */
130 tmp_pos = cache->cache_write_pos;
131
132 /* cache中没有新数据,直接退出 */
133 if (tmp_pos == cache->cache_read_pos) {
134 return ERRCODE_SUCC;
135 }
136
137 read_data = (uint8_t *)cache->data + cache->cache_read_pos;
138 osal_mutex *file_write_mutex = &(logfile_get_manage()->file_write_mutex);
139 osal_mutex_lock(file_write_mutex);
140 if (tmp_pos > cache->cache_read_pos) {
141 read_len = (int32_t)(tmp_pos - cache->cache_read_pos);
142 write_cache_to_flash(file_info, read_data, (uint32_t)read_len);
143 } else {
144 read_len = (int32_t)(cache->cache_size - cache->cache_read_pos);
145 write_cache_to_flash(file_info, read_data, (uint32_t)read_len);
146 write_cache_to_flash(file_info, (uint8_t *)cache->data, tmp_pos);
147 }
148
149 cache->cache_read_pos = tmp_pos;
150 osal_mutex_unlock(file_write_mutex);
151 return ERRCODE_SUCC;
152 }
153
logfile_flash_without_head(store_file_info_t * file_info)154 STATIC bool logfile_flash_without_head(store_file_info_t *file_info)
155 {
156 store_file_head_t *read_flash_head = (store_file_head_t *)dfx_malloc(0, sizeof(store_file_head_t));
157 if (read_flash_head == NULL) {
158 return false;
159 }
160
161 dfx_flash_op_type_t flash_op_type = logfile_get_flash_op_type(file_info->type);
162 dfx_flash_read(flash_op_type, 0, (uint8_t *)read_flash_head, sizeof(store_file_head_t));
163
164 logfile_init_file_head(file_info);
165 if (read_flash_head->start_flag != FILE_HEAD_START_FLAG) {
166 dfx_flash_erase(flash_op_type, 0, FLASH_SECTOR_SIZE);
167 dfx_flash_write(flash_op_type, 0, (const uint8_t *)&file_info->file_head, sizeof(store_file_head_t), 0);
168 dfx_free(0, read_flash_head);
169 file_info->index = 0;
170 file_info->flash_cur_pos = (uint32_t)sizeof(store_file_head_t);
171 return true;
172 }
173
174 dfx_free(0, read_flash_head);
175 return false;
176 }
177
logfile_read_record_from_flash(store_file_info_t * file_info,store_record_info_t * record_info,uint32_t start_addr)178 STATIC void logfile_read_record_from_flash(store_file_info_t *file_info, store_record_info_t *record_info,
179 uint32_t start_addr)
180 {
181 if (start_addr > file_info->file_cfg.file_size) {
182 return;
183 }
184
185 memset_s(record_info, sizeof(store_record_info_t), 0, sizeof(store_record_info_t));
186 dfx_flash_op_type_t flash_op_type = logfile_get_flash_op_type(file_info->type);
187 if (start_addr + (uint32_t)sizeof(store_record_info_t) > file_info->file_cfg.file_size) {
188 uint32_t tmp_len = file_info->file_cfg.file_size - start_addr;
189 dfx_flash_read(flash_op_type, start_addr, (uint8_t *)record_info, tmp_len);
190 dfx_flash_read(flash_op_type, sizeof(store_file_head_t),
191 (uint8_t *)record_info + tmp_len, (sizeof(store_record_info_t) - tmp_len));
192 } else {
193 dfx_flash_read(flash_op_type, start_addr, (uint8_t *)record_info, sizeof(store_record_info_t));
194 }
195 }
196
get_circled_cur_pos(store_file_info_t * file_info,uint32_t pos_in)197 STATIC uint32_t get_circled_cur_pos(store_file_info_t *file_info, uint32_t pos_in)
198 {
199 uint32_t pos_out;
200
201 if (pos_in < file_info->file_cfg.file_size) {
202 pos_out = pos_in;
203 } else {
204 pos_out = pos_in - file_info->file_cfg.file_size + (uint32_t)sizeof(store_file_head_t);
205 }
206 return pos_out;
207 }
208
logfile_is_index_continuous(uint32_t last_index,uint32_t cur_index)209 STATIC bool logfile_is_index_continuous(uint32_t last_index, uint32_t cur_index)
210 {
211 /*
212 * 比较当前记录与上一条记录的index,下列三种情况说明index是连续的:
213 * 1、当前记录是遍历的第一条记录
214 * 2、当前记录index上一条记录大1
215 * 3、当前记录的index发生翻转(当前是0,上一条是65535)
216 */
217 if ((last_index == 0) ||
218 (cur_index == last_index + 1) ||
219 (cur_index == 0 && last_index == MAX_INDEX_NUM)) {
220 return true;
221 }
222 return false;
223 }
224
logfile_flash_prepare(store_file_info_t * file_info)225 errcode_t logfile_flash_prepare(store_file_info_t *file_info)
226 {
227 store_record_info_t record_info = { 0 };
228 uint32_t first_jump_pos = 0;
229 uint32_t first_jump_index = INVAID_INDEX_ID;
230 uint32_t last_index = 0;
231 uint32_t i;
232
233 /* 如果flash中没有有效的文件头,即第一次打开logfile,直接返回 */
234 if (logfile_flash_without_head(file_info)) {
235 return ERRCODE_SUCC;
236 }
237
238 file_info->index = INVAID_INDEX_ID;
239
240 /* 遍历flash区域,找到最新的写入地址 */
241 for (i = (uint32_t)sizeof(store_file_head_t); i < file_info->file_cfg.file_size;) {
242 /* 从头开始遍历,从flash读取数据 */
243 logfile_read_record_from_flash(file_info, &record_info, i);
244
245 /* 检查当前位置是否为全FF */
246 uint32_t null_char_num = logfile_check_record_head_null(&record_info, i);
247 if (null_char_num == sizeof(store_record_info_t)) {
248 /* 找到记录头全部为FF的数据,结束遍历,此处即为最新记录的位置 */
249 file_info->index = (last_index == 0) ? 0 : (last_index + 1);
250 file_info->flash_cur_pos = i;
251 break;
252 } else if (null_char_num > 0 && null_char_num < sizeof(store_record_info_t)) {
253 /* 找到页的结尾处有FF,但长度不够记录头的长度 */
254 file_info->index = (last_index == 0) ? 0 : (last_index + 1);
255 file_info->flash_cur_pos = i;
256 i += null_char_num;
257 continue;
258 }
259
260 /* 检查当前位置是否是一个有效的数据头 */
261 if (logfile_check_record_head_valid(&record_info) != true) {
262 i++; /* 如果不是有效记录头,移至下一个字节 */
263 continue;
264 }
265
266 if (!logfile_is_index_continuous(last_index, record_info.index)) {
267 if (file_info->index != INVAID_INDEX_ID) {
268 /* 在flash页结尾找到FF的情况下,找到index不连续的情况,结束遍历,此处即为最新记录的位置 */
269 break;
270 } else if (first_jump_index == INVAID_INDEX_ID) {
271 /* 在未找到全FF数据的情况下,记录第一个index不连续的位置 */
272 first_jump_index = last_index;
273 first_jump_pos = i;
274 }
275 }
276
277 last_index = record_info.index;
278 i += record_info.len;
279 }
280
281 if ((file_info->index == INVAID_INDEX_ID) && (first_jump_index != INVAID_INDEX_ID)) {
282 file_info->index = (first_jump_index == 0) ? 0 : (first_jump_index + 1);
283 file_info->flash_cur_pos = first_jump_pos;
284 } else if ((file_info->index == INVAID_INDEX_ID) && (first_jump_index == INVAID_INDEX_ID)) {
285 file_info->index = (last_index == 0) ? 0 : (last_index + 1);
286 file_info->flash_cur_pos = get_circled_cur_pos(file_info, i);
287 }
288
289 dfx_log_info("Found flash_cur_pos = 0x%x last index = 0x%x\r\n", file_info->flash_cur_pos, file_info->index);
290 return ERRCODE_SUCC;
291 }
292
logfile_flash_erase(store_service_t service_type,const store_file_cfg_t * cfg)293 errcode_t logfile_flash_erase(store_service_t service_type, const store_file_cfg_t *cfg)
294 {
295 return dfx_flash_erase(logfile_get_flash_op_type(service_type), 0, cfg->file_size);
296 }
297
298 #endif /* CONFIG_DFX_SUPPORT_FILE_SYSTEM */
299 #endif /* CONFIG_DFX_SUPPORT_OFFLINE_LOG_FILE */