1 /*
2 This file is part of UFFS, the Ultra-low-cost Flash File System.
3
4 Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5
6 UFFS is free software; you can redistribute it and/or modify it under
7 the GNU Library General Public License as published by the Free Software
8 Foundation; either version 2 of the License, or (at your option) any
9 later version.
10
11 UFFS is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 or GNU Library General Public License, as applicable, for more details.
15
16 You should have received a copy of the GNU General Public License
17 and GNU Library General Public License along with UFFS; if not, write
18 to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 Boston, MA 02110-1301, USA.
20
21 As a special exception, if other files instantiate templates or use
22 macros or inline functions from this file, or you compile this file
23 and link it with other works to produce a work based on this file,
24 this file does not by itself cause the resulting work to be covered
25 by the GNU General Public License. However the source code for this
26 file must still be made available in accordance with section (3) of
27 the GNU General Public License v2.
28
29 This exception does not invalidate any other reasons why a work based
30 on this file might be covered by the GNU General Public License.
31 */
32
33 /**
34 * \file uffs_test.c
35 * \brief uffs test main entry
36 * \author Ricky Zheng
37 */
38
39 #include <stdio.h>
40 #include <string.h>
41 #include <stdlib.h>
42 #include "uffs_config.h"
43 #include "uffs/uffs_os.h"
44 #include "uffs/uffs_public.h"
45 #include "uffs/uffs_fs.h"
46 #include "uffs/uffs_utils.h"
47 #include "uffs/uffs_core.h"
48 #include "uffs/uffs_mtb.h"
49
50 #include "cmdline.h"
51 #include "uffs_fileem.h"
52
53 #define PFX NULL
54 #define MSG(msg,...) uffs_PerrorRaw(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
55 #define MSGLN(msg,...) uffs_Perror(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
56
57 #if CONFIG_USE_STATIC_MEMORY_ALLOCATOR > 0
main()58 int main()
59 {
60 MSGLN("Static memory allocator is not supported.");
61 return 0;
62 }
63 #else
64
65 extern struct cli_commandset * get_helper_cmds(void);
66 extern struct cli_commandset * get_test_cmds(void);
67 extern void femu_init_uffs_device(uffs_Device *dev);
68
69 static int conf_command_line_mode = 0;
70 static int conf_verbose_mode = 0;
71
72 static int conf_exec_script = 0;
73 static char script_command[256];
74
75 #define DEFAULT_EMU_FILENAME "uffsemfile.bin"
76 const char * conf_emu_filename = DEFAULT_EMU_FILENAME;
77
78
79 /* default basic parameters of the NAND device */
80 #define PAGES_PER_BLOCK_DEFAULT 32
81 #define PAGE_DATA_SIZE_DEFAULT 512
82 #define PAGE_SPARE_SIZE_DEFAULT 16
83 #define STATUS_BYTE_OFFSET_DEFAULT 5
84 #define TOTAL_BLOCKS_DEFAULT 128
85 #define ECC_OPTION_DEFAULT UFFS_ECC_SOFT
86 //#define ECC_OPTION_DEFAULT UFFS_ECC_HW
87 //#define ECC_OPTION_DEFAULT UFFS_ECC_HW_AUTO
88
89 #define MAX_MOUNT_TABLES 10
90 #define MAX_MOUNT_POINT_NAME 32
91
92 static int conf_pages_per_block = PAGES_PER_BLOCK_DEFAULT;
93 static int conf_page_data_size = PAGE_DATA_SIZE_DEFAULT;
94 static int conf_page_spare_size = PAGE_SPARE_SIZE_DEFAULT;
95 static int conf_status_byte_offset = STATUS_BYTE_OFFSET_DEFAULT;
96 static int conf_total_blocks = TOTAL_BLOCKS_DEFAULT;
97 static int conf_ecc_option = ECC_OPTION_DEFAULT;
98 static int conf_ecc_size = 0; // 0 - Let UFFS choose the size
99
100 static const char *g_ecc_option_strings[] = UFFS_ECC_OPTION_STRING;
101
102 static struct uffs_MountTableEntrySt conf_mounts[MAX_MOUNT_TABLES] = {{0}};
103 static uffs_Device conf_devices[MAX_MOUNT_TABLES] = {{0}};
104 static char mount_point_name[MAX_MOUNT_TABLES][MAX_MOUNT_POINT_NAME] = {{0}};
105
setup_storage(struct uffs_StorageAttrSt * attr)106 static void setup_storage(struct uffs_StorageAttrSt *attr)
107 {
108 attr->total_blocks = conf_total_blocks; /* total blocks */
109 attr->page_data_size = conf_page_data_size; /* page data size */
110 attr->spare_size = conf_page_spare_size; /* page spare size */
111 attr->pages_per_block = conf_pages_per_block; /* pages per block */
112
113 attr->block_status_offs = conf_status_byte_offset; /* block status offset is 5th byte in spare */
114 attr->ecc_opt = conf_ecc_option; /* ECC option */
115 attr->ecc_size = conf_ecc_size; /* ECC size */
116 attr->layout_opt = UFFS_LAYOUT_UFFS; /* let UFFS handle layout */
117 }
118
119
setup_device(uffs_Device * dev)120 static void setup_device(uffs_Device *dev)
121 {
122 dev->Init = femu_InitDevice;
123 dev->Release = femu_ReleaseDevice;
124 dev->attr = femu_GetStorage();
125 }
126
setup_emu_private(uffs_FileEmu * emu)127 static void setup_emu_private(uffs_FileEmu *emu)
128 {
129 memset(emu, 0, sizeof(uffs_FileEmu));
130 emu->emu_filename = conf_emu_filename;
131 }
132
init_uffs_fs(void)133 static int init_uffs_fs(void)
134 {
135 static int bIsFileSystemInited = 0;
136 struct uffs_MountTableEntrySt *mtbl = &(conf_mounts[0]);
137 struct uffs_ConfigSt cfg = {
138 0, // bc_caches - default
139 0, // page_buffers - default
140 0, // dirty_pages - default
141 0, // dirty_groups - default
142 0, // reserved_free_blocks - default
143 };
144
145 if (bIsFileSystemInited)
146 return -4;
147
148 bIsFileSystemInited = 1;
149
150 while (mtbl->dev) {
151
152 memcpy(&mtbl->dev->cfg, &cfg, sizeof(struct uffs_ConfigSt));
153
154 #if CONFIG_USE_SYSTEM_MEMORY_ALLOCATOR > 0
155 uffs_MemSetupSystemAllocator(&mtbl->dev->mem);
156 #endif
157 setup_device(mtbl->dev);
158 uffs_RegisterMountTable(mtbl);
159 mtbl++;
160 }
161
162 // mount partitions
163 for (mtbl = &(conf_mounts[0]); mtbl->mount != NULL; mtbl++) {
164 uffs_Mount(mtbl->mount);
165 }
166
167 return uffs_InitFileSystemObjects() == U_SUCC ? 0 : -1;
168 }
169
release_uffs_fs(void)170 static int release_uffs_fs(void)
171 {
172 int ret = 0;
173 uffs_MountTable *mtb;
174
175 for (mtb = &(conf_mounts[0]); ret == 0 && mtb->mount != NULL; mtb++) {
176 uffs_UnMount(mtb->mount);
177 }
178
179 if (ret == 0)
180 ret = (uffs_ReleaseFileSystemObjects() == U_SUCC ? 0 : -1);
181
182 return ret;
183 }
184
185 /* mount point arg: /sys/,100,-1 */
parse_mount_point(char * arg,int m_idx)186 static int parse_mount_point(char *arg, int m_idx)
187 {
188 int start = 0, end = -1;
189 char *p = arg;
190 struct uffs_MountTableEntrySt *mtbl = &(conf_mounts[m_idx]);
191
192 while(*p && *p != ',' && *p != ' ' && *p != '\t')
193 p++;
194
195 if (*p == 0 || p == arg)
196 return -1;
197
198 mtbl->mount = &(mount_point_name[m_idx][0]);
199 memcpy((char *)mtbl->mount, arg, p - arg);
200 ((char *)(mtbl->mount))[p - arg] = 0;
201
202 p++;
203 arg = p;
204 while(*p && *p != ',' && *p != ' ' && *p != '\t')
205 p++;
206
207 if (p != arg) {
208 if (sscanf(arg, "%i", &start) < 1)
209 return -1;
210 p++;
211 arg = p;
212
213 while(*p && *p != ',' && *p != ' ' && *p != '\t')
214 p++;
215
216 if (p != arg) {
217 if (sscanf(arg, "%i", &end) < 1)
218 return -1;
219 }
220 }
221 mtbl->start_block = start;
222 mtbl->end_block = end;
223 mtbl->dev = &(conf_devices[m_idx]);
224
225 return 0;
226 }
227
parse_options(int argc,char * argv[])228 static int parse_options(int argc, char *argv[])
229 {
230 int iarg;
231 int usage = 0;
232 int m_idx = 0;
233 static char em_file[128];
234 int i;
235
236 for (iarg = 1; iarg < argc && !usage; iarg++) {
237 const char *arg = argv[iarg];
238
239 if (arg[0] == '-') {
240 if (!strcmp(arg, "-h") || !strcmp(arg, "--help")) {
241 usage++;
242 }
243 else if (!strcmp(arg, "-f") || !strcmp(arg, "--file")) {
244 if (++iarg >= argc)
245 usage++;
246 else {
247 strcpy(em_file, argv[iarg]);
248 conf_emu_filename = (const char *)em_file;
249 }
250 }
251 else if (!strcmp(arg, "-c") || !strcmp(arg, "--command-line")) {
252 conf_command_line_mode = 1;
253 }
254 else if (!strcmp(arg, "-p") || !strcmp(arg, "--page-size")) {
255 if (++iarg >= argc)
256 usage++;
257 else if (sscanf(argv[iarg], "%i", &conf_page_data_size) < 1)
258 usage++;
259 if (conf_page_data_size <= 0 || conf_page_data_size > UFFS_MAX_PAGE_SIZE) {
260 MSGLN("ERROR: Invalid page data size");
261 usage++;
262 }
263 }
264 else if (!strcmp(arg, "-s") || !strcmp(arg, "--spare-size")) {
265 if (++iarg >= argc)
266 usage++;
267 else if (sscanf(argv[iarg], "%i", &conf_page_spare_size) < 1)
268 usage++;
269 if (conf_page_spare_size < sizeof(struct uffs_TagStoreSt) + 1 ||
270 (conf_page_spare_size % 4) != 0 || conf_page_spare_size > UFFS_MAX_SPARE_SIZE) {
271 MSGLN("ERROR: Invalid spare size");
272 usage++;
273 }
274 }
275 else if (!strcmp(arg, "-o") || !strcmp(arg, "--status-offset")) {
276 if (++iarg >= argc)
277 usage++;
278 else if (sscanf(argv[iarg], "%i", &conf_status_byte_offset) < 1)
279 usage++;
280 if (conf_status_byte_offset < 0)
281 usage++;
282 }
283 else if (!strcmp(arg, "-b") || !strcmp(arg, "--block-pages")) {
284 if (++iarg >= argc)
285 usage++;
286 else if (sscanf(argv[iarg], "%i", &conf_pages_per_block) < 1)
287 usage++;
288 if (conf_pages_per_block < 2)
289 usage++;
290 }
291 else if (!strcmp(arg, "-t") || !strcmp(arg, "--total-blocks")) {
292 if (++iarg >= argc)
293 usage++;
294 else if (sscanf(argv[iarg], "%i", &conf_total_blocks) < 1)
295 usage++;
296 if (conf_total_blocks < 2)
297 usage++;
298 }
299 else if (!strcmp(arg, "-v") || !strcmp(arg, "--verbose")) {
300 conf_verbose_mode++;
301 }
302 else if (!strcmp(arg, "-m") || !strcmp(arg, "--mount")) {
303 if (++iarg > argc)
304 usage++;
305 else if (parse_mount_point(argv[iarg], m_idx) < 0)
306 usage++;
307 m_idx++;
308 }
309 else if (!strcmp(arg, "-e") || !strcmp(arg, "--exec")) {
310 if (++iarg > argc)
311 usage++;
312 else {
313 sprintf(script_command, "script %s", argv[iarg]);
314 conf_exec_script = 1;
315 }
316 }
317 else if (!strcmp(arg, "-x") || !strcmp(arg, "--ecc-option")) {
318 if (++iarg > argc)
319 usage++;
320 else {
321 for (i = 0; i < ARRAY_SIZE(g_ecc_option_strings); i++) {
322 if (!strcmp(argv[iarg], g_ecc_option_strings[i])) {
323 conf_ecc_option = i;
324 break;
325 }
326 }
327 if (i == ARRAY_SIZE(g_ecc_option_strings)) {
328 MSGLN("ERROR: Invalid ECC option");
329 usage++;
330 }
331 }
332 }
333 else if (!strcmp(arg, "-z") || !strcmp(arg, "--ecc-size")) {
334 if (++iarg >= argc)
335 usage++;
336 else if (sscanf(argv[iarg], "%i", &conf_ecc_size) < 1)
337 usage++;
338 if (conf_ecc_size < 0 || conf_ecc_size > UFFS_MAX_ECC_SIZE) {
339 MSGLN("ERROR: Invalid ecc size");
340 usage++;
341 }
342 }
343 else {
344 MSGLN("Unknown option: %s, try %s --help", arg, argv[0]);
345 return -1;
346 }
347 }
348 else {
349 MSGLN("Unexpected parameter: %s, try %s --help", arg, argv[0]);
350 return -1;
351 }
352 }
353
354 if (usage) {
355 MSGLN("Usage: %s [options]", argv[0]);
356 MSGLN(" -h --help show usage");
357 MSGLN(" -c --command-line command line mode");
358 MSGLN(" -v --verbose verbose mode");
359 MSGLN(" -f --file <file> uffs image file");
360 MSGLN(" -p --page-size <n> page data size, default=%d", PAGE_DATA_SIZE_DEFAULT);
361 MSGLN(" -s --spare-size <n> page spare size, default=%d", PAGE_SPARE_SIZE_DEFAULT);
362 MSGLN(" -o --status-offset <n> status byte offset, default=%d", STATUS_BYTE_OFFSET_DEFAULT);
363 MSGLN(" -b --block-pages <n> pages per block, default=%d", PAGES_PER_BLOCK_DEFAULT);
364 MSGLN(" -t --total-blocks <n> total blocks");
365 MSGLN(" -m --mount <mount_point,start,end> , for example: -m /,0,-1");
366 MSGLN(" -x --ecc-option <none|soft|hw|auto> ECC option, default=%s", g_ecc_option_strings[ECC_OPTION_DEFAULT]);
367 MSGLN(" -z --ecc-size <n> ECC size, default=0 (auto)");
368 MSGLN(" -e --exec <file> execute a script file");
369 MSGLN("");
370
371 return -1;
372 }
373
374 if (m_idx == 0) {
375 // if not given mount information, use default ('/' for whole partition)
376 parse_mount_point("/,0,-1", 0);
377 }
378
379 return 0;
380 }
381
382
print_mount_points(void)383 static void print_mount_points(void)
384 {
385 struct uffs_MountTableEntrySt *m;
386
387 m = &(conf_mounts[0]);
388 while (m->dev) {
389 MSGLN ("Mount point: %s, start: %d, end: %d", m->mount, m->start_block, m->end_block);
390 m++;
391 }
392 }
393
print_params(void)394 static void print_params(void)
395 {
396 MSGLN("Parameters summary:");
397 MSGLN(" uffs image file: %s", conf_emu_filename);
398 MSGLN(" page size: %d", conf_page_data_size);
399 MSGLN(" page spare size: %d", conf_page_spare_size);
400 MSGLN(" pages per block: %d", conf_pages_per_block);
401 MSGLN(" total blocks: %d", conf_total_blocks);
402 MSGLN(" ecc option: %d (%s)", conf_ecc_option, g_ecc_option_strings[conf_ecc_option]);
403 MSGLN(" ecc size: %d%s", conf_ecc_size, conf_ecc_size == 0 ? " (auto)" : "");
404 MSGLN(" bad block status offset: %d", conf_status_byte_offset);
405 MSGLN("");
406 }
407
408 #ifdef UNIX
409 #include <execinfo.h>
410 #include <signal.h>
crash_handler(int sig)411 void crash_handler(int sig)
412 {
413 void *array[10];
414 size_t size;
415
416 // get void*'s for all entries on the stack
417 size = backtrace(array, 10);
418
419 // print out all the frames to stderr
420 fprintf(stderr, "Error: signal %d:\n", sig);
421 backtrace_symbols_fd(array, size, 2);
422 exit(1);
423 }
424 #endif
425
main(int argc,char * argv[])426 int main(int argc, char *argv[])
427 {
428 int ret;
429
430 #ifdef UNIX
431 signal(SIGSEGV, crash_handler);
432 #endif
433
434 uffs_SetupDebugOutput(); // setup debug output as early as possible
435
436 if (parse_options(argc, argv) < 0) {
437 return -1;
438 }
439
440 if (conf_verbose_mode) {
441 #if 1
442 MSGLN("Internal data structure size:");
443 MSGLN(" TreeNode: %d", sizeof(TreeNode));
444 MSGLN(" struct BlockListSt: %d", sizeof(struct BlockListSt));
445 MSGLN(" struct DirhSt: %d", sizeof(struct DirhSt));
446 MSGLN(" struct FilehSt: %d", sizeof(struct FilehSt));
447 MSGLN(" struct FdataSt: %d", sizeof(struct FdataSt));
448 MSGLN(" struct uffs_TagStoreSt: %d", sizeof(struct uffs_TagStoreSt));
449 MSGLN(" uffs_Buf: %d", sizeof(uffs_Buf));
450 MSGLN(" struct uffs_BlockInfoSt: %d", sizeof(struct uffs_BlockInfoSt));
451 MSGLN("");
452 #endif
453 print_params();
454 print_mount_points();
455 }
456
457 // setup file emulator storage with parameters from command line
458 setup_storage(femu_GetStorage());
459
460 // setup file emulator private data
461 setup_emu_private(femu_GetPrivate());
462
463 ret = init_uffs_fs();
464 if (ret != 0) {
465 MSGLN ("Init file system fail: %d", ret);
466 return -1;
467 }
468
469 cli_add_commandset(get_helper_cmds());
470 cli_add_commandset(get_test_cmds());
471 if (conf_command_line_mode) {
472 if (conf_exec_script) {
473 cli_interpret(script_command);
474 }
475 cli_main_entry();
476 }
477 else {
478 if (conf_exec_script) {
479 cli_interpret(script_command);
480 }
481 else {
482 cli_main_entry();
483 }
484 }
485
486 release_uffs_fs();
487
488 return 0;
489 }
490 #endif
491
492
493
494