From 1c778c3bd4a01a5cad8db6ff52c24c99a3e9fa0e Mon Sep 17 00:00:00 2001 From: Charles Manning Date: Fri, 12 Oct 2012 15:23:30 +1300 Subject: [PATCH] Add yaffs driver for regular NOR on simulator Signed-off-by: Charles Manning --- direct/test-framework/FrameworkRules.mk | 3 +- .../tests/init_fw_update_test_nor.sh | 2 +- direct/test-framework/tests/nor_stress.c | 76 ++-- .../tests/run_fw_update_test_nor.sh | 2 +- direct/test-framework/yaffs_m18_drv.c | 18 +- direct/test-framework/yaffs_nor_drv.c | 346 ++++++++++++++++++ direct/test-framework/yaffs_nor_drv.h | 25 ++ direct/test-framework/yaffscfg2k.c | 2 + direct/test-framework/ynorsim.c | 218 ++++++----- direct/test-framework/ynorsim.h | 16 +- 10 files changed, 558 insertions(+), 150 deletions(-) create mode 100644 direct/test-framework/yaffs_nor_drv.c create mode 100644 direct/test-framework/yaffs_nor_drv.h diff --git a/direct/test-framework/FrameworkRules.mk b/direct/test-framework/FrameworkRules.mk index da47e49..52cd4da 100644 --- a/direct/test-framework/FrameworkRules.mk +++ b/direct/test-framework/FrameworkRules.mk @@ -36,7 +36,7 @@ COMMONTESTOBJS = yaffscfg2k.o yaffs_osglue.o yaffs_hweight.o\ yaffs_packedtags2.o yaffs_nand.o \ yaffs_checkptrw.o yaffs_qsort.o\ yaffs_nameval.o yaffs_attribs.o \ - yaffs_m18_drv.o ynorsim.o \ + yaffs_m18_drv.o yaffs_nor_drv.o ynorsim.o \ yaffs_allocator.o \ yaffs_bitmap.o \ yaffs_yaffs1.o \ @@ -76,6 +76,7 @@ YAFFSDIRECTSYMLINKS = \ FRAMEWORKEXTRASYMLINKS = \ yaffscfg2k.c yaffs_fileem2k.c yaffs_fileem2k.h\ yaffs_fileem.c yaffs_m18_drv.c yaffs_m18_drv.h \ + yaffs_nor_drv.c yaffs_nor_drv.h \ yaffs_ramdisk.c yaffs_ramdisk.h yaffs_ramem2k.c \ ynorsim.h ynorsim.c yaffs_osglue.c diff --git a/direct/test-framework/tests/init_fw_update_test_nor.sh b/direct/test-framework/tests/init_fw_update_test_nor.sh index 8a0cb1a..963f081 100755 --- a/direct/test-framework/tests/init_fw_update_test_nor.sh +++ b/direct/test-framework/tests/init_fw_update_test_nor.sh @@ -2,4 +2,4 @@ # Run this to initialise the file system for the test runs. rm seed-nor-* rm emfile-nor* -./yaffs_test -u -i M18-1 +./yaffs_test -u -i nor diff --git a/direct/test-framework/tests/nor_stress.c b/direct/test-framework/tests/nor_stress.c index 3905771..adf1b29 100644 --- a/direct/test-framework/tests/nor_stress.c +++ b/direct/test-framework/tests/nor_stress.c @@ -51,7 +51,7 @@ static unsigned cycleEnds; static int interleave_fsx; static int no_verification; - + char fullPathName[100]; char fullPowerUpName[100]; char fullStartName[100]; @@ -96,7 +96,7 @@ static void FatalError(int line_no) if(ext_fatal) ext_fatal(); - + while(1){ sleep(1); } @@ -113,11 +113,11 @@ static void UpdateCounter(const char *name, unsigned *val, int initialise) unsigned x[2]; int nread = 0; int nwritten = 0; - + x[0] = x[1] = 0; - + if(initialise){ - x[0] = 0; + x[0] = 0; x[1] = 1; } else { inh = yaffs_open(name,O_RDONLY, S_IREAD | S_IWRITE); @@ -132,18 +132,18 @@ static void UpdateCounter(const char *name, unsigned *val, int initialise) printf("Error reading counter %s handle %d, x[0] %u x[1] %u last error %d\n", name, inh, x[0], x[1],yaffsfs_GetLastError()); FatalError(__LINE__); - + } x[0]++; x[1]++; } - + FSX(); outh = yaffs_open(fullTempCounterName, O_RDWR | O_TRUNC | O_CREAT, S_IREAD | S_IWRITE); - + if(outh >= 0){ struct yaffs_stat tmpstat, oldstat, tmpfstat; - FSX(); + FSX(); yaffs_fstat(outh,&tmpfstat); printf("\n\n\n*** Writing file %s inode %d\n",fullTempCounterName,tmpfstat.st_ino); nwritten = yaffs_write(outh,x,sizeof(x)); @@ -160,15 +160,15 @@ static void UpdateCounter(const char *name, unsigned *val, int initialise) yaffs_rename(fullTempCounterName,name); FSX(); } - + if(nwritten != sizeof(x)){ printf("Error writing counter %s handle %d, x[0] %u x[1] %u\n", name, inh, x[0], x[1]); FatalError(__LINE__); } - + *val = x[0]; - + printf("##\n" "## Set counter %s to %u\n" "##\n", name,x[0]); @@ -183,9 +183,9 @@ static void dump_directory_tree_worker(const char *dname,int recursive) char str[1000]; int error_line = 0; int nentries; - + d = yaffs_opendir(dname); - + if(!d) { printf("opendir failed\n"); @@ -199,9 +199,9 @@ static void dump_directory_tree_worker(const char *dname,int recursive) strcat(str,"/"); strcat(str,de->d_name); nentries++; - + yaffs_lstat(str,&s); - + printf("%s inode %ld %d obj %x length %d mode %X ",str, de->d_ino, s.st_ino,de->d_dont_use,(int)s.st_size,s.st_mode);\ if(de->d_ino != s.st_ino){ printf(" \n\n!!!! HEY inode mismatch\n\n"); @@ -216,21 +216,21 @@ static void dump_directory_tree_worker(const char *dname,int recursive) if(yaffs_readlink(str,str,100) < 0) printf("no alias"); else - printf("\"%s\"",str); + printf("\"%s\"",str); break; default: printf("unknown"); break; } - + printf("\n"); if((s.st_mode & S_IFMT) == S_IFDIR && recursive) dump_directory_tree_worker(str,1); - + if(s.st_ino > 10000) error_line = __LINE__; - + } - + if(strstr(dname,"lost+found") && nentries >0){ printf("\n\n!!! HEY lost+found not empty, had %d entries\n\n\n",nentries); error_line = __LINE__; @@ -238,7 +238,7 @@ static void dump_directory_tree_worker(const char *dname,int recursive) if(error_line && !no_verification) FatalError(error_line); - + yaffs_closedir(d); } @@ -265,13 +265,13 @@ static int y_wr_file(const char *fname, unsigned sz32) int i; struct yaffs_stat st; unsigned checksum = 0; - + FSX(); h = yaffs_open(fname,O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); yaffs_fstat(h,&st); printf("\n\n\n**** Open writing file %s inode %d\n",fname, st.st_ino); - + FSX(); if(h < 0){ @@ -291,7 +291,7 @@ static int y_wr_file(const char *fname, unsigned sz32) xx[i] = sz32 + i; checksum ^= xx[i]; } - + FSX(); if((r = yaffs_write(h,xx,sizeof(xx))) != sizeof(xx)){ goto WRITE_ERROR; @@ -304,7 +304,7 @@ static int y_wr_file(const char *fname, unsigned sz32) if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){ goto WRITE_ERROR; } - + FSX(); yaffs_close(h); printf("File closed\n"); @@ -314,7 +314,7 @@ WRITE_ERROR: printf("ywrite error at position %d\n",(int)yaffs_lseek(h,0,SEEK_END)); yaffs_close(h); return -1; - + } static int y_verify_file(const char *fName) @@ -332,7 +332,7 @@ static int y_verify_file(const char *fName) return 0; printf("Verifying file %s\n",fName); - + h = yaffs_open(fName, O_RDONLY,S_IREAD | S_IWRITE); if(h < 0){ @@ -350,7 +350,7 @@ static int y_verify_file(const char *fName) yaffs_close(h); return -1; } - + recordedSize = sz32 * sizeof(xx) + 8; printf("verify %s: file size is %d, recorded size is %d\n", fName, totalSize, recordedSize); @@ -380,7 +380,7 @@ static int y_verify_file(const char *fName) yaffs_close(h); return -1; } - + checksum ^= xx[0]; if(checksum != 0){ @@ -399,12 +399,12 @@ static void DoUpdateMainFile(void) int result; int sz32; sz32 = (myrand() % 1000) + 20; - + result = y_wr_file(fullTempMainName,sz32); FSX(); if(!no_verification && result) FatalError(__LINE__); - printf("Raname file %s to %s\n",fullTempMainName,fullMainName); + printf("Rename file %s to %s\n",fullTempMainName,fullMainName); yaffs_rename(fullTempMainName,fullMainName); FSX(); } @@ -424,7 +424,7 @@ static void DoVerifyMainFile(void) void NorStressTestInitialise(const char *prefix) { MakeFullNames(prefix); - + UpdateCounter(fullPowerUpName,&powerUps,1); UpdateCounter(fullStartName,&cycleStarts,1); UpdateCounter(fullEndName,&cycleEnds,1); @@ -439,16 +439,16 @@ void NorStressTestRun(const char *prefix, int n_cycles, int do_fsx, int skip_ver interleave_fsx = do_fsx; no_verification = skip_verification; - + MakeFullNames(prefix); dump_directory_tree(fullPathName); FSX_INIT(prefix); - + dump_directory_tree(fullPathName); - + UpdateCounter(fullPowerUpName,&powerUps,0); dump_directory_tree(fullPathName); - + while(n_cycles < 0 || n_cycles > 0){ if(n_cycles > 0) n_cycles--; @@ -457,7 +457,7 @@ void NorStressTestRun(const char *prefix, int n_cycles, int do_fsx, int skip_ver DoVerifyMainFile(); DoUpdateMainFile(); dump_directory_tree(fullPathName); - + UpdateCounter(fullEndName,&cycleEnds,0); dump_directory_tree(fullPathName); } diff --git a/direct/test-framework/tests/run_fw_update_test_nor.sh b/direct/test-framework/tests/run_fw_update_test_nor.sh index 9265336..82eebb7 100755 --- a/direct/test-framework/tests/run_fw_update_test_nor.sh +++ b/direct/test-framework/tests/run_fw_update_test_nor.sh @@ -33,7 +33,7 @@ do echo "#########" echo "#########" echo "#########" - ./yaffs_test -u -f -p -s$seed -t0 M18-1 + ./yaffs_test -u -f -p -s$seed -t0 nor #>log-nor-$i done diff --git a/direct/test-framework/yaffs_m18_drv.c b/direct/test-framework/yaffs_m18_drv.c index 0325968..eca97ec 100644 --- a/direct/test-framework/yaffs_m18_drv.c +++ b/direct/test-framework/yaffs_m18_drv.c @@ -67,12 +67,16 @@ /* Compile this for a simulation */ #include "ynorsim.h" -#define m18_drv_FlashInit() ynorsim_initialise() -#define m18_drv_FlashDeinit() ynorsim_shutdown() -#define m18_drv_FlashWrite32(addr,buf,nwords) ynorsim_wr32(addr,buf,nwords) -#define m18_drv_FlashRead32(addr,buf,nwords) ynorsim_rd32(addr,buf,nwords) -#define m18_drv_FlashEraseBlock(addr) ynorsim_erase(addr) -#define DEVICE_BASE ynorsim_get_base() + +static struct nor_sim *nor_sim; + +#define m18_drv_FlashInit() do {nor_sim = ynorsim_initialise("emfile-m18", BLOCKS_IN_DEVICE, BLOCK_SIZE_IN_BYTES); } while(0) +#define m18_drv_FlashDeinit() ynorsim_shutdown(nor_sim) +#define m18_drv_FlashWrite32(addr,buf,nwords) ynorsim_wr32(nor_sim,addr,buf,nwords) +#define m18_drv_FlashRead32(addr,buf,nwords) ynorsim_rd32(nor_sim,addr,buf,nwords) +#define m18_drv_FlashEraseBlock(addr) ynorsim_erase(nor_sim,addr) +#define DEVICE_BASE ynorsim_get_base(nor_sim) + #else /* Compile this to hook up to read hardware */ @@ -85,6 +89,7 @@ #define DEVICE_BASE (32 * 1024 * 1024) #endif + static u32 *Block2Addr(struct yaffs_dev *dev, int blockNumber) { u32 addr; @@ -315,6 +320,7 @@ static int m18_drv_InitialiseNAND(struct yaffs_dev *dev) static int m18_drv_Deinitialise_flash_fn(struct yaffs_dev *dev) { dev=dev; + m18_drv_FlashDeinit(); return YAFFS_OK; diff --git a/direct/test-framework/yaffs_nor_drv.c b/direct/test-framework/yaffs_nor_drv.c new file mode 100644 index 0000000..a510979 --- /dev/null +++ b/direct/test-framework/yaffs_nor_drv.c @@ -0,0 +1,346 @@ +/* + * YAFFS: Yet Another Flash File System. A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ + +/* + * This is an interface module for handling NOR in yaffs1 mode. + */ + +/* This code is intended to be used with "regular" NOR that is bit-modifyable. + * + * Each "chunk" is a contguous area of 512 + 16 bytes. + * This makes 248 such chunks with some space left over where a format markerr + * is stored. + */ + +#include "yaffs_nor_drv.h" + +#include "yportenv.h" +#include "yaffs_trace.h" + +#include "yaffs_flashif.h" +#include "yaffs_guts.h" + +/* Tunable data */ +#define DATA_BYTES_PER_CHUNK 512 +#define SPARE_BYTES_PER_CHUNK 16 +#define BLOCK_SIZE_IN_BYTES (128*1024) +#define BYTES_IN_DEVICE (4*1024*1024) + +#define BYTES_PER_CHUNK (DATA_BYTES_PER_CHUNK + SPARE_BYTES_PER_CHUNK) +#define SPARE_AREA_OFFSET DATA_BYTES_PER_CHUNK +#define CHUNKS_PER_BLOCK (BLOCK_SIZE_IN_BYTES/BYTES_PER_CHUNK) + +#define BLOCKS_IN_DEVICE (BYTES_IN_DEVICE/BLOCK_SIZE_IN_BYTES) + +#define YNOR_PREMARKER (0xF6) +#define YNOR_POSTMARKER (0xF0) + +#define FORMAT_OFFSET (CHUNKS_PER_BLOCK * BYTES_PER_CHUNK) +#define FORMAT_VALUE 0x1234 + +#if 1 + +/* Compile this for a simulation */ +#include "ynorsim.h" + +static struct nor_sim *nor_sim; + +#define nor_drv_FlashInit() do {nor_sim = ynorsim_initialise("emfile-nor", BLOCKS_IN_DEVICE, BLOCK_SIZE_IN_BYTES); } while(0) +#define nor_drv_FlashDeinit() ynorsim_shutdown(nor_sim) +#define nor_drv_FlashWrite32(addr,buf,nwords) ynorsim_wr32(nor_sim,addr,buf,nwords) +#define nor_drv_FlashRead32(addr,buf,nwords) ynorsim_rd32(nor_sim,addr,buf,nwords) +#define nor_drv_FlashEraseBlock(addr) ynorsim_erase(nor_sim,addr) +#define DEVICE_BASE ynorsim_get_base(nor_sim) + +#else + +/* Compile this to hook up to read hardware */ +#include "../blob/yflashrw.h" +#define nor_drv_FlashInit() do{} while(0) +#define nor_drv_FlashDeinit() do {} while(0) +#define nor_drv_FlashWrite32(addr,buf,nwords) Y_FlashWrite(addr,buf,nwords) +#define nor_drv_FlashRead32(addr,buf,nwords) Y_FlashRead(addr,buf,nwords) +#define nor_drv_FlashEraseBlock(addr) Y_FlashErase(addr,BLOCK_SIZE_IN_BYTES) +#define DEVICE_BASE (32 * 1024 * 1024) +#endif + + +static u32 *Block2Addr(struct yaffs_dev *dev, int blockNumber) +{ + u8 *addr; + + dev=dev; + + addr = (u8*)DEVICE_BASE; + addr += blockNumber * BLOCK_SIZE_IN_BYTES; + + return (u32 *) addr; +} + +static u32 *Block2FormatAddr(struct yaffs_dev *dev, int blockNumber) +{ + u8 *addr; + + addr = (u8*) Block2Addr(dev,blockNumber); + addr += FORMAT_OFFSET; + + return (u32 *)addr; +} + +static u32 *Chunk2DataAddr(struct yaffs_dev *dev, int chunk_id) +{ + unsigned block; + unsigned chunkInBlock; + u8 *addr; + + block = chunk_id/dev->param.chunks_per_block; + chunkInBlock = chunk_id % dev->param.chunks_per_block; + + addr = (u8*) Block2Addr(dev,block); + addr += chunkInBlock * BYTES_PER_CHUNK; + + return (u32 *)addr; +} + +static u32 *Chunk2SpareAddr(struct yaffs_dev *dev, int chunk_id) +{ + u8 *addr; + + addr = (u8*) Chunk2DataAddr(dev, chunk_id); + addr += SPARE_AREA_OFFSET; + return (u32 *)addr; +} + + +static void nor_drv_AndBytes(u8*target, const u8 *src, int nbytes) +{ + while(nbytes > 0){ + *target &= *src; + target++; + src++; + nbytes--; + } +} + +static int nor_drv_WriteChunkToNAND(struct yaffs_dev *dev,int nand_chunk, + const u8 *data, int data_len, + const u8 *oob, int oob_len) +{ + u32 *dataAddr = Chunk2DataAddr(dev,nand_chunk); + u32 *spareAddr = Chunk2SpareAddr(dev,nand_chunk); + + struct yaffs_spare *spare = (struct yaffs_spare *)oob; + struct yaffs_spare tmpSpare; + + (void) oob_len; + + /* We should only be getting called for one of 3 reasons: + * Writing a chunk: data and spare will not be NULL + * Writing a deletion marker: data will be NULL, spare not NULL + * Writing a bad block marker: data will be NULL, spare not NULL + */ + + if(sizeof(struct yaffs_spare) != SPARE_BYTES_PER_CHUNK) + BUG(); + + if(data && oob) { + if(spare->page_status != 0xff) + BUG(); + /* Write a pre-marker */ + memset(&tmpSpare,0xff,sizeof(tmpSpare)); + tmpSpare.page_status = YNOR_PREMARKER; + nor_drv_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(struct yaffs_spare)/sizeof(u32)); + + /* Write the data */ + nor_drv_FlashWrite32(dataAddr,(u32 *)data, data_len/ sizeof(u32)); + + memcpy(&tmpSpare,spare,sizeof(struct yaffs_spare)); + + /* Write the real tags, but override the premarker*/ + tmpSpare.page_status = YNOR_PREMARKER; + nor_drv_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(struct yaffs_spare)/sizeof(u32)); + + /* Write a post-marker */ + tmpSpare.page_status = YNOR_POSTMARKER; + nor_drv_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(tmpSpare)/sizeof(u32)); + + } else if(spare){ + /* This has to be a read-modify-write operation to handle NOR-ness */ + + nor_drv_FlashRead32(spareAddr,(u32 *)&tmpSpare,sizeof(struct yaffs_spare)/sizeof(u32)); + + nor_drv_AndBytes((u8 *)&tmpSpare,(u8 *)spare,sizeof(struct yaffs_spare)); + + nor_drv_FlashWrite32(spareAddr,(u32 *)&tmpSpare,sizeof(struct yaffs_spare)/sizeof(u32)); + } else { + BUG(); + } + + return YAFFS_OK; +} + +static int nor_drv_ReadChunkFromNAND(struct yaffs_dev *dev,int nand_chunk, + u8 *data, int data_len, + u8 *oob, int oob_len, + enum yaffs_ecc_result *ecc_result) +{ + struct yaffs_spare *spare = (struct yaffs_spare *)oob; + + u32 *dataAddr = Chunk2DataAddr(dev,nand_chunk); + u32 *spareAddr = Chunk2SpareAddr(dev,nand_chunk); + + if (data) { + nor_drv_FlashRead32(dataAddr,(u32 *)data,dev->param.total_bytes_per_chunk / sizeof(u32)); + } + + if (oob) { + nor_drv_FlashRead32(spareAddr,(u32 *)spare, oob_len/ sizeof(u32)); + + /* If the page status is YNOR_POSTMARKER then it was written properly + * so change that to 0xFF so that the rest of yaffs is happy. + */ + if(spare->page_status == YNOR_POSTMARKER) + spare->page_status = 0xff; + else if(spare->page_status != 0xff && + (spare->page_status | YNOR_PREMARKER) != 0xff) + spare->page_status = YNOR_PREMARKER; + } + + if(ecc_result) + *ecc_result = YAFFS_ECC_RESULT_NO_ERROR; + + return YAFFS_OK; + +} + + +static int nor_drv_FormatBlock(struct yaffs_dev *dev, int blockNumber) +{ + u32 *blockAddr = Block2Addr(dev,blockNumber); + u32 *formatAddr = Block2FormatAddr(dev,blockNumber); + u32 formatValue = FORMAT_VALUE; + + nor_drv_FlashEraseBlock(blockAddr); + nor_drv_FlashWrite32(formatAddr,&formatValue,1); + + return YAFFS_OK; +} + +static int nor_drv_UnformatBlock(struct yaffs_dev *dev, int blockNumber) +{ + u32 *formatAddr = Block2FormatAddr(dev,blockNumber); + u32 formatValue = 0; + + nor_drv_FlashWrite32(formatAddr,&formatValue,1); + + return YAFFS_OK; +} + +static int nor_drv_IsBlockFormatted(struct yaffs_dev *dev, int blockNumber) +{ + u32 *formatAddr = Block2FormatAddr(dev,blockNumber); + u32 formatValue; + + + nor_drv_FlashRead32(formatAddr,&formatValue,1); + + return (formatValue == FORMAT_VALUE); +} + +static int nor_drv_EraseBlockInNAND(struct yaffs_dev *dev, int blockNumber) +{ + + if(blockNumber < 0 || blockNumber >= BLOCKS_IN_DEVICE) + { + yaffs_trace(YAFFS_TRACE_ALWAYS, + "Attempt to erase non-existant block %d\n", + blockNumber); + return YAFFS_FAIL; + } + else + { + nor_drv_UnformatBlock(dev,blockNumber); + nor_drv_FormatBlock(dev,blockNumber); + return YAFFS_OK; + } + +} + +static int nor_drv_InitialiseNAND(struct yaffs_dev *dev) +{ + int i; + + nor_drv_FlashInit(); + /* Go through the blocks formatting them if they are not formatted */ + for(i = dev->param.start_block; i <= dev->param.end_block; i++){ + if(!nor_drv_IsBlockFormatted(dev,i)){ + nor_drv_FormatBlock(dev,i); + } + } + return YAFFS_OK; +} + +static int nor_drv_Deinitialise_flash_fn(struct yaffs_dev *dev) +{ + dev=dev; + + nor_drv_FlashDeinit(); + + return YAFFS_OK; +} + + +struct yaffs_dev *yaffs_nor_install_drv(const char *name) +{ + + struct yaffs_dev *dev = malloc(sizeof(struct yaffs_dev)); + char *name_copy = strdup(name); + struct yaffs_param *param; + struct yaffs_driver *drv; + + + if(!dev || !name_copy) { + free(name_copy); + free(dev); + return NULL; + } + + param = &dev->param; + drv = &dev->drv; + + memset(dev, 0, sizeof(*dev)); + + param->name = name_copy; + + param->total_bytes_per_chunk = DATA_BYTES_PER_CHUNK; + param->chunks_per_block = CHUNKS_PER_BLOCK; + param->n_reserved_blocks = 2; + param->start_block = 0; // Can use block 0 + param->end_block = BLOCKS_IN_DEVICE - 1; // Last block + param->use_nand_ecc = 0; // use YAFFS's ECC + + drv->drv_write_chunk_fn = nor_drv_WriteChunkToNAND; + drv->drv_read_chunk_fn = nor_drv_ReadChunkFromNAND; + drv->drv_erase_fn = nor_drv_EraseBlockInNAND; + drv->drv_initialise_fn = nor_drv_InitialiseNAND; + drv->drv_deinitialise_fn = nor_drv_Deinitialise_flash_fn; + + param->n_caches = 10; + param->disable_soft_del = 1; + + dev->driver_context = (void *) nor_sim; + + yaffs_add_device(dev); + + return NULL; +} diff --git a/direct/test-framework/yaffs_nor_drv.h b/direct/test-framework/yaffs_nor_drv.h new file mode 100644 index 0000000..f856223 --- /dev/null +++ b/direct/test-framework/yaffs_nor_drv.h @@ -0,0 +1,25 @@ +/* + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * + * Copyright (C) 2002-2011 Aleph One Ltd. + * for Toby Churchill Ltd and Brightstar Engineering + * + * Created by Charles Manning + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 2.1 as + * published by the Free Software Foundation. + * + * Note: Only YAFFS headers are LGPL, YAFFS C code is covered by GPL. + */ + + +#ifndef __YAFFS_NOR_DRV_H__ +#define __YAFFS_NOR_DRV_H__ + +struct yaffs_dev; +struct yaffs_dev *yaffs_nor_install_drv(const char *name); + +#endif + + diff --git a/direct/test-framework/yaffscfg2k.c b/direct/test-framework/yaffscfg2k.c index b9a09a7..9e24866 100644 --- a/direct/test-framework/yaffscfg2k.c +++ b/direct/test-framework/yaffscfg2k.c @@ -48,6 +48,7 @@ unsigned yaffs_trace_mask = #include "yaffs_flashif2.h" #include "yaffs_m18_drv.h" +#include "yaffs_nor_drv.h" int yaffs_start_up(void) { @@ -63,6 +64,7 @@ int yaffs_start_up(void) yaffs_m18_install_drv("M18-1"); + yaffs_nor_install_drv("nor"); // /yaffs2 yaffs2 file emulation yflash2_install_drv("yaffs2"); diff --git a/direct/test-framework/ynorsim.c b/direct/test-framework/ynorsim.c index 36bfa62..38a4632 100644 --- a/direct/test-framework/ynorsim.c +++ b/direct/test-framework/ynorsim.c @@ -13,8 +13,6 @@ #include "ynorsim.h" - - #include #include #include @@ -23,12 +21,12 @@ #define YNORSIM_FNAME "emfile-nor" -/* Set YNORSIM_BIT_CHANGES to a a value from 1..30 to - *simulate bit flipping as the programming happens. +/* Set YNORSIM_BIT_CHANGES to a a value from 1..30 to + *simulate bit flipping as the programming happens. * A low value results in faster simulation with less chance of encountering a partially programmed - * word. + * word. */ - + //#define YNORSIM_BIT_CHANGES 15 #define YNORSIM_BIT_CHANGES 2 @@ -48,134 +46,162 @@ #define YNORSIM_DEV_SIZE_U32 (8*1024 * 1024/4) #endif -static u32 word[YNORSIM_DEV_SIZE_U32]; +struct nor_sim { + int n_blocks; + int block_size_bytes; + int file_size; + u32 *word; + int initialised; + char *fname; + int remaining_ops; + int nops_so_far; +}; +int ops_multiplier = 500; extern int random_seed; extern int simulate_power_failure; -static void NorError(void) +static void NorError(struct nor_sim *sim) { - printf("Nor error\n"); - while(1){} + printf("Nor error on device %s\n", sim->fname); + while (1) { + } } -static void ynorsim_save_image(void) +static void ynorsim_save_image(struct nor_sim *sim) { - int h = open(YNORSIM_FNAME, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); - write(h,word,sizeof(word)); - close(h); + int h; + + h = open(sim->fname, O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IWRITE); + write(h, sim->word, sim->file_size); + close(h); } -static void ynorsim_restore_image(void) +static void ynorsim_restore_image(struct nor_sim *sim) { - int h = open(YNORSIM_FNAME, O_RDONLY, S_IREAD | S_IWRITE); - memset(word,0xFF,sizeof(word)); - read(h,word,sizeof(word)); - close(h); -} + int h; + h = open(sim->fname, O_RDONLY, S_IREAD | S_IWRITE); + memset(sim->word, 0xFF, sim->file_size); + read(h, sim->word, sim->file_size); + close(h); +} -static void ynorsim_power_fail(void) +static void ynorsim_power_fail(struct nor_sim *sim) { - ynorsim_save_image(); - exit(1); + ynorsim_save_image(sim); + exit(1); } -static int initialised = 0; -static int remaining_ops; -static int nops_so_far; - -int ops_multiplier = 500; - -static void ynorsim_maybe_power_fail(void) +static void ynorsim_maybe_power_fail(struct nor_sim *sim) { - - nops_so_far++; - - - remaining_ops--; - if(simulate_power_failure && - remaining_ops < 1){ - printf("Simulated power failure after %d operations\n",nops_so_far); - ynorsim_power_fail(); - } + sim->nops_so_far++; + sim->remaining_ops--; + if (simulate_power_failure && sim->remaining_ops < 1) { + printf("Simulated power failure after %d operations\n", + sim->nops_so_far); + ynorsim_power_fail(sim); + } } -static void ynorsim_ready(void) +static void ynorsim_ready(struct nor_sim *sim) { - if(initialised) - return; - srand(random_seed); - remaining_ops = 1000000000; - remaining_ops = (rand() % 10000) * ops_multiplier * YNORSIM_BIT_CHANGES; - ynorsim_restore_image(); + if (sim->initialised) + return; + srand(random_seed); + sim->remaining_ops = 1000000000; + sim->remaining_ops = + (rand() % 10000) * ops_multiplier * YNORSIM_BIT_CHANGES; + ynorsim_restore_image(sim); + sim->initialised = 1; } -void ynorsim_rd32(u32 *addr,u32 *buf, int nwords) -{ - while(nwords > 0){ - *buf = *addr; - buf++; - addr++; - nwords--; - } +/* Public functions. */ + +void ynorsim_rd32(struct nor_sim *sim, u32 * addr, u32 * buf, int nwords) +{ + sim = sim; + while (nwords > 0) { + *buf = *addr; + buf++; + addr++; + nwords--; + } } -void ynorsim_wr_one_word32(u32 *addr,u32 val) +void ynorsim_wr_one_word32(struct nor_sim *sim, u32 * addr, u32 val) { - u32 tmp; - u32 m; - int i; - - tmp = *addr; - if(val & ~tmp){ - // Fail due to trying to change a zero into a 1 - printf("attempt to set a zero to one (%x)->(%x)\n",tmp,val); - NorError(); - } - - for(i = 0; i < YNORSIM_BIT_CHANGES; i++){ - m = 1 << (rand() & 31); - if(!(m & val)){ - tmp &= ~m; - *addr = tmp; - ynorsim_maybe_power_fail(); - } - - } - - *addr = tmp & val; - ynorsim_maybe_power_fail(); + u32 tmp; + u32 m; + int i; + + tmp = *addr; + if (val & ~tmp) { + /* Fail due to trying to change a zero into a 1 */ + printf("attempt to set a zero to one (%x)->(%x)\n", tmp, val); + NorError(sim); + } + + for (i = 0; i < YNORSIM_BIT_CHANGES; i++) { + m = 1 << (rand() & 31); + if (!(m & val)) { + tmp &= ~m; + *addr = tmp; + ynorsim_maybe_power_fail(sim); + } + + } + + *addr = tmp & val; + ynorsim_maybe_power_fail(sim); } -void ynorsim_wr32(u32 *addr, u32 *buf, int nwords) +void ynorsim_wr32(struct nor_sim *sim, u32 * addr, u32 * buf, int nwords) { - while(nwords >0){ - ynorsim_wr_one_word32(addr,*buf); - addr++; - buf++; - nwords--; - } + while (nwords > 0) { + ynorsim_wr_one_word32(sim, addr, *buf); + addr++; + buf++; + nwords--; + } } -void ynorsim_erase(u32 *addr) +void ynorsim_erase(struct nor_sim *sim, u32 * addr) { - /* Todo... bit flipping */ - memset(addr,0xFF,YNORSIM_BLOCK_SIZE_U32 * 4); + /* Todo... bit flipping */ + memset(addr, 0xFF, sim->block_size_bytes); } -void ynorsim_initialise(void) +struct nor_sim *ynorsim_initialise(char *name, int n_blocks, + int block_size_bytes) { - ynorsim_ready(); + struct nor_sim *sim; + + sim = malloc(sizeof(*sim)); + if (!sim) + return NULL; + + memset(sim, 0, sizeof(*sim)); + sim->n_blocks = n_blocks; + sim->block_size_bytes = block_size_bytes; + sim->file_size = n_blocks * block_size_bytes; + sim->word = malloc(sim->file_size); + sim->fname = strdup(name); + + if(!sim->word) + return NULL; + + ynorsim_ready(sim); + return sim; } -void ynorsim_shutdown(void) +void ynorsim_shutdown(struct nor_sim *sim) { - ynorsim_save_image(); - initialised=0; + ynorsim_save_image(sim); + sim->initialised = 0; } -u32 *ynorsim_get_base(void) +u32 *ynorsim_get_base(struct nor_sim *sim) { - return word; + return sim->word; } diff --git a/direct/test-framework/ynorsim.h b/direct/test-framework/ynorsim.h index 6b1193f..a51617e 100644 --- a/direct/test-framework/ynorsim.h +++ b/direct/test-framework/ynorsim.h @@ -1,5 +1,5 @@ /* - * YAFFS: Yet another Flash File System . A NAND-flash specific file system. + * YAFFS: Yet another Flash File System . A NAND-flash specific file system. * * Copyright (C) 2002-2011 Aleph One Ltd. * for Toby Churchill Ltd and Brightstar Engineering @@ -18,11 +18,13 @@ #include "yaffs_guts.h" -void ynorsim_rd32(u32 *addr, u32 *data, int nwords); -void ynorsim_wr32(u32 *addr, u32 *data, int nwords); -void ynorsim_erase(u32 *addr); -void ynorsim_shutdown(void); -void ynorsim_initialise(void); -u32 * ynorsim_get_base(void); +struct nor_sim; + +void ynorsim_rd32(struct nor_sim *sim, u32 *addr, u32 *data, int nwords); +void ynorsim_wr32(struct nor_sim *sim, u32 *addr, u32 *data, int nwords); +void ynorsim_erase(struct nor_sim *sim, u32 *addr); +void ynorsim_shutdown(struct nor_sim *sim); +struct nor_sim *ynorsim_initialise(char *name, int n_blocks, int block_size_bytes); +u32 * ynorsim_get_base(struct nor_sim *sim); #endif -- 2.30.2