• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */