首页 / 操作系统 / Linux / 裸机移植yaffs2文件系统
裸机移植yaffs2演示 Linux系统上 [fulinux@CentOS6 ~]$ cd yaffs2/ [fulinux@centos6 yaffs2]$ ls bootstrap.c bootstrap.lds bsp common makefile start.S yaffs2 [fulinux@centos6 yaffs2]$ make ........................ ........................ ........................ [fulinux@centos6 yaffs2]$ ls bootstrap.bin bootstrap.c bootstrap.lds bootstrap.map bsp common makefile start.S yaffs2 [fulinux@centos6 yaffs2]$ 将bootstrap.bin文件拷贝到/tfpt目录下 s3c2440开发板上 [ s3c2440@guowenxue ]# set bstarp "tftp 31000000 bootstrap.bin;go 31000000" [ s3c2440@guowenxue ]# save Saving Environment to NAND... Erasing Nand... Erasing at 0x60000 -- 100% complete. Writing to Nand... done [ s3c2440@guowenxue ]# run bstarp dm9000 i/o: 0x20000300, id: 0x90000a46 DM9000: running in 16 bit mode MAC: 08:00:3e:26:0a:6b could not establish link operating at 100M full duplex mode Using dm9000 device TFTP from server 192.168.1.2; our IP address is 192.168.1.111 Filename "bootstrap.bin". Load address: 0x31000000 Loading: T ############## done Bytes transferred = 193924 (2f584 hex) ## Starting application at 0x31000000 ... Bootstrap nandflash yaffs2 test Version 0.0.1 malloc memory space: 0x30f00000~0x31000000 Malloc address: 30f00008, string: Hello World! Configures yaffs mount /nand: start block 16, end block 96 "/nand" mounted Create directory [/nand/foo] Create File [/nand/foo/f1] content: [foo/f1] Create File [/nand/foo/f2] content: [foo/f2] Create File [/nand/foo/f3] content: [foo/f3] Create File [/nand/foo/f4] content: [foo/f4] Create directory [/nand/bar] Create File [/nand/bar/f1] content: [bar/f1] List folder "/nand" with recursive: drw- 1 /nand/bar 2048 bytes -rw- 1 /nand/bar/f1 6 bytes drw- 1 /nand/foo 2048 bytes -rw- 1 /nand/foo/f4 6 bytes -rw- 1 /nand/foo/f3 6 bytes -rw- 1 /nand/foo/f2 6 bytes -rw- 1 /nand/foo/f1 6 bytes drw- 1 /nand/lost+found 2048 bytes Remove /nand/foo/f4 Remove /nand/bar List folder "/nand" with recursive: drw- 1 /nand/foo 2048 bytes -rw- 1 /nand/foo/f3 6 bytes -rw- 1 /nand/foo/f2 6 bytes -rw- 1 /nand/foo/f1 6 bytes drw- 1 /nand/lost+found 2048 bytes unmount and remount List folder "/nand" with recursive: drw- 1 /nand/lost+found 2048 bytes 代码分析 [fulinux@centos6 yaffs2]$ ls bootstrap.bin bootstrap.c bootstrap.lds bootstrap.map bsp common makefile start.S yaffs2 [fulinux@centos6 yaffs2]$ 先看看make后生成的bootstrap.map文件中主要的段: Linker script and memory map startsize size 0x0000000000000000 . = ALIGN (0x4) (.stack xxxxxxxxxxxxxxxxxx xxxx 运行时初始化这个段) .text 0x0000000031000000 0x2c3dc .rodata 0x000000003102c3dc 0x2c58 .data 0x000000003102f054 0x10 .bss 0x000000003102f588 0x36b4 其中代码段的第一个代码是start.S start.S文件 /******************************************************************************************** * File: start.S - Startup Code for ARM920 CPU-core * Version: 1.0.0 * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> * Description: When system power up, the CPU will comes here to excute the first code here. * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" * *******************************************************************************************/ /* ************************************************************************* * * Jump vector table as in table 3.1 in [1] * ************************************************************************* */ .globl _start _start: b start_code _TEXT_BASE: .word TEXT_BASE .globl _armboot_start _armboot_start: .word _start /* * These are defined in the board-specific linker script. */ .globl _bss_start _bss_start: .word __bss_start .globl _bss_end _bss_end: .word _end start_code: /* Set up the stack */ stack_setup: ldr r0, =TEXT_BASE /* upper 128 KiB: relocated uboot */ sub r0, r0, #CONFIG_SYS_MALLOC_LEN /* malloc area */ sub sp, r0, #12 /* leave 3 words for abort-stack */ bic sp, sp, #7 /* 8-byte alignment for ABI compliance */ clear_bss: ldr r0, _bss_start /* find start of bss segment */ ldr r1, _bss_end /* stop here */ mov r2, #0x00000000 /* clear */ clbss_l:str r2, [r0] /* clear loop... */ add r0, r0, #4 cmp r0, r1 ble clbss_l bl bootstrap_main 堆栈段初始化 其中TEXT_BASE和#CONFIG_SYS_MALLOC_LEN变量是在makefile文件中定义的,如下: # Set the stack top base address here TEXT_BASE=0x31000000 STACK_BASE=0x31010000 MALLOC_SIZE=0x100000 CFLAGS+=-DTEXT_BASE=$(TEXT_BASE) -DSTACK_BASE=${STACK_BASE} -DCONFIG_SYS_MALLOC_LEN=${MALLOC_SIZE} 上面的CFLAGS一行中的-D的意思类似于#define,,例如-DTEXT_BASE=$(TEXT_BASE) 等于#define TEXT_BASE 0X31000000。. BSS段初始化 Bss段初始化代码其中的_bss_start ---> __bss_start是在makefile文件中 APP_NAME=bootstrap LDFLAGS=-Bstatic -T$(APP_NAME).lds -Ttext $(TEXT_BASE) 参数LDFLAGS依赖于文件bootstrap.lds文件,如下 /******************************************************************************************** * File: bootstrap.lds * Version: 1.0.0 * Copyright: 2011 (c) Guo Wenxue <guowenxue@gmail.com> * Description: This is the LD linker configure script for bootstrap * ChangeLog: 1, Release initial version on "Tue Jul 12 16:43:18 CST 2011" * *******************************************************************************************/ OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") OUTPUT_ARCH(arm) ENTRY(_start) SECTIONS{ . = ALIGN(4); .text : { start.o (.text) *(.text) } . = ALIGN(4); .rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } . = ALIGN(4); .rodata : { *(.rodata) } . = ALIGN(4); .data : { *(.data) } . = ALIGN(4); __bss_start = .; .bss : { *(.bss) } _end = .; } 然后是跳转到c函数中的bootstarp_main()函数中去,bootstarp_main()函数如下: 位置:yaffs2/bootstrap.c int bootstrap_main(void) { char *ptr = NULL; int rv = -1; console_serial_init(); printf("
"); printf("Bootstrap nandflash yaffs2 test Version 0.0.1
"); /* armboot_start is defined in the board-specific linker script */ mem_malloc_init (TEXT_BASE - CONFIG_SYS_MALLOC_LEN, CONFIG_SYS_MALLOC_LEN); ptr = (char *)malloc(MALLOC_SIZE); strncpy(ptr, "Hello World!
", MALLOC_SIZE); printf("Malloc address: %p, string: %s
", ptr, ptr); free(ptr); yaffs_test(YAFFSFS_MNT_POINT); hang: while(1) ; return 0; } 首先是初始化串口,console_serial_init()函数如下: 位置:yaffs2/bsp/s3c_board.h #define CONSOLE_BAUDRATE 115200 #define CONSOLE_SERIAL S3C2440_UART0 其中S3C2440_UART0在文件yaffs2/bsp/s3c2440.h中定义: enum s3c2440_uarts_nr { S3C2440_UART0 = 0, S3C2440_UART1 = 1, S3C2440_UART2 = 2 }; #define console_serial_init() s3c2440_serial_init(CONSOLE_BAUDRATE, CONSOLE_SERIAL) 即--> console_serial_init()-->s3c2440_serial_init()如下: int s3c2440_serial_init(unsigned int baudrate, int index) { struct s3c2440_uart *uart = s3c2440_get_base_uart(index); /* FIFO enable, Tx/Rx FIFO clear */ uart->UFCON = 0x07; uart->UMCON = 0x0; /* Normal,No parity,1 stop,8 bit */ uart->ULCON = 0x3; /* * tx=level,rx=edge,disable timeout int.,enable rx error int., * normal,interrupt or polling */ uart->UCON = (1<<8) | (1<<2) | (1<<0); // uart->UMCON = 0x1; /* RTS up */ s3c2440_set_baudrate(baudrate, index); return (0); } 设置波特率函数s3c2440_set_baudrate() void s3c2440_set_baudrate(unsigned int baudrate, int index) { struct s3c2440_uart *uart = s3c2440_get_base_uart(index); unsigned int reg = 0; int i; reg = s3c2440_get_pclk() / (16 * baudrate) - 1; uart->UBRDIV = reg; for (i = 0; i < 100; i++); } 返回到bootstrap_main()函数中去,看下printf()函数如何将打印信息通过串口显示出来。 #define CFG_PBSIZE 1024 /* Print Buffer Size */ void printf(const char *fmt, ...) { va_list args; uint i; char printbuffer[CFG_PBSIZE]; va_start(args, fmt); /* For this to work, printbuffer must be larger than * anything we ever want to print. */ i = vsprintf(printbuffer, fmt, args); va_end(args); console_serial_puts(printbuffer); } 调用函数console_serial_puts()函数,如下: #define console_serial_puts(s) s3c2440_serial_puts(s, CONSOLE_SERIAL) void s3c2440_serial_puts(const char *s, int index) { while (*s) { if (*s == "
") /* If
, also do
*/ s3c2440_serial_putc("
", index); s3c2440_serial_putc (*s++, index); } } 调用函数s3c2440_serial_putc()函数,如下: /* * Output a single byte to the serial port. */ void s3c2440_serial_putc (char c, int index) { struct s3c2440_uart *uart = s3c2440_get_base_uart(index); /* wait for room in the tx FIFO */ //while ((!(uart->UTRSTAT & 0x2))); while (uart->UFSTAT & (1<<14)); uart->UTXH = c; } 返回bootstrap_main()函数,调用mem_mallloc_init()函数初始化动态分配的存储区,为我们调用malloc()函数做好准备工作,如下: void mem_malloc_init(ulong start, ulong size) { mem_malloc_start = start; mem_malloc_end = start + size; mem_malloc_brk = start; memset((void *)mem_malloc_start, 0, size); printf("malloc memory space: 0x%lx~0x%lx
", start, start+size); } 函数返回,调用函数 ptr = (char *)malloc(MALLOC_SIZE); 其中MALLOC_SIZE定义在makefile函数,MALLOC_SIZE=0x100000。我们深入到malloc函数中去,如下 声明位置:yaffs2/common/malloc.h #define mALLOc malloc Void_t* mALLOc(size_t); 定义位置:yaffs2/common/dlmalloc.c 代码量很大,不拷贝了。 返回bootstrap_main()函数,调用如下函数目的是测试动态分配到存储区域是否成功: strncpy(ptr, "Hello World!
", MALLOC_SIZE); printf("Malloc address: %p, string: %s
", ptr, ptr); free(ptr); 接着就到了测试yaffs2文件系统的阶段了。 #define YAFFSFS_MNT_POINT "/nand" yaffs_test(YAFFSFS_MNT_POINT); hang: while(1) ; return 0; } 其中yaffs_test()函数主要是通过创建文件或目录,并删除一些文件的功能来达到测试yaffs2文件系统是否移植成功,代码如下: 位置:与bootstrap_main()函数同处于一个位置。 void yaffs_test(const char *mountpt) { yaffs_start_up(); yaffs_format(mountpt,0,0,0); yaffs_mount(mountpt); printf(""%s" mounted
", mountpt); mkdir(mountpt, "foo"); mkfile(mountpt, "foo/f1"); mkfile(mountpt, "foo/f2"); mkfile(mountpt, "foo/f3"); mkfile(mountpt, "foo/f4"); mkdir(mountpt, "bar"); mkfile(mountpt, "bar/f1"); ls(mountpt, NULL); rm(mountpt, "foo/f4"); rm(mountpt, "bar"); ls(mountpt, NULL); printf("unmount and remount
"); /* Unmount/remount yaffs_trace_mask */ yaffs_unmount(mountpt); yaffs_mount(mountpt); ls(mountpt, NULL); } 其中yaffs_start_up()函数用来配置将要用到的设备,如下: 位置:yaffs2/yaffs2/yaffscfg2k.c /* Configure the devices that will be used */ int yaffs_start_up(void) { static int start_up_called = 0; if(start_up_called) return 0; start_up_called = 1; yaffs_devconfig(YAFFSFS_MNT_POINT, YAFFSFS_START_BLOCK, YAFFSFS_END_BLOCK); /* Call the OS initialisation (eg. set up lock semaphore */ yaffsfs_OSInitialisation(); return 0; } 其中yaffs_devconfig(YAFFSFS_MNT_POINT, YAFFSFS_START_BLOCK, YAFFSFS_END_BLOCK),的参数是宏,如下: #define YAFFSFS_MNT_POINT "/nand" #define YAFFSFS_OFFSET (2*SIZE_1M) /* YAFFS2 file system start offset address */ #define YAFFSFS_SIZE (10*SIZE_1M) /* YAFFS2 file system size */ #define YAFFSFS_START_BLOCK ( YAFFSFS_OFFSET/NF_BLOCK_SIZE ) #define K9F2G08_BLOCK_SIZE 0x20000 /* Nandflash block size: 128K */ #define NF_BLOCK_SIZE K9F2G08_BLOCK_SIZE #define YAFFSFS_END_BLOCK ( YAFFSFS_START_BLOCK+(YAFFSFS_SIZE/NF_BLOCK_SIZE) ) yaffs_devconfig()函数的代码如下: 位置:yaffs2/yaffs2/yaffscfg2k.c int yaffs_devconfig(char *_mp, int start_block, int end_block) { struct yaffs_dev *dev = NULL; char *mp = NULL; dev = malloc(sizeof(*dev)); mp = strdup(_mp); if (!dev || !mp) { /* Alloc error */ printf("Failed to allocate memory
"); return -1; } /* Seems sane, so configure */ memset(dev, 0, sizeof(*dev)); dev->param.name = mp; dev->param.is_yaffs2 = 1; dev->param.total_bytes_per_chunk = NF_PAGE_SIZE; dev->param.spare_bytes_per_chunk = NF_SPARE_SIZE; dev->param.chunks_per_block = NF_BLOCK_SIZE / NF_PAGE_SIZE; dev->param.start_block = start_block; dev->param.end_block = end_block; dev->param.n_reserved_blocks = 8; dev->param.inband_tags = 0; dev->param.use_nand_ecc = 0; dev->param.no_tags_ecc = 0; dev->param.n_caches=0; dev->param.empty_lost_n_found = 1; dev->param.skip_checkpt_rd = 0; dev->param.skip_checkpt_wr = 0; dev->param.refresh_period = 1000; dev->param.initialise_flash_fn = ynf_init; dev->param.erase_fn = ynf_erase_block; dev->param.write_chunk_tags_fn = ynf_write_chunk_tags; dev->param.read_chunk_tags_fn = ynf_read_chunk_tags; dev->param.bad_block_fn = ynf_mark_block_bad; dev->param.query_block_fn = ynf_query_block; dev->driver_context = NULL; yaffs_add_device(dev); printf("Configures yaffs mount %s: start block %d, end block %d %s
", mp, start_block, end_block, dev->param.inband_tags ? "using inband tags" : ""); return 0; } 其中主要是有一个重要的数据结构体struct yaffs_dev,如下 代码清单 struct yaffs_dev结构体 struct yaffs_dev { struct yaffs_param param; /* Context storage. Holds extra OS specific data for this device */ void *os_context; void *driver_context; struct list_head dev_list; /* Runtime parameters. Set up by YAFFS. */ int data_bytes_per_chunk; /* Non-wide tnode stuff */ u16 chunk_grp_bits; /* Number of bits that need to be resolved if * the tnodes are not wide enough. */ u16 chunk_grp_size; /* == 2^^chunk_grp_bits */ /* Stuff to support wide tnodes */ u32 tnode_width; u32 tnode_mask; u32 tnode_size; /* Stuff for figuring out file offset to chunk conversions */ u32 chunk_shift; /* Shift value */ u32 chunk_div; /* Divisor after shifting: 1 for 2^n sizes */ u32 chunk_mask; /* Mask to use for power-of-2 case */ int is_mounted; int read_only; int is_checkpointed; /* Stuff to support block offsetting to support start block zero */ int internal_start_block; int internal_end_block; int block_offset; int chunk_offset; /* Runtime checkpointing stuff */ int checkpt_page_seq; /* running sequence number of checkpt pages */ int checkpt_byte_count; int checkpt_byte_offs; u8 *checkpt_buffer; int checkpt_open_write; int blocks_in_checkpt; int checkpt_cur_chunk; int checkpt_cur_block; int checkpt_next_block; int *checkpt_block_list; int checkpt_max_blocks; u32 checkpt_sum; u32 checkpt_xor; int checkpoint_blocks_required; /* Number of blocks needed to store * current checkpoint set */ /* Block Info */ struct yaffs_block_info *block_info; u8 *chunk_bits; /* bitmap of chunks in use */ unsigned block_info_alt:1; /* allocated using alternative alloc */ unsigned chunk_bits_alt:1; /* allocated using alternative alloc */ int chunk_bit_stride; /* Number of bytes of chunk_bits per block. * Must be consistent with chunks_per_block. */ int n_erased_blocks; int alloc_block; /* Current block being allocated off */ u32 alloc_page; int alloc_block_finder; /* Used to search for next allocation block */ /* Object and Tnode memory management */ void *allocator; int n_obj; int n_tnodes; int n_hardlinks; struct yaffs_obj_bucket obj_bucket[YAFFS_NOBJECT_BUCKETS]; u32 bucket_finder; int n_free_chunks; /* Garbage collection control */ u32 *gc_cleanup_list; /* objects to delete at the end of a GC. */ u32 n_clean_ups; unsigned has_pending_prioritised_gc; /* We think this device might have pending prioritised gcs */ unsigned gc_disable; unsigned gc_block_finder; unsigned gc_dirtiest; unsigned gc_pages_in_use; unsigned gc_not_done; unsigned gc_block; unsigned gc_chunk; unsigned gc_skip; struct yaffs_summary_tags *gc_sum_tags; /* Special directories */ struct yaffs_obj *root_dir; struct yaffs_obj *lost_n_found; int buffered_block; /* Which block is buffered here? */ int doing_buffered_block_rewrite; struct yaffs_cache *cache; int cache_last_use; /* Stuff for background deletion and unlinked files. */ struct yaffs_obj *unlinked_dir; /* Directory where unlinked and deleted files live. */ struct yaffs_obj *del_dir; /* Directory where deleted objects are sent to disappear. */ struct yaffs_obj *unlinked_deletion; /* Current file being background deleted. */ int n_deleted_files; /* Count of files awaiting deletion; */ int n_unlinked_files; /* Count of unlinked files. */ int n_bg_deletions; /* Count of background deletions. */ /* Temporary buffer management */ struct yaffs_buffer temp_buffer[YAFFS_N_TEMP_BUFFERS]; int max_temp; int temp_in_use; int unmanaged_buffer_allocs; int unmanaged_buffer_deallocs; /* yaffs2 runtime stuff */ unsigned seq_number; /* Sequence number of currently allocating block */ unsigned oldest_dirty_seq; unsigned oldest_dirty_block; /* Block refreshing */ int refresh_skip; /* A skip down counter. * Refresh happens when this gets to zero. */ /* Dirty directory handling */ struct list_head dirty_dirs; /* List of dirty directories */ /* Summary */ int chunks_per_summary; struct yaffs_summary_tags *sum_tags; /* Statistics */ u32 n_page_writes; u32 n_page_reads; u32 n_erasures; u32 n_erase_failures; u32 n_gc_copies; u32 all_gcs; u32 passive_gc_count; u32 oldest_dirty_gc_count; u32 n_gc_blocks; u32 bg_gcs; u32 n_retried_writes; u32 n_retired_blocks; u32 n_ecc_fixed; u32 n_ecc_unfixed; u32 n_tags_ecc_fixed; u32 n_tags_ecc_unfixed; u32 n_deletions; u32 n_unmarked_deletions; u32 refresh_count; u32 cache_hits; u32 tags_used; u32 summary_used; }; 这个结构体真是庞大啊。
收藏该网址