mtd: sync upstream source code

This commit is contained in:
AmadeusGhost 2020-05-31 20:01:05 +08:00
parent 4969d9fde3
commit 50f3cf27ef
12 changed files with 310 additions and 61 deletions

View File

@ -3,13 +3,13 @@
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
#
include $(TOPDIR)/rules.mk
include $(INCLUDE_DIR)/kernel.mk
PKG_NAME:=mtd
PKG_RELEASE:=23
PKG_RELEASE:=25
PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME)
STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS)

View File

@ -6,12 +6,15 @@ obj = mtd.o jffs2.o crc32.o md5.o
obj.seama = seama.o md5.o
obj.wrg = wrg.o md5.o
obj.wrgg = wrgg.o md5.o
obj.tpl = tpl_ramips_recoveryflag.o
obj.ar71xx = trx.o $(obj.seama) $(obj.wrgg)
obj.ath79 = $(obj.seama)
obj.gemini = $(obj.wrgg)
obj.brcm = trx.o
obj.brcm47xx = $(obj.brcm)
obj.bcm53xx = $(obj.brcm) $(obj.seama)
obj.brcm63xx = imagetag.o
obj.ramips = $(obj.seama) $(obj.wrg) linksys_bootcount.o
obj.ramips = $(obj.seama) $(obj.tpl) $(obj.wrg) linksys_bootcount.o
obj.mvebu = linksys_bootcount.o
obj.kirkwood = linksys_bootcount.o
obj.ipq806x = linksys_bootcount.o

View File

@ -139,8 +139,6 @@ done:
int
fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
{
struct fis_image_desc *fisdir = NULL;
struct fis_image_desc *redboot = NULL;
struct fis_image_desc *first = NULL;
struct fis_image_desc *last = NULL;
struct fis_image_desc *first_fb = NULL;
@ -164,12 +162,6 @@ fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff))
break;
if (!strcmp((char *) desc->hdr.name, "FIS directory"))
fisdir = desc;
if (!strcmp((char *) desc->hdr.name, "RedBoot"))
redboot = desc;
/* update max offset */
if (offset < desc->hdr.flash_base)
offset = desc->hdr.flash_base;
@ -210,18 +202,6 @@ fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
size = offset - first_fb->hdr.flash_base;
#ifdef notyet
desc = first - 1;
if (redboot && (desc >= redboot)) {
if (first->hdr.flash_base - desc->hdr.size > desc->hdr.flash_base) {
int delta = first->hdr.flash_base - desc->hdr.size - desc->hdr.flash_base;
offset -= delta;
size += delta;
}
}
#endif
last++;
desc = first + n_new;
offset = first_fb->hdr.flash_base;
@ -243,14 +223,14 @@ fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new)
memset(desc, 0, sizeof(struct fis_image_desc));
memcpy(desc->hdr.name, part->name, sizeof(desc->hdr.name));
desc->crc.desc = 0;
desc->crc.file = 0;
desc->crc.file = part->crc;
desc->hdr.flash_base = offset;
desc->hdr.mem_base = part->loadaddr;
desc->hdr.entry_point = part->loadaddr;
desc->hdr.size = (part->size > 0) ? part->size : size;
desc->hdr.data_length = desc->hdr.size;
desc->hdr.data_length = (part->length > 0) ? part->length :
desc->hdr.size;
offset += desc->hdr.size;
size -= desc->hdr.size;
}

View File

@ -6,6 +6,8 @@ struct fis_part {
uint32_t offset;
uint32_t loadaddr;
uint32_t size;
uint32_t length;
uint32_t crc;
};
int fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new);

View File

