xref: /nrf52832-nimble/rt-thread/components/dfs/filesystems/uffs/src/emu/uffs_fileem_wrap.c (revision 104654410c56c573564690304ae786df310c91fc)
1 /*
2   This file is part of UFFS, the Ultra-low-cost Flash File System.
3 
4   Copyright (C) 2005-2009 Ricky Zheng <[email protected]>
5 
6   UFFS is free software; you can redistribute it and/or modify it under
7   the GNU Library General Public License as published by the Free Software
8   Foundation; either version 2 of the License, or (at your option) any
9   later version.
10 
11   UFFS is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   or GNU Library General Public License, as applicable, for more details.
15 
16   You should have received a copy of the GNU General Public License
17   and GNU Library General Public License along with UFFS; if not, write
18   to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19   Boston, MA  02110-1301, USA.
20 
21   As a special exception, if other files instantiate templates or use
22   macros or inline functions from this file, or you compile this file
23   and link it with other works to produce a work based on this file,
24   this file does not by itself cause the resulting work to be covered
25   by the GNU General Public License. However the source code for this
26   file must still be made available in accordance with section (3) of
27   the GNU General Public License v2.
28 
29   This exception does not invalidate any other reasons why a work based
30   on this file might be covered by the GNU General Public License.
31 */
32 
33 /**
34  * \file uffs_fileem_wrap.c
35  *
36  * \brief file emulator wrapper functions for injecting bad blocks or ECC errors.
37  *
38  * \author Ricky Zheng, created Nov, 2010
39  */
40 
41 #include <sys/types.h>
42 #include <string.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include "uffs_config.h"
46 #include "uffs/uffs_device.h"
47 #include "uffs_fileem.h"
48 
49 #define PFX "femu: "
50 #define MSGLN(msg,...) uffs_Perror(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
51 #define MSG(msg,...) uffs_PerrorRaw(UFFS_MSG_NORMAL, msg, ## __VA_ARGS__)
52 
53 // #define UFFS_FEMU_SHOW_FLASH_IO
54 
55 #ifdef UFFS_FEMU_ENABLE_INJECTION
56 
57 struct uffs_FileEmuBitFlip {
58 	int block;
59 	int page;
60 	int offset;
61 	u8 mask;
62 };
63 
64 /* simulate bad blocks */
65 #define FILEEMU_STOCK_BAD_BLOCKS	{5, 180}	// bad block come from manufacture
66 #define FILEEMU_ERASE_BAD_BLOCKS	{100, 150}	// new bad block discovered when erasing
67 
68 /* simulating bit flip */
69 #define FILEEMU_WRITE_BIT_FLIP \
70 	{ \
71 		{20, 2, 10, 1 << 4},	/* block 20, page 2, offset 10, bit 4 */	\
72 		{24, 4, -3, 1 << 2},	/* block 24, page 4, spare offset 3, bit 2*/ \
73 		{60, 1, 5, 1 << 3},		/* block 60, page 1, offset 5, bit 3 */ \
74 		{66, 1, 15, 1 << 7},	/* block 66, page 1, offset 300, bit 7 */ \
75 		{80, 2, 2, 1 << 1},		/* block 80, page 2, offset 2, bit 1 */ \
76 		{88, 2, 100, 1 << 5},	/* block 88, page 2, offset 100, bit 5 */ \
77 	}
78 
79 
80 static int femu_InitFlash_wrap(uffs_Device *dev);
81 
82 static int femu_ReadPage_wrap(uffs_Device *dev, u32 block, u32 page, u8 *data, int data_len, u8 *ecc,
83 							u8 *spare, int spare_len);
84 static int femu_ReadPageWithLayout_wrap(uffs_Device *dev, u32 block, u32 page, u8* data, int data_len, u8 *ecc,
85 									uffs_TagStore *ts, u8 *ecc_store);
86 static int femu_WritePage_wrap(uffs_Device *dev, u32 block, u32 page,
87 							const u8 *data, int data_len, const u8 *spare, int spare_len);
88 static int femu_WritePageWithLayout_wrap(uffs_Device *dev, u32 block, u32 page, const u8* data, int data_len, const u8 *ecc,
89 									const uffs_TagStore *ts);
90 static int femu_EraseBlock_wrap(uffs_Device *dev, u32 blockNumber);
91 
92 
93 /////////////////////////////////////////////////////////////////////////////////
94 
femu_setup_wrapper_functions(uffs_Device * dev)95 void femu_setup_wrapper_functions(uffs_Device *dev)
96 {
97 	uffs_FileEmu *emu;
98 	emu = (uffs_FileEmu *)(dev->attr->_private);
99 
100 	// setup wrap functions, for inject ECC errors, etc.
101 
102 	memcpy(&emu->ops_orig, dev->ops, sizeof(struct uffs_FlashOpsSt));
103 
104 	if (dev->ops->InitFlash)
105 		dev->ops->InitFlash = femu_InitFlash_wrap;
106 	if (dev->ops->EraseBlock)
107 		dev->ops->EraseBlock = femu_EraseBlock_wrap;
108 	if (dev->ops->ReadPage)
109 		dev->ops->ReadPage = femu_ReadPage_wrap;
110 	if (dev->ops->ReadPageWithLayout)
111 		dev->ops->ReadPageWithLayout = femu_ReadPageWithLayout_wrap;
112 	if (dev->ops->WritePage)
113 		dev->ops->WritePage = femu_WritePage_wrap;
114 	if (dev->ops->WritePageWithLayout)
115 		dev->ops->WritePageWithLayout = femu_WritePageWithLayout_wrap;
116 }
117 
femu_InitFlash_wrap(uffs_Device * dev)118 static int femu_InitFlash_wrap(uffs_Device *dev)
119 {
120 	int ret;
121 	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
122 
123 #ifdef FILEEMU_STOCK_BAD_BLOCKS
124 	u32 bad_blocks[] = FILEEMU_STOCK_BAD_BLOCKS;
125 	int j;
126 	u8 x = 0;
127 	struct uffs_StorageAttrSt *attr = dev->attr;
128 	int full_page_size = attr->page_data_size + attr->spare_size;
129 	int blk_size = full_page_size * attr->pages_per_block;
130 #endif
131 
132 	if (emu->initCount == 0) {
133 		ret = emu->ops_orig.InitFlash(dev);
134 #ifdef FILEEMU_STOCK_BAD_BLOCKS
135 		if (ret >= 0) {
136 			for (j = 0; j < ARRAY_SIZE(bad_blocks); j++) {
137 				if (bad_blocks[j] < dev->attr->total_blocks) {
138 					printf(" --- manufacture bad block %d ---\n", bad_blocks[j]);
139 					fseek(emu->fp, bad_blocks[j] * blk_size + attr->page_data_size + dev->attr->block_status_offs, SEEK_SET);
140 					fwrite(&x, 1, 1, emu->fp);
141 				}
142 			}
143 		}
144 #endif
145 	}
146 	else {
147 		ret = emu->ops_orig.InitFlash(dev);
148 	}
149 
150 	return ret;
151 }
152 
femu_ReadPage_wrap(uffs_Device * dev,u32 block,u32 page,u8 * data,int data_len,u8 * ecc,u8 * spare,int spare_len)153 static int femu_ReadPage_wrap(uffs_Device *dev, u32 block, u32 page, u8 *data, int data_len, u8 *ecc,
154 							u8 *spare, int spare_len)
155 {
156 	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
157 
158 #ifdef UFFS_FEMU_SHOW_FLASH_IO
159 	if (data || spare) {
160 		MSG(PFX " Read block %d page %d", block, page);
161 		if (data)
162 			MSG(" DATA[%d]", data_len);
163 		if (spare)
164 			MSG(" SPARE[%d]", spare_len);
165 		MSG(TENDSTR);
166 	}
167 #endif
168 	return emu->ops_orig.ReadPage(dev, block, page, data, data_len, ecc, spare, spare_len);
169 }
170 
femu_ReadPageWithLayout_wrap(uffs_Device * dev,u32 block,u32 page,u8 * data,int data_len,u8 * ecc,uffs_TagStore * ts,u8 * ecc_store)171 static int femu_ReadPageWithLayout_wrap(uffs_Device *dev, u32 block, u32 page, u8* data, int data_len, u8 *ecc,
172 									uffs_TagStore *ts, u8 *ecc_store)
173 {
174 	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
175 
176 #ifdef UFFS_FEMU_SHOW_FLASH_IO
177 	if (data || ts) {
178 		MSG(PFX " Read block %d page %d", block, page);
179 		if (data)
180 			MSG(" DATA[%d]", data_len);
181 		if (ts)
182 			MSG(" TS");
183 		MSG(TENDSTR);
184 	}
185 #endif
186 	return emu->ops_orig.ReadPageWithLayout(dev, block, page, data, data_len, ecc, ts, ecc_store);
187 }
188 
189 
190 ////////////////////// wraper functions ///////////////////////////
191 
InjectBitFlip(uffs_Device * dev,u32 block,u32 page)192 static void InjectBitFlip(uffs_Device *dev, u32 block, u32 page)
193 {
194 #ifdef FILEEMU_WRITE_BIT_FLIP
195 	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
196 	struct uffs_FileEmuBitFlip flips[] = FILEEMU_WRITE_BIT_FLIP;
197 	struct uffs_FileEmuBitFlip *x;
198 	u8 buf[UFFS_MAX_PAGE_SIZE + UFFS_MAX_SPARE_SIZE];
199 	u8 *data = buf;
200 	u8 *spare = buf + dev->attr->page_data_size;
201 	int full_page_size = dev->attr->page_data_size + dev->attr->spare_size;
202 	int blk_size = full_page_size * dev->attr->pages_per_block;
203 	int page_offset = block * blk_size + full_page_size * page;
204 
205 	int i;
206 	u8 *p;
207 
208 	fseek(emu->fp, page_offset, SEEK_SET);
209 	fread(buf, 1, full_page_size, emu->fp);
210 
211 	p = NULL;
212 	for (i = 0; i < ARRAY_SIZE(flips); i++) {
213 		x = &flips[i];
214 		if (x->block == block && x->page == page) {
215 			if (x->offset >= 0) {
216 				printf(" --- Inject data bit flip at block%d, page%d, offset%d, mask%d --- \n", block, page, x->offset, x->mask);
217 				p = (u8 *)(data + x->offset);
218 			}
219 			else {
220 				printf(" --- Inject spare bit flip at block%d, page%d, offset%d, mask%d --- \n", block, page, -x->offset, x->mask);
221 				p = (u8 *)(spare - x->offset);
222 			}
223 			*p = (*p & ~x->mask) | (~(*p & x->mask) & x->mask);
224 		}
225 	}
226 
227 	if (p) {
228 		fseek(emu->fp, page_offset, SEEK_SET);
229 		fwrite(buf, 1, full_page_size, emu->fp);
230 	}
231 #endif
232 }
233 
femu_WritePage_wrap(uffs_Device * dev,u32 block,u32 page,const u8 * data,int data_len,const u8 * spare,int spare_len)234 static int femu_WritePage_wrap(uffs_Device *dev, u32 block, u32 page,
235 							const u8 *data, int data_len, const u8 *spare, int spare_len)
236 {
237 	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
238 	int ret;
239 
240 #ifdef UFFS_FEMU_SHOW_FLASH_IO
241 	if (data || spare) {
242 		MSG(PFX " Write block %d page %d", block, page);
243 		if (data)
244 			MSG(" DATA[%d]", data_len);
245 		if (spare)
246 			MSG(" SPARE[%d]", spare_len);
247 		MSG(TENDSTR);
248 	}
249 #endif
250 
251 	ret = emu->ops_orig.WritePage(dev, block, page, data, data_len, spare, spare_len);
252 
253 	InjectBitFlip(dev, block, page);
254 
255 	return ret;
256 }
257 
femu_WritePageWithLayout_wrap(uffs_Device * dev,u32 block,u32 page,const u8 * data,int data_len,const u8 * ecc,const uffs_TagStore * ts)258 static int femu_WritePageWithLayout_wrap(uffs_Device *dev, u32 block, u32 page, const u8* data, int data_len, const u8 *ecc,
259 									const uffs_TagStore *ts)
260 {
261 	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
262 	int ret;
263 
264 #ifdef UFFS_FEMU_SHOW_FLASH_IO
265 	if (data || ts) {
266 		MSG(PFX " Write block %d page %d", block, page);
267 		if (data)
268 			MSG(" DATA[%d]", data_len);
269 		if (ts)
270 			MSG(" TS");
271 		MSG(TENDSTR);
272 	}
273 #endif
274 
275 	ret = emu->ops_orig.WritePageWithLayout(dev, block, page, data, data_len, ecc, ts);
276 
277 	InjectBitFlip(dev, block, page);
278 
279 	return ret;
280 }
281 
282 
femu_EraseBlock_wrap(uffs_Device * dev,u32 blockNumber)283 static int femu_EraseBlock_wrap(uffs_Device *dev, u32 blockNumber)
284 {
285 	uffs_FileEmu *emu = (uffs_FileEmu *)(dev->attr->_private);
286 
287 #ifdef FILEEMU_ERASE_BAD_BLOCKS
288 	int blocks[] = FILEEMU_ERASE_BAD_BLOCKS;
289 	int i;
290 	URET ret;
291 	ret = emu->ops_orig.EraseBlock(dev, blockNumber);
292 
293 	for (i = 0; i < ARRAY_SIZE(blocks); i++) {
294 		if (blockNumber == blocks[i]) {
295 			printf(" --- Inject bad block%d when erasing --- \n", blockNumber);
296 			ret = UFFS_FLASH_BAD_BLK;
297 		}
298 	}
299 
300 	return ret;
301 
302 #else
303 
304 	return emu->ops_orig.EraseBlock(dev, blockNumber);
305 
306 #endif
307 }
308 
309 #endif // UFFS_FEMU_ENABLE_INJECTION
310 
311 /////////////////////////////////////////////////////////////////////////////////
312