📄 fw_env.c
字号:
blockstart += blocklen; } return processed;}/* * Write count bytes at offset, but stay within ENVSETCORS (dev) sectors of * DEVOFFSET (dev). Similar to the read case above, on NOR we erase and write * the whole data at once. */static int flash_write_buf (int dev, int fd, void *buf, size_t count, off_t offset, uint8_t mtd_type){ void *data; struct erase_info_user erase; size_t blocklen; /* length of NAND block / NOR erase sector */ size_t erase_len; /* whole area that can be erased - may include bad blocks */ size_t erasesize; /* erase / write length - one block on NAND, whole area on NOR */ size_t processed = 0; /* progress counter */ size_t write_total; /* total size to actually write - excludinig bad blocks */ off_t erase_offset; /* offset to the first erase block (aligned) below offset */ off_t block_seek; /* offset inside the erase block to the start of the data */ off_t top_of_range; /* end of the last block we may use */ loff_t blockstart; /* running start of the current block - MEMGETBADBLOCK needs 64 bits */ int rc; blocklen = DEVESIZE (dev); /* Erase sector size is always a power of 2 */ top_of_range = (DEVOFFSET (dev) & ~(blocklen - 1)) + ENVSECTORS (dev) * blocklen; erase_offset = offset & ~(blocklen - 1); /* Maximum area we may use */ erase_len = top_of_range - erase_offset; blockstart = erase_offset; /* Offset inside a block */ block_seek = offset - erase_offset; /* * Data size we actually have to write: from the start of the block * to the start of the data, then count bytes of data, and to the * end of the block */ write_total = (block_seek + count + blocklen - 1) & ~(blocklen - 1); /* * Support data anywhere within erase sectors: read out the complete * area to be erased, replace the environment image, write the whole * block back again. */ if (write_total > count) { data = malloc (erase_len); if (!data) { fprintf (stderr, "Cannot malloc %u bytes: %s\n", erase_len, strerror (errno)); return -1; } rc = flash_read_buf (dev, fd, data, write_total, erase_offset, mtd_type); if (write_total != rc) return -1; /* Overwrite the old environment */ memcpy (data + block_seek, buf, count); } else { /* * We get here, iff offset is block-aligned and count is a * multiple of blocklen - see write_total calculation above */ data = buf; } if (mtd_type == MTD_NANDFLASH) { /* * NAND: calculate which blocks we are writing. We have * to write one block at a time to skip bad blocks. */ erasesize = blocklen; } else { erasesize = erase_len; } erase.length = erasesize; /* This only runs once on NOR flash */ while (processed < write_total) { rc = flash_bad_block (fd, mtd_type, &blockstart); if (rc < 0) /* block test failed */ return rc; if (blockstart + erasesize > top_of_range) { fprintf (stderr, "End of range reached, aborting\n"); return -1; } if (rc) { /* block is bad */ blockstart += blocklen; continue; } erase.start = blockstart; ioctl (fd, MEMUNLOCK, &erase); if (ioctl (fd, MEMERASE, &erase) != 0) { fprintf (stderr, "MTD erase error on %s: %s\n", DEVNAME (dev), strerror (errno)); return -1; } if (lseek (fd, blockstart, SEEK_SET) == -1) { fprintf (stderr, "Seek error on %s: %s\n", DEVNAME (dev), strerror (errno)); return -1; }#ifdef DEBUG printf ("Write 0x%x bytes at 0x%llx\n", erasesize, blockstart);#endif if (write (fd, data + processed, erasesize) != erasesize) { fprintf (stderr, "Write error on %s: %s\n", DEVNAME (dev), strerror (errno)); return -1; } ioctl (fd, MEMLOCK, &erase); processed += blocklen; block_seek = 0; blockstart += blocklen; } if (write_total > count) free (data); return processed;}/* * Set obsolete flag at offset - NOR flash only */static int flash_flag_obsolete (int dev, int fd, off_t offset){ int rc; /* This relies on the fact, that obsolete_flag == 0 */ rc = lseek (fd, offset, SEEK_SET); if (rc < 0) { fprintf (stderr, "Cannot seek to set the flag on %s \n", DEVNAME (dev)); return rc; } rc = write (fd, &obsolete_flag, sizeof (obsolete_flag)); if (rc < 0) perror ("Could not set obsolete flag"); return rc;}static int flash_write (int fd_current, int fd_target, int dev_target){ int rc; switch (environment.flag_scheme) { case FLAG_NONE: break; case FLAG_INCREMENTAL: (*environment.flags)++; break; case FLAG_BOOLEAN: *environment.flags = active_flag; break; default: fprintf (stderr, "Unimplemented flash scheme %u \n", environment.flag_scheme); return -1; }#ifdef DEBUG printf ("Writing new environment at 0x%lx on %s\n", DEVOFFSET (dev_target), DEVNAME (dev_target));#endif rc = flash_write_buf (dev_target, fd_target, environment.image, CONFIG_ENV_SIZE, DEVOFFSET (dev_target), DEVTYPE(dev_target)); if (rc < 0) return rc; if (environment.flag_scheme == FLAG_BOOLEAN) { /* Have to set obsolete flag */ off_t offset = DEVOFFSET (dev_current) + offsetof (struct env_image_redundant, flags);#ifdef DEBUG printf ("Setting obsolete flag in environment at 0x%lx on %s\n", DEVOFFSET (dev_current), DEVNAME (dev_current));#endif flash_flag_obsolete (dev_current, fd_current, offset); } return 0;}static int flash_read (int fd){ struct mtd_info_user mtdinfo; int rc; rc = ioctl (fd, MEMGETINFO, &mtdinfo); if (rc < 0) { perror ("Cannot get MTD information"); return -1; } if (mtdinfo.type != MTD_NORFLASH && mtdinfo.type != MTD_NANDFLASH) { fprintf (stderr, "Unsupported flash type %u\n", mtdinfo.type); return -1; } DEVTYPE(dev_current) = mtdinfo.type; rc = flash_read_buf (dev_current, fd, environment.image, CONFIG_ENV_SIZE, DEVOFFSET (dev_current), mtdinfo.type); return (rc != CONFIG_ENV_SIZE) ? -1 : 0;}static int flash_io (int mode){ int fd_current, fd_target, rc, dev_target; /* dev_current: fd_current, erase_current */ fd_current = open (DEVNAME (dev_current), mode); if (fd_current < 0) { fprintf (stderr, "Can't open %s: %s\n", DEVNAME (dev_current), strerror (errno)); return -1; } if (mode == O_RDWR) { if (HaveRedundEnv) { /* switch to next partition for writing */ dev_target = !dev_current; /* dev_target: fd_target, erase_target */ fd_target = open (DEVNAME (dev_target), mode); if (fd_target < 0) { fprintf (stderr, "Can't open %s: %s\n", DEVNAME (dev_target), strerror (errno)); rc = -1; goto exit; } } else { dev_target = dev_current; fd_target = fd_current; } rc = flash_write (fd_current, fd_target, dev_target); if (HaveRedundEnv) { if (close (fd_target)) { fprintf (stderr, "I/O error on %s: %s\n", DEVNAME (dev_target), strerror (errno)); rc = -1; } } } else { rc = flash_read (fd_current); }exit: if (close (fd_current)) { fprintf (stderr, "I/O error on %s: %s\n", DEVNAME (dev_current), strerror (errno)); return -1; } return rc;}/* * s1 is either a simple 'name', or a 'name=value' pair. * s2 is a 'name=value' pair. * If the names match, return the value of s2, else NULL. */static char *envmatch (char * s1, char * s2){ while (*s1 == *s2++) if (*s1++ == '=') return s2; if (*s1 == '\0' && *(s2 - 1) == '=') return s2; return NULL;}/* * Prevent confusion if running from erased flash memory */static int env_init (void){ int crc0, crc0_ok; char flag0; void *addr0; int crc1, crc1_ok; char flag1; void *addr1; struct env_image_single *single; struct env_image_redundant *redundant; if (parse_config ()) /* should fill envdevices */ return -1; addr0 = calloc (1, CONFIG_ENV_SIZE); if (addr0 == NULL) { fprintf (stderr, "Not enough memory for environment (%ld bytes)\n", CONFIG_ENV_SIZE); return -1; } /* read environment from FLASH to local buffer */ environment.image = addr0; if (HaveRedundEnv) { redundant = addr0; environment.crc = &redundant->crc; environment.flags = &redundant->flags; environment.data = redundant->data; } else { single = addr0; environment.crc = &single->crc; environment.flags = NULL; environment.data = single->data; } dev_current = 0; if (flash_io (O_RDONLY)) return -1; crc0 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE); crc0_ok = (crc0 == *environment.crc); if (!HaveRedundEnv) { if (!crc0_ok) { fprintf (stderr, "Warning: Bad CRC, using default environment\n"); memcpy(environment.data, default_environment, sizeof default_environment); } } else { flag0 = *environment.flags; dev_current = 1; addr1 = calloc (1, CONFIG_ENV_SIZE); if (addr1 == NULL) { fprintf (stderr, "Not enough memory for environment (%ld bytes)\n", CONFIG_ENV_SIZE); return -1; } redundant = addr1; /* * have to set environment.image for flash_read(), careful - * other pointers in environment still point inside addr0 */ environment.image = addr1; if (flash_io (O_RDONLY)) return -1; /* Check flag scheme compatibility */ if (DEVTYPE(dev_current) == MTD_NORFLASH && DEVTYPE(!dev_current) == MTD_NORFLASH) { environment.flag_scheme = FLAG_BOOLEAN; } else if (DEVTYPE(dev_current) == MTD_NANDFLASH && DEVTYPE(!dev_current) == MTD_NANDFLASH) { environment.flag_scheme = FLAG_INCREMENTAL; } else { fprintf (stderr, "Incompatible flash types!\n"); return -1; } crc1 = crc32 (0, (uint8_t *) redundant->data, ENV_SIZE); crc1_ok = (crc1 == redundant->crc); flag1 = redundant->flags; if (crc0_ok && !crc1_ok) { dev_current = 0; } else if (!crc0_ok && crc1_ok) { dev_current = 1; } else if (!crc0_ok && !crc1_ok) { fprintf (stderr, "Warning: Bad CRC, using default environment\n"); memcpy (environment.data, default_environment, sizeof default_environment); dev_current = 0; } else { switch (environment.flag_scheme) { case FLAG_BOOLEAN: if (flag0 == active_flag && flag1 == obsolete_flag) { dev_current = 0; } else if (flag0 == obsolete_flag && flag1 == active_flag) { dev_current = 1; } else if (flag0 == flag1) { dev_current = 0; } else if (flag0 == 0xFF) { dev_current = 0; } else if (flag1 == 0xFF) { dev_current = 1; } else { dev_current = 0; } break; case FLAG_INCREMENTAL: if ((flag0 == 255 && flag1 == 0) || flag1 > flag0) dev_current = 1; else if ((flag1 == 255 && flag0 == 0) || flag0 > flag1) dev_current = 0; else /* flags are equal - almost impossible */ dev_current = 0; break; default: fprintf (stderr, "Unknown flag scheme %u \n", environment.flag_scheme); return -1; } } /* * If we are reading, we don't need the flag and the CRC any * more, if we are writing, we will re-calculate CRC and update * flags before writing out */ if (dev_current) { environment.image = addr1; environment.crc = &redundant->crc; environment.flags = &redundant->flags; environment.data = redundant->data; free (addr0); } else { environment.image = addr0; /* Other pointers are already set */ free (addr1); } } return 0;}static int parse_config (){ struct stat st;#if defined(CONFIG_FILE) /* Fills in DEVNAME(), ENVSIZE(), DEVESIZE(). Or don't. */ if (get_config (CONFIG_FILE)) { fprintf (stderr, "Cannot parse config file: %s\n", strerror (errno)); return -1; }#else strcpy (DEVNAME (0), DEVICE1_NAME); DEVOFFSET (0) = DEVICE1_OFFSET; ENVSIZE (0) = ENV1_SIZE; DEVESIZE (0) = DEVICE1_ESIZE; ENVSECTORS (0) = DEVICE1_ENVSECTORS;#ifdef HAVE_REDUND strcpy (DEVNAME (1), DEVICE2_NAME); DEVOFFSET (1) = DEVICE2_OFFSET; ENVSIZE (1) = ENV2_SIZE; DEVESIZE (1) = DEVICE2_ESIZE; ENVSECTORS (1) = DEVICE2_ENVSECTORS; HaveRedundEnv = 1;#endif#endif if (stat (DEVNAME (0), &st)) { fprintf (stderr, "Cannot access MTD device %s: %s\n", DEVNAME (0), strerror (errno)); return -1; } if (HaveRedundEnv && stat (DEVNAME (1), &st)) { fprintf (stderr, "Cannot access MTD device %s: %s\n", DEVNAME (1), strerror (errno)); return -1; } return 0;}#if defined(CONFIG_FILE)static int get_config (char *fname){ FILE *fp; int i = 0; int rc; char dump[128]; fp = fopen (fname, "r"); if (fp == NULL) return -1; while (i < 2 && fgets (dump, sizeof (dump), fp)) { /* Skip incomplete conversions and comment strings */ if (dump[0] == '#') continue; rc = sscanf (dump, "%s %lx %lx %lx %lx", DEVNAME (i), &DEVOFFSET (i), &ENVSIZE (i), &DEVESIZE (i), &ENVSECTORS (i)); if (rc < 4) continue; if (rc < 5) /* Default - 1 sector */ ENVSECTORS (i) = 1; i++; } fclose (fp); HaveRedundEnv = i - 1; if (!i) { /* No valid entries found */ errno = EINVAL; return -1; } else return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -