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: littlefs adapt layer
15 */
16
17 #include "lfs.h"
18 #include "fcntl.h"
19 #include "sfc.h"
20 #include "securec.h"
21 #include "soc_osal.h"
22 #include "littlefs_config.h"
23 #include "securec.h"
24 #include "partition.h"
25 #include "littlefs_adapt.h"
26
27 #define LFS_NAME_LEN_MAX 64
28 #define LFS_OPEN_MAX 32
29 #define LFS_FLASH_START 0x200000
30 #define LFS_FLASH_4K_MASK 0xFFF
31 #define LFS_FLASH_4K 0x1000
32 #define LFS_RAM_BASE 0xA00000
33
34 // variables used by the filesystem
35 typedef struct {
36 uint32_t start_block;
37 uint32_t max_block;
38 } lfs_block_info_t;
39 static lfs_block_info_t g_lfs_block_info;
40 static lfs_t g_lfs;
41 static uint8_t g_lfs_open_file_cnt = 0;
42 #ifdef LFS_THREADSAFE
43 uint32_t g_lfs_lock;
44 #endif
45 static const char lfs_root_path[] = ".";
46
littlefs_adapt_read(const struct lfs_config * c,lfs_block_t block,lfs_off_t off,void * buffer,lfs_size_t size)47 static int littlefs_adapt_read(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, void *buffer,
48 lfs_size_t size)
49 {
50 errcode_t ret = ERRCODE_FAIL;
51 ret = uapi_sfc_reg_read(c->block_size * (g_lfs_block_info.start_block + block) + off, (uint8_t *)buffer, size);
52 if (ret != ERRCODE_SUCC) {
53 return (int)ret;
54 }
55 return LFS_ERR_OK;
56 }
57
littlefs_adapt_write(const struct lfs_config * c,lfs_block_t block,lfs_off_t off,const void * buffer,lfs_size_t size)58 static int littlefs_adapt_write(const struct lfs_config *c, lfs_block_t block, lfs_off_t off, const void *buffer,
59 lfs_size_t size)
60 {
61 errcode_t ret = ERRCODE_FAIL;
62 ret = uapi_sfc_reg_write(c->block_size * (g_lfs_block_info.start_block + block) + off, (uint8_t *)buffer, size);
63 if (ret != ERRCODE_SUCC) {
64 return (int)ret;
65 }
66
67 return LFS_ERR_OK;
68 }
69
littlefs_adapt_erase(const struct lfs_config * c,lfs_block_t block)70 static int littlefs_adapt_erase(const struct lfs_config *c, lfs_block_t block)
71 {
72 lfs_debug_print_info("littlefs_adapt_erase enter\r\n");
73 errcode_t ret = ERRCODE_FAIL;
74 uint32_t start_sector = c->block_size * (block + g_lfs_block_info.start_block);
75 ret = uapi_sfc_reg_erase(start_sector, c->block_size);
76 lfs_debug_print_info("uapi_sfc_reg_erase, ret=%d\r\n", ret);
77 if (ret != ERRCODE_SUCC) {
78 return (int)ret;
79 }
80 return LFS_ERR_OK;
81 }
82
littlefs_adapt_sync(const struct lfs_config * c)83 static int littlefs_adapt_sync(const struct lfs_config *c)
84 {
85 (void)c;
86 return LFS_ERR_OK;
87 }
88
89 #ifdef LFS_THREADSAFE
littlefs_adapt_lock(const struct lfs_config * c)90 static int littlefs_adapt_lock(const struct lfs_config *c)
91 {
92 (void)c;
93 g_lfs_lock = osal_irq_lock();
94 return LFS_ERR_OK;
95 }
96
littlefs_adapt_unlock(const struct lfs_config * c)97 static int littlefs_adapt_unlock(const struct lfs_config *c)
98 {
99 (void)c;
100 osal_irq_restore(g_lfs_lock);
101 return LFS_ERR_OK;
102 }
103 #endif
104
littlefs_adapt_get_block_info(uint32_t * start_block,uint32_t * max_block)105 static errcode_t littlefs_adapt_get_block_info(uint32_t *start_block, uint32_t *max_block)
106 {
107 partition_information_t info;
108
109 errcode_t ret_val = uapi_partition_get_info(CONFIG_LFS_PARTITION_ID, &info);
110 if (ret_val != ERRCODE_SUCC || info.part_info.addr_info.size == 0 ||
111 (info.part_info.addr_info.addr & LFS_FLASH_4K_MASK) != 0 ||
112 (info.part_info.addr_info.size & LFS_FLASH_4K_MASK) != 0) {
113 return ERRCODE_FAIL;
114 }
115 *start_block = info.part_info.addr_info.addr / LFS_FLASH_4K;
116 *max_block = info.part_info.addr_info.size / LFS_FLASH_4K;
117 return ERRCODE_SUCC;
118 }
119
fs_adapt_mount(void)120 void fs_adapt_mount(void)
121 {
122 // configuration of the filesystem is provided by this struct
123 uint32_t ret_val = littlefs_adapt_get_block_info(&g_lfs_block_info.start_block, &g_lfs_block_info.max_block);
124 if (ret_val != ERRCODE_SUCC) {
125 lfs_debug_print_error("fs init failed, ret = 0x%x\r\n", ret_val);
126 }
127 static struct lfs_config cfg = {
128 // block device operations
129 .read = littlefs_adapt_read,
130 .prog = littlefs_adapt_write,
131 .erase = littlefs_adapt_erase,
132 .sync = littlefs_adapt_sync,
133 #ifdef LFS_THREADSAFE
134 .lock = littlefs_adapt_lock,
135 .unlock = littlefs_adapt_unlock,
136 #endif
137
138 // block device configuration
139 .read_size = 4,
140 .prog_size = 4,
141 .block_size = 4096,
142 .cache_size = 16,
143 .lookahead_size = 16,
144 .block_cycles = 500,
145 .name_max = LFS_NAME_LEN_MAX,
146 };
147 cfg.block_count = g_lfs_block_info.max_block;
148
149 int ret = memset_s(&g_lfs, sizeof(g_lfs), 0, sizeof(g_lfs));
150 ret = lfs_mount(&g_lfs, &cfg);
151 if (ret < LFS_ERR_OK) {
152 ret = lfs_format(&g_lfs, &cfg);
153 if (ret < LFS_ERR_OK) {
154 lfs_debug_print_error("lfs_format failed, ret = %d\r\n", ret);
155 }
156 ret = lfs_mount(&g_lfs, &cfg);
157 lfs_debug_print_info("lfs_mount 2, ret = %d\r\n", ret);
158 if (ret < LFS_ERR_OK) {
159 lfs_debug_print_error("lfs_mount failed, ret = %d\r\n", ret);
160 }
161 }
162 }
163
fs_adapt_unmount(void)164 void fs_adapt_unmount(void)
165 {
166 lfs_unmount(&g_lfs);
167 }
168
fs_adapt_mkdir(const char * path)169 int fs_adapt_mkdir(const char *path)
170 {
171 if (path == NULL) {
172 return -1;
173 }
174 int ret = lfs_mkdir(&g_lfs, path);
175 if (ret == LFS_ERR_EXIST) {
176 lfs_debug_print_info("dir exists, ret = %d, dir = %s\r\n", ret, path);
177 return LFS_ERR_OK;
178 }
179 if (ret < 0) {
180 lfs_debug_print_error("lfs_mkdir failed, ret = %d, dir = %s\r\n", ret, path);
181 return -1;
182 }
183 return ret;
184 }
185
fs_adapt_path_format(const char * path)186 static int fs_adapt_path_format(const char* path)
187 {
188 if (path == NULL) {
189 return -1;
190 }
191 char *dir = NULL;
192 dir = strrchr(path, '/');
193 if (dir == NULL || strlen(path) == strlen(dir)) {
194 return LFS_ERR_OK;
195 }
196 uint32_t len = strlen(path) - strlen(dir);
197 char *dir_str = (char *)malloc(len + 1);
198 if (dir_str == NULL) {
199 lfs_debug_print_error("dir string malloc failed\r\n");
200 return -1;
201 }
202 dir_str[len] = '\0';
203 int ret = strncpy_s(dir_str, len + 1, path, len);
204 if (ret != 0) {
205 lfs_debug_print_error("ret : %d\r\n", ret);
206 free(dir_str);
207 return -1;
208 }
209 lfs_debug_print_info("dir_str: %s, %d\r\n", dir_str, strlen(dir_str));
210
211 ret = fs_adapt_mkdir(dir_str);
212 if (ret < 0 && ret != LFS_ERR_EXIST) {
213 lfs_debug_print_error("mkdir failed: %s\r\n", dir_str);
214 free(dir_str);
215 return ret;
216 }
217 free(dir_str);
218 return LFS_ERR_OK;
219 }
220
fs_adapt_flag_format(int oflag)221 static int fs_adapt_flag_format(int oflag)
222 {
223 uint32_t input_flag = (uint32_t)oflag;
224 uint32_t ret_flag = 0;
225 if (input_flag == O_RDONLY) {
226 return LFS_O_RDONLY;
227 }
228 if ((input_flag & O_WRONLY) != 0) {
229 ret_flag |= LFS_O_RDWR;
230 }
231 if ((input_flag & O_RDWR) != 0) {
232 ret_flag |= LFS_O_RDWR;
233 }
234 if ((input_flag & O_CREAT) != 0) {
235 ret_flag |= LFS_O_CREAT;
236 }
237 if ((input_flag & O_EXCL) != 0) {
238 ret_flag |= LFS_O_EXCL;
239 }
240 if ((input_flag & O_TRUNC) != 0) {
241 ret_flag |= LFS_O_TRUNC;
242 }
243 if ((input_flag & O_APPEND) != 0) {
244 ret_flag |= LFS_O_APPEND;
245 }
246 return (int)ret_flag;
247 }
248
fs_adapt_open(const char * path,int oflag)249 int fs_adapt_open(const char* path, int oflag)
250 {
251 if (path == NULL || strlen(path) >= LFS_NAME_LEN_MAX || g_lfs_open_file_cnt >= LFS_OPEN_MAX) {
252 return -1;
253 }
254 int ret;
255 const char *name = NULL;
256 int real_flag = fs_adapt_flag_format(oflag);
257 lfs_file_t *fp = (lfs_file_t *)malloc(sizeof(lfs_file_t));
258 if (fp == NULL) {
259 lfs_debug_print_error("fp malloc failed\r\n");
260 return -1;
261 }
262 name = path;
263 if (name[0] == '/' && name[1] == 0) {
264 name = lfs_root_path;
265 } else if (name[0] == '/') {
266 name++;
267 }
268 lfs_debug_print_info("fs_adapt_open enter, name = %s, oflag = 0x%x, real_flag = 0x%x\r\n",
269 name, oflag, real_flag);
270 ret = fs_adapt_path_format(path);
271 if (ret != LFS_ERR_OK) {
272 free(fp);
273 return -1;
274 }
275 ret = lfs_file_open(&g_lfs, fp, name, real_flag);
276 if (ret < LFS_ERR_OK) {
277 lfs_debug_print_error("lfs_file_open failed, ret = %d, name = %s\r\n", ret, name);
278 free(fp);
279 return -1;
280 }
281 g_lfs_open_file_cnt++;
282 lfs_debug_print_info("fs_adapt_open done\r\n");
283 return (int)(intptr_t)fp;
284 }
285
fs_adapt_close(int fd)286 int fs_adapt_close(int fd)
287 {
288 lfs_debug_print_info("fs_adapt_close enter, fd = 0x%x\r\n", fd);
289 if (fd < LFS_RAM_BASE) {
290 return -1;
291 }
292 int ret = lfs_file_close(&g_lfs, (lfs_file_t *)(intptr_t)fd);
293 if (ret < 0) {
294 lfs_debug_print_error("lfs_file_close failed, ret = %d\r\n", ret);
295 free((lfs_file_t *)(intptr_t)fd);
296 return -1;
297 }
298 if (g_lfs_open_file_cnt > 0) {
299 g_lfs_open_file_cnt--;
300 }
301 free((lfs_file_t *)(intptr_t)fd);
302 lfs_debug_print_info("fs_adapt_close done\r\n");
303 return ret;
304 }
305
fs_adapt_read(int fd,char * buf,unsigned int len)306 int fs_adapt_read(int fd, char *buf, unsigned int len)
307 {
308 lfs_debug_print_info("fs_adapt_read enter, len = %d, fd = 0x%x\r\n", len, fd);
309 if (len == 0 || fd < LFS_RAM_BASE) {
310 return -1;
311 }
312 int ret = lfs_file_read(&g_lfs, (lfs_file_t *)(intptr_t)fd, buf, len);
313 if (ret < 0) {
314 lfs_debug_print_error("lfs_file_read failed, ret = %d\r\n", ret);
315 return -1;
316 }
317 lfs_debug_print_info("fs_adapt_read done\r\n");
318 return ret;
319 }
320
fs_adapt_write(int fd,const char * buf,unsigned int len)321 int fs_adapt_write(int fd, const char *buf, unsigned int len)
322 {
323 lfs_debug_print_info("fs_adapt_write enter, len = %d, fd = 0x%x\r\n", len, fd);
324 if (len == 0 || fd < LFS_RAM_BASE) {
325 return -1;
326 }
327 int ret = lfs_file_write(&g_lfs, (lfs_file_t *)(intptr_t)fd, buf, len);
328 if (ret < 0) {
329 lfs_debug_print_error("lfs_file_write failed, ret = %d\r\n", ret);
330 return -1;
331 }
332 lfs_debug_print_info("fs_adapt_write done\r\n");
333 return ret;
334 }
335
fs_adapt_delete(const char * path)336 int fs_adapt_delete(const char *path)
337 {
338 lfs_debug_print_info("fs_adapt_delete enter, path = %s\r\n", path);
339 if (path == NULL) {
340 return -1;
341 }
342 int ret = lfs_remove(&g_lfs, path);
343 if (ret < 0) {
344 lfs_debug_print_error("lfs_remove failed, ret = %d\r\n", ret);
345 return -1;
346 }
347 lfs_debug_print_info("fs_adapt_delete done\r\n");
348 return ret;
349 }
350
fs_adapt_stat(const char * path,unsigned int * file_size)351 int fs_adapt_stat(const char *path, unsigned int *file_size)
352 {
353 lfs_debug_print_info("fs_adapt_stat enter, path = %s\r\n", path);
354 if (path == NULL) {
355 return -1;
356 }
357 struct lfs_info info = {0};
358 int ret = lfs_stat(&g_lfs, path, &info);
359 if (ret < 0) {
360 lfs_debug_print_error("lfs_stat failed, ret = %d\r\n", ret);
361 return -1;
362 }
363 *file_size = info.size;
364 lfs_debug_print_info("fs_adapt_stat done\r\n");
365 return 0;
366 }
367
fs_adapt_seek(int fd,int offset,unsigned int whence)368 int fs_adapt_seek(int fd, int offset, unsigned int whence)
369 {
370 lfs_debug_print_info("fs_adapt_stat enter, fd = 0x%x\r\n", fd);
371 if (fd < LFS_RAM_BASE) {
372 return -1;
373 }
374 int file_size = lfs_file_size(&g_lfs, (lfs_file_t *)(intptr_t)fd);
375 int file_pos = lfs_file_tell(&g_lfs, (lfs_file_t *)(intptr_t)fd);
376 int next_pos;
377 if (whence == LFS_SEEK_SET) {
378 next_pos = offset;
379 } else if (whence == LFS_SEEK_CUR) {
380 next_pos = file_pos + offset;
381 } else if (whence == LFS_SEEK_END) {
382 next_pos = file_size + offset;
383 } else {
384 return -1;
385 }
386 if (next_pos < 0 || next_pos > file_size) {
387 return -1;
388 }
389 int ret = lfs_file_seek(&g_lfs, (lfs_file_t *)(intptr_t)fd, offset, (int)whence);
390 if (ret < 0) {
391 lfs_debug_print_error("lfs_file_seek failed, ret = %d\r\n", ret);
392 return -1;
393 }
394 lfs_debug_print_info("fs_adapt_seek done\r\n");
395 return ret;
396 }
397
fs_adapt_sync(int fd)398 int fs_adapt_sync(int fd)
399 {
400 int ret = lfs_file_sync(&g_lfs, (lfs_file_t *)(intptr_t)fd);
401 if (ret < 0) {
402 lfs_debug_print_error("fs_adapt_sync failed, ret = %d\r\n", ret);
403 return -1;
404 }
405 return ret;
406 }
407
lfs_test(void)408 void lfs_test(void)
409 {
410 // read current count
411 char boot_count = 0;
412
413 int fp = fs_adapt_open("/lfs_test", O_RDWR | O_CREAT);
414 if (fp < 0) {
415 return;
416 }
417 int ret = fs_adapt_read(fp, &boot_count, sizeof(boot_count));
418 lfs_debug_print_info("lfs_test read, ret = %d\r\n", ret);
419
420 // print the boot count
421 lfs_debug_print_info("===========boot_count: %d=============\r\n", boot_count);
422
423 // update boot count
424 boot_count = (char)((uint8_t)boot_count + 1);
425 ret = fs_adapt_seek(fp, 0, LFS_SEEK_SET);
426 lfs_debug_print_info("lfs_test seek, ret = %d\r\n", ret);
427 if (ret < LFS_ERR_OK) {
428 return;
429 }
430 ret = fs_adapt_write(fp, &boot_count, sizeof(boot_count));
431 lfs_debug_print_info("lfs_test write, ret = %d\r\n", ret);
432
433 // remember the storage is not updated until the file is closed successfully
434 ret = fs_adapt_close(fp);
435 lfs_debug_print_info("lfs_test close, ret = %d\r\n", ret);
436 if (ret < LFS_ERR_OK) {
437 return;
438 }
439 }
440
441 #ifdef LFS_NEED_LIB_STDIO
open(const char * path,int oflags,...)442 int open(const char *path, int oflags, ...)
443 {
444 return fs_adapt_open(path, oflags);
445 }
446
close(int fd)447 int close(int fd)
448 {
449 return fs_adapt_close(fd);
450 }
451
read(int fd,void * buf,size_t nbytes)452 ssize_t read(int fd, void *buf, size_t nbytes)
453 {
454 return fs_adapt_read(fd, buf, nbytes);
455 }
456
write(int fd,const void * buf,size_t nbytes)457 ssize_t write(int fd, const void *buf, size_t nbytes)
458 {
459 return fs_adapt_write(fd, buf, nbytes);
460 }
461
lseek(int fd,off_t offset,int whence)462 off_t lseek(int fd, off_t offset, int whence)
463 {
464 return fs_adapt_seek(fd, offset, whence);
465 }
466
unlink(const char * pathname)467 int unlink(const char *pathname)
468 {
469 return fs_adapt_delete(pathname);
470 }
471
fsync(int fd)472 int fsync(int fd)
473 {
474 return fs_adapt_sync(fd);
475 }
476 #endif