@ -2,6 +2,7 @@
* Linksys boot counter reset code for mtd
*
* Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
* Portions Copyright (c) 2019, Jeff Kletsky
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
@ -29,6 +30,7 @@
#include <string.h>
#include <errno.h>
#include <stdint.h>
#include <syslog.h>
#include <sys/ioctl.h>
#include <mtd/mtd-user.h>
@ -37,6 +39,30 @@
#define BOOTCOUNT_MAGIC 0x20110811
/*
* EA6350v3, and potentially other NOR-boot devices,
* use an offset increment of 16 between records,
* not mtd_info_user.writesize (often 1 on NOR devices).
*/
#define BC_OFFSET_INCREMENT_MIN 16
#define DLOG_OPEN()
#define DLOG_ERR(...) do { \
fprintf(stderr, "ERROR: " __VA_ARGS__); fprintf(stderr, "\n"); \
} while (0)
#define DLOG_NOTICE(...) do { \
fprintf(stderr, __VA_ARGS__); fprintf(stderr, "\n"); \
} while (0)
#define DLOG_DEBUG(...)
struct bootcounter {
uint32_t magic;
uint32_t count;
@ -50,25 +76,50 @@ int mtd_resetbc(const char *mtd)
struct mtd_info_user mtd_info;
struct bootcounter *curr = (struct bootcounter *)page;
unsigned int i;
unsigned int bc_offset_increment;
int last_count = 0;
int num_bc;
int fd;
int ret;
int retval = 0;
DLOG_OPEN();
fd = mtd_check_open(mtd);
if (ioctl(fd, MEMGETINFO, &mtd_info) < 0) {
fprintf(stderr, "failed to get mtd info!\n");
return -1;
DLOG_ERR("Unable to obtain mtd_info for given partition name.");
retval = -1;
goto out;
}
num_bc = mtd_info.size / mtd_info.writesize;
/* Detect need to override increment (for EA6350v3) */
if (mtd_info.writesize < BC_OFFSET_INCREMENT_MIN) {
bc_offset_increment = BC_OFFSET_INCREMENT_MIN;
DLOG_DEBUG("Offset increment set to %i for writesize of %i",
bc_offset_increment, mtd_info.writesize);
} else {
bc_offset_increment = mtd_info.writesize;
}
num_bc = mtd_info.size / bc_offset_increment;
for (i = 0; i < num_bc; i++) {
pread(fd, curr, sizeof(*curr), i * mtd_info.writesize);
pread(fd, curr, sizeof(*curr), i * bc_offset_increment);
if (curr->magic != BOOTCOUNT_MAGIC && curr->magic != 0xffffffff) {
fprintf(stderr, "unexpected magic %08x, bailing out\n", curr->magic);
/* Existing code assumes erase is to 0xff; left as-is (2019) */
if (curr->magic != BOOTCOUNT_MAGIC &&
curr->magic != 0xffffffff) {
DLOG_ERR("Unexpected magic %08x at offset %08x; aborting.",
curr->magic, i * bc_offset_increment);
retval = -2;
goto out;
}
@ -78,38 +129,59 @@ int mtd_resetbc(const char *mtd)
last_count = curr->count;
}
/* no need to do writes when last boot count is already 0 */
if (last_count == 0)
if (last_count == 0) { /* bootcount is already 0 */
retval = 0;
goto out;
}
if (i == num_bc) {
DLOG_NOTICE("Boot-count log full with %i entries; erasing (expected occasionally).",
i);
struct erase_info_user erase_info;
erase_info.start = 0;
erase_info.length = mtd_info.size;
/* erase block */
ret = ioctl(fd, MEMERASE, &erase_info);
if (ret < 0) {
fprintf(stderr, "failed to erase block: %i\n", ret);
return -1;
DLOG_ERR("Failed to erase boot-count log MTD; ioctl() MEMERASE returned %i",
ret);
retval = -3;
goto out;
}
i = 0;
}
memset(curr, 0xff, mtd_info.writesize);
memset(curr, 0xff, bc_offset_increment);
curr->magic = BOOTCOUNT_MAGIC;
curr->count = 0;
curr->checksum = BOOTCOUNT_MAGIC;
ret = pwrite(fd, curr, mtd_info.writesize, i * mtd_info.writesize);
if (ret < 0)
fprintf(stderr, "failed to write: %i\n", ret);
sync();
/* Assumes bc_offset_increment is a multiple of mtd_info.writesize */
ret = pwrite(fd, curr, bc_offset_increment, i * bc_offset_increment);
if (ret < 0) {
DLOG_ERR("Failed to write boot-count log entry; pwrite() returned %i",
errno);
retval = -4;
goto out;
} else {
sync();
DLOG_NOTICE("Boot count sucessfully reset to zero.");
retval = 0;
goto out;
}
out:
close(fd);
return 0;
return retval;
}

View File

@ -44,6 +44,7 @@
#include <sys/reboot.h>
#include <linux/reboot.h>
#include <mtd/mtd-user.h>
#include "crc32.h"
#include "fis.h"
#include "mtd.h"
@ -85,6 +86,7 @@ static char *buf = NULL;
static char *imagefile = NULL;
static enum mtd_image_format imageformat = MTD_IMAGE_FORMAT_UNKNOWN;
static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR;
static char *tpl_uboot_args_part;
static int buflen = 0;
int quiet;
int no_erase;
@ -472,12 +474,14 @@ mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset)
ssize_t r, w, e;
ssize_t skip = 0;
uint32_t offset = 0;
int buflen_raw = 0;
int jffs2_replaced = 0;
int skip_bad_blocks = 0;
#ifdef FIS_SUPPORT
static struct fis_part new_parts[MAX_ARGS];
static struct fis_part old_parts[MAX_ARGS];
struct fis_part *cur_part = NULL;
int n_new = 0, n_old = 0;
if (fis_layout) {
@ -487,6 +491,8 @@ mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset)
memset(&old_parts, 0, sizeof(old_parts));
memset(&new_parts, 0, sizeof(new_parts));
if (!part_offset)
cur_part = new_parts;
do {
next = strchr(tmp, ':');
@ -554,6 +560,17 @@ resume:
lseek(fd, part_offset, SEEK_SET);
}
/* Write TP-Link recovery flag */
if (tpl_uboot_args_part && mtd_tpl_recoverflag_write) {
if (quiet < 2)
fprintf(stderr, "Writing recovery flag to %s\n", tpl_uboot_args_part);
result = mtd_tpl_recoverflag_write(tpl_uboot_args_part, true);
if (result < 0) {
fprintf(stderr, "Could not write TP-Link recovery flag to %s: %i", mtd, result);
exit(1);
}
}
indicate_writing(mtd);
w = e = 0;
@ -576,6 +593,9 @@ resume:
buflen += r;
}
if (buflen_raw == 0)
buflen_raw = buflen;
if (buflen == 0)
break;
@ -587,6 +607,7 @@ resume:
if (skip > 0) {
skip -= buflen;
buflen_raw = 0;
buflen = 0;
if (skip <= 0)
indicate_writing(mtd);
@ -610,6 +631,7 @@ resume:
w += skip;
e += skip;
skip -= buflen;
buflen_raw = 0;
buflen = 0;
offset = 0;
continue;
@ -675,6 +697,17 @@ resume:
}
w += buflen;
#ifdef FIS_SUPPORT
if (cur_part && cur_part->size
&& cur_part < &new_parts[MAX_ARGS - 1]
&& cur_part->length + buflen_raw > cur_part->size)
cur_part++;
if (cur_part) {
cur_part->length += buflen_raw;
cur_part->crc = crc32(cur_part->crc, buf, buflen_raw);
}
#endif
buflen_raw = 0;
buflen = 0;
offset = 0;
}
@ -716,6 +749,18 @@ resume:
#endif
close(fd);
/* Clear TP-Link recovery flag */
if (tpl_uboot_args_part && mtd_tpl_recoverflag_write) {
if (quiet < 2)
fprintf(stderr, "Removing recovery flag from %s\n", tpl_uboot_args_part);
result = mtd_tpl_recoverflag_write(tpl_uboot_args_part, false);
if (result < 0) {
fprintf(stderr, "Could not clear TP-Link recovery flag to %s: %i", mtd, result);
exit(1);
}
}
return 0;
}
@ -771,6 +816,10 @@ static void usage(void)
fprintf(stderr,
" -c datasize amount of data to be used for checksum calculation (for fixtrx / fixseama / fixwrg / fixwrgg)\n");
}
if (mtd_tpl_recoverflag_write) {
fprintf(stderr,
" -t <partition> write TP-Link recovery-flag to <partition> (for write)\n");
}
fprintf(stderr,
#ifdef FIS_SUPPORT
" -F <part>[:<size>[:<entrypoint>]][,<part>...]\n"
@ -828,7 +877,7 @@ int main (int argc, char **argv)
#ifdef FIS_SUPPORT
"F:"
#endif
"frnqe:d:s:j:p:o:c:l:")) != -1)
"frnqe:d:s:j:p:o:c:t:l:")) != -1)
switch (ch) {
case 'f':
force = 1;
@ -896,6 +945,9 @@ int main (int argc, char **argv)
usage();
}
break;
case 't':
tpl_uboot_args_part = optarg;
break;
#ifdef FIS_SUPPORT
case 'F':
fis_layout = optarg;

