1 /* 2 * Allwinner NAND randomizer and image builder implementation: 3 * 4 * Copyright © 2016 NextThing Co. 5 * Copyright © 2016 Free Electrons 6 * 7 * Author: Boris Brezillon <boris.brezillon@free-electrons.com> 8 * 9 */ 10 11 #include <linux/bch.h> 12 13 #include <getopt.h> 14 #include <version.h> 15 16 #define BCH_PRIMITIVE_POLY 0x5803 17 18 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 19 #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) 20 21 struct image_info { 22 int ecc_strength; 23 int ecc_step_size; 24 int page_size; 25 int oob_size; 26 int usable_page_size; 27 int eraseblock_size; 28 int scramble; 29 int boot0; 30 off_t offset; 31 const char *source; 32 const char *dest; 33 }; 34 35 static void swap_bits(uint8_t *buf, int len) 36 { 37 int i, j; 38 39 for (j = 0; j < len; j++) { 40 uint8_t byte = buf[j]; 41 42 buf[j] = 0; 43 for (i = 0; i < 8; i++) { 44 if (byte & (1 << i)) 45 buf[j] |= (1 << (7 - i)); 46 } 47 } 48 } 49 50 static uint16_t lfsr_step(uint16_t state, int count) 51 { 52 state &= 0x7fff; 53 while (count--) 54 state = ((state >> 1) | 55 ((((state >> 0) ^ (state >> 1)) & 1) << 14)) & 0x7fff; 56 57 return state; 58 } 59 60 static uint16_t default_scrambler_seeds[] = { 61 0x2b75, 0x0bd0, 0x5ca3, 0x62d1, 0x1c93, 0x07e9, 0x2162, 0x3a72, 62 0x0d67, 0x67f9, 0x1be7, 0x077d, 0x032f, 0x0dac, 0x2716, 0x2436, 63 0x7922, 0x1510, 0x3860, 0x5287, 0x480f, 0x4252, 0x1789, 0x5a2d, 64 0x2a49, 0x5e10, 0x437f, 0x4b4e, 0x2f45, 0x216e, 0x5cb7, 0x7130, 65 0x2a3f, 0x60e4, 0x4dc9, 0x0ef0, 0x0f52, 0x1bb9, 0x6211, 0x7a56, 66 0x226d, 0x4ea7, 0x6f36, 0x3692, 0x38bf, 0x0c62, 0x05eb, 0x4c55, 67 0x60f4, 0x728c, 0x3b6f, 0x2037, 0x7f69, 0x0936, 0x651a, 0x4ceb, 68 0x6218, 0x79f3, 0x383f, 0x18d9, 0x4f05, 0x5c82, 0x2912, 0x6f17, 69 0x6856, 0x5938, 0x1007, 0x61ab, 0x3e7f, 0x57c2, 0x542f, 0x4f62, 70 0x7454, 0x2eac, 0x7739, 0x42d4, 0x2f90, 0x435a, 0x2e52, 0x2064, 71 0x637c, 0x66ad, 0x2c90, 0x0bad, 0x759c, 0x0029, 0x0986, 0x7126, 72 0x1ca7, 0x1605, 0x386a, 0x27f5, 0x1380, 0x6d75, 0x24c3, 0x0f8e, 73 0x2b7a, 0x1418, 0x1fd1, 0x7dc1, 0x2d8e, 0x43af, 0x2267, 0x7da3, 74 0x4e3d, 0x1338, 0x50db, 0x454d, 0x764d, 0x40a3, 0x42e6, 0x262b, 75 0x2d2e, 0x1aea, 0x2e17, 0x173d, 0x3a6e, 0x71bf, 0x25f9, 0x0a5d, 76 0x7c57, 0x0fbe, 0x46ce, 0x4939, 0x6b17, 0x37bb, 0x3e91, 0x76db, 77 }; 78 79 static uint16_t brom_scrambler_seeds[] = { 0x4a80 }; 80 81 static void scramble(const struct image_info *info, 82 int page, uint8_t *data, int datalen) 83 { 84 uint16_t state; 85 int i; 86 87 /* Boot0 is always scrambled no matter the command line option. */ 88 if (info->boot0) { 89 state = brom_scrambler_seeds[0]; 90 } else { 91 unsigned seedmod = info->eraseblock_size / info->page_size; 92 93 /* Bail out earlier if the user didn't ask for scrambling. */ 94 if (!info->scramble) 95 return; 96 97 if (seedmod > ARRAY_SIZE(default_scrambler_seeds)) 98 seedmod = ARRAY_SIZE(default_scrambler_seeds); 99 100 state = default_scrambler_seeds[page % seedmod]; 101 } 102 103 /* Prepare the initial state... */ 104 state = lfsr_step(state, 15); 105 106 /* and start scrambling data. */ 107 for (i = 0; i < datalen; i++) { 108 data[i] ^= state; 109 state = lfsr_step(state, 8); 110 } 111 } 112 113 static int write_page(const struct image_info *info, uint8_t *buffer, 114 FILE *src, FILE *rnd, FILE *dst, 115 struct bch_control *bch, int page) 116 { 117 int steps = info->usable_page_size / info->ecc_step_size; 118 int eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8); 119 off_t pos = ftell(dst); 120 size_t pad, cnt; 121 int i; 122 123 if (eccbytes % 2) 124 eccbytes++; 125 126 memset(buffer, 0xff, info->page_size + info->oob_size); 127 cnt = fread(buffer, 1, info->usable_page_size, src); 128 if (!cnt) { 129 if (!feof(src)) { 130 fprintf(stderr, 131 "Failed to read data from the source\n"); 132 return -1; 133 } else { 134 return 0; 135 } 136 } 137 138 fwrite(buffer, info->page_size + info->oob_size, 1, dst); 139 140 for (i = 0; i < info->usable_page_size; i++) { 141 if (buffer[i] != 0xff) 142 break; 143 } 144 145 /* We leave empty pages at 0xff. */ 146 if (i == info->usable_page_size) 147 return 0; 148 149 /* Restore the source pointer to read it again. */ 150 fseek(src, -cnt, SEEK_CUR); 151 152 /* Randomize unused space if scrambling is required. */ 153 if (info->scramble) { 154 int offs; 155 156 if (info->boot0) { 157 size_t ret; 158 159 offs = steps * (info->ecc_step_size + eccbytes + 4); 160 cnt = info->page_size + info->oob_size - offs; 161 ret = fread(buffer + offs, 1, cnt, rnd); 162 if (!ret && !feof(rnd)) { 163 fprintf(stderr, 164 "Failed to read random data\n"); 165 return -1; 166 } 167 } else { 168 offs = info->page_size + (steps * (eccbytes + 4)); 169 cnt = info->page_size + info->oob_size - offs; 170 memset(buffer + offs, 0xff, cnt); 171 scramble(info, page, buffer + offs, cnt); 172 } 173 fseek(dst, pos + offs, SEEK_SET); 174 fwrite(buffer + offs, cnt, 1, dst); 175 } 176 177 for (i = 0; i < steps; i++) { 178 int ecc_offs, data_offs; 179 uint8_t *ecc; 180 181 memset(buffer, 0xff, info->ecc_step_size + eccbytes + 4); 182 ecc = buffer + info->ecc_step_size + 4; 183 if (info->boot0) { 184 data_offs = i * (info->ecc_step_size + eccbytes + 4); 185 ecc_offs = data_offs + info->ecc_step_size + 4; 186 } else { 187 data_offs = i * info->ecc_step_size; 188 ecc_offs = info->page_size + 4 + (i * (eccbytes + 4)); 189 } 190 191 cnt = fread(buffer, 1, info->ecc_step_size, src); 192 if (!cnt && !feof(src)) { 193 fprintf(stderr, 194 "Failed to read data from the source\n"); 195 return -1; 196 } 197 198 pad = info->ecc_step_size - cnt; 199 if (pad) { 200 if (info->scramble && info->boot0) { 201 size_t ret; 202 203 ret = fread(buffer + cnt, 1, pad, rnd); 204 if (!ret && !feof(rnd)) { 205 fprintf(stderr, 206 "Failed to read random data\n"); 207 return -1; 208 } 209 } else { 210 memset(buffer + cnt, 0xff, pad); 211 } 212 } 213 214 memset(ecc, 0, eccbytes); 215 swap_bits(buffer, info->ecc_step_size + 4); 216 encode_bch(bch, buffer, info->ecc_step_size + 4, ecc); 217 swap_bits(buffer, info->ecc_step_size + 4); 218 swap_bits(ecc, eccbytes); 219 scramble(info, page, buffer, info->ecc_step_size + 4 + eccbytes); 220 221 fseek(dst, pos + data_offs, SEEK_SET); 222 fwrite(buffer, info->ecc_step_size, 1, dst); 223 fseek(dst, pos + ecc_offs - 4, SEEK_SET); 224 fwrite(ecc - 4, eccbytes + 4, 1, dst); 225 } 226 227 /* Fix BBM. */ 228 fseek(dst, pos + info->page_size, SEEK_SET); 229 memset(buffer, 0xff, 2); 230 fwrite(buffer, 2, 1, dst); 231 232 /* Make dst pointer point to the next page. */ 233 fseek(dst, pos + info->page_size + info->oob_size, SEEK_SET); 234 235 return 0; 236 } 237 238 static int create_image(const struct image_info *info) 239 { 240 off_t page = info->offset / info->page_size; 241 struct bch_control *bch; 242 FILE *src, *dst, *rnd; 243 uint8_t *buffer; 244 245 bch = init_bch(14, info->ecc_strength, BCH_PRIMITIVE_POLY); 246 if (!bch) { 247 fprintf(stderr, "Failed to init the BCH engine\n"); 248 return -1; 249 } 250 251 buffer = malloc(info->page_size + info->oob_size); 252 if (!buffer) { 253 fprintf(stderr, "Failed to allocate the NAND page buffer\n"); 254 return -1; 255 } 256 257 memset(buffer, 0xff, info->page_size + info->oob_size); 258 259 src = fopen(info->source, "r"); 260 if (!src) { 261 fprintf(stderr, "Failed to open source file (%s)\n", 262 info->source); 263 return -1; 264 } 265 266 dst = fopen(info->dest, "w"); 267 if (!dst) { 268 fprintf(stderr, "Failed to open dest file (%s)\n", info->dest); 269 return -1; 270 } 271 272 rnd = fopen("/dev/urandom", "r"); 273 if (!rnd) { 274 fprintf(stderr, "Failed to open /dev/urandom\n"); 275 return -1; 276 } 277 278 while (!feof(src)) { 279 int ret; 280 281 ret = write_page(info, buffer, src, rnd, dst, bch, page++); 282 if (ret) 283 return ret; 284 } 285 286 return 0; 287 } 288 289 static void display_help(int status) 290 { 291 fprintf(status == EXIT_SUCCESS ? stdout : stderr, 292 "sunxi-nand-image-builder %s\n" 293 "\n" 294 "Usage: sunxi-nand-image-builder [OPTIONS] source-image output-image\n" 295 "\n" 296 "Creates a raw NAND image that can be read by the sunxi NAND controller.\n" 297 "\n" 298 "-h --help Display this help and exit\n" 299 "-c <str>/<step> --ecc=<str>/<step> ECC config (strength/step-size)\n" 300 "-p <size> --page=<size> Page size\n" 301 "-o <size> --oob=<size> OOB size\n" 302 "-u <size> --usable=<size> Usable page size\n" 303 "-e <size> --eraseblock=<size> Erase block size\n" 304 "-b --boot0 Build a boot0 image.\n" 305 "-s --scramble Scramble data\n" 306 "-a <offset> --address=<offset> Where the image will be programmed.\n" 307 "\n" 308 "Notes:\n" 309 "All the information you need to pass to this tool should be part of\n" 310 "the NAND datasheet.\n" 311 "\n" 312 "The NAND controller only supports the following ECC configs\n" 313 " Valid ECC strengths: 16, 24, 28, 32, 40, 48, 56, 60 and 64\n" 314 " Valid ECC step size: 512 and 1024\n" 315 "\n" 316 "If you are building a boot0 image, you'll have specify extra options.\n" 317 "These options should be chosen based on the layouts described here:\n" 318 " http://linux-sunxi.org/NAND#More_information_on_BROM_NAND\n" 319 "\n" 320 " --usable should be assigned the 'Hardware page' value\n" 321 " --ecc should be assigned the 'ECC capacity'/'ECC page' values\n" 322 " --usable should be smaller than --page\n" 323 "\n" 324 "The --address option is only required for non-boot0 images that are \n" 325 "meant to be programmed at a non eraseblock aligned offset.\n" 326 "\n" 327 "Examples:\n" 328 " The H27UCG8T2BTR-BC NAND exposes\n" 329 " * 16k pages\n" 330 " * 1280 OOB bytes per page\n" 331 " * 4M eraseblocks\n" 332 " * requires data scrambling\n" 333 " * expects a minimum ECC of 40bits/1024bytes\n" 334 "\n" 335 " A normal image can be generated with\n" 336 " sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -c 40/1024\n" 337 " A boot0 image can be generated with\n" 338 " sunxi-nand-image-builder -p 16384 -o 1280 -e 0x400000 -s -b -u 4096 -c 64/1024\n", 339 PLAIN_VERSION); 340 exit(status); 341 } 342 343 static int check_image_info(struct image_info *info) 344 { 345 static int valid_ecc_strengths[] = { 16, 24, 28, 32, 40, 48, 56, 60, 64 }; 346 int eccbytes, eccsteps; 347 unsigned i; 348 349 if (!info->page_size) { 350 fprintf(stderr, "--page is missing\n"); 351 return -EINVAL; 352 } 353 354 if (!info->page_size) { 355 fprintf(stderr, "--oob is missing\n"); 356 return -EINVAL; 357 } 358 359 if (!info->eraseblock_size) { 360 fprintf(stderr, "--eraseblock is missing\n"); 361 return -EINVAL; 362 } 363 364 if (info->ecc_step_size != 512 && info->ecc_step_size != 1024) { 365 fprintf(stderr, "Invalid ECC step argument: %d\n", 366 info->ecc_step_size); 367 return -EINVAL; 368 } 369 370 for (i = 0; i < ARRAY_SIZE(valid_ecc_strengths); i++) { 371 if (valid_ecc_strengths[i] == info->ecc_strength) 372 break; 373 } 374 375 if (i == ARRAY_SIZE(valid_ecc_strengths)) { 376 fprintf(stderr, "Invalid ECC strength argument: %d\n", 377 info->ecc_strength); 378 return -EINVAL; 379 } 380 381 eccbytes = DIV_ROUND_UP(info->ecc_strength * 14, 8); 382 if (eccbytes % 2) 383 eccbytes++; 384 eccbytes += 4; 385 386 eccsteps = info->usable_page_size / info->ecc_step_size; 387 388 if (info->page_size + info->oob_size < 389 info->usable_page_size + (eccsteps * eccbytes)) { 390 fprintf(stderr, 391 "ECC bytes do not fit in the NAND page, choose a weaker ECC\n"); 392 return -EINVAL; 393 } 394 395 return 0; 396 } 397 398 int main(int argc, char **argv) 399 { 400 struct image_info info; 401 402 memset(&info, 0, sizeof(info)); 403 /* 404 * Process user arguments 405 */ 406 for (;;) { 407 int option_index = 0; 408 char *endptr = NULL; 409 static const struct option long_options[] = { 410 {"help", no_argument, 0, 'h'}, 411 {"ecc", required_argument, 0, 'c'}, 412 {"page", required_argument, 0, 'p'}, 413 {"oob", required_argument, 0, 'o'}, 414 {"usable", required_argument, 0, 'u'}, 415 {"eraseblock", required_argument, 0, 'e'}, 416 {"boot0", no_argument, 0, 'b'}, 417 {"scramble", no_argument, 0, 's'}, 418 {"address", required_argument, 0, 'a'}, 419 {0, 0, 0, 0}, 420 }; 421 422 int c = getopt_long(argc, argv, "c:p:o:u:e:ba:sh", 423 long_options, &option_index); 424 if (c == EOF) 425 break; 426 427 switch (c) { 428 case 'h': 429 display_help(0); 430 break; 431 case 's': 432 info.scramble = 1; 433 break; 434 case 'c': 435 info.ecc_strength = strtol(optarg, &endptr, 0); 436 if (endptr || *endptr == '/') 437 info.ecc_step_size = strtol(endptr + 1, NULL, 0); 438 break; 439 case 'p': 440 info.page_size = strtol(optarg, NULL, 0); 441 break; 442 case 'o': 443 info.oob_size = strtol(optarg, NULL, 0); 444 break; 445 case 'u': 446 info.usable_page_size = strtol(optarg, NULL, 0); 447 break; 448 case 'e': 449 info.eraseblock_size = strtol(optarg, NULL, 0); 450 break; 451 case 'b': 452 info.boot0 = 1; 453 break; 454 case 'a': 455 info.offset = strtoull(optarg, NULL, 0); 456 break; 457 case '?': 458 display_help(-1); 459 break; 460 } 461 } 462 463 if ((argc - optind) != 2) 464 display_help(-1); 465 466 info.source = argv[optind]; 467 info.dest = argv[optind + 1]; 468 469 if (!info.boot0) { 470 info.usable_page_size = info.page_size; 471 } else if (!info.usable_page_size) { 472 if (info.page_size > 8192) 473 info.usable_page_size = 8192; 474 else if (info.page_size > 4096) 475 info.usable_page_size = 4096; 476 else 477 info.usable_page_size = 1024; 478 } 479 480 if (check_image_info(&info)) 481 display_help(-1); 482 483 return create_image(&info); 484 } 485