• 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: 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