View File

@ -30,4 +30,5 @@ extern int mtd_fixseama(const char *mtd, size_t offset, size_t data_size) __attr
extern int mtd_fixwrg(const char *mtd, size_t offset, size_t data_size) __attribute__ ((weak));
extern int mtd_fixwrgg(const char *mtd, size_t offset, size_t data_size) __attribute__ ((weak));
extern int mtd_resetbc(const char *mtd) __attribute__ ((weak));
extern int mtd_tpl_recoverflag_write(const char *mtd, const bool recovery_active) __attribute__ ((weak));
#endif /* __mtd_h */

View File

@ -0,0 +1,94 @@
/*
* TP-Link recovery flag set and unset code for ramips target
*
* Copyright (C) 2018 David Bauer <mail@david-bauer.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License v2
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <sys/mman.h>
#include <errno.h>
#include <stdint.h>
#include <mtd/mtd-user.h>
#include <sys/ioctl.h>
#include "mtd.h"
#define TPL_RECOVER_MAGIC 0x89abcdef
#define TPL_NO_RECOVER_MAGIC 0x00000000
struct uboot_args {
uint32_t magic;
};
int mtd_tpl_recoverflag_write(const char *mtd, const bool recovery_active)
{
struct erase_info_user erase_info;
struct uboot_args *args;
uint32_t magic;
int ret = 0;
int fd;
args = malloc(erasesize);
if (!args) {
fprintf(stderr, "Could not allocate memory!\n");
return -1;
}
fd = mtd_check_open(mtd);
if (fd < 0) {
fprintf(stderr, "Could not open mtd device: %s\n", mtd);
ret = -1;
goto out;
}
/* read first block (containing the magic) */
pread(fd, args, erasesize, 0);
/* set magic to desired value */
magic = TPL_RECOVER_MAGIC;
if (!recovery_active)
magic = TPL_NO_RECOVER_MAGIC;
/* no need to write when magic is already set correctly */
if (magic == args->magic)
goto out;
/* erase first block (containing the magic) */
erase_info.start = 0;
erase_info.length = erasesize;
ret = ioctl(fd, MEMERASE, &erase_info);
if (ret < 0) {
fprintf(stderr, "failed to erase block: %i\n", ret);
goto out;
}
/* write magic to flash */
args->magic = magic;
ret = pwrite(fd, args, erasesize, 0);
if (ret < 0)
fprintf(stderr, "failed to write: %i\n", ret);
sync();
out:
free(args);
close(fd);
return ret;
}

View File

@ -39,13 +39,10 @@
#include "wrgg.h"
#include "md5.h"
#if __BYTE_ORDER == __BIG_ENDIAN
#define STORE32_LE(X) ((((X) & 0x000000FF) << 24) | (((X) & 0x0000FF00) << 8) | (((X) & 0x00FF0000) >> 8) | (((X) & 0xFF000000) >> 24))
#elif __BYTE_ORDER == __LITTLE_ENDIAN
#define STORE32_LE(X) (X)
#else
#error unknown endianness!
#endif
static inline uint32_t le32_to_cpu(uint8_t *buf)
{
return buf[0] | buf[1] << 8 | buf[2] << 16 | buf[3] << 24;
}
ssize_t pread(int fd, void *buf, size_t count, off_t offset);
ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset);
@ -94,7 +91,7 @@ wrgg_fix_md5(struct wrgg03_header *shdr, int fd, size_t data_offset, size_t data
}
/* update the size in the image */
shdr->size = htonl(data_size);
shdr->size = data_size;
/* update the checksum in the image */
memcpy(shdr->digest, digest, sizeof(digest));
@ -147,12 +144,14 @@ mtd_fixwrgg(const char *mtd, size_t offset, size_t data_size)
}
shdr = (struct wrgg03_header *)(first_block + offset);
if (shdr->magic1 != htonl(STORE32_LE(WRGG03_MAGIC))) {
fprintf(stderr, "magic1 %x\n", shdr->magic1);
fprintf(stderr, "htonl(WRGG03_MAGIC) %x\n", WRGG03_MAGIC);
/* The magic is always stored in little-endian byte order */
if (le32_to_cpu((uint8_t *)&shdr->magic1) != WRGG03_MAGIC) {
fprintf(stderr, "magic1 = %x\n", shdr->magic1);
fprintf(stderr, "WRGG03_MAGIC = %x\n", WRGG03_MAGIC);
fprintf(stderr, "No WRGG header found\n");
exit(1);
} else if (!ntohl(shdr->size)) {
} else if (!shdr->size) {
fprintf(stderr, "WRGG entity with empty image\n");
exit(1);
}
@ -160,8 +159,8 @@ mtd_fixwrgg(const char *mtd, size_t offset, size_t data_size)
data_offset = offset + sizeof(struct wrgg03_header);
if (!data_size)
data_size = mtdsize - data_offset;
if (data_size > ntohl(shdr->size))
data_size = ntohl(shdr->size);
if (data_size > shdr->size)
data_size = shdr->size;
if (wrgg_fix_md5(shdr, fd, data_offset, data_size))
goto out;

View File

@ -32,7 +32,7 @@ define Host/Compile
$(call cc,dgfirmware)
$(call cc,mksenaofw md5, -Wall --std=gnu99)
$(call cc,trx2usr)
$(call cc,ptgen)
$(call cc,ptgen cyg_crc32)
$(call cc,srec2bin)
$(call cc,mkmylofw)
$(call cc,mkcsysimg)

View File

@ -137,6 +137,15 @@ struct fw_info fw_info[] = {
},
.sign = true,
},
{
.name = "XC",
.fw_layout = {
.kern_start = 0x9f050000,
.kern_entry = 0x80002000,
.firmware_max_length= 0x00F60000,
},
.sign = true,
},
{
.name = "ACB-ISP",
.fw_layout = {

View File

@ -891,7 +891,7 @@ static struct device_info boards[] = {
"{product_name:Archer C6,product_ver:2.0.0,special_id:52550000}\r\n"
"{product_name:Archer C6,product_ver:2.0.0,special_id:4A500000}\r\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:1.1.1\n",
.soft_ver = "soft_ver:1.2.1\n",
.partitions = {
{"fs-uboot", 0x00000, 0x20000},
@ -1021,6 +1021,42 @@ static struct device_info boards[] = {
.last_sysupgrade_partition = "file-system",
},
/** Firmware layout for the C60v3 */
{
.id = "ARCHER-C60-V3",
.vendor = "",
.support_list =
"SupportList:\r\n"
"{product_name:Archer C60,product_ver:3.0.0,special_id:42520000}\r\n"
"{product_name:Archer C60,product_ver:3.0.0,special_id:45550000}\r\n"
"{product_name:Archer C60,product_ver:3.0.0,special_id:55530000}\r\n",
.support_trail = '\x00',
.soft_ver = "soft_ver:3.0.0\n",
.partitions = {
{"factory-boot", 0x00000, 0x1fb00},
{"default-mac", 0x1fb00, 0x00200},
{"pin", 0x1fd00, 0x00100},
{"product-info", 0x1fe00, 0x00100},
{"device-id", 0x1ff00, 0x00100},
{"fs-uboot", 0x20000, 0x10000},
{"firmware", 0x30000, 0x7a0000},
{"soft-version", 0x7d9500, 0x00100},
{"support-list", 0x7d9600, 0x00100},
{"extra-para", 0x7d9700, 0x00100},
{"profile", 0x7d9800, 0x03000},
{"default-config", 0x7dc800, 0x03000},
{"partition-table", 0x7df800, 0x00800},
{"user-config", 0x7e0000, 0x0c000},
{"certificate", 0x7ec000, 0x04000},
{"radio", 0x7f0000, 0x10000},
{NULL, 0, 0}
},
.first_sysupgrade_partition = "os-image",
.last_sysupgrade_partition = "file-system",
},
/** Firmware layout for the C5 */
{
.id = "ARCHER-C5-V2",
@ -2172,6 +2208,7 @@ static void build_image(const char *output,
strcasecmp(info->id, "ARCHER-C25-V1") == 0 ||
strcasecmp(info->id, "ARCHER-C59-V2") == 0 ||
strcasecmp(info->id, "ARCHER-C60-V2") == 0 ||
strcasecmp(info->id, "ARCHER-C60-V3") == 0 ||
strcasecmp(info->id, "TLWR1043NV5") == 0) {
const char mdat[11] = {0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00};
parts[5] = put_data("extra-para", mdat, 11);