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 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 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 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 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 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 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 */ 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 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 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 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> 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 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