裸機移植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;
};
這個結構體真是龐大啊。