1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30#define _FILE_OFFSET_BITS 64
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <stdint.h>
35#include <stdbool.h>
36#include <unistd.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <fcntl.h>
40#include <string.h>
41#include <assert.h>
42#include <errno.h>
43
44#define ECC_CODEWORD_SIZE 512
45
46#ifdef DEBUG
47 #define DPRINT(...) do { fprintf(stdout, __VA_ARGS__); } while (0)
48#else
49 #define DPRINT(...) do { } while (0)
50#endif
51
52uint32_t ecc_size;
53uint32_t ecc_pos;
54uint32_t ecc_subpage_offset;
55
56static void ecc_digest(uint8_t *data , uint8_t * oob, uint32_t bytes_read,
57 uint32_t page_size);
58
59
60
61
62
63
64
65
66
67
68
69
70int main(int argc, char *argv[])
71{
72 uint32_t page_size;
73 uint32_t oob_size;
74 uint32_t num_pages_per_block;
75 uint32_t num_pages = 0;
76 uint32_t block = 0;
77 uint32_t num_of_blocks = 0;
78 uint32_t bb_pat = 0;
79 uint8_t *oob_pbuf;
80 uint8_t *buf;
81 uint8_t *ecc_data;
82 int i, j;
83 bool Image_done = false;
84 bool page_empty = false;
85 bool Image_wip = true;
86 int nand_flash;
87
88 const char *exe_name = argv[0];
89 argc--;
90 argv++;
91
92 if (argc != 5) {
93 fprintf(stderr, "Usage: %s <page size> <oob size> " \
94 "<num of pages per block> <num_blocks> "\
95 "<ecc size>\n", exe_name);
96 return 1;
97 }
98
99 page_size = strtol(argv[0], NULL, 0);
100 argc--;
101 if (errno) {
102 perror(argv[0]);
103 exit(1);
104 }
105
106 oob_size = strtol(argv[1], NULL, 0);
107
108 if (argc) {
109 num_pages_per_block = strtol(argv[2], NULL, 0);
110 }
111 argc--;
112 num_of_blocks = strtol(argv[3], NULL, 0);
113 ecc_size = strtol(argv[4], NULL, 0);
114 ecc_data = (uint8_t *)malloc(ecc_size);
115
116 uint8_t *oob_buf = (uint8_t *)malloc(oob_size);
117 memset(oob_buf, 0xFF, oob_size);
118
119 nand_flash = open("./qemu_nand.bin", O_CREAT | O_WRONLY, S_IRWXU);
120
121
122 uint8_t oob_buf_bad[oob_size];
123 memset(oob_buf_bad, 0xFF, oob_size);
124 oob_buf_bad[0] = 0x00;
125
126#ifdef CREATE_BB
127
128 bb_pat = rand();
129
130
131 bb_pat &= ~(1 << 0);
132#endif
133
134
135 buf = (uint8_t *)malloc(page_size);
136
137 fprintf(stderr, "Creating Nand Flash Image:\n");
138 while (true) {
139
140 bool block_is_bad = (block < 32) ? ((bb_pat >> block) & 0x1) : 0;
141
142 if (block_is_bad) {
143
144 page_empty = true;
145 DPRINT("Bad Block %d\n", block);
146 } else if (!Image_done) {
147
148 page_empty = false;
149
150 memset(oob_buf, 0xFF, oob_size);
151 memset(ecc_data, 0xFF, ecc_size);
152 ecc_pos = 0;
153 ecc_subpage_offset = 0;
154
155 for (i = 0; i < page_size; ++i) {
156
157 ssize_t bytes_read = read(STDIN_FILENO, &buf[i], page_size - i);
158 DPRINT("Block %d page %d bytes_read %d\n", block,
159 num_pages, bytes_read);
160
161
162 if (ecc_size && bytes_read) {
163 ecc_digest(&buf[i], ecc_data, bytes_read, page_size);
164
165 memcpy(&oob_buf[oob_size - ecc_size], ecc_data, ecc_size);
166
167 DPRINT("\tECC pos %d\nECC Digest:\n", ecc_pos);
168 for (j = oob_size - ecc_size; j < oob_size; j++) {
169 DPRINT("%d:%x ", j, oob_buf[j]);
170 if (!(j % 5)) {
171 DPRINT("\n");
172 }
173 }
174 DPRINT("\n");
175 }
176
177 switch (bytes_read) {
178 case 0:
179 Image_done = true;
180 memset(&buf[i], 0xFF, page_size - i);
181 break;
182 case -1:
183 perror("stdin");
184 return 1;
185 default:
186 if (bytes_read < page_size) {
187 Image_done = true;
188
189 memset(&buf[bytes_read], 0xFF, page_size - bytes_read);
190 ecc_digest(&buf[bytes_read], ecc_data,
191 page_size - bytes_read, page_size);
192
193 memcpy(&oob_buf[oob_size - ecc_size], ecc_data,
194 ecc_size);
195 i = page_size;
196 } else {
197 i += bytes_read;
198 }
199 break;
200 }
201 }
202 } else {
203
204 page_empty = true;
205 }
206
207 for (i = 0; i < page_size; ++i) {
208 ssize_t bytes_written;
209 if (page_empty == false) {
210 bytes_written = write(nand_flash, &buf[i], page_size - i);
211 } else {
212 lseek64(nand_flash, page_size - i, SEEK_CUR);
213 bytes_written = page_size;
214 }
215
216 switch (bytes_written) {
217 case -1:
218 perror("stdin");
219 return 1;
220 default:
221 i += bytes_written;
222 }
223 }
224
225
226 oob_pbuf = (num_pages <= 1) && block_is_bad ? &oob_buf_bad[0]
227 : &oob_buf[0];
228 for (i = 0; i < oob_size; ++i) {
229 ssize_t bytes_written = write(nand_flash, &oob_pbuf[i],
230 oob_size - i);
231 switch (bytes_written) {
232 case -1:
233 perror("stdin");
234 return 1;
235 default:
236 i += bytes_written;
237 }
238 }
239
240 if (Image_wip == Image_done) {
241
242
243
244 memset(oob_buf, 0xFF, oob_size);
245 Image_wip = false;
246 }
247 num_pages++;
248
249 if (num_pages_per_block && !(num_pages % num_pages_per_block)) {
250 block++;
251 fprintf(stderr, "\r. . .");
252 if (block > num_of_blocks) {
253 goto done;
254 }
255 num_pages = 0;
256 }
257
258 }
259
260done:
261 fprintf(stderr, "Done!\n");
262 sync();
263 close(nand_flash);
264 return 0;
265}
266
267static void ecc_digest(uint8_t *data , uint8_t * oob,
268 uint32_t bytes_read, uint32_t page_size)
269{
270 int ecc_bytes_per_subpage = ecc_size /
271 (page_size / ECC_CODEWORD_SIZE);
272 uint32_t head = 0;
273 while (head < bytes_read) {
274 oob[ecc_pos++] ^= ~data[head];
275 if (!(ecc_pos % ecc_bytes_per_subpage)) {
276 ecc_pos -= ecc_bytes_per_subpage;
277 }
278
279 ecc_subpage_offset++;
280 if (ecc_subpage_offset == ECC_CODEWORD_SIZE) {
281 ecc_subpage_offset = 0;
282 do {
283 ecc_pos++;
284 } while (ecc_pos % ecc_bytes_per_subpage);
285 }
286 head++;
287 }
288}
289