ef_log.c 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764
  1. /*
  2. * This file is part of the EasyFlash Library.
  3. *
  4. * Copyright (c) 2015-2019, Armink, <armink.ztl@gmail.com>
  5. *
  6. * Permission is hereby granted, free of charge, to any person obtaining
  7. * a copy of this software and associated documentation files (the
  8. * 'Software'), to deal in the Software without restriction, including
  9. * without limitation the rights to use, copy, modify, merge, publish,
  10. * distribute, sublicense, and/or sell copies of the Software, and to
  11. * permit persons to whom the Software is furnished to do so, subject to
  12. * the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be
  15. * included in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
  18. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  19. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  20. * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  21. * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  22. * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  23. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  24. *
  25. * Function: Save logs to flash.
  26. * Created on: 2015-06-04
  27. */
  28. #include <easyflash.h>
  29. #ifdef EF_USING_LOG
  30. #if defined(EF_USING_LOG) && !defined(LOG_AREA_SIZE)
  31. #error "Please configure log area size (in ef_cfg.h)"
  32. #endif
  33. /* magic code on every sector header. 'EF' is 0xEF30EF30 */
  34. #define LOG_SECTOR_MAGIC 0xEF30EF30
  35. /* sector header size, includes the sector magic code and status magic code */
  36. #define LOG_SECTOR_HEADER_SIZE 12
  37. /* sector header word size,what is equivalent to the total number of sectors header index */
  38. #define LOG_SECTOR_HEADER_WORD_SIZE 3
  39. /**
  40. * Sector status magic code
  41. * The sector status is 8B after LOG_SECTOR_MAGIC at every sector header.
  42. * ==============================================
  43. * | header(12B) | status |
  44. * ----------------------------------------------
  45. * | 0xEF30EF30 0xFFFFFFFF 0xFFFFFFFF | empty |
  46. * | 0xEF30EF30 0xFEFEFEFE 0xFFFFFFFF | using |
  47. * | 0xEF30EF30 0xFEFEFEFE 0xFCFCFCFC | full |
  48. * ==============================================
  49. *
  50. * State transition relationship: empty->using->full
  51. * The FULL status will change to EMPTY after sector clean.
  52. */
  53. #define SECTOR_STATUS_MAGIC_EMPUT 0xFFFFFFFF
  54. #define SECTOR_STATUS_MAGIC_USING 0xFEFEFEFE
  55. #define SECTOR_STATUS_MAGIC_FULL 0xFCFCFCFC
  56. typedef enum {
  57. SECTOR_STATUS_EMPUT,
  58. SECTOR_STATUS_USING,
  59. SECTOR_STATUS_FULL,
  60. SECTOR_STATUS_HEADER_ERROR,
  61. } SectorStatus;
  62. typedef enum {
  63. SECTOR_HEADER_MAGIC_INDEX,
  64. SECTOR_HEADER_USING_INDEX,
  65. SECTOR_HEADER_FULL_INDEX,
  66. } SectorHeaderIndex;
  67. #if 0
  68. /* the stored logs start address and end address. It's like a ring buffer implemented on flash. */
  69. static uint32_t log_start_addr = 0, log_end_addr = 0;
  70. /* saved log area address for flash */
  71. static uint32_t log_area_start_addr = 0;
  72. /* initialize OK flag */
  73. static bool init_ok = false;
  74. #else
  75. #define log_start_addr (ctx->log_start_addr)
  76. #define log_end_addr (ctx->log_end_addr)
  77. #define log_area_start_addr (ctx->base_addr)
  78. #define init_ok (ctx->init_flag)
  79. #endif
  80. static void find_start_and_end_addr(struct flash_buffer_ctx *ctx);
  81. static uint32_t get_next_flash_sec_addr(struct flash_buffer_ctx *ctx, uint32_t cur_addr);
  82. /**
  83. * The flash save log function initialize.
  84. *
  85. * @return result
  86. */
  87. EfErrCode ef_log_init(struct flash_buffer_ctx *ctx) {
  88. EfErrCode result = EF_NO_ERR;
  89. EF_ASSERT(LOG_AREA_SIZE);
  90. EF_ASSERT(EF_ERASE_MIN_SIZE);
  91. /* the log area size must be an integral multiple of erase minimum size. */
  92. EF_ASSERT(LOG_AREA_SIZE % EF_ERASE_MIN_SIZE == 0);
  93. /* the log area size must be more than twice of EF_ERASE_MIN_SIZE */
  94. EF_ASSERT(LOG_AREA_SIZE / EF_ERASE_MIN_SIZE >= 2);
  95. #ifdef EF_USING_ENV
  96. //log_area_start_addr = EF_START_ADDR + ENV_AREA_SIZE;
  97. #else
  98. //log_area_start_addr = EF_START_ADDR;
  99. #endif
  100. /* find the log store start address and end address */
  101. find_start_and_end_addr(ctx);
  102. /* initialize OK */
  103. init_ok = true;
  104. EF_DEBUG("scan area:%x size:%x, start %x end %x\n", EF_START_ADDR, LOG_AREA_SIZE,\
  105. log_start_addr, log_end_addr);
  106. return result;
  107. }
  108. /**
  109. * Get flash sector current status.
  110. *
  111. * @param addr sector address, this function will auto calculate the sector header address by this address.
  112. *
  113. * @return the flash sector current status
  114. */
  115. static SectorStatus get_sector_status(struct flash_buffer_ctx *ctx, uint32_t addr) {
  116. uint32_t header_buf[LOG_SECTOR_HEADER_WORD_SIZE] = {0}, header_addr = 0;
  117. uint32_t sector_header_magic = 0;
  118. uint32_t status_full_magic = 0, status_use_magic = 0;
  119. /* calculate the sector header address */
  120. header_addr = addr & (~(EF_ERASE_MIN_SIZE - 1));
  121. if (ef_port_read(ctx->storage_dev, header_addr, header_buf, sizeof(header_buf)) == EF_NO_ERR) {
  122. sector_header_magic = header_buf[SECTOR_HEADER_MAGIC_INDEX];
  123. status_use_magic = header_buf[SECTOR_HEADER_USING_INDEX];
  124. status_full_magic = header_buf[SECTOR_HEADER_FULL_INDEX];
  125. } else {
  126. EF_DEBUG("Error: Read sector header data error.\n");
  127. return SECTOR_STATUS_HEADER_ERROR;
  128. }
  129. /* compare header magic code */
  130. if(sector_header_magic == LOG_SECTOR_MAGIC){
  131. if((status_use_magic == SECTOR_STATUS_MAGIC_EMPUT) && (status_full_magic == SECTOR_STATUS_MAGIC_EMPUT)) {
  132. return SECTOR_STATUS_EMPUT;
  133. } else if((status_use_magic == SECTOR_STATUS_MAGIC_USING) && (status_full_magic == SECTOR_STATUS_MAGIC_EMPUT)) {
  134. return SECTOR_STATUS_USING;
  135. } else if((status_use_magic == SECTOR_STATUS_MAGIC_USING) && (status_full_magic == SECTOR_STATUS_MAGIC_FULL)) {
  136. return SECTOR_STATUS_FULL;
  137. } else {
  138. return SECTOR_STATUS_HEADER_ERROR;
  139. }
  140. } else {
  141. return SECTOR_STATUS_HEADER_ERROR;
  142. }
  143. }
  144. /**
  145. * Write flash sector current status.
  146. *
  147. * @param addr sector address, this function will auto calculate the sector header address by this address.
  148. * @param status sector cur status
  149. *
  150. * @return result
  151. */
  152. static EfErrCode write_sector_status(struct flash_buffer_ctx *ctx, uint64_t addr, SectorStatus status) {
  153. uint32_t header;
  154. uint64_t header_addr = 0;
  155. /* calculate the sector header address */
  156. header_addr = addr & (~(EF_ERASE_MIN_SIZE - 1));
  157. /* calculate the sector staus magic */
  158. switch (status) {
  159. case SECTOR_STATUS_EMPUT: {
  160. header = LOG_SECTOR_MAGIC;
  161. return ef_port_write(ctx->storage_dev, header_addr, &header, sizeof(header));
  162. }
  163. case SECTOR_STATUS_USING: {
  164. header = SECTOR_STATUS_MAGIC_USING;
  165. return ef_port_write(ctx->storage_dev, header_addr + sizeof(header), &header, sizeof(header));
  166. }
  167. case SECTOR_STATUS_FULL: {
  168. header = SECTOR_STATUS_MAGIC_FULL;
  169. return ef_port_write(ctx->storage_dev, header_addr + sizeof(header) * 2, &header, sizeof(header));
  170. }
  171. default:
  172. return EF_WRITE_ERR;
  173. }
  174. }
  175. /**
  176. * Find the current flash sector using end address by continuous 0xFF.
  177. *
  178. * @param addr sector address
  179. *
  180. * @return current flash sector using end address
  181. */
  182. static uint32_t find_sec_using_end_addr(struct flash_buffer_ctx *ctx, uint32_t addr) {
  183. /* read section data buffer size */
  184. #define READ_BUF_SIZE 32
  185. uint32_t sector_start = addr, data_start = addr, continue_ff = 0, read_buf_size = 0, i;
  186. uint8_t buf[READ_BUF_SIZE];
  187. EF_ASSERT(READ_BUF_SIZE % 4 == 0);
  188. /* calculate the sector start and data start address */
  189. sector_start = addr & (~(EF_ERASE_MIN_SIZE - 1));
  190. data_start = sector_start + LOG_SECTOR_HEADER_SIZE;
  191. /* counts continuous 0xFF which is end of sector */
  192. while (data_start < sector_start + EF_ERASE_MIN_SIZE) {
  193. if (data_start + READ_BUF_SIZE < sector_start + EF_ERASE_MIN_SIZE) {
  194. read_buf_size = READ_BUF_SIZE;
  195. } else {
  196. read_buf_size = sector_start + EF_ERASE_MIN_SIZE - data_start;
  197. }
  198. ef_port_read(ctx->storage_dev, data_start, (uint32_t *)buf, read_buf_size);
  199. for (i = 0; i < read_buf_size; i++) {
  200. if (buf[i] == 0xFF) {
  201. continue_ff++;
  202. } else {
  203. continue_ff = 0;
  204. }
  205. }
  206. data_start += read_buf_size;
  207. }
  208. /* calculate current flash sector using end address */
  209. if (continue_ff >= EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) {
  210. /* from 0 to sec_size all sector is 0xFF, so the sector is empty */
  211. return sector_start + LOG_SECTOR_HEADER_SIZE;
  212. } else if (continue_ff >= 4) {
  213. /* form end_addr - 4 to sec_size length all area is 0xFF, so it's used part of the sector.
  214. * the address must be word alignment. */
  215. if (continue_ff % 4 != 0) {
  216. continue_ff = (continue_ff / 4 + 1) * 4;
  217. }
  218. return sector_start + EF_ERASE_MIN_SIZE - continue_ff;
  219. } else {
  220. /* all sector not has continuous 0xFF, so the sector is full */
  221. return sector_start + EF_ERASE_MIN_SIZE;
  222. }
  223. }
  224. void scan_error_deal(struct flash_buffer_ctx *ctx, SectorStatus cur_sec_status, SectorStatus last_sec_status, int cur_addr)
  225. {
  226. EF_DEBUG("Error: Log area error(last %d cur %d addr %d)! Now will clean all log area.\n", last_sec_status, cur_sec_status, cur_addr);
  227. ef_log_clean(ctx);
  228. }
  229. /**
  230. * Find the log store start address and end address.
  231. * It's like a ring buffer implemented on flash.
  232. * The flash log area can be in two states depending on start address and end address:
  233. * state 1 state 2
  234. * |============| |============|
  235. * log area start--> |############| <-- start address |############| <-- end address
  236. * |############| | empty |
  237. * |------------| |------------|
  238. * |############| |############| <-- start address
  239. * |############| |############|
  240. * |------------| |------------|
  241. * | . | | . |
  242. * | . | | . |
  243. * | . | | . |
  244. * |------------| |------------|
  245. * |############| <-- end address |############|
  246. * | empty | |############|
  247. * log area end --> |============| |============|
  248. *
  249. * LOG_AREA_SIZE = log area end - log area star
  250. *
  251. */
  252. static void find_start_and_end_addr(struct flash_buffer_ctx *ctx) {
  253. size_t cur_size = 0;
  254. SectorStatus cur_sec_status, last_sec_status;
  255. uint32_t cur_using_sec_addr = 0;
  256. /* all status sector counts */
  257. size_t empty_sec_counts = 0, using_sec_counts = 0, full_sector_counts = 0;
  258. /* total sector number */
  259. size_t total_sec_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
  260. /* see comment of find_start_and_end_addr function */
  261. uint8_t cur_log_sec_state = 0;
  262. /* get the first sector status */
  263. cur_sec_status = get_sector_status(ctx, log_area_start_addr);
  264. last_sec_status = cur_sec_status;
  265. for (cur_size = EF_ERASE_MIN_SIZE; cur_size < LOG_AREA_SIZE; cur_size += EF_ERASE_MIN_SIZE) {
  266. /* get current sector status */
  267. cur_sec_status = get_sector_status(ctx, log_area_start_addr + cur_size);
  268. /* compare last and current status */
  269. switch (last_sec_status) {
  270. case SECTOR_STATUS_EMPUT: {
  271. switch (cur_sec_status) {
  272. case SECTOR_STATUS_EMPUT:
  273. break;
  274. default:
  275. scan_error_deal(ctx, cur_sec_status, last_sec_status, log_area_start_addr + cur_size);
  276. return;
  277. }
  278. empty_sec_counts++;
  279. break;
  280. }
  281. case SECTOR_STATUS_USING: {
  282. switch (cur_sec_status) {
  283. case SECTOR_STATUS_EMPUT:
  284. /* like state 1 */
  285. cur_log_sec_state = 1;
  286. log_start_addr = log_area_start_addr;
  287. cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
  288. break;
  289. case SECTOR_STATUS_FULL:
  290. /* like state 2 */
  291. cur_log_sec_state = 2;
  292. log_start_addr = log_area_start_addr + cur_size;
  293. cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
  294. break;
  295. default:
  296. scan_error_deal(ctx, cur_sec_status, last_sec_status, log_area_start_addr + cur_size);
  297. return;
  298. }
  299. using_sec_counts++;
  300. break;
  301. }
  302. case SECTOR_STATUS_FULL: {
  303. switch (cur_sec_status) {
  304. case SECTOR_STATUS_EMPUT:
  305. /* like state 1 */
  306. if (cur_log_sec_state == 2) {
  307. scan_error_deal(ctx, cur_sec_status, last_sec_status, log_area_start_addr + cur_size);
  308. return;
  309. } else {
  310. cur_log_sec_state = 1;
  311. log_start_addr = log_area_start_addr;
  312. log_end_addr = log_area_start_addr + cur_size;
  313. cur_using_sec_addr = log_area_start_addr + cur_size - EF_ERASE_MIN_SIZE;
  314. }
  315. break;
  316. case SECTOR_STATUS_USING:
  317. if(total_sec_num <= 2) {
  318. /* like state 1 */
  319. cur_log_sec_state = 1;
  320. log_start_addr = log_area_start_addr;
  321. cur_using_sec_addr = log_area_start_addr + cur_size;
  322. } else {
  323. /* like state 2 when the sector is the last one */
  324. if (cur_size + EF_ERASE_MIN_SIZE >= LOG_AREA_SIZE) {
  325. cur_log_sec_state = 2;
  326. log_start_addr = get_next_flash_sec_addr(ctx, log_area_start_addr + cur_size);
  327. cur_using_sec_addr = log_area_start_addr + cur_size;
  328. }
  329. }
  330. break;
  331. case SECTOR_STATUS_FULL:
  332. break;
  333. default:
  334. scan_error_deal(ctx, cur_sec_status, last_sec_status, log_area_start_addr + cur_size);
  335. return;
  336. }
  337. full_sector_counts++;
  338. break;
  339. }
  340. default:
  341. scan_error_deal(ctx, cur_sec_status, last_sec_status, log_area_start_addr + cur_size);
  342. return;
  343. }
  344. last_sec_status = cur_sec_status;
  345. }
  346. /* the last sector status counts */
  347. if (cur_sec_status == SECTOR_STATUS_EMPUT) {
  348. empty_sec_counts++;
  349. } else if (cur_sec_status == SECTOR_STATUS_USING) {
  350. using_sec_counts++;
  351. } else if (cur_sec_status == SECTOR_STATUS_FULL) {
  352. full_sector_counts++;
  353. } else {
  354. scan_error_deal(ctx, cur_sec_status, last_sec_status, log_area_start_addr + cur_size);
  355. return;
  356. }
  357. if (using_sec_counts != 1) {
  358. /* this state is almost impossible */
  359. EF_DEBUG("Error: There must be only one sector status is USING! Now will clean all log area.\n");
  360. ef_log_clean(ctx);
  361. } else {
  362. /* find the end address */
  363. log_end_addr = find_sec_using_end_addr(ctx, cur_using_sec_addr);
  364. }
  365. }
  366. /**
  367. * Get log used flash total size.
  368. *
  369. * @return log used flash total size. @note NOT contain sector headers
  370. */
  371. size_t ef_log_get_used_size(struct flash_buffer_ctx *ctx) {
  372. size_t header_total_num = 0, physical_size = 0;
  373. /* must be call this function after initialize OK */
  374. if (!init_ok) {
  375. return 0;
  376. }
  377. if (log_start_addr < log_end_addr) {
  378. physical_size = log_end_addr - log_start_addr;
  379. } else {
  380. physical_size = LOG_AREA_SIZE - (log_start_addr - log_end_addr);
  381. }
  382. header_total_num = physical_size / EF_ERASE_MIN_SIZE + 1;
  383. return physical_size - header_total_num * LOG_SECTOR_HEADER_SIZE;
  384. }
  385. /**
  386. * Sequential reading log data. It will ignore sector headers.
  387. *
  388. * @param addr address
  389. * @param log log buffer
  390. * @param size log size, not contain sector headers.
  391. *
  392. * @return result
  393. */
  394. static EfErrCode log_seq_read(struct flash_buffer_ctx *ctx, uint32_t addr, uint32_t *log, size_t size) {
  395. EfErrCode result = EF_NO_ERR;
  396. size_t read_size = 0, read_size_temp = 0;
  397. while (size) {
  398. /* move to sector data address */
  399. if ((addr + read_size) % EF_ERASE_MIN_SIZE == 0) {
  400. addr += LOG_SECTOR_HEADER_SIZE;
  401. }
  402. /* calculate current sector last data size */
  403. read_size_temp = EF_ERASE_MIN_SIZE - (addr % EF_ERASE_MIN_SIZE);
  404. if (size < read_size_temp) {
  405. read_size_temp = size;
  406. }
  407. result = ef_port_read(ctx->storage_dev, addr + read_size, log + read_size / 4, read_size_temp);
  408. if (result != EF_NO_ERR) {
  409. return result;
  410. }
  411. read_size += read_size_temp;
  412. size -= read_size_temp;
  413. }
  414. return result;
  415. }
  416. /**
  417. * Calculate flash physical address by log index.
  418. *
  419. * @param index log index
  420. *
  421. * @return flash physical address
  422. */
  423. static uint32_t log_index2addr(struct flash_buffer_ctx *ctx, size_t index) {
  424. size_t header_total_offset = 0;
  425. /* total include sector number */
  426. size_t sector_num = index / (EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE) + 1;
  427. header_total_offset = sector_num * LOG_SECTOR_HEADER_SIZE;
  428. if (log_start_addr < log_end_addr) {
  429. return log_start_addr + index + header_total_offset;
  430. } else {
  431. if (log_start_addr + index + header_total_offset < log_area_start_addr + LOG_AREA_SIZE) {
  432. return log_start_addr + index + header_total_offset;
  433. } else {
  434. return log_start_addr + index + header_total_offset - LOG_AREA_SIZE;
  435. }
  436. }
  437. }
  438. /**
  439. * Read log from flash.
  440. *
  441. * @param index index for saved log.
  442. * Minimum index is 0.
  443. * Maximum index is ef_log_get_used_size() - 1.
  444. * @param log the log which will read from flash
  445. * @param size read bytes size
  446. *
  447. * @return result
  448. */
  449. EfErrCode ef_log_read(struct flash_buffer_ctx *ctx, size_t index, uint32_t *log, size_t *read_size) {
  450. EfErrCode result = EF_NO_ERR;
  451. size_t cur_using_size = ef_log_get_used_size(ctx);
  452. size_t read_size_temp = 0;
  453. size_t header_total_num = 0;
  454. size_t size = *read_size;
  455. if (!size) {
  456. return result;
  457. }
  458. EF_ASSERT(size % 4 == 0);
  459. //EF_ASSERT(index < cur_using_size);
  460. if (index >= cur_using_size){
  461. return EF_READ_ERR;
  462. }
  463. EF_DEBUG("log read %x size %x total size %x start %x end %x\n", index, size, \
  464. cur_using_size, log_start_addr, log_end_addr);
  465. if (index + size > cur_using_size) {
  466. EF_DEBUG("Warning: Log read size out of bound. Cut read size.\n");
  467. size = cur_using_size - index;
  468. }
  469. *read_size = size;
  470. /* must be call this function after initialize OK */
  471. if (!init_ok) {
  472. return EF_ENV_INIT_FAILED;
  473. }
  474. if (log_start_addr < log_end_addr) {
  475. log_seq_read(ctx, log_index2addr(ctx, index), log, size);
  476. } else {
  477. if (log_index2addr(ctx, index) + size <= log_area_start_addr + LOG_AREA_SIZE) {
  478. /* Flash log area
  479. * |--------------|
  480. * log_area_start_addr --> |##############|
  481. * |##############|
  482. * |##############|
  483. * |--------------|
  484. * |##############|
  485. * |##############|
  486. * |##############| <-- log_end_addr
  487. * |--------------|
  488. * log_start_addr --> |##############|
  489. * read start --> |**************| <-- read end
  490. * |##############|
  491. * |--------------|
  492. *
  493. * read from (log_start_addr + log_index2addr(index)) to (log_start_addr + index + log_index2addr(index))
  494. */
  495. result = log_seq_read(ctx, log_index2addr(ctx, index), log, size);
  496. } else if (log_index2addr(ctx, index) < log_area_start_addr + LOG_AREA_SIZE) {
  497. /* Flash log area
  498. * |--------------|
  499. * log_area_start_addr --> |**************| <-- read end
  500. * |##############|
  501. * |##############|
  502. * |--------------|
  503. * |##############|
  504. * |##############|
  505. * |##############| <-- log_end_addr
  506. * |--------------|
  507. * log_start_addr --> |##############|
  508. * read start --> |**************|
  509. * |**************|
  510. * |--------------|
  511. * read will by 2 steps
  512. * step1: read from (log_start_addr + log_index2addr(index)) to flash log area end address
  513. * step2: read from flash log area start address to read size's end address
  514. */
  515. read_size_temp = (log_area_start_addr + LOG_AREA_SIZE) - log_index2addr(ctx, index);
  516. header_total_num = read_size_temp / EF_ERASE_MIN_SIZE;
  517. /* Minus some ignored bytes */
  518. read_size_temp -= header_total_num * LOG_SECTOR_HEADER_SIZE;
  519. result = log_seq_read(ctx, log_index2addr(ctx, index), log, read_size_temp);
  520. if (result == EF_NO_ERR) {
  521. result = log_seq_read(ctx, log_area_start_addr, log + read_size_temp / 4, size - read_size_temp);
  522. }
  523. } else {
  524. /* Flash log area
  525. * |--------------|
  526. * log_area_start_addr --> |##############|
  527. * read start --> |**************|
  528. * |**************| <-- read end
  529. * |--------------|
  530. * |##############|
  531. * |##############|
  532. * |##############| <-- log_end_addr
  533. * |--------------|
  534. * log_start_addr --> |##############|
  535. * |##############|
  536. * |##############|
  537. * |--------------|
  538. * read from (log_start_addr + log_index2addr(index) - LOG_AREA_SIZE) to read size's end address
  539. */
  540. result = log_seq_read(ctx, log_index2addr(ctx, index) - LOG_AREA_SIZE, log, size);
  541. }
  542. }
  543. return result;
  544. }
  545. int ef_log_erase_enable(struct flash_buffer_ctx *ctx)
  546. {
  547. return ctx->erase_enable;
  548. }
  549. /**
  550. * Write log to flash.
  551. *
  552. * @param log the log which will be write to flash
  553. * @param size write bytes size
  554. *
  555. * @return result
  556. */
  557. EfErrCode ef_log_write(struct flash_buffer_ctx *ctx, const uint32_t *log, size_t size) {
  558. EfErrCode result = EF_NO_ERR;
  559. size_t write_size = 0, writable_size = 0;
  560. uint64_t write_addr = log_end_addr, erase_addr;
  561. SectorStatus sector_status;
  562. EF_ASSERT(size % 4 == 0);
  563. /* must be call this function after initialize OK */
  564. if (!init_ok) {
  565. return EF_ENV_INIT_FAILED;
  566. }
  567. if ((sector_status = get_sector_status(ctx, write_addr)) == SECTOR_STATUS_HEADER_ERROR) {
  568. return EF_WRITE_ERR;
  569. }
  570. /* write some log when current sector status is USING and EMPTY */
  571. if ((sector_status == SECTOR_STATUS_USING) || (sector_status == SECTOR_STATUS_EMPUT)) {
  572. /* write the already erased but not used area */
  573. writable_size = EF_ERASE_MIN_SIZE - ((write_addr - log_area_start_addr) % EF_ERASE_MIN_SIZE);
  574. if (size >= writable_size) {
  575. if (!ef_log_erase_enable(ctx)){
  576. result = -ENOMEM;
  577. goto exit;
  578. }
  579. result = ef_port_write(ctx->storage_dev, write_addr, log, writable_size);
  580. if (result != EF_NO_ERR) {
  581. goto exit;
  582. }
  583. /* change the current sector status to FULL */
  584. result = write_sector_status(ctx, write_addr, SECTOR_STATUS_FULL);
  585. if (result != EF_NO_ERR) {
  586. goto exit;
  587. }
  588. write_size += writable_size;
  589. } else {
  590. result = ef_port_write(ctx->storage_dev, write_addr, log, size);
  591. log_end_addr = write_addr + size;
  592. goto exit;
  593. }
  594. }
  595. /* erase and write remain log */
  596. while (true) {
  597. /* calculate next available sector address */
  598. erase_addr = write_addr = get_next_flash_sec_addr(ctx, write_addr - 4);
  599. /* move the flash log start address to next available sector address */
  600. if (log_start_addr == erase_addr) {
  601. log_start_addr = get_next_flash_sec_addr(ctx, log_start_addr);
  602. }
  603. /* erase sector */
  604. result = ef_port_erase(ctx->storage_dev, erase_addr, EF_ERASE_MIN_SIZE);
  605. if (result != EF_NO_ERR) {
  606. goto exit;
  607. }
  608. /* change the sector status to EMPTY and USING when write begin sector start address */
  609. result = write_sector_status(ctx, write_addr, SECTOR_STATUS_EMPUT);
  610. result = write_sector_status(ctx, write_addr, SECTOR_STATUS_USING);
  611. if (result == EF_NO_ERR) {
  612. write_addr += LOG_SECTOR_HEADER_SIZE;
  613. } else {
  614. goto exit;
  615. }
  616. /* calculate current sector writable data size */
  617. writable_size = EF_ERASE_MIN_SIZE - LOG_SECTOR_HEADER_SIZE;
  618. if (size - write_size >= writable_size) {
  619. result = ef_port_write(ctx->storage_dev, write_addr, log + write_size / 4, writable_size);
  620. if (result != EF_NO_ERR) {
  621. goto exit;
  622. }
  623. /* change the current sector status to FULL */
  624. result = write_sector_status(ctx, write_addr, SECTOR_STATUS_FULL);
  625. if (result != EF_NO_ERR) {
  626. goto exit;
  627. }
  628. log_end_addr = write_addr + writable_size;
  629. write_size += writable_size;
  630. write_addr += writable_size;
  631. } else {
  632. result = ef_port_write(ctx->storage_dev, write_addr, log + write_size / 4, size - write_size);
  633. if (result != EF_NO_ERR) {
  634. goto exit;
  635. }
  636. log_end_addr = write_addr + (size - write_size);
  637. break;
  638. }
  639. }
  640. exit:
  641. return result;
  642. }
  643. /**
  644. * Get next flash sector address.The log total sector like ring buffer which implement by flash.
  645. *
  646. * @param cur_addr cur flash address
  647. *
  648. * @return next flash sector address
  649. */
  650. static uint32_t get_next_flash_sec_addr(struct flash_buffer_ctx *ctx, uint32_t cur_addr) {
  651. size_t cur_sec_id = (cur_addr - log_area_start_addr) / EF_ERASE_MIN_SIZE;
  652. size_t sec_total_num = LOG_AREA_SIZE / EF_ERASE_MIN_SIZE;
  653. if (cur_sec_id + 1 >= sec_total_num) {
  654. /* return to ring head */
  655. return log_area_start_addr;
  656. } else {
  657. return log_area_start_addr + (cur_sec_id + 1) * EF_ERASE_MIN_SIZE;
  658. }
  659. }
  660. /**
  661. * Clean all log which in flash.
  662. *
  663. * @return result
  664. */
  665. EfErrCode ef_log_clean(struct flash_buffer_ctx *ctx) {
  666. EfErrCode result = EF_NO_ERR;
  667. uint32_t write_addr = log_area_start_addr;
  668. /* clean address */
  669. log_start_addr = log_area_start_addr;
  670. log_end_addr = log_start_addr + LOG_SECTOR_HEADER_SIZE;
  671. /* erase log flash area */
  672. result = ef_port_erase(ctx->storage_dev, log_area_start_addr, LOG_AREA_SIZE);
  673. if (result != EF_NO_ERR) {
  674. goto exit;
  675. }
  676. /* setting first sector is EMPTY to USING */
  677. write_sector_status(ctx, write_addr, SECTOR_STATUS_EMPUT);
  678. write_sector_status(ctx, write_addr, SECTOR_STATUS_USING);
  679. if (result != EF_NO_ERR) {
  680. goto exit;
  681. }
  682. write_addr += EF_ERASE_MIN_SIZE;
  683. /* add sector header */
  684. while (true) {
  685. write_sector_status(ctx, write_addr, SECTOR_STATUS_EMPUT);
  686. if (result != EF_NO_ERR) {
  687. goto exit;
  688. }
  689. write_addr += EF_ERASE_MIN_SIZE;
  690. if (write_addr >= log_area_start_addr + LOG_AREA_SIZE) {
  691. break;
  692. }
  693. }
  694. exit:
  695. return result;
  696. }
  697. #endif /* EF_USING_LOG */