s5pv210 Development Series eight yaffs porting
Chess Boy 1048272975
NAND, one of the most important nonvolatile flash technologies on the market, is used in a wide range of solid-state mass storage solutions. Due to the characteristics of NAND flash itself, NAND memory often requires a dedicated NAND file system for management. Open source Yaffs file system due to its excellent performance, in the NAND flash is widely used, the author here on the yaffs of the transplant for a simple introduction.
1. Yaffs Overview
Yaffs is a NAND Flash file system developed by Aleph One, designed specifically for NAND flash memory and suitable for large-capacity storage devices. Published under the GPL, the source code can be obtained free of charge on its official website.
Yaffs is a log-based file system that provides robustness for bad block management, wear balancing, and power-down recovery, ensuring that data is accidentally and not destroyed during system modifications to the file system. Especially for NAND flash, in the boot time, memory space occupancy, read-write speed and other aspects of the optimization has been used in Linux, Android, wince and other commercial products.
2. Yaffs Transplant
The Yaffs file system is divided into the file System management interface, the Yaffs internal implementation layer and the NAND interface layer, which simplifies the interface design with the system and facilitates integration into the system. Porting is the implementation of the NAND interface layer. Since Yaffs has been maintaining the update, its internal data structure, function implementation process and other minor updates. Therefore, for the larger time span version, there will be a large difference between the migration. For portable open source projects, generally should be in the source package corresponding to the makefile, Readme and other documents to learn the project directory structure, extract the corresponding source code. Interface porting should also refer to the source package of the demo interface porting, to understand the corresponding interface should realize the functional requirements, to facilitate the implementation of similar interface functions for specific devices. Application programming can also be referenced in the source code for application testing. The author here to 2015/06 version of the source code as an example to illustrate the yaffs transplant.
2.1. Compiler-related
For portable open source projects, there is no compiler data type, extension syntax, etc., because the CPU of different systems, different compilers this part is different, is not portable, open source project has its own definition of data type, which needs to be defined according to the specific CPU, the specific compiler. Yaffs provides a POSIX file manipulation interface that uses POSIX file manipulation data types, and POSIX is an application programming interface for UNIX under portable operating systems, not the C standard, and the C compiler does not have to implement POSIX, so you need to customize the POSIX data types used in yaffs. Yaffs application programming is completely consistent with POSIX file operation application programming. That is, POSIX-based applications are source-level portable in Unix-based classes, Windows, POSIX-enabled RTOs, and so on.
#ifndef __yaffs_config_h__
#define __yaffs_config_h__
#define Config_yaffs_direct
#define CONFIG_YAFFS_YAFFS2
#define Config_yaffs_provide_defs
#define Config_yaffsfs_provide_values
#define Config_yaffs_defines_types
typedef unsigned short dev_t;
typedef unsigned short mode_t;
typedef long OFF_T;
typedef long Long loff_t;
#endif
2.2. Operating system-related
Yaffs requires access to operating system resources, such as providing locks, timestamps, system errors, and so on. For single-threaded access, no operating system does not require operating system locks and other related features. In Yaffs, yaffs_osglue.h lists the operating system-related interface functions that are required for implementation.
#include "stdio.h"
#include "Stdlib.h"
#include "time.h"
Static Intyaffs_errno;
/*
* YAFFS_BUG_FN ()
* Function to report a bug.
*/
VOIDYAFFS_BUG_FN (const char *FN, int n)
{
printf ("Yaffs Bug at%s:%d\n", fn,n);
}
/*
* Yaffsfs_currenttime () retrns a 32-bittimestamp.
*
* Can return 0 If your system does not careabout time.
*/
unsigned intyaffsfs_currenttime (void)
{
Return time (NULL);
}
/*
* Yaffsfs_seterror () Andyaffsfs_getlasterror ()
* Do whatever to set the system error.
* YAFFSFS_GETLASTERROR () just fetches the lasterror.
*/
Voidyaffsfs_seterror (int err)
{
Yaffs_errno = err;
}
Intyaffsfs_getlasterror (void)
{
return yaffs_errno;
}
/*
* Yaffsfs_checkmemregion ()
* Check that access to a address is valid.
* This can check memory are in bounds and iswritable etc.
*
* Returns 0 if OK, negative if not.
*/
Intyaffsfs_checkmemregion (const void *ADDR, size_t size, int write_request)
{
if (!ADDR) {
return-1;
}
return 0;
}
/*
* YAFFSFS_MALLOC ()
* Yaffsfs_free ()
*
* Functions to allocate and free memory.
*/
Void*yaffsfs_malloc (size_t size)
{
return malloc (size);
}
Voidyaffsfs_free (void *ptr)
{
Free (PTR);
}
/*
* Yaffsfs_lock ()
* Yaffsfs_unlock ()
* A single mechanism to lock and unlock yaffs. Hook up to a mutex or whatever.
*/
Voidyaffsfs_lock (void)
{
}
Voidyaffsfs_unlock (void)
{
}
Voidyaffsfs_osinitialisation (void)
{
/* No Locking used */
}
2.3. NAND interface Related
NAND drivers are described in detail in the previous sections, typically for NAND flash, NAND-based drivers should implement NAND initialization, NAND page reading, NAND page programming, NAND block Erasure, NAND bad block tagging, NAND bad block checking. Yaffs access to the above NAND underlying driver interface by means of a function pointer, the NAND interface function pointers to be implemented are as follows:
Int (*DRV_WRITE_CHUNK_FN) (struct yaffs_dev *dev, int nand_chunk,
Const U8 *data, int data_len,
Constu8 *oob, int oob_len);
Int (*DRV_READ_CHUNK_FN) (struct yaffs_dev *dev, int nand_chunk,
U8 *data, int data_len,
U8 *oob, int oob_len,
Enum Yaffs_ecc_result *ecc_result);
Int (*DRV_ERASE_FN) (struct yaffs_dev *dev, int block_no);
Int (*DRV_MARK_BAD_FN) (struct yaffs_dev *dev, int block_no);
Int (*DRV_CHECK_BAD_FN) (struct yaffs_dev *dev, int block_no);
Int (*DRV_INITIALISE_FN) (struct Yaffs_dev *dev);
Int (*DRV_DEINITIALISE_FN) (struct Yaffs_dev *dev);
2.3.1. Drv_initialise_fn function pointer
DRV_INITIALISE_FN primarily implements the initialization of NAND, which is first called by the function pointer when the file system is mounted.
static int yaffs_nand_drv_initialise (struct Yaffs_dev*dev)
{
Nand_init ();
RETURNYAFFS_OK;
}
2.3.2. Drv_erase_fn function pointer
Drv_erase_fn mainly erases a block.
static int Yaffs_nand_drv_eraseblock (struct yaffs_dev*dev, int block_no)
{
if (Nand_eraseblock (block_no)! = 0) {
Returnyaffs_fail;
}
RETURNYAFFS_OK;
}
2.3.3. Drv_mark_bad_fn function pointer
DRV_MARK_BAD_FN need to implement a bad block tag for a piece.
static int Yaffs_nand_drv_markbad (struct yaffs_dev*dev, int block_no)
{
if (Nand_markbadblock (block_no)! = 0) {
Returnyaffs_fail;
}
RETURNYAFFS_OK;
}
2.3.4. Drv_check_bad_fn function pointer
DRV_CHECK_BAD_FN need to implement a piece to check, whether bad block.
static int Yaffs_nand_drv_checkbad (struct yaffs_dev*dev, int block_no)
{
if (Nand_isbadblock (block_no)! = 0) {
Badblock
Returnyaffs_fail;
}
RETURNYAFFS_OK;
}
2.3.5. Drv_write_chunk_fn function pointer
DRV_WRITE_CHUNK_FN is required to implement a specific length of data written to a chunk (page) in the NAND data area, typically 1 chunk (page), and to write OOB data (tags) of a specific length in the NAND spare area.
static int Yaffs_nand_drv_writechunk (struct yaffs_dev*dev, int nand_chunk,
Const U8*data, int data_len, const u8 *oob, int oob_len)
{
if (!data | |! OOB) {
Returnyaffs_fail;
}
if (Nand_writewithoob (nand_chunk, data, Data_len, OOB, oob_len)! = 0) {
Returnyaffs_fail;
}
RETURNYAFFS_OK;
}
2.3.6.DRV_READ_CHUNK_FN function pointer
DRV_READ_CHUNK_FN is required to read data of a certain length on a chunk (page) in the NAND data area, typically 1 chunk (page), and to read OOB data (tags) of a specific length in the NAND spare area. The NAND-driven hardware ECC is used here, and the software ECC, which is not yaffs, is required to process the data without error or error correction.
static int Yaffs_nand_drv_readchunk (struct yaffs_dev*dev, int nand_chunk,
U8*data, int data_len, U8 *oob, int oob_len,
Enumyaffs_ecc_result *ecc_result_out)
{
int ret;
if (data ==null) {
data_len= 0;
}
RET =nand_readwithoob (nand_chunk, data, Data_len, OOB, Oob_len);
if (ret! = 0) {
if (ecc_result_out) {
*ecc_result_out= Yaffs_ecc_result_unknown;
}
Returnyaffs_fail;
} else {
if (ecc_result_out) {
*ecc_result_out= Yaffs_ecc_result_no_error;
}
}
RETURNYAFFS_OK;
}
2.3.7.DRV_DEINITIALISE_FN function pointer
DRV_DEINITIALISE_FN to uncheck Nand flash,do nothing.
static int yaffs_nand_drv_deinitialise (Structyaffs_dev *dev)
{
RETURNYAFFS_OK;
}
2.3.8.yaffs_start_up function
Yaffs before mounting, the NAND driver must be installed and the corresponding NAND underlying access interface is loaded into the Yaffs interface layer via the YAFFS_START_UP function.
struct Yaffs_dev *yaffs_nand_install_drv (const char*dev_name)
{
struct yaffs_driver*drv;
Structyaffs_dev *dev;
Structyaffs_param *param;
Dev =malloc (sizeof (struct yaffs_dev));
if (!dev) {
Returnnull;
}
memset (dev,0, sizeof (*dev));
Param =&dev->param;
Param->name= StrDup (dev_name);
if (!param->name) {
Free (dev);
Returnnull;
}
param->total_bytes_per_chunk= 2048;
param->chunks_per_block= 64;
Param->n_reserved_blocks= 5;
Param->start_block= 32; First block, reserve 4M for boot
Param->end_block= 4096-1;
Param->is_yaffs2= 1;
Param->use_nand_ecc= 1; Use driver ' s ECC
Param->n_caches= 10;
DRV =&dev->drv;
Drv->drv_write_chunk_fn= Yaffs_nand_drv_writechunk;
Drv->drv_read_chunk_fn= Yaffs_nand_drv_readchunk;
Drv->drv_erase_fn= Yaffs_nand_drv_eraseblock;
Drv->drv_mark_bad_fn= Yaffs_nand_drv_markbad;
Drv->drv_check_bad_fn= Yaffs_nand_drv_checkbad;
Drv->drv_initialise_fn= yaffs_nand_drv_initialise;
Drv->drv_deinitialise_fn= yaffs_nand_drv_deinitialise;
/* The Yaffsdevice have been configured, install it into yaffs */
Yaffs_add_device (Dev);
return dev;
}
int yaffs_start_up (void)
{
static u8start_up_called = 0;
if (start_up_called) {
return 0;
}
Start_up_called= 1;
Stuff toinitialise anything special (eg lock semaphore).
Yaffsfs_osinitialisation ();
Yaffs_nand_install_drv ("/");
return 0;
}
3. Application Testing
Yaffs provides POSIX file operation application interfaces, so yaffs application programming is virtually identical to the POSIX file operation application programming. Here the test in the "/" directory can be selected by the creation of the Test.txt test file, each time the file can be accumulated to write test string, the corresponding options to read the contents of the file, you can choose to enumerate all the "/" Directory of all Files, the first time you use Yaffs, you must first the NAND Flash is formatted, otherwise the dirty data of different NAND drivers will cause errors in NAND information.
static const char test[] = "This is yaffs testfile\r\n";
static const char *YAFFS_FILE_TYPE_STR (Structyaffs_stat *stat)
{
Switch (Stat->st_mode & s_ifmt) {
Case S_ifreg:return "regular file";
Case S_ifdir:return "Directory";
Case S_iflnk:return "Symlink";
Default:return "Unknown";
}
}
int Yaffs_ls (const char *MOUNTPT, int longlist)
{
int i;
Yaffs_dir *d;
Structyaffs_dirent *de;
Structyaffs_stat Stat;
CHARTEMPSTR[255];
D =yaffs_opendir (MOUNTPT);
if (!d) {
printf ("opendirfailed,%s\n", Yaffs_error_to_str (Yaffsfs_getlasterror ()));
return-1;
}
for (i = 0; (de = Yaffs_readdir (d))! = NULL; i++) {
if (longlist) {
sprintf (TempStr, "%s/%s", MOUNTPT, De->d_name);
Yaffs_lstat (Tempstr,&stat);
printf ("%-25s\t%7ld",
De->d_name,
(long) stat.st_size);
printf ("%5d%s\n",
Stat.st_ino,
Yaffs_file_type_str (&stat));
} else {
printf ("%s\n", de->d_name);
}
}
Yaffs_closedir (d);
return 0;
}
Re-scan labeled bad blocks against new drive rules
void Nand_scan_bad_block (void)
{
int i;
for (i = 8; i<= (2048-1); i++) {
if (Nand_isbadblock (i)) {
if (Nand_eraseblock (i)) {
Nand_markbadblock (i);//REALLY bad block
}
}
}
}
void Main (void)
{
Char text[1024];
int handle;
int bytesread;
uint8_t Command;
Rtc_time time = {
2015, 7, 1, 22, 00, 0, 3
};
Uart_init ();
Rtc_init (&time);
Yaffs_start_up ();
Yaffs_mount ("/");
while (1) {
printf ("1:write test.txt\n");
printf ("2:view test.txt\n");
printf ("3:list files in nand\n");
printf ("4:format nand flash\n");
Command = Uart_waitchar ();
Switch (Command) {
Case ' 1 ':
Handle =yaffs_open ("/test.txt", o_creat| o_wronly| O_append, s_iread| S_iwrite);
if (handle ==-1) {
printf ("Createtest.txt failed\n");
Break
}
Yaffs_write (Handle,test, strlen (test));
Yaffs_close (handle);
Break
Case ' 2 ':
Handle =yaffs_open ("/test.txt", O_rdonly, s_iread| S_iwrite);
if (handle ==-1) {
printf ("Opentest.txt failed\n");
Break
}
while (1) {
Bytesread =yaffs_read (handle, text, sizeof (text)-1);
if (bytesread==-1) {
printf ("Read test.txt error\n");
Yaffs_close (handle);
Break
}
text[bytesread]= 0;
printf ("%s", Text);
if (bytesread< (sizeof (Text)-1)) {
Yaffs_close (handle);
Break
}
}
Break
Case ' 3 ':
Yaffs_ls ("/", 1);
Break
Case ' 4 ':
Yaffs_unmount ("/");
Nand_scan_bad_block ();
Yaffs_format ("/", 0, 0, 0);
Yaffs_mount ("/");
Break
Default
Break
}
printf ("\ n");
}
}
4. Appendix
S5pv210_yaffs.rar,yaffs in the IAR transplant project, including s5pv210 Bootloader, yaffs source, and the corresponding NAND flash drive.
Http://pan.baidu.com/s/1gdxYmqB
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
s5pv210 Development Series eight _yaffs porting