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 \
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
# 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
static int interleave_fsx;
static int no_verification;
-
+
char fullPathName[100];
char fullPowerUpName[100];
char fullStartName[100];
if(ext_fatal)
ext_fatal();
-
+
while(1){
sleep(1);
}
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);
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));
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]);
char str[1000];
int error_line = 0;
int nentries;
-
+
d = yaffs_opendir(dname);
-
+
if(!d)
{
printf("opendir failed\n");
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");
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__;
if(error_line && !no_verification)
FatalError(error_line);
-
+
yaffs_closedir(d);
}
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){
xx[i] = sz32 + i;
checksum ^= xx[i];
}
-
+
FSX();
if((r = yaffs_write(h,xx,sizeof(xx))) != sizeof(xx)){
goto WRITE_ERROR;
if((r = yaffs_write(h,xx,sizeof(unsigned))) != sizeof(unsigned)){
goto WRITE_ERROR;
}
-
+
FSX();
yaffs_close(h);
printf("File closed\n");
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)
return 0;
printf("Verifying file %s\n",fName);
-
+
h = yaffs_open(fName, O_RDONLY,S_IREAD | S_IWRITE);
if(h < 0){
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);
yaffs_close(h);
return -1;
}
-
+
checksum ^= xx[0];
if(checksum != 0){
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();
}
void NorStressTestInitialise(const char *prefix)
{
MakeFullNames(prefix);
-
+
UpdateCounter(fullPowerUpName,&powerUps,1);
UpdateCounter(fullStartName,&cycleStarts,1);
UpdateCounter(fullEndName,&cycleEnds,1);
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--;
DoVerifyMainFile();
DoUpdateMainFile();
dump_directory_tree(fullPathName);
-
+
UpdateCounter(fullEndName,&cycleEnds,0);
dump_directory_tree(fullPathName);
}
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
/* 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 */
#define DEVICE_BASE (32 * 1024 * 1024)
#endif
+
static u32 *Block2Addr(struct yaffs_dev *dev, int blockNumber)
{
u32 addr;
static int m18_drv_Deinitialise_flash_fn(struct yaffs_dev *dev)
{
dev=dev;
+
m18_drv_FlashDeinit();
return YAFFS_OK;
--- /dev/null
+/*
+ * 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 <charles@aleph1.co.uk>
+ *
+ * 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;
+}
--- /dev/null
+/*
+ * 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 <charles@aleph1.co.uk>
+ *
+ * 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
+
+
#include "yaffs_flashif2.h"
#include "yaffs_m18_drv.h"
+#include "yaffs_nor_drv.h"
int yaffs_start_up(void)
{
yaffs_m18_install_drv("M18-1");
+ yaffs_nor_install_drv("nor");
// /yaffs2 yaffs2 file emulation
yflash2_install_drv("yaffs2");
#include "ynorsim.h"
-
-
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#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
#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;
}
/*
- * 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
#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