1 /* 2 * (C) Copyright 2000-2010 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * (C) Copyright 2008 6 * Guennadi Liakhovetski, DENX Software Engineering, lg@denx.de. 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #define _GNU_SOURCE 12 13 #include <compiler.h> 14 #include <errno.h> 15 #include <env_flags.h> 16 #include <fcntl.h> 17 #include <linux/stringify.h> 18 #include <stdio.h> 19 #include <stdlib.h> 20 #include <stddef.h> 21 #include <string.h> 22 #include <sys/types.h> 23 #include <sys/ioctl.h> 24 #include <sys/stat.h> 25 #include <unistd.h> 26 27 #ifdef MTD_OLD 28 # include <stdint.h> 29 # include <linux/mtd/mtd.h> 30 #else 31 # define __user /* nothing */ 32 # include <mtd/mtd-user.h> 33 #endif 34 35 #include "fw_env.h" 36 37 #include <aes.h> 38 39 #define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d)) 40 41 #define WHITESPACE(c) ((c == '\t') || (c == ' ')) 42 43 #define min(x, y) ({ \ 44 typeof(x) _min1 = (x); \ 45 typeof(y) _min2 = (y); \ 46 (void) (&_min1 == &_min2); \ 47 _min1 < _min2 ? _min1 : _min2; }) 48 49 struct envdev_s { 50 const char *devname; /* Device name */ 51 ulong devoff; /* Device offset */ 52 ulong env_size; /* environment size */ 53 ulong erase_size; /* device erase size */ 54 ulong env_sectors; /* number of environment sectors */ 55 uint8_t mtd_type; /* type of the MTD device */ 56 }; 57 58 static struct envdev_s envdevices[2] = 59 { 60 { 61 .mtd_type = MTD_ABSENT, 62 }, { 63 .mtd_type = MTD_ABSENT, 64 }, 65 }; 66 static int dev_current; 67 68 #define DEVNAME(i) envdevices[(i)].devname 69 #define DEVOFFSET(i) envdevices[(i)].devoff 70 #define ENVSIZE(i) envdevices[(i)].env_size 71 #define DEVESIZE(i) envdevices[(i)].erase_size 72 #define ENVSECTORS(i) envdevices[(i)].env_sectors 73 #define DEVTYPE(i) envdevices[(i)].mtd_type 74 75 #define CUR_ENVSIZE ENVSIZE(dev_current) 76 77 #define ENV_SIZE getenvsize() 78 79 struct env_image_single { 80 uint32_t crc; /* CRC32 over data bytes */ 81 char data[]; 82 }; 83 84 struct env_image_redundant { 85 uint32_t crc; /* CRC32 over data bytes */ 86 unsigned char flags; /* active or obsolete */ 87 char data[]; 88 }; 89 90 enum flag_scheme { 91 FLAG_NONE, 92 FLAG_BOOLEAN, 93 FLAG_INCREMENTAL, 94 }; 95 96 struct environment { 97 void *image; 98 uint32_t *crc; 99 unsigned char *flags; 100 char *data; 101 enum flag_scheme flag_scheme; 102 }; 103 104 static struct environment environment = { 105 .flag_scheme = FLAG_NONE, 106 }; 107 108 /* Is AES encryption used? */ 109 static int aes_flag; 110 static uint8_t aes_key[AES_KEY_LENGTH] = { 0 }; 111 static int env_aes_cbc_crypt(char *data, const int enc); 112 113 static int HaveRedundEnv = 0; 114 115 static unsigned char active_flag = 1; 116 /* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */ 117 static unsigned char obsolete_flag = 0; 118 119 #define DEFAULT_ENV_INSTANCE_STATIC 120 #include <env_default.h> 121 122 static int flash_io (int mode); 123 static char *envmatch (char * s1, char * s2); 124 static int parse_config (void); 125 126 #if defined(CONFIG_FILE) 127 static int get_config (char *); 128 static char *config_file = CONFIG_FILE; 129 #endif 130 static inline ulong getenvsize (void) 131 { 132 ulong rc = CUR_ENVSIZE - sizeof(uint32_t); 133 134 if (HaveRedundEnv) 135 rc -= sizeof (char); 136 137 if (aes_flag) 138 rc &= ~(AES_KEY_LENGTH - 1); 139 140 return rc; 141 } 142 143 static char *fw_string_blank(char *s, int noblank) 144 { 145 int i; 146 int len = strlen(s); 147 148 for (i = 0; i < len; i++, s++) { 149 if ((noblank && !WHITESPACE(*s)) || 150 (!noblank && WHITESPACE(*s))) 151 break; 152 } 153 if (i == len) 154 return NULL; 155 156 return s; 157 } 158 159 /* 160 * Search the environment for a variable. 161 * Return the value, if found, or NULL, if not found. 162 */ 163 char *fw_getenv (char *name) 164 { 165 char *env, *nxt; 166 167 for (env = environment.data; *env; env = nxt + 1) { 168 char *val; 169 170 for (nxt = env; *nxt; ++nxt) { 171 if (nxt >= &environment.data[ENV_SIZE]) { 172 fprintf (stderr, "## Error: " 173 "environment not terminated\n"); 174 return NULL; 175 } 176 } 177 val = envmatch (name, env); 178 if (!val) 179 continue; 180 return val; 181 } 182 return NULL; 183 } 184 185 /* 186 * Search the default environment for a variable. 187 * Return the value, if found, or NULL, if not found. 188 */ 189 char *fw_getdefenv(char *name) 190 { 191 char *env, *nxt; 192 193 for (env = default_environment; *env; env = nxt + 1) { 194 char *val; 195 196 for (nxt = env; *nxt; ++nxt) { 197 if (nxt >= &default_environment[ENV_SIZE]) { 198 fprintf(stderr, "## Error: " 199 "default environment not terminated\n"); 200 return NULL; 201 } 202 } 203 val = envmatch(name, env); 204 if (!val) 205 continue; 206 return val; 207 } 208 return NULL; 209 } 210 211 static int parse_aes_key(char *key) 212 { 213 char tmp[5] = { '0', 'x', 0, 0, 0 }; 214 unsigned long ul; 215 int i; 216 217 if (strnlen(key, 64) != 32) { 218 fprintf(stderr, 219 "## Error: '-a' option requires 16-byte AES key\n"); 220 return -1; 221 } 222 223 for (i = 0; i < 16; i++) { 224 tmp[2] = key[0]; 225 tmp[3] = key[1]; 226 errno = 0; 227 ul = strtoul(tmp, NULL, 16); 228 if (errno) { 229 fprintf(stderr, 230 "## Error: '-a' option requires valid AES key\n"); 231 return -1; 232 } 233 aes_key[i] = ul & 0xff; 234 key += 2; 235 } 236 aes_flag = 1; 237 238 return 0; 239 } 240 241 /* 242 * Print the current definition of one, or more, or all 243 * environment variables 244 */ 245 int fw_printenv (int argc, char *argv[]) 246 { 247 char *env, *nxt; 248 int i, n_flag; 249 int rc = 0; 250 251 #ifdef CONFIG_FILE 252 if (argc >= 2 && strcmp(argv[1], "-c") == 0) { 253 if (argc < 3) { 254 fprintf(stderr, 255 "## Error: '-c' option requires the config file to use\n"); 256 return -1; 257 } 258 config_file = argv[2]; 259 argv += 2; 260 argc -= 2; 261 } 262 #endif 263 264 if (argc >= 2 && strcmp(argv[1], "-a") == 0) { 265 if (argc < 3) { 266 fprintf(stderr, 267 "## Error: '-a' option requires AES key\n"); 268 return -1; 269 } 270 rc = parse_aes_key(argv[2]); 271 if (rc) 272 return rc; 273 argv += 2; 274 argc -= 2; 275 } 276 277 if (fw_env_open()) 278 return -1; 279 280 if (argc == 1) { /* Print all env variables */ 281 for (env = environment.data; *env; env = nxt + 1) { 282 for (nxt = env; *nxt; ++nxt) { 283 if (nxt >= &environment.data[ENV_SIZE]) { 284 fprintf (stderr, "## Error: " 285 "environment not terminated\n"); 286 return -1; 287 } 288 } 289 290 printf ("%s\n", env); 291 } 292 return 0; 293 } 294 295 if (strcmp (argv[1], "-n") == 0) { 296 n_flag = 1; 297 ++argv; 298 --argc; 299 if (argc != 2) { 300 fprintf (stderr, "## Error: " 301 "`-n' option requires exactly one argument\n"); 302 return -1; 303 } 304 } else { 305 n_flag = 0; 306 } 307 308 for (i = 1; i < argc; ++i) { /* print single env variables */ 309 char *name = argv[i]; 310 char *val = NULL; 311 312 for (env = environment.data; *env; env = nxt + 1) { 313 314 for (nxt = env; *nxt; ++nxt) { 315 if (nxt >= &environment.data[ENV_SIZE]) { 316 fprintf (stderr, "## Error: " 317 "environment not terminated\n"); 318 return -1; 319 } 320 } 321 val = envmatch (name, env); 322 if (val) { 323 if (!n_flag) { 324 fputs (name, stdout); 325 putc ('=', stdout); 326 } 327 puts (val); 328 break; 329 } 330 } 331 if (!val) { 332 fprintf (stderr, "## Error: \"%s\" not defined\n", name); 333 rc = -1; 334 } 335 } 336 337 return rc; 338 } 339 340 int fw_env_close(void) 341 { 342 int ret; 343 if (aes_flag) { 344 ret = env_aes_cbc_crypt(environment.data, 1); 345 if (ret) { 346 fprintf(stderr, 347 "Error: can't encrypt env for flash\n"); 348 return ret; 349 } 350 } 351 352 /* 353 * Update CRC 354 */ 355 *environment.crc = crc32(0, (uint8_t *) environment.data, ENV_SIZE); 356 357 /* write environment back to flash */ 358 if (flash_io(O_RDWR)) { 359 fprintf(stderr, 360 "Error: can't write fw_env to flash\n"); 361 return -1; 362 } 363 364 return 0; 365 } 366 367 368 /* 369 * Set/Clear a single variable in the environment. 370 * This is called in sequence to update the environment 371 * in RAM without updating the copy in flash after each set 372 */ 373 int fw_env_write(char *name, char *value) 374 { 375 int len; 376 char *env, *nxt; 377 char *oldval = NULL; 378 int deleting, creating, overwriting; 379 380 /* 381 * search if variable with this name already exists 382 */ 383 for (nxt = env = environment.data; *env; env = nxt + 1) { 384 for (nxt = env; *nxt; ++nxt) { 385 if (nxt >= &environment.data[ENV_SIZE]) { 386 fprintf(stderr, "## Error: " 387 "environment not terminated\n"); 388 errno = EINVAL; 389 return -1; 390 } 391 } 392 if ((oldval = envmatch (name, env)) != NULL) 393 break; 394 } 395 396 deleting = (oldval && !(value && strlen(value))); 397 creating = (!oldval && (value && strlen(value))); 398 overwriting = (oldval && (value && strlen(value))); 399 400 /* check for permission */ 401 if (deleting) { 402 if (env_flags_validate_varaccess(name, 403 ENV_FLAGS_VARACCESS_PREVENT_DELETE)) { 404 printf("Can't delete \"%s\"\n", name); 405 errno = EROFS; 406 return -1; 407 } 408 } else if (overwriting) { 409 if (env_flags_validate_varaccess(name, 410 ENV_FLAGS_VARACCESS_PREVENT_OVERWR)) { 411 printf("Can't overwrite \"%s\"\n", name); 412 errno = EROFS; 413 return -1; 414 } else if (env_flags_validate_varaccess(name, 415 ENV_FLAGS_VARACCESS_PREVENT_NONDEF_OVERWR)) { 416 const char *defval = fw_getdefenv(name); 417 418 if (defval == NULL) 419 defval = ""; 420 if (strcmp(oldval, defval) 421 != 0) { 422 printf("Can't overwrite \"%s\"\n", name); 423 errno = EROFS; 424 return -1; 425 } 426 } 427 } else if (creating) { 428 if (env_flags_validate_varaccess(name, 429 ENV_FLAGS_VARACCESS_PREVENT_CREATE)) { 430 printf("Can't create \"%s\"\n", name); 431 errno = EROFS; 432 return -1; 433 } 434 } else 435 /* Nothing to do */ 436 return 0; 437 438 if (deleting || overwriting) { 439 if (*++nxt == '\0') { 440 *env = '\0'; 441 } else { 442 for (;;) { 443 *env = *nxt++; 444 if ((*env == '\0') && (*nxt == '\0')) 445 break; 446 ++env; 447 } 448 } 449 *++env = '\0'; 450 } 451 452 /* Delete only ? */ 453 if (!value || !strlen(value)) 454 return 0; 455 456 /* 457 * Append new definition at the end 458 */ 459 for (env = environment.data; *env || *(env + 1); ++env); 460 if (env > environment.data) 461 ++env; 462 /* 463 * Overflow when: 464 * "name" + "=" + "val" +"\0\0" > CUR_ENVSIZE - (env-environment) 465 */ 466 len = strlen (name) + 2; 467 /* add '=' for first arg, ' ' for all others */ 468 len += strlen(value) + 1; 469 470 if (len > (&environment.data[ENV_SIZE] - env)) { 471 fprintf (stderr, 472 "Error: environment overflow, \"%s\" deleted\n", 473 name); 474 return -1; 475 } 476 477 while ((*env = *name++) != '\0') 478 env++; 479 *env = '='; 480 while ((*++env = *value++) != '\0') 481 ; 482 483 /* end is marked with double '\0' */ 484 *++env = '\0'; 485 486 return 0; 487 } 488 489 /* 490 * Deletes or sets environment variables. Returns -1 and sets errno error codes: 491 * 0 - OK 492 * EINVAL - need at least 1 argument 493 * EROFS - certain variables ("ethaddr", "serial#") cannot be 494 * modified or deleted 495 * 496 */ 497 int fw_setenv(int argc, char *argv[]) 498 { 499 int i, rc; 500 size_t len; 501 char *name; 502 char *value = NULL; 503 504 #ifdef CONFIG_FILE 505 if (argc >= 2 && strcmp(argv[1], "-c") == 0) { 506 if (argc < 3) { 507 fprintf(stderr, 508 "## Error: '-c' option requires the config file to use\n"); 509 return -1; 510 } 511 config_file = argv[2]; 512 argv += 2; 513 argc -= 2; 514 } 515 #endif 516 517 if (argc < 2) { 518 errno = EINVAL; 519 return -1; 520 } 521 522 if (strcmp(argv[1], "-a") == 0) { 523 if (argc < 3) { 524 fprintf(stderr, 525 "## Error: '-a' option requires AES key\n"); 526 return -1; 527 } 528 rc = parse_aes_key(argv[2]); 529 if (rc) 530 return rc; 531 argv += 2; 532 argc -= 2; 533 } 534 535 if (argc < 2) { 536 errno = EINVAL; 537 return -1; 538 } 539 540 if (fw_env_open()) { 541 fprintf(stderr, "Error: environment not initialized\n"); 542 return -1; 543 } 544 545 name = argv[1]; 546 547 if (env_flags_validate_env_set_params(argc, argv) < 0) 548 return 1; 549 550 len = 0; 551 for (i = 2; i < argc; ++i) { 552 char *val = argv[i]; 553 size_t val_len = strlen(val); 554 555 if (value) 556 value[len - 1] = ' '; 557 value = realloc(value, len + val_len + 1); 558 if (!value) { 559 fprintf(stderr, 560 "Cannot malloc %zu bytes: %s\n", 561 len, strerror(errno)); 562 return -1; 563 } 564 565 memcpy(value + len, val, val_len); 566 len += val_len; 567 value[len++] = '\0'; 568 } 569 570 fw_env_write(name, value); 571 572 free(value); 573 574 return fw_env_close(); 575 } 576 577 /* 578 * Parse a file and configure the u-boot variables. 579 * The script file has a very simple format, as follows: 580 * 581 * Each line has a couple with name, value: 582 * <white spaces>variable_name<white spaces>variable_value 583 * 584 * Both variable_name and variable_value are interpreted as strings. 585 * Any character after <white spaces> and before ending \r\n is interpreted 586 * as variable's value (no comment allowed on these lines !) 587 * 588 * Comments are allowed if the first character in the line is # 589 * 590 * Returns -1 and sets errno error codes: 591 * 0 - OK 592 * -1 - Error 593 */ 594 int fw_parse_script(char *fname) 595 { 596 FILE *fp; 597 char dump[1024]; /* Maximum line length in the file */ 598 char *name; 599 char *val; 600 int lineno = 0; 601 int len; 602 int ret = 0; 603 604 if (fw_env_open()) { 605 fprintf(stderr, "Error: environment not initialized\n"); 606 return -1; 607 } 608 609 if (strcmp(fname, "-") == 0) 610 fp = stdin; 611 else { 612 fp = fopen(fname, "r"); 613 if (fp == NULL) { 614 fprintf(stderr, "I cannot open %s for reading\n", 615 fname); 616 return -1; 617 } 618 } 619 620 while (fgets(dump, sizeof(dump), fp)) { 621 lineno++; 622 len = strlen(dump); 623 624 /* 625 * Read a whole line from the file. If the line is too long 626 * or is not terminated, reports an error and exit. 627 */ 628 if (dump[len - 1] != '\n') { 629 fprintf(stderr, 630 "Line %d not corrected terminated or too long\n", 631 lineno); 632 ret = -1; 633 break; 634 } 635 636 /* Drop ending line feed / carriage return */ 637 while (len > 0 && (dump[len - 1] == '\n' || 638 dump[len - 1] == '\r')) { 639 dump[len - 1] = '\0'; 640 len--; 641 } 642 643 /* Skip comment or empty lines */ 644 if ((len == 0) || dump[0] == '#') 645 continue; 646 647 /* 648 * Search for variable's name, 649 * remove leading whitespaces 650 */ 651 name = fw_string_blank(dump, 1); 652 if (!name) 653 continue; 654 655 /* The first white space is the end of variable name */ 656 val = fw_string_blank(name, 0); 657 len = strlen(name); 658 if (val) { 659 *val++ = '\0'; 660 if ((val - name) < len) 661 val = fw_string_blank(val, 1); 662 else 663 val = NULL; 664 } 665 666 #ifdef DEBUG 667 fprintf(stderr, "Setting %s : %s\n", 668 name, val ? val : " removed"); 669 #endif 670 671 if (env_flags_validate_type(name, val) < 0) { 672 ret = -1; 673 break; 674 } 675 676 /* 677 * If there is an error setting a variable, 678 * try to save the environment and returns an error 679 */ 680 if (fw_env_write(name, val)) { 681 fprintf(stderr, 682 "fw_env_write returns with error : %s\n", 683 strerror(errno)); 684 ret = -1; 685 break; 686 } 687 688 } 689 690 /* Close file if not stdin */ 691 if (strcmp(fname, "-") != 0) 692 fclose(fp); 693 694 ret |= fw_env_close(); 695 696 return ret; 697 698 } 699 700 /* 701 * Test for bad block on NAND, just returns 0 on NOR, on NAND: 702 * 0 - block is good 703 * > 0 - block is bad 704 * < 0 - failed to test 705 */ 706 static int flash_bad_block (int fd, uint8_t mtd_type, loff_t *blockstart) 707 { 708 if (mtd_type == MTD_NANDFLASH) { 709 int badblock = ioctl (fd, MEMGETBADBLOCK, blockstart); 710 711 if (badblock < 0) { 712 perror ("Cannot read bad block mark"); 713 return badblock; 714 } 715 716 if (badblock) { 717 #ifdef DEBUG 718 fprintf (stderr, "Bad block at 0x%llx, " 719 "skipping\n", *blockstart); 720 #endif 721 return badblock; 722 } 723 } 724 725 return 0; 726 } 727 728 /* 729 * Read data from flash at an offset into a provided buffer. On NAND it skips 730 * bad blocks but makes sure it stays within ENVSECTORS (dev) starting from 731 * the DEVOFFSET (dev) block. On NOR the loop is only run once. 732 */ 733 static int flash_read_buf (int dev, int fd, void *buf, size_t count, 734 off_t offset, uint8_t mtd_type) 735 { 736 size_t blocklen; /* erase / write length - one block on NAND, 737 0 on NOR */ 738 size_t processed = 0; /* progress counter */ 739 size_t readlen = count; /* current read length */ 740 off_t top_of_range; /* end of the last block we may use */ 741 off_t block_seek; /* offset inside the current block to the start 742 of the data */ 743 loff_t blockstart; /* running start of the current block - 744 MEMGETBADBLOCK needs 64 bits */ 745 int rc; 746 747 blockstart = (offset / DEVESIZE (dev)) * DEVESIZE (dev); 748 749 /* Offset inside a block */ 750 block_seek = offset - blockstart; 751 752 if (mtd_type == MTD_NANDFLASH) { 753 /* 754 * NAND: calculate which blocks we are reading. We have 755 * to read one block at a time to skip bad blocks. 756 */ 757 blocklen = DEVESIZE (dev); 758 759 /* 760 * To calculate the top of the range, we have to use the 761 * global DEVOFFSET (dev), which can be different from offset 762 */ 763 top_of_range = ((DEVOFFSET(dev) / blocklen) + 764 ENVSECTORS (dev)) * blocklen; 765 766 /* Limit to one block for the first read */ 767 if (readlen > blocklen - block_seek) 768 readlen = blocklen - block_seek; 769 } else { 770 blocklen = 0; 771 top_of_range = offset + count; 772 } 773 774 /* This only runs once on NOR flash */ 775 while (processed < count) { 776 rc = flash_bad_block (fd, mtd_type, &blockstart); 777 if (rc < 0) /* block test failed */ 778 return -1; 779 780 if (blockstart + block_seek + readlen > top_of_range) { 781 /* End of range is reached */ 782 fprintf (stderr, 783 "Too few good blocks within range\n"); 784 return -1; 785 } 786 787 if (rc) { /* block is bad */ 788 blockstart += blocklen; 789 continue; 790 } 791 792 /* 793 * If a block is bad, we retry in the next block at the same 794 * offset - see common/env_nand.c::writeenv() 795 */ 796 lseek (fd, blockstart + block_seek, SEEK_SET); 797 798 rc = read (fd, buf + processed, readlen); 799 if (rc != readlen) { 800 fprintf (stderr, "Read error on %s: %s\n", 801 DEVNAME (dev), strerror (errno)); 802 return -1; 803 } 804 #ifdef DEBUG 805 fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n", 806 rc, blockstart + block_seek, DEVNAME(dev)); 807 #endif 808 processed += readlen; 809 readlen = min (blocklen, count - processed); 810 block_seek = 0; 811 blockstart += blocklen; 812 } 813 814 return processed; 815 } 816 817 /* 818 * Write count bytes at offset, but stay within ENVSECTORS (dev) sectors of 819 * DEVOFFSET (dev). Similar to the read case above, on NOR and dataflash we 820 * erase and write the whole data at once. 821 */ 822 static int flash_write_buf (int dev, int fd, void *buf, size_t count, 823 off_t offset, uint8_t mtd_type) 824 { 825 void *data; 826 struct erase_info_user erase; 827 size_t blocklen; /* length of NAND block / NOR erase sector */ 828 size_t erase_len; /* whole area that can be erased - may include 829 bad blocks */ 830 size_t erasesize; /* erase / write length - one block on NAND, 831 whole area on NOR */ 832 size_t processed = 0; /* progress counter */ 833 size_t write_total; /* total size to actually write - excluding 834 bad blocks */ 835 off_t erase_offset; /* offset to the first erase block (aligned) 836 below offset */ 837 off_t block_seek; /* offset inside the erase block to the start 838 of the data */ 839 off_t top_of_range; /* end of the last block we may use */ 840 loff_t blockstart; /* running start of the current block - 841 MEMGETBADBLOCK needs 64 bits */ 842 int rc; 843 844 /* 845 * For mtd devices only offset and size of the environment do matter 846 */ 847 if (mtd_type == MTD_ABSENT) { 848 blocklen = count; 849 top_of_range = offset + count; 850 erase_len = blocklen; 851 blockstart = offset; 852 block_seek = 0; 853 write_total = blocklen; 854 } else { 855 blocklen = DEVESIZE(dev); 856 857 top_of_range = ((DEVOFFSET(dev) / blocklen) + 858 ENVSECTORS(dev)) * blocklen; 859 860 erase_offset = (offset / blocklen) * blocklen; 861 862 /* Maximum area we may use */ 863 erase_len = top_of_range - erase_offset; 864 865 blockstart = erase_offset; 866 /* Offset inside a block */ 867 block_seek = offset - erase_offset; 868 869 /* 870 * Data size we actually write: from the start of the block 871 * to the start of the data, then count bytes of data, and 872 * to the end of the block 873 */ 874 write_total = ((block_seek + count + blocklen - 1) / 875 blocklen) * blocklen; 876 } 877 878 /* 879 * Support data anywhere within erase sectors: read out the complete 880 * area to be erased, replace the environment image, write the whole 881 * block back again. 882 */ 883 if (write_total > count) { 884 data = malloc (erase_len); 885 if (!data) { 886 fprintf (stderr, 887 "Cannot malloc %zu bytes: %s\n", 888 erase_len, strerror (errno)); 889 return -1; 890 } 891 892 rc = flash_read_buf (dev, fd, data, write_total, erase_offset, 893 mtd_type); 894 if (write_total != rc) 895 return -1; 896 897 #ifdef DEBUG 898 fprintf(stderr, "Preserving data "); 899 if (block_seek != 0) 900 fprintf(stderr, "0x%x - 0x%lx", 0, block_seek - 1); 901 if (block_seek + count != write_total) { 902 if (block_seek != 0) 903 fprintf(stderr, " and "); 904 fprintf(stderr, "0x%lx - 0x%x", 905 block_seek + count, write_total - 1); 906 } 907 fprintf(stderr, "\n"); 908 #endif 909 /* Overwrite the old environment */ 910 memcpy (data + block_seek, buf, count); 911 } else { 912 /* 913 * We get here, iff offset is block-aligned and count is a 914 * multiple of blocklen - see write_total calculation above 915 */ 916 data = buf; 917 } 918 919 if (mtd_type == MTD_NANDFLASH) { 920 /* 921 * NAND: calculate which blocks we are writing. We have 922 * to write one block at a time to skip bad blocks. 923 */ 924 erasesize = blocklen; 925 } else { 926 erasesize = erase_len; 927 } 928 929 erase.length = erasesize; 930 931 /* This only runs once on NOR flash and SPI-dataflash */ 932 while (processed < write_total) { 933 rc = flash_bad_block (fd, mtd_type, &blockstart); 934 if (rc < 0) /* block test failed */ 935 return rc; 936 937 if (blockstart + erasesize > top_of_range) { 938 fprintf (stderr, "End of range reached, aborting\n"); 939 return -1; 940 } 941 942 if (rc) { /* block is bad */ 943 blockstart += blocklen; 944 continue; 945 } 946 947 if (mtd_type != MTD_ABSENT) { 948 erase.start = blockstart; 949 ioctl(fd, MEMUNLOCK, &erase); 950 /* These do not need an explicit erase cycle */ 951 if (mtd_type != MTD_DATAFLASH) 952 if (ioctl(fd, MEMERASE, &erase) != 0) { 953 fprintf(stderr, 954 "MTD erase error on %s: %s\n", 955 DEVNAME(dev), strerror(errno)); 956 return -1; 957 } 958 } 959 960 if (lseek (fd, blockstart, SEEK_SET) == -1) { 961 fprintf (stderr, 962 "Seek error on %s: %s\n", 963 DEVNAME (dev), strerror (errno)); 964 return -1; 965 } 966 967 #ifdef DEBUG 968 fprintf(stderr, "Write 0x%x bytes at 0x%llx\n", erasesize, 969 blockstart); 970 #endif 971 if (write (fd, data + processed, erasesize) != erasesize) { 972 fprintf (stderr, "Write error on %s: %s\n", 973 DEVNAME (dev), strerror (errno)); 974 return -1; 975 } 976 977 if (mtd_type != MTD_ABSENT) 978 ioctl(fd, MEMLOCK, &erase); 979 980 processed += erasesize; 981 block_seek = 0; 982 blockstart += erasesize; 983 } 984 985 if (write_total > count) 986 free (data); 987 988 return processed; 989 } 990 991 /* 992 * Set obsolete flag at offset - NOR flash only 993 */ 994 static int flash_flag_obsolete (int dev, int fd, off_t offset) 995 { 996 int rc; 997 struct erase_info_user erase; 998 999 erase.start = DEVOFFSET (dev); 1000 erase.length = DEVESIZE (dev); 1001 /* This relies on the fact, that obsolete_flag == 0 */ 1002 rc = lseek (fd, offset, SEEK_SET); 1003 if (rc < 0) { 1004 fprintf (stderr, "Cannot seek to set the flag on %s \n", 1005 DEVNAME (dev)); 1006 return rc; 1007 } 1008 ioctl (fd, MEMUNLOCK, &erase); 1009 rc = write (fd, &obsolete_flag, sizeof (obsolete_flag)); 1010 ioctl (fd, MEMLOCK, &erase); 1011 if (rc < 0) 1012 perror ("Could not set obsolete flag"); 1013 1014 return rc; 1015 } 1016 1017 /* Encrypt or decrypt the environment before writing or reading it. */ 1018 static int env_aes_cbc_crypt(char *payload, const int enc) 1019 { 1020 uint8_t *data = (uint8_t *)payload; 1021 const int len = getenvsize(); 1022 uint8_t key_exp[AES_EXPAND_KEY_LENGTH]; 1023 uint32_t aes_blocks; 1024 1025 /* First we expand the key. */ 1026 aes_expand_key(aes_key, key_exp); 1027 1028 /* Calculate the number of AES blocks to encrypt. */ 1029 aes_blocks = DIV_ROUND_UP(len, AES_KEY_LENGTH); 1030 1031 if (enc) 1032 aes_cbc_encrypt_blocks(key_exp, data, data, aes_blocks); 1033 else 1034 aes_cbc_decrypt_blocks(key_exp, data, data, aes_blocks); 1035 1036 return 0; 1037 } 1038 1039 static int flash_write (int fd_current, int fd_target, int dev_target) 1040 { 1041 int rc; 1042 1043 switch (environment.flag_scheme) { 1044 case FLAG_NONE: 1045 break; 1046 case FLAG_INCREMENTAL: 1047 (*environment.flags)++; 1048 break; 1049 case FLAG_BOOLEAN: 1050 *environment.flags = active_flag; 1051 break; 1052 default: 1053 fprintf (stderr, "Unimplemented flash scheme %u \n", 1054 environment.flag_scheme); 1055 return -1; 1056 } 1057 1058 #ifdef DEBUG 1059 fprintf(stderr, "Writing new environment at 0x%lx on %s\n", 1060 DEVOFFSET (dev_target), DEVNAME (dev_target)); 1061 #endif 1062 1063 rc = flash_write_buf(dev_target, fd_target, environment.image, 1064 CUR_ENVSIZE, DEVOFFSET(dev_target), 1065 DEVTYPE(dev_target)); 1066 if (rc < 0) 1067 return rc; 1068 1069 if (environment.flag_scheme == FLAG_BOOLEAN) { 1070 /* Have to set obsolete flag */ 1071 off_t offset = DEVOFFSET (dev_current) + 1072 offsetof (struct env_image_redundant, flags); 1073 #ifdef DEBUG 1074 fprintf(stderr, 1075 "Setting obsolete flag in environment at 0x%lx on %s\n", 1076 DEVOFFSET (dev_current), DEVNAME (dev_current)); 1077 #endif 1078 flash_flag_obsolete (dev_current, fd_current, offset); 1079 } 1080 1081 return 0; 1082 } 1083 1084 static int flash_read (int fd) 1085 { 1086 struct mtd_info_user mtdinfo; 1087 struct stat st; 1088 int rc; 1089 1090 rc = fstat(fd, &st); 1091 if (rc < 0) { 1092 fprintf(stderr, "Cannot stat the file %s\n", 1093 DEVNAME(dev_current)); 1094 return -1; 1095 } 1096 1097 if (S_ISCHR(st.st_mode)) { 1098 rc = ioctl(fd, MEMGETINFO, &mtdinfo); 1099 if (rc < 0) { 1100 fprintf(stderr, "Cannot get MTD information for %s\n", 1101 DEVNAME(dev_current)); 1102 return -1; 1103 } 1104 if (mtdinfo.type != MTD_NORFLASH && 1105 mtdinfo.type != MTD_NANDFLASH && 1106 mtdinfo.type != MTD_DATAFLASH && 1107 mtdinfo.type != MTD_UBIVOLUME) { 1108 fprintf (stderr, "Unsupported flash type %u on %s\n", 1109 mtdinfo.type, DEVNAME(dev_current)); 1110 return -1; 1111 } 1112 } else { 1113 memset(&mtdinfo, 0, sizeof(mtdinfo)); 1114 mtdinfo.type = MTD_ABSENT; 1115 } 1116 1117 DEVTYPE(dev_current) = mtdinfo.type; 1118 1119 rc = flash_read_buf(dev_current, fd, environment.image, CUR_ENVSIZE, 1120 DEVOFFSET (dev_current), mtdinfo.type); 1121 if (rc != CUR_ENVSIZE) 1122 return -1; 1123 1124 return 0; 1125 } 1126 1127 static int flash_io (int mode) 1128 { 1129 int fd_current, fd_target, rc, dev_target; 1130 1131 /* dev_current: fd_current, erase_current */ 1132 fd_current = open (DEVNAME (dev_current), mode); 1133 if (fd_current < 0) { 1134 fprintf (stderr, 1135 "Can't open %s: %s\n", 1136 DEVNAME (dev_current), strerror (errno)); 1137 return -1; 1138 } 1139 1140 if (mode == O_RDWR) { 1141 if (HaveRedundEnv) { 1142 /* switch to next partition for writing */ 1143 dev_target = !dev_current; 1144 /* dev_target: fd_target, erase_target */ 1145 fd_target = open (DEVNAME (dev_target), mode); 1146 if (fd_target < 0) { 1147 fprintf (stderr, 1148 "Can't open %s: %s\n", 1149 DEVNAME (dev_target), 1150 strerror (errno)); 1151 rc = -1; 1152 goto exit; 1153 } 1154 } else { 1155 dev_target = dev_current; 1156 fd_target = fd_current; 1157 } 1158 1159 rc = flash_write (fd_current, fd_target, dev_target); 1160 1161 if (HaveRedundEnv) { 1162 if (close (fd_target)) { 1163 fprintf (stderr, 1164 "I/O error on %s: %s\n", 1165 DEVNAME (dev_target), 1166 strerror (errno)); 1167 rc = -1; 1168 } 1169 } 1170 } else { 1171 rc = flash_read (fd_current); 1172 } 1173 1174 exit: 1175 if (close (fd_current)) { 1176 fprintf (stderr, 1177 "I/O error on %s: %s\n", 1178 DEVNAME (dev_current), strerror (errno)); 1179 return -1; 1180 } 1181 1182 return rc; 1183 } 1184 1185 /* 1186 * s1 is either a simple 'name', or a 'name=value' pair. 1187 * s2 is a 'name=value' pair. 1188 * If the names match, return the value of s2, else NULL. 1189 */ 1190 1191 static char *envmatch (char * s1, char * s2) 1192 { 1193 if (s1 == NULL || s2 == NULL) 1194 return NULL; 1195 1196 while (*s1 == *s2++) 1197 if (*s1++ == '=') 1198 return s2; 1199 if (*s1 == '\0' && *(s2 - 1) == '=') 1200 return s2; 1201 return NULL; 1202 } 1203 1204 /* 1205 * Prevent confusion if running from erased flash memory 1206 */ 1207 int fw_env_open(void) 1208 { 1209 int crc0, crc0_ok; 1210 unsigned char flag0; 1211 void *addr0; 1212 1213 int crc1, crc1_ok; 1214 unsigned char flag1; 1215 void *addr1; 1216 1217 int ret; 1218 1219 struct env_image_single *single; 1220 struct env_image_redundant *redundant; 1221 1222 if (parse_config ()) /* should fill envdevices */ 1223 return -1; 1224 1225 addr0 = calloc(1, CUR_ENVSIZE); 1226 if (addr0 == NULL) { 1227 fprintf(stderr, 1228 "Not enough memory for environment (%ld bytes)\n", 1229 CUR_ENVSIZE); 1230 return -1; 1231 } 1232 1233 /* read environment from FLASH to local buffer */ 1234 environment.image = addr0; 1235 1236 if (HaveRedundEnv) { 1237 redundant = addr0; 1238 environment.crc = &redundant->crc; 1239 environment.flags = &redundant->flags; 1240 environment.data = redundant->data; 1241 } else { 1242 single = addr0; 1243 environment.crc = &single->crc; 1244 environment.flags = NULL; 1245 environment.data = single->data; 1246 } 1247 1248 dev_current = 0; 1249 if (flash_io (O_RDONLY)) 1250 return -1; 1251 1252 crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE); 1253 1254 if (aes_flag) { 1255 ret = env_aes_cbc_crypt(environment.data, 0); 1256 if (ret) 1257 return ret; 1258 } 1259 1260 crc0_ok = (crc0 == *environment.crc); 1261 if (!HaveRedundEnv) { 1262 if (!crc0_ok) { 1263 fprintf (stderr, 1264 "Warning: Bad CRC, using default environment\n"); 1265 memcpy(environment.data, default_environment, sizeof default_environment); 1266 } 1267 } else { 1268 flag0 = *environment.flags; 1269 1270 dev_current = 1; 1271 addr1 = calloc(1, CUR_ENVSIZE); 1272 if (addr1 == NULL) { 1273 fprintf(stderr, 1274 "Not enough memory for environment (%ld bytes)\n", 1275 CUR_ENVSIZE); 1276 return -1; 1277 } 1278 redundant = addr1; 1279 1280 /* 1281 * have to set environment.image for flash_read(), careful - 1282 * other pointers in environment still point inside addr0 1283 */ 1284 environment.image = addr1; 1285 if (flash_io (O_RDONLY)) 1286 return -1; 1287 1288 /* Check flag scheme compatibility */ 1289 if (DEVTYPE(dev_current) == MTD_NORFLASH && 1290 DEVTYPE(!dev_current) == MTD_NORFLASH) { 1291 environment.flag_scheme = FLAG_BOOLEAN; 1292 } else if (DEVTYPE(dev_current) == MTD_NANDFLASH && 1293 DEVTYPE(!dev_current) == MTD_NANDFLASH) { 1294 environment.flag_scheme = FLAG_INCREMENTAL; 1295 } else if (DEVTYPE(dev_current) == MTD_DATAFLASH && 1296 DEVTYPE(!dev_current) == MTD_DATAFLASH) { 1297 environment.flag_scheme = FLAG_BOOLEAN; 1298 } else if (DEVTYPE(dev_current) == MTD_UBIVOLUME && 1299 DEVTYPE(!dev_current) == MTD_UBIVOLUME) { 1300 environment.flag_scheme = FLAG_INCREMENTAL; 1301 } else if (DEVTYPE(dev_current) == MTD_ABSENT && 1302 DEVTYPE(!dev_current) == MTD_ABSENT) { 1303 environment.flag_scheme = FLAG_INCREMENTAL; 1304 } else { 1305 fprintf (stderr, "Incompatible flash types!\n"); 1306 return -1; 1307 } 1308 1309 crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE); 1310 1311 if (aes_flag) { 1312 ret = env_aes_cbc_crypt(redundant->data, 0); 1313 if (ret) 1314 return ret; 1315 } 1316 1317 crc1_ok = (crc1 == redundant->crc); 1318 flag1 = redundant->flags; 1319 1320 if (crc0_ok && !crc1_ok) { 1321 dev_current = 0; 1322 } else if (!crc0_ok && crc1_ok) { 1323 dev_current = 1; 1324 } else if (!crc0_ok && !crc1_ok) { 1325 fprintf (stderr, 1326 "Warning: Bad CRC, using default environment\n"); 1327 memcpy (environment.data, default_environment, 1328 sizeof default_environment); 1329 dev_current = 0; 1330 } else { 1331 switch (environment.flag_scheme) { 1332 case FLAG_BOOLEAN: 1333 if (flag0 == active_flag && 1334 flag1 == obsolete_flag) { 1335 dev_current = 0; 1336 } else if (flag0 == obsolete_flag && 1337 flag1 == active_flag) { 1338 dev_current = 1; 1339 } else if (flag0 == flag1) { 1340 dev_current = 0; 1341 } else if (flag0 == 0xFF) { 1342 dev_current = 0; 1343 } else if (flag1 == 0xFF) { 1344 dev_current = 1; 1345 } else { 1346 dev_current = 0; 1347 } 1348 break; 1349 case FLAG_INCREMENTAL: 1350 if (flag0 == 255 && flag1 == 0) 1351 dev_current = 1; 1352 else if ((flag1 == 255 && flag0 == 0) || 1353 flag0 >= flag1) 1354 dev_current = 0; 1355 else /* flag1 > flag0 */ 1356 dev_current = 1; 1357 break; 1358 default: 1359 fprintf (stderr, "Unknown flag scheme %u \n", 1360 environment.flag_scheme); 1361 return -1; 1362 } 1363 } 1364 1365 /* 1366 * If we are reading, we don't need the flag and the CRC any 1367 * more, if we are writing, we will re-calculate CRC and update 1368 * flags before writing out 1369 */ 1370 if (dev_current) { 1371 environment.image = addr1; 1372 environment.crc = &redundant->crc; 1373 environment.flags = &redundant->flags; 1374 environment.data = redundant->data; 1375 free (addr0); 1376 } else { 1377 environment.image = addr0; 1378 /* Other pointers are already set */ 1379 free (addr1); 1380 } 1381 #ifdef DEBUG 1382 fprintf(stderr, "Selected env in %s\n", DEVNAME(dev_current)); 1383 #endif 1384 } 1385 return 0; 1386 } 1387 1388 1389 static int parse_config () 1390 { 1391 struct stat st; 1392 1393 #if defined(CONFIG_FILE) 1394 /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ 1395 if (get_config (config_file)) { 1396 fprintf (stderr, 1397 "Cannot parse config file '%s': %s\n", config_file, strerror (errno)); 1398 return -1; 1399 } 1400 #else 1401 DEVNAME (0) = DEVICE1_NAME; 1402 DEVOFFSET (0) = DEVICE1_OFFSET; 1403 ENVSIZE (0) = ENV1_SIZE; 1404 /* Default values are: erase-size=env-size */ 1405 DEVESIZE (0) = ENVSIZE (0); 1406 /* #sectors=env-size/erase-size (rounded up) */ 1407 ENVSECTORS (0) = (ENVSIZE(0) + DEVESIZE(0) - 1) / DEVESIZE(0); 1408 #ifdef DEVICE1_ESIZE 1409 DEVESIZE (0) = DEVICE1_ESIZE; 1410 #endif 1411 #ifdef DEVICE1_ENVSECTORS 1412 ENVSECTORS (0) = DEVICE1_ENVSECTORS; 1413 #endif 1414 1415 #ifdef HAVE_REDUND 1416 DEVNAME (1) = DEVICE2_NAME; 1417 DEVOFFSET (1) = DEVICE2_OFFSET; 1418 ENVSIZE (1) = ENV2_SIZE; 1419 /* Default values are: erase-size=env-size */ 1420 DEVESIZE (1) = ENVSIZE (1); 1421 /* #sectors=env-size/erase-size (rounded up) */ 1422 ENVSECTORS (1) = (ENVSIZE(1) + DEVESIZE(1) - 1) / DEVESIZE(1); 1423 #ifdef DEVICE2_ESIZE 1424 DEVESIZE (1) = DEVICE2_ESIZE; 1425 #endif 1426 #ifdef DEVICE2_ENVSECTORS 1427 ENVSECTORS (1) = DEVICE2_ENVSECTORS; 1428 #endif 1429 HaveRedundEnv = 1; 1430 #endif 1431 #endif 1432 if (stat (DEVNAME (0), &st)) { 1433 fprintf (stderr, 1434 "Cannot access MTD device %s: %s\n", 1435 DEVNAME (0), strerror (errno)); 1436 return -1; 1437 } 1438 1439 if (HaveRedundEnv && stat (DEVNAME (1), &st)) { 1440 fprintf (stderr, 1441 "Cannot access MTD device %s: %s\n", 1442 DEVNAME (1), strerror (errno)); 1443 return -1; 1444 } 1445 return 0; 1446 } 1447 1448 #if defined(CONFIG_FILE) 1449 static int get_config (char *fname) 1450 { 1451 FILE *fp; 1452 int i = 0; 1453 int rc; 1454 char dump[128]; 1455 char *devname; 1456 1457 fp = fopen (fname, "r"); 1458 if (fp == NULL) 1459 return -1; 1460 1461 while (i < 2 && fgets (dump, sizeof (dump), fp)) { 1462 /* Skip incomplete conversions and comment strings */ 1463 if (dump[0] == '#') 1464 continue; 1465 1466 rc = sscanf (dump, "%ms %lx %lx %lx %lx", 1467 &devname, 1468 &DEVOFFSET (i), 1469 &ENVSIZE (i), 1470 &DEVESIZE (i), 1471 &ENVSECTORS (i)); 1472 1473 if (rc < 3) 1474 continue; 1475 1476 DEVNAME(i) = devname; 1477 1478 if (rc < 4) 1479 /* Assume the erase size is the same as the env-size */ 1480 DEVESIZE(i) = ENVSIZE(i); 1481 1482 if (rc < 5) 1483 /* Assume enough env sectors to cover the environment */ 1484 ENVSECTORS (i) = (ENVSIZE(i) + DEVESIZE(i) - 1) / DEVESIZE(i); 1485 1486 i++; 1487 } 1488 fclose (fp); 1489 1490 HaveRedundEnv = i - 1; 1491 if (!i) { /* No valid entries found */ 1492 errno = EINVAL; 1493 return -1; 1494 } else 1495 return 0; 1496 } 1497 #endif 1498