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