裸机移植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 

 * 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 

 * 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("\b\n");     

    printf("\bBootstrap nandflash yaffs2 test Version 0.0.1\n");

    /*  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!\n", MALLOC_SIZE);

    printf("Malloc address: %p, string: %s\n", 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 == '\n')              /*  If \n, also do \r */

            s3c2440_serial_putc('\r', 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\n", 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!\n", MALLOC_SIZE);

    printf("Malloc address: %p, string: %s\n", 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\n", 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\n\n");

    

    /*  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\n");

        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\n",

            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;

};

这个结构体真是庞大啊,

你可能感兴趣的:(文件系统篇,嵌入式系统开发流程)