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