歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 裸機移植yaffs2文件系統

裸機移植yaffs2文件系統

日期:2017/3/1 9:55:43   编辑:Linux編程

裸機移植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 <[email protected]>

* 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 <[email protected]>

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

};

這個結構體真是龐大啊。

Copyright © Linux教程網 All Rights Reserved