From 716ca530e1c4515d8683c9d5be3d56b301758b66 Mon Sep 17 00:00:00 2001 From: James <> Date: Wed, 4 Nov 2015 11:49:21 +0000 Subject: trunk-47381 --- package/system/mtd/Makefile | 54 ++ package/system/mtd/src/Makefile | 21 + package/system/mtd/src/crc32.c | 95 +++ package/system/mtd/src/crc32.h | 26 + package/system/mtd/src/fis.c | 262 ++++++++ package/system/mtd/src/fis.h | 14 + package/system/mtd/src/imagetag.c | 407 +++++++++++++ package/system/mtd/src/jffs2.c | 366 ++++++++++++ package/system/mtd/src/jffs2.h | 216 +++++++ package/system/mtd/src/linksys_bootcount.c | 114 ++++ package/system/mtd/src/md5.c | 307 ++++++++++ package/system/mtd/src/md5.h | 65 ++ package/system/mtd/src/mtd.c | 919 +++++++++++++++++++++++++++++ package/system/mtd/src/mtd.h | 31 + package/system/mtd/src/seama.c | 179 ++++++ package/system/mtd/src/seama.h | 108 ++++ package/system/mtd/src/trx.c | 223 +++++++ 17 files changed, 3407 insertions(+) create mode 100644 package/system/mtd/Makefile create mode 100644 package/system/mtd/src/Makefile create mode 100644 package/system/mtd/src/crc32.c create mode 100644 package/system/mtd/src/crc32.h create mode 100644 package/system/mtd/src/fis.c create mode 100644 package/system/mtd/src/fis.h create mode 100644 package/system/mtd/src/imagetag.c create mode 100644 package/system/mtd/src/jffs2.c create mode 100644 package/system/mtd/src/jffs2.h create mode 100644 package/system/mtd/src/linksys_bootcount.c create mode 100644 package/system/mtd/src/md5.c create mode 100644 package/system/mtd/src/md5.h create mode 100644 package/system/mtd/src/mtd.c create mode 100644 package/system/mtd/src/mtd.h create mode 100644 package/system/mtd/src/seama.c create mode 100644 package/system/mtd/src/seama.h create mode 100644 package/system/mtd/src/trx.c (limited to 'package/system/mtd') diff --git a/package/system/mtd/Makefile b/package/system/mtd/Makefile new file mode 100644 index 0000000..ae1922f --- /dev/null +++ b/package/system/mtd/Makefile @@ -0,0 +1,54 @@ +# +# Copyright (C) 2006-2012 OpenWrt.org +# +# 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:=21 + +PKG_BUILD_DIR := $(KERNEL_BUILD_DIR)/$(PKG_NAME) +STAMP_PREPARED := $(STAMP_PREPARED)_$(call confvar,CONFIG_MTD_REDBOOT_PARTS) + +PKG_LICENSE:=GPL-2.0+ +PKG_LICENSE_FILES:= + +include $(INCLUDE_DIR)/package.mk + +define Package/mtd + SECTION:=utils + CATEGORY:=Base system + DEPENDS:=+libubox + TITLE:=Update utility for trx firmware images +endef + +define Package/mtd/description + This package contains an utility useful to upgrade from other firmware or + older OpenWrt releases. +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) + $(CP) ./src/* $(PKG_BUILD_DIR)/ +endef + +target=$(firstword $(subst -, ,$(BOARD))) + +MAKE_FLAGS += TARGET="$(target)" +TARGET_CFLAGS := $(TARGET_CFLAGS) -Dtarget_$(target)=1 -Wall + +ifdef CONFIG_MTD_REDBOOT_PARTS + MAKE_FLAGS += FIS_SUPPORT=1 + TARGET_CFLAGS += -DFIS_SUPPORT=1 +endif + +define Package/mtd/install + $(INSTALL_DIR) $(1)/sbin + $(INSTALL_BIN) $(PKG_BUILD_DIR)/mtd $(1)/sbin/ +endef + +$(eval $(call BuildPackage,mtd)) diff --git a/package/system/mtd/src/Makefile b/package/system/mtd/src/Makefile new file mode 100644 index 0000000..40a165e --- /dev/null +++ b/package/system/mtd/src/Makefile @@ -0,0 +1,21 @@ +CC = gcc +CFLAGS += -Wall +LDFLAGS += -lubox + +obj = mtd.o jffs2.o crc32.o md5.o +obj.seama = seama.o md5.o +obj.ar71xx = trx.o $(obj.seama) +obj.brcm = trx.o +obj.brcm47xx = $(obj.brcm) +obj.bcm53xx = $(obj.brcm) +obj.brcm63xx = imagetag.o +obj.ramips = $(obj.seama) +obj.mvebu = linksys_bootcount.o + +ifdef FIS_SUPPORT + obj += fis.o +endif + +mtd: $(obj) $(obj.$(TARGET)) +clean: + rm -f *.o jffs2 diff --git a/package/system/mtd/src/crc32.c b/package/system/mtd/src/crc32.c new file mode 100644 index 0000000..6b1e50c --- /dev/null +++ b/package/system/mtd/src/crc32.c @@ -0,0 +1,95 @@ +/* + * COPYRIGHT (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + * + * First, the polynomial itself and its table of feedback terms. The + * polynomial is + * X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 + * + * Note that we take it "backwards" and put the highest-order term in + * the lowest-order bit. The X^32 term is "implied"; the LSB is the + * X^31 term, etc. The X^0 term (usually shown as "+1") results in + * the MSB being 1 + * + * Note that the usual hardware shift register implementation, which + * is what we're using (we're merely optimizing it by doing eight-bit + * chunks at a time) shifts bits into the lowest-order term. In our + * implementation, that means shifting towards the right. Why do we + * do it this way? Because the calculated CRC must be transmitted in + * order from highest-order term to lowest-order term. UARTs transmit + * characters in order from LSB to MSB. By storing the CRC this way + * we hand it to the UART in the order low-byte to high-byte; the UART + * sends each low-bit to hight-bit; and the result is transmission bit + * by bit from highest- to lowest-order term without requiring any bit + * shuffling on our part. Reception works similarly + * + * The feedback terms table consists of 256, 32-bit entries. Notes + * + * The table can be generated at runtime if desired; code to do so + * is shown later. It might not be obvious, but the feedback + * terms simply represent the results of eight shift/xor opera + * tions for all combinations of data and CRC register values + * + * The values must be right-shifted by eight bits by the "updcrc + * logic; the shift must be unsigned (bring in zeroes). On some + * hardware you could probably optimize the shift in assembler by + * using byte-swap instructions + * polynomial $edb88320 + */ + +#include + +const uint32_t crc32_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; diff --git a/package/system/mtd/src/crc32.h b/package/system/mtd/src/crc32.h new file mode 100644 index 0000000..68f8ee4 --- /dev/null +++ b/package/system/mtd/src/crc32.h @@ -0,0 +1,26 @@ +#ifndef CRC32_H +#define CRC32_H + +#include + +extern const uint32_t crc32_table[256]; + +/* Return a 32-bit CRC of the contents of the buffer. */ + +static inline uint32_t +crc32(uint32_t val, const void *ss, int len) +{ + const unsigned char *s = ss; + while (--len >= 0) + val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); + return val; +} + +static inline unsigned int crc32buf(char *buf, size_t len) +{ + return crc32(0xFFFFFFFF, buf, len); +} + + + +#endif diff --git a/package/system/mtd/src/fis.c b/package/system/mtd/src/fis.c new file mode 100644 index 0000000..f825f59 --- /dev/null +++ b/package/system/mtd/src/fis.c @@ -0,0 +1,262 @@ +/* + * FIS table updating code for mtd + * + * Copyright (C) 2009 Felix Fietkau + * + * 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 +#include +#include +#include +#include +#include +#include "crc32.h" +#include "mtd.h" +#include "fis.h" + +struct fis_image_hdr { + unsigned char name[16]; + uint32_t flash_base; + uint32_t mem_base; + uint32_t size; + uint32_t entry_point; + uint32_t data_length; +} __attribute__((packed)); + +struct fis_image_crc { + uint32_t desc; + uint32_t file; +} __attribute__((packed)); + +struct fis_image_desc { + struct fis_image_hdr hdr; + char _pad[256 - sizeof(struct fis_image_hdr) - sizeof(struct fis_image_crc)]; + struct fis_image_crc crc; +} __attribute__((packed)); + +static int fis_fd = -1; +static struct fis_image_desc *fis_desc; +static int fis_erasesize = 0; + +static void +fis_close(void) +{ + if (fis_desc) + munmap(fis_desc, fis_erasesize); + + if (fis_fd >= 0) + close(fis_fd); + + fis_fd = -1; + fis_desc = NULL; +} + +static struct fis_image_desc * +fis_open(void) +{ + struct fis_image_desc *desc; + + if (fis_fd >= 0) + fis_close(); + + fis_fd = mtd_check_open("FIS directory"); + if (fis_fd < 0) + goto error; + + close(fis_fd); + fis_fd = mtd_open("FIS directory", true); + if (fis_fd < 0) + goto error; + + fis_erasesize = erasesize; + desc = mmap(NULL, erasesize, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_LOCKED, fis_fd, 0); + if (desc == MAP_FAILED) + goto error; + + fis_desc = desc; + return desc; + +error: + fis_close(); + return NULL; +} + +int +fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new) +{ + struct fis_image_desc *desc; + void *end; + int found = 0; + int i; + + desc = fis_open(); + if (!desc) + return -1; + + for (i = 0; i < n_new - 1; i++) { + if (!new[i].size) { + fprintf(stderr, "FIS error: only the last partition can detect the size automatically\n"); + i = -1; + goto done; + } + } + + end = desc; + end = (char *) end + fis_erasesize; + while ((void *) desc < end) { + if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff)) + break; + + for (i = 0; i < n_old; i++) { + if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) { + found++; + goto next; + } + } +next: + desc++; + continue; + } + + if (found == n_old) + i = 1; + else + i = -1; + +done: + fis_close(); + return i; +} + +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; + struct fis_image_desc *last_fb = NULL; + struct fis_image_desc *desc; + struct fis_part *part; + uint32_t offset = 0, size = 0; + char *start, *end, *tmp; + int i; + + desc = fis_open(); + if (!desc) + return -1; + + if (!quiet) + fprintf(stderr, "Updating FIS table... \n"); + + start = (char *) desc; + end = (char *) desc + fis_erasesize; + while ((char *) desc < end) { + 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; + + for (i = 0; i < n_old; i++) { + if (!strncmp((char *) desc->hdr.name, (char *) old[i].name, sizeof(desc->hdr.name))) { + last = desc; + if (!first) + first = desc; + break; + } + } + desc++; + } + desc--; + + first_fb = first; + last_fb = last; + + if (first_fb->hdr.flash_base > last_fb->hdr.flash_base) { + first_fb = last; + last_fb = first; + } + + /* determine size of available space */ + desc = (struct fis_image_desc *) start; + while ((char *) desc < end) { + if (!desc->hdr.name[0] || (desc->hdr.name[0] == 0xff)) + break; + + if (desc->hdr.flash_base > last_fb->hdr.flash_base && + desc->hdr.flash_base < offset) + offset = desc->hdr.flash_base; + + desc++; + } + desc--; + + 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; + + if (desc != last) { + if (desc > last) + tmp = (char *) desc; + else + tmp = (char *) last; + + memmove(desc, last, end - tmp); + if (desc < last) { + tmp = end - (last - desc) * sizeof(struct fis_image_desc); + memset(tmp, 0xff, tmp - end); + } + } + + for (part = new, desc = first; desc < first + n_new; desc++, part++) { + 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->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; + + offset += desc->hdr.size; + size -= desc->hdr.size; + } + + msync(fis_desc, fis_erasesize, MS_SYNC|MS_INVALIDATE); + fis_close(); + + return 0; +} diff --git a/package/system/mtd/src/fis.h b/package/system/mtd/src/fis.h new file mode 100644 index 0000000..bdf1103 --- /dev/null +++ b/package/system/mtd/src/fis.h @@ -0,0 +1,14 @@ +#ifndef __FIS_H +#define __FIS_H + +struct fis_part { + unsigned char name[16]; + uint32_t offset; + uint32_t loadaddr; + uint32_t size; +}; + +int fis_validate(struct fis_part *old, int n_old, struct fis_part *new, int n_new); +int fis_remap(struct fis_part *old, int n_old, struct fis_part *new, int n_new); + +#endif diff --git a/package/system/mtd/src/imagetag.c b/package/system/mtd/src/imagetag.c new file mode 100644 index 0000000..b850837 --- /dev/null +++ b/package/system/mtd/src/imagetag.c @@ -0,0 +1,407 @@ +/* + * imagetag.c + * + * Copyright (C) 2005 Mike Baker + * Copyright (C) 2008 Felix Fietkau + * Copyrigth (C) 2010 Daniel Dickinson + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mtd.h" +#include "crc32.h" + +#define TAGVER_LEN 4 /* Length of Tag Version */ +#define TAGLAYOUT_LEN 4 /* Length of FlashLayoutVer */ +#define SIG1_LEN 20 /* Company Signature 1 Length */ +#define SIG2_LEN 14 /* Company Signature 2 Length */ +#define BOARDID_LEN 16 /* Length of BoardId */ +#define ENDIANFLAG_LEN 2 /* Endian Flag Length */ +#define CHIPID_LEN 6 /* Chip Id Length */ +#define IMAGE_LEN 10 /* Length of Length Field */ +#define ADDRESS_LEN 12 /* Length of Address field */ +#define DUALFLAG_LEN 2 /* Dual Image flag Length */ +#define INACTIVEFLAG_LEN 2 /* Inactie Flag Length */ +#define RSASIG_LEN 20 /* Length of RSA Signature in tag */ +#define TAGINFO1_LEN 30 /* Length of vendor information field1 in tag */ +#define FLASHLAYOUTVER_LEN 4 /* Length of Flash Layout Version String tag */ +#define TAGINFO2_LEN 16 /* Length of vendor information field2 in tag */ +#define ALTTAGINFO_LEN 54 /* Alternate length for vendor information; Pirelli */ + +#define NUM_PIRELLI 2 +#define IMAGETAG_CRC_START 0xFFFFFFFF + +#define PIRELLI_BOARDS { \ + "AGPF-S0", \ + "DWV-S0", \ +} +/* + * The broadcom firmware assumes the rootfs starts the image, + * therefore uses the rootfs start (flash_image_address) + * to determine where to flash the image. Since we have the kernel first + * we have to give it the kernel address, but the crc uses the length + * associated with this address (root_length), which is added to the kernel + * length (kernel_length) to determine the length of image to flash and thus + * needs to be rootfs + deadcode (jffs2 EOF marker) +*/ + +struct bcm_tag { + /* 0-3: Version of the image tag */ + char tag_version[TAGVER_LEN]; + /* 4-23: Company Line 1 */ + char sig_1[SIG1_LEN]; + /* 24-37: Company Line 2 */ + char sig_2[SIG2_LEN]; + /* 38-43: Chip this image is for */ + char chip_id[CHIPID_LEN]; + /* 44-59: Board name */ + char board_id[BOARDID_LEN]; + /* 60-61: Map endianness -- 1 BE 0 LE */ + char big_endian[ENDIANFLAG_LEN]; + /* 62-71: Total length of image */ + char total_length[IMAGE_LEN]; + /* 72-83: Address in memory of CFE */ + char cfe__address[ADDRESS_LEN]; + /* 84-93: Size of CFE */ + char cfe_length[IMAGE_LEN]; + /* 94-105: Address in memory of image start + * (kernel for OpenWRT, rootfs for stock firmware) + */ + char flash_image_start[ADDRESS_LEN]; + /* 106-115: Size of rootfs */ + char root_length[IMAGE_LEN]; + /* 116-127: Address in memory of kernel */ + char kernel_address[ADDRESS_LEN]; + /* 128-137: Size of kernel */ + char kernel_length[IMAGE_LEN]; + /* 138-139: Unused at the moment */ + char dual_image[DUALFLAG_LEN]; + /* 140-141: Unused at the moment */ + char inactive_flag[INACTIVEFLAG_LEN]; + /* 142-161: RSA Signature (not used; some vendors may use this) */ + char rsa_signature[RSASIG_LEN]; + /* 162-191: Compilation and related information (not used in OpenWrt) */ + char information1[TAGINFO1_LEN]; + /* 192-195: Version flash layout */ + char flash_layout_ver[FLASHLAYOUTVER_LEN]; + /* 196-199: kernel+rootfs CRC32 */ + __u32 fskernel_crc; + /* 200-215: Unused except on Alice Gate where is is information */ + char information2[TAGINFO2_LEN]; + /* 216-219: CRC32 of image less imagetag (kernel for Alice Gate) */ + __u32 image_crc; + /* 220-223: CRC32 of rootfs partition */ + __u32 rootfs_crc; + /* 224-227: CRC32 of kernel partition */ + __u32 kernel_crc; + /* 228-231: Image sequence number */ + char image_sequence[4]; + /* 222-235: Openwrt: real rootfs length */ + __u32 real_rootfs_length; + /* 236-239: CRC32 of header excluding last 20 bytes */ + __u32 header_crc; + /* 240-255: Unused at present */ + char reserved2[16]; +}; +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); + +#define CRC_START 0xFFFFFFFF + +static uint32_t strntoul(char *str, char **endptr, int base, size_t len) { + char *newstr; + uint32_t res = 0; + + newstr = calloc(len + 1, sizeof(char)); + if (newstr) { + strncpy(newstr, str, len); + res = strtoul(newstr, endptr, base); + free(newstr); + } + return res; +} + +uint32_t compute_crc32(uint32_t crc, off_t start, size_t compute_len, int fd) +{ + uint8_t readbuf[1024]; + ssize_t res; + off_t offset = start; + + /* Read a buffer's worth of bytes */ + while (fd && (compute_len >= sizeof(readbuf))) { + res = pread(fd, readbuf, sizeof(readbuf), offset); + crc = crc32(crc, readbuf, res); + compute_len = compute_len - res; + offset += res; + } + + /* Less than buffer-size bytes remains, read compute_len bytes */ + if (fd && (compute_len > 0)) { + res = pread(fd, readbuf, compute_len, offset); + crc = crc32(crc, readbuf, res); + } + + return crc; +} + +int +trx_fixup(int fd, const char *name) +{ + struct mtd_info_user mtdInfo; + unsigned long len; + void *ptr, *scan; + int bfd; + struct bcm_tag *tag; + ssize_t res; + uint32_t cfelen, imagelen, imagestart, rootfslen; + uint32_t imagecrc, rootfscrc, headercrc; + uint32_t offset = 0; + cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0; + + + if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) { + fprintf(stderr, "Failed to get mtd info\n"); + goto err; + } + + len = mtdInfo.size; + if (mtdInfo.size <= 0) { + fprintf(stderr, "Invalid MTD device size\n"); + goto err; + } + + bfd = mtd_open(name, true); + ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0); + if (!ptr || (ptr == (void *) -1)) { + perror("mmap"); + goto err1; + } + + tag = (struct bcm_tag *) (ptr); + + cfelen = strntoul(&tag->cfe_length[0], NULL, 10, IMAGE_LEN); + if (cfelen) { + fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n"); + exit(1); + } + + headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd); + if (headercrc != *(uint32_t *)(&tag->header_crc)) { + fprintf(stderr, "Tag verify failed. This may not be a valid image.\n"); + exit(1); + } + + sprintf(&tag->root_length[0], "%u", 0); + strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN); + + imagestart = sizeof(tag); + memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t)); + memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t)); + rootfscrc = CRC_START; + memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t)); + headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc)); + memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t)); + + msync(ptr, sizeof(struct bcm_tag), MS_SYNC|MS_INVALIDATE); + munmap(ptr, len); + close(bfd); + return 0; + +err1: + close(bfd); +err: + fprintf(stderr, "Error fixing up imagetag header\n"); + return -1; +} + + +int +trx_check(int imagefd, const char *mtd, char *buf, int *len) +{ + struct bcm_tag *tag = (const struct bcm_tag *) buf; + int fd; + uint32_t headerCRC; + uint32_t imageLen; + + if (strcmp(mtd, "linux") != 0) + return 1; + + *len = read(imagefd, buf, sizeof(struct bcm_tag)); + if (*len < sizeof(struct bcm_tag)) { + fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len); + return 0; + } + headerCRC = crc32buf(buf, offsetof(struct bcm_tag, header_crc)); + if (*(uint32_t *)(&tag->header_crc) != headerCRC) { + + if (quiet < 2) { + fprintf(stderr, "Bad header CRC got %08x, calculated %08x\n", + *(uint32_t *)(&tag->header_crc), headerCRC); + fprintf(stderr, "This is not the correct file format; refusing to flash.\n" + "Please specify the correct file or use -f to force.\n"); + } + return 0; + } + + /* check if image fits to mtd device */ + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } + + imageLen = strntoul(&tag->total_length[0], NULL, 10, IMAGE_LEN); + + if(mtdsize < imageLen) { + fprintf(stderr, "Image too big for partition: %s\n", mtd); + close(fd); + return 0; + } + + close(fd); + return 1; +} + +int +mtd_fixtrx(const char *mtd, size_t offset) +{ + int fd; + struct bcm_tag *tag; + char *buf; + ssize_t res; + size_t block_offset; + uint32_t cfelen, imagelen, imagestart, rootfslen; + uint32_t imagecrc, rootfscrc, headercrc; + cfelen = imagelen = imagestart = imagecrc = rootfscrc = headercrc = rootfslen = 0; + + if (quiet < 2) + fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset); + + block_offset = offset & ~(erasesize - 1); + offset -= block_offset; + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } + + if (block_offset + erasesize > mtdsize) { + fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize); + exit(1); + } + + buf = malloc(erasesize); + if (!buf) { + perror("malloc"); + exit(1); + } + + res = pread(fd, buf, erasesize, block_offset); + if (res != erasesize) { + perror("pread"); + exit(1); + } + + tag = (struct bcm_tag *) (buf + offset); + + cfelen = strntoul(tag->cfe_length, NULL, 10, IMAGE_LEN); + if (cfelen) { + fprintf(stderr, "Non-zero CFE length. This is currently unsupported.\n"); + exit(1); + } + + if (quiet < 2) { + fprintf(stderr, "Verifying we actually have an imagetag.\n"); + } + + headercrc = compute_crc32(CRC_START, offset, offsetof(struct bcm_tag, header_crc), fd); + if (headercrc != *(uint32_t *)(&tag->header_crc)) { + fprintf(stderr, "Tag verify failed. This may not be a valid image.\n"); + exit(1); + } + + if (quiet < 2) { + fprintf(stderr, "Checking current fixed status.\n"); + } + + rootfslen = strntoul(&tag->root_length[0], NULL, 10, IMAGE_LEN); + if (rootfslen == 0) { + if (quiet < 2) + fprintf(stderr, "Header already fixed, exiting\n"); + close(fd); + return 0; + } + + if (quiet < 2) { + fprintf(stderr, "Setting root length to 0.\n"); + } + + sprintf(&tag->root_length[0], "%u", 0); + strncpy(&tag->total_length[0], &tag->kernel_length[0], IMAGE_LEN); + + if (quiet < 2) { + fprintf(stderr, "Recalculating CRCs.\n"); + } + + imagestart = sizeof(tag); + memcpy(&tag->image_crc, &tag->kernel_crc, sizeof(uint32_t)); + memcpy(&tag->fskernel_crc, &tag->kernel_crc, sizeof(uint32_t)); + rootfscrc = CRC_START; + memcpy(&tag->rootfs_crc, &rootfscrc, sizeof(uint32_t)); + headercrc = crc32(CRC_START, tag, offsetof(struct bcm_tag, header_crc)); + memcpy(&tag->header_crc, &headercrc, sizeof(uint32_t)); + + if (quiet < 2) { + fprintf(stderr, "Erasing imagetag block\n"); + } + + if (mtd_erase_block(fd, block_offset)) { + fprintf(stderr, "Can't erase block at 0x%x (%s)\n", block_offset, strerror(errno)); + exit(1); + } + + if (quiet < 2) { + fprintf(stderr, "New image crc32: 0x%x, rewriting block\n", + *(uint32_t *)(&tag->image_crc)); + fprintf(stderr, "New header crc32: 0x%x, rewriting block\n", headercrc); + } + + if (pwrite(fd, buf, erasesize, block_offset) != erasesize) { + fprintf(stderr, "Error writing block (%s)\n", strerror(errno)); + exit(1); + } + + if (quiet < 2) + fprintf(stderr, "Done.\n"); + + close (fd); + sync(); + return 0; + +} diff --git a/package/system/mtd/src/jffs2.c b/package/system/mtd/src/jffs2.c new file mode 100644 index 0000000..c29fb33 --- /dev/null +++ b/package/system/mtd/src/jffs2.c @@ -0,0 +1,366 @@ +/* + * jffs2 on-disk structure generator for mtd + * + * Copyright (C) 2008 Felix Fietkau + * + * 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. + * Based on: + * JFFS2 -- Journalling Flash File System, Version 2. + * Copyright © 2001-2007 Red Hat, Inc. + * Created by David Woodhouse + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "jffs2.h" +#include "crc32.h" +#include "mtd.h" + +#define PAD(x) (((x)+3)&~3) + +#if BYTE_ORDER == BIG_ENDIAN +# define CLEANMARKER "\x19\x85\x20\x03\x00\x00\x00\x0c\xf0\x60\xdc\x98" +#else +# define CLEANMARKER "\x85\x19\x03\x20\x0c\x00\x00\x00\xb1\xb0\x1e\xe4" +#endif + +static int last_ino = 0; +static int last_version = 0; +static char *buf = NULL; +static int ofs = 0; +static int outfd = -1; +static int mtdofs = 0; +static int target_ino = 0; + +static void prep_eraseblock(void); + +static void pad(int size) +{ + if ((ofs % size == 0) && (ofs < erasesize)) + return; + + if (ofs < erasesize) { + memset(buf + ofs, 0xff, (size - (ofs % size))); + ofs += (size - (ofs % size)); + } + ofs = ofs % erasesize; + if (ofs == 0) { + while (mtd_block_is_bad(outfd, mtdofs) && (mtdofs < mtdsize)) { + if (!quiet) + fprintf(stderr, "\nSkipping bad block at 0x%08x ", mtdofs); + + mtdofs += erasesize; + + /* Move the file pointer along over the bad block. */ + lseek(outfd, erasesize, SEEK_CUR); + } + mtd_erase_block(outfd, mtdofs); + write(outfd, buf, erasesize); + mtdofs += erasesize; + } +} + +static inline int rbytes(void) +{ + return erasesize - (ofs % erasesize); +} + +static inline void add_data(char *ptr, int len) +{ + if (ofs + len > erasesize) { + pad(erasesize); + prep_eraseblock(); + } + memcpy(buf + ofs, ptr, len); + ofs += len; +} + +static void prep_eraseblock(void) +{ + if (ofs > 0) + return; + + add_data(CLEANMARKER, sizeof(CLEANMARKER) - 1); +} + +static int add_dirent(const char *name, const char type, int parent) +{ + struct jffs2_raw_dirent *de; + + if (ofs - erasesize < sizeof(struct jffs2_raw_dirent) + strlen(name)) + pad(erasesize); + + prep_eraseblock(); + last_ino++; + memset(buf + ofs, 0, sizeof(struct jffs2_raw_dirent)); + de = (struct jffs2_raw_dirent *) (buf + ofs); + + de->magic = JFFS2_MAGIC_BITMASK; + de->nodetype = JFFS2_NODETYPE_DIRENT; + de->type = type; + de->name_crc = crc32(0, name, strlen(name)); + de->ino = last_ino++; + de->pino = parent; + de->totlen = sizeof(*de) + strlen(name); + de->hdr_crc = crc32(0, (void *) de, sizeof(struct jffs2_unknown_node) - 4); + de->version = last_version++; + de->mctime = 0; + de->nsize = strlen(name); + de->node_crc = crc32(0, (void *) de, sizeof(*de) - 8); + memcpy(de->name, name, strlen(name)); + + ofs += sizeof(struct jffs2_raw_dirent) + de->nsize; + pad(4); + + return de->ino; +} + +static int add_dir(const char *name, int parent) +{ + struct jffs2_raw_inode ri; + int inode; + + inode = add_dirent(name, IFTODT(S_IFDIR), parent); + + if (rbytes() < sizeof(ri)) + pad(erasesize); + prep_eraseblock(); + + memset(&ri, 0, sizeof(ri)); + ri.magic = JFFS2_MAGIC_BITMASK; + ri.nodetype = JFFS2_NODETYPE_INODE; + ri.totlen = sizeof(ri); + ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4); + + ri.ino = inode; + ri.mode = S_IFDIR | 0755; + ri.uid = ri.gid = 0; + ri.atime = ri.ctime = ri.mtime = 0; + ri.isize = ri.csize = ri.dsize = 0; + ri.version = 1; + ri.node_crc = crc32(0, &ri, sizeof(ri) - 8); + ri.data_crc = 0; + + add_data((char *) &ri, sizeof(ri)); + pad(4); + return inode; +} + +static void add_file(const char *name, int parent) +{ + int inode, f_offset = 0, fd; + struct jffs2_raw_inode ri; + struct stat st; + char wbuf[4096]; + const char *fname; + + if (stat(name, &st)) { + fprintf(stderr, "File %s does not exist\n", name); + return; + } + + fname = strrchr(name, '/'); + if (fname) + fname++; + else + fname = name; + + inode = add_dirent(fname, IFTODT(S_IFREG), parent); + memset(&ri, 0, sizeof(ri)); + ri.magic = JFFS2_MAGIC_BITMASK; + ri.nodetype = JFFS2_NODETYPE_INODE; + + ri.ino = inode; + ri.mode = st.st_mode; + ri.uid = ri.gid = 0; + ri.atime = st.st_atime; + ri.ctime = st.st_ctime; + ri.mtime = st.st_mtime; + ri.isize = st.st_size; + ri.compr = 0; + ri.usercompr = 0; + + fd = open(name, 0); + if (fd < 0) { + fprintf(stderr, "File %s does not exist\n", name); + return; + } + + for (;;) { + int len = 0; + + for (;;) { + len = rbytes() - sizeof(ri); + if (len > 128) + break; + + pad(erasesize); + prep_eraseblock(); + } + + if (len > sizeof(wbuf)) + len = sizeof(wbuf); + + len = read(fd, wbuf, len); + if (len <= 0) + break; + + ri.totlen = sizeof(ri) + len; + ri.hdr_crc = crc32(0, &ri, sizeof(struct jffs2_unknown_node) - 4); + ri.version = ++last_version; + ri.offset = f_offset; + ri.csize = ri.dsize = len; + ri.node_crc = crc32(0, &ri, sizeof(ri) - 8); + ri.data_crc = crc32(0, wbuf, len); + f_offset += len; + add_data((char *) &ri, sizeof(ri)); + add_data(wbuf, len); + pad(4); + prep_eraseblock(); + } + + close(fd); +} + +int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename) +{ + outfd = fd; + mtdofs = ofs; + + buf = malloc(erasesize); + target_ino = 1; + if (!last_ino) + last_ino = 1; + add_file(filename, target_ino); + pad(erasesize); + + /* add eof marker, pad to eraseblock size and write the data */ + add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1); + pad(erasesize); + free(buf); + + return (mtdofs - ofs); +} + +void mtd_parse_jffs2data(const char *buf, const char *dir) +{ + struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf; + unsigned int ofs = 0; + + while (ofs < erasesize) { + node = (struct jffs2_unknown_node *) (buf + ofs); + if (node->magic != 0x1985) + break; + + ofs += PAD(node->totlen); + if (node->nodetype == JFFS2_NODETYPE_DIRENT) { + struct jffs2_raw_dirent *de = (struct jffs2_raw_dirent *) node; + + /* is this the right directory name and is it a subdirectory of / */ + if (*dir && (de->pino == 1) && !strncmp((char *) de->name, dir, de->nsize)) + target_ino = de->ino; + + /* store the last inode and version numbers for adding extra files */ + if (last_ino < de->ino) + last_ino = de->ino; + if (last_version < de->version) + last_version = de->version; + } + } +} + +int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir) +{ + int err = -1, fdeof = 0; + + outfd = mtd_check_open(mtd); + if (outfd < 0) + return -1; + + if (quiet < 2) + fprintf(stderr, "Appending %s to jffs2 partition %s\n", filename, mtd); + + buf = malloc(erasesize); + if (!buf) { + fprintf(stderr, "Out of memory!\n"); + goto done; + } + + if (!*dir) + target_ino = 1; + + /* parse the structure of the jffs2 first + * locate the directory that the file is going to be placed in */ + for(;;) { + struct jffs2_unknown_node *node = (struct jffs2_unknown_node *) buf; + + if (read(outfd, buf, erasesize) != erasesize) { + fdeof = 1; + break; + } + mtdofs += erasesize; + + if (node->magic == 0x8519) { + fprintf(stderr, "Error: wrong endianness filesystem\n"); + goto done; + } + + /* assume no magic == end of filesystem + * the filesystem will probably end with be32(0xdeadc0de) */ + if (node->magic != 0x1985) + break; + + mtd_parse_jffs2data(buf, dir); + } + + if (fdeof) { + fprintf(stderr, "Error: No room for additional data\n"); + goto done; + } + + /* jump back one eraseblock */ + mtdofs -= erasesize; + lseek(outfd, mtdofs, SEEK_SET); + + ofs = 0; + + if (!last_ino) + last_ino = 1; + + if (!target_ino) + target_ino = add_dir(dir, 1); + + add_file(filename, target_ino); + pad(erasesize); + + /* add eof marker, pad to eraseblock size and write the data */ + add_data(JFFS2_EOF, sizeof(JFFS2_EOF) - 1); + pad(erasesize); + + err = 0; + + if (trx_fixup) { + trx_fixup(outfd, mtd); + } + +done: + close(outfd); + if (buf) + free(buf); + + return err; +} diff --git a/package/system/mtd/src/jffs2.h b/package/system/mtd/src/jffs2.h new file mode 100644 index 0000000..858e77a --- /dev/null +++ b/package/system/mtd/src/jffs2.h @@ -0,0 +1,216 @@ +/* + * JFFS2 -- Journalling Flash File System, Version 2. + * + * Copyright (C) 2001-2003 Red Hat, Inc. + * + * Created by David Woodhouse + * + * For licensing information, see the file 'LICENCE' in the + * jffs2 directory. + * + * + */ + +#ifndef __LINUX_JFFS2_H__ +#define __LINUX_JFFS2_H__ + +#define JFFS2_SUPER_MAGIC 0x72b6 + +/* You must include something which defines the C99 uintXX_t types. + We don't do it from here because this file is used in too many + different environments. */ + +/* Values we may expect to find in the 'magic' field */ +#define JFFS2_OLD_MAGIC_BITMASK 0x1984 +#define JFFS2_MAGIC_BITMASK 0x1985 +#define KSAMTIB_CIGAM_2SFFJ 0x8519 /* For detecting wrong-endian fs */ +#define JFFS2_EMPTY_BITMASK 0xffff +#define JFFS2_DIRTY_BITMASK 0x0000 + +/* Summary node MAGIC marker */ +#define JFFS2_SUM_MAGIC 0x02851885 + +/* We only allow a single char for length, and 0xFF is empty flash so + we don't want it confused with a real length. Hence max 254. +*/ +#define JFFS2_MAX_NAME_LEN 254 + +/* How small can we sensibly write nodes? */ +#define JFFS2_MIN_DATA_LEN 128 + +#define JFFS2_COMPR_NONE 0x00 +#define JFFS2_COMPR_ZERO 0x01 +#define JFFS2_COMPR_RTIME 0x02 +#define JFFS2_COMPR_RUBINMIPS 0x03 +#define JFFS2_COMPR_COPY 0x04 +#define JFFS2_COMPR_DYNRUBIN 0x05 +#define JFFS2_COMPR_ZLIB 0x06 +/* Compatibility flags. */ +#define JFFS2_COMPAT_MASK 0xc000 /* What do to if an unknown nodetype is found */ +#define JFFS2_NODE_ACCURATE 0x2000 +/* INCOMPAT: Fail to mount the filesystem */ +#define JFFS2_FEATURE_INCOMPAT 0xc000 +/* ROCOMPAT: Mount read-only */ +#define JFFS2_FEATURE_ROCOMPAT 0x8000 +/* RWCOMPAT_COPY: Mount read/write, and copy the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_COPY 0x4000 +/* RWCOMPAT_DELETE: Mount read/write, and delete the node when it's GC'd */ +#define JFFS2_FEATURE_RWCOMPAT_DELETE 0x0000 + +#define JFFS2_NODETYPE_DIRENT (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 1) +#define JFFS2_NODETYPE_INODE (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 2) +#define JFFS2_NODETYPE_CLEANMARKER (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +#define JFFS2_NODETYPE_PADDING (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 4) + +#define JFFS2_NODETYPE_SUMMARY (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 6) + +#define JFFS2_NODETYPE_XATTR (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 8) +#define JFFS2_NODETYPE_XREF (JFFS2_FEATURE_INCOMPAT | JFFS2_NODE_ACCURATE | 9) + +/* XATTR Related */ +#define JFFS2_XPREFIX_USER 1 /* for "user." */ +#define JFFS2_XPREFIX_SECURITY 2 /* for "security." */ +#define JFFS2_XPREFIX_ACL_ACCESS 3 /* for "system.posix_acl_access" */ +#define JFFS2_XPREFIX_ACL_DEFAULT 4 /* for "system.posix_acl_default" */ +#define JFFS2_XPREFIX_TRUSTED 5 /* for "trusted.*" */ + +#define JFFS2_ACL_VERSION 0x0001 + +// Maybe later... +//#define JFFS2_NODETYPE_CHECKPOINT (JFFS2_FEATURE_RWCOMPAT_DELETE | JFFS2_NODE_ACCURATE | 3) +//#define JFFS2_NODETYPE_OPTIONS (JFFS2_FEATURE_RWCOMPAT_COPY | JFFS2_NODE_ACCURATE | 4) + + +#define JFFS2_INO_FLAG_PREREAD 1 /* Do read_inode() for this one at + mount time, don't wait for it to + happen later */ +#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific + compression type */ + + +/* These can go once we've made sure we've caught all uses without + byteswapping */ + +typedef uint32_t jint32_t; + +typedef uint32_t jmode_t; + +typedef uint16_t jint16_t; + +struct jffs2_unknown_node +{ + /* All start like this */ + jint16_t magic; + jint16_t nodetype; + jint32_t totlen; /* So we can skip over nodes we don't grok */ + jint32_t hdr_crc; +}; + +struct jffs2_raw_dirent +{ + jint16_t magic; + jint16_t nodetype; /* == JFFS2_NODETYPE_DIRENT */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t pino; + jint32_t version; + jint32_t ino; /* == zero for unlink */ + jint32_t mctime; + uint8_t nsize; + uint8_t type; + uint8_t unused[2]; + jint32_t node_crc; + jint32_t name_crc; + uint8_t name[0]; +}; + +/* The JFFS2 raw inode structure: Used for storage on physical media. */ +/* The uid, gid, atime, mtime and ctime members could be longer, but + are left like this for space efficiency. If and when people decide + they really need them extended, it's simple enough to add support for + a new type of raw node. +*/ +struct jffs2_raw_inode +{ + jint16_t magic; /* A constant magic number. */ + jint16_t nodetype; /* == JFFS2_NODETYPE_INODE */ + jint32_t totlen; /* Total length of this node (inc data, etc.) */ + jint32_t hdr_crc; + jint32_t ino; /* Inode number. */ + jint32_t version; /* Version number. */ + jmode_t mode; /* The file's type or mode. */ + jint16_t uid; /* The file's owner. */ + jint16_t gid; /* The file's group. */ + jint32_t isize; /* Total resultant size of this inode (used for truncations) */ + jint32_t atime; /* Last access time. */ + jint32_t mtime; /* Last modification time. */ + jint32_t ctime; /* Change time. */ + jint32_t offset; /* Where to begin to write. */ + jint32_t csize; /* (Compressed) data size */ + jint32_t dsize; /* Size of the node's data. (after decompression) */ + uint8_t compr; /* Compression algorithm used */ + uint8_t usercompr; /* Compression algorithm requested by the user */ + jint16_t flags; /* See JFFS2_INO_FLAG_* */ + jint32_t data_crc; /* CRC for the (compressed) data. */ + jint32_t node_crc; /* CRC for the raw inode (excluding data) */ + uint8_t data[0]; +}; + +struct jffs2_raw_xattr { + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XATTR */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t xid; /* XATTR identifier number */ + jint32_t version; + uint8_t xprefix; + uint8_t name_len; + jint16_t value_len; + jint32_t data_crc; + jint32_t node_crc; + uint8_t data[0]; +} __attribute__((packed)); + +struct jffs2_raw_xref +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_XREF */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t ino; /* inode number */ + jint32_t xid; /* XATTR identifier number */ + jint32_t xseqno; /* xref sequencial number */ + jint32_t node_crc; +} __attribute__((packed)); + +struct jffs2_raw_summary +{ + jint16_t magic; + jint16_t nodetype; /* = JFFS2_NODETYPE_SUMMARY */ + jint32_t totlen; + jint32_t hdr_crc; + jint32_t sum_num; /* number of sum entries*/ + jint32_t cln_mkr; /* clean marker size, 0 = no cleanmarker */ + jint32_t padded; /* sum of the size of padding nodes */ + jint32_t sum_crc; /* summary information crc */ + jint32_t node_crc; /* node crc */ + jint32_t sum[0]; /* inode summary info */ +}; + +union jffs2_node_union +{ + struct jffs2_raw_inode i; + struct jffs2_raw_dirent d; + struct jffs2_raw_xattr x; + struct jffs2_raw_xref r; + struct jffs2_raw_summary s; + struct jffs2_unknown_node u; +}; + +/* Data payload for device nodes. */ +union jffs2_device_node { + jint16_t old; + jint32_t new; +}; + +#endif /* __LINUX_JFFS2_H__ */ diff --git a/package/system/mtd/src/linksys_bootcount.c b/package/system/mtd/src/linksys_bootcount.c new file mode 100644 index 0000000..95f75fe --- /dev/null +++ b/package/system/mtd/src/linksys_bootcount.c @@ -0,0 +1,114 @@ +/* + * Linksys boot counter reset code for mtd + * + * Copyright (C) 2013 Jonas Gorski + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "mtd.h" + +#define BOOTCOUNT_MAGIC 0x20110811 + +struct bootcounter { + uint32_t magic; + uint32_t count; + uint32_t checksum; +}; + +static char page[2048]; + +int mtd_resetbc(const char *mtd) +{ + struct mtd_info_user mtd_info; + struct bootcounter *curr = (struct bootcounter *)page; + unsigned int i; + int last_count = 0; + int num_bc; + int fd; + int ret; + + fd = mtd_check_open(mtd); + + if (ioctl(fd, MEMGETINFO, &mtd_info) < 0) { + fprintf(stderr, "failed to get mtd info!\n"); + return -1; + } + + num_bc = mtd_info.size / mtd_info.writesize; + + for (i = 0; i < num_bc; i++) { + pread(fd, curr, sizeof(*curr), i * mtd_info.writesize); + + if (curr->magic != BOOTCOUNT_MAGIC && curr->magic != 0xffffffff) { + fprintf(stderr, "unexpected magic %08x, bailing out\n", curr->magic); + goto out; + } + + if (curr->magic == 0xffffffff) + break; + + last_count = curr->count; + } + + /* no need to do writes when last boot count is already 0 */ + if (last_count == 0) + goto out; + + + if (i == num_bc) { + 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; + } + + i = 0; + } + + memset(curr, 0xff, mtd_info.writesize); + + 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(); +out: + close(fd); + + return 0; +} diff --git a/package/system/mtd/src/md5.c b/package/system/mtd/src/md5.c new file mode 100644 index 0000000..2039760 --- /dev/null +++ b/package/system/mtd/src/md5.c @@ -0,0 +1,307 @@ + + +/* + *********************************************************************** + ** md5.c -- the source code for MD5 routines ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#include +#include "md5.h" + +/* + *********************************************************************** + ** Message-digest routines: ** + ** To form the message digest for a message M ** + ** (1) Initialize a context buffer mdContext using MD5_Init ** + ** (2) Call MD5_Update on mdContext and M ** + ** (3) Call MD5_Final on mdContext ** + ** The message digest is now in mdContext->digest[0...15] ** + *********************************************************************** + */ + +/* forward declaration */ +static void Transform (); + +static unsigned char PADDING[64] = { + 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ + {(a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define GG(a, b, c, d, x, s, ac) \ + {(a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define HH(a, b, c, d, x, s, ac) \ + {(a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } +#define II(a, b, c, d, x, s, ac) \ + {(a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ + } + +#ifdef __STDC__ +#define UL(x) x##U +#else +#define UL(x) x +#endif + +/* The routine MD5_Init initializes the message-digest context + mdContext. All fields are set to zero. + */ +void MD5_Init (mdContext) +MD5_CTX *mdContext; +{ + mdContext->i[0] = mdContext->i[1] = (UINT4)0; + + /* Load magic initialization constants. + */ + mdContext->buf[0] = (UINT4)0x67452301; + mdContext->buf[1] = (UINT4)0xefcdab89; + mdContext->buf[2] = (UINT4)0x98badcfe; + mdContext->buf[3] = (UINT4)0x10325476; +} + +/* The routine MD5Update updates the message-digest context to + account for the presence of each of the characters inBuf[0..inLen-1] + in the message whose digest is being computed. + */ +void MD5_Update (mdContext, inBuf, inLen) +MD5_CTX *mdContext; +unsigned char *inBuf; +unsigned int inLen; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* update number of bits */ + if ((mdContext->i[0] + ((UINT4)inLen << 3)) < mdContext->i[0]) + mdContext->i[1]++; + mdContext->i[0] += ((UINT4)inLen << 3); + mdContext->i[1] += ((UINT4)inLen >> 29); + + while (inLen--) { + /* add new character to buffer, increment mdi */ + mdContext->in[mdi++] = *inBuf++; + + /* transform if necessary */ + if (mdi == 0x40) { + for (i = 0, ii = 0; i < 16; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + mdi = 0; + } + } +} + +/* The routine MD5Final terminates the message-digest computation and + ends with the desired message digest in mdContext->digest[0...15]. + */ +void MD5_Final (hash, mdContext) +unsigned char hash[]; +MD5_CTX *mdContext; +{ + UINT4 in[16]; + int mdi; + unsigned int i, ii; + unsigned int padLen; + + /* save number of bits */ + in[14] = mdContext->i[0]; + in[15] = mdContext->i[1]; + + /* compute number of bytes mod 64 */ + mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + + /* pad out to 56 mod 64 */ + padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); + MD5_Update (mdContext, PADDING, padLen); + + /* append length in bits and transform */ + for (i = 0, ii = 0; i < 14; i++, ii += 4) + in[i] = (((UINT4)mdContext->in[ii+3]) << 24) | + (((UINT4)mdContext->in[ii+2]) << 16) | + (((UINT4)mdContext->in[ii+1]) << 8) | + ((UINT4)mdContext->in[ii]); + Transform (mdContext->buf, in); + + /* store buffer in digest */ + for (i = 0, ii = 0; i < 4; i++, ii += 4) { + mdContext->digest[ii] = (unsigned char)(mdContext->buf[i] & 0xFF); + mdContext->digest[ii+1] = + (unsigned char)((mdContext->buf[i] >> 8) & 0xFF); + mdContext->digest[ii+2] = + (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); + mdContext->digest[ii+3] = + (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); + } + memcpy(hash, mdContext->digest, 16); +} + +/* Basic MD5 step. Transforms buf based on in. + */ +static void Transform (buf, in) +UINT4 *buf; +UINT4 *in; +{ + UINT4 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 + FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ + FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ + FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ + FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ + FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ + FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ + FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ + FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ + FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ + FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ + FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ + FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ + FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ + FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ + FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ + FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ + + /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 + GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ + GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ + GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ + GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ + GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ + GG ( d, a, b, c, in[10], S22, UL( 38016083)); /* 22 */ + GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ + GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ + GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ + GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ + GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ + GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ + GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ + GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ + GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ + GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ + + /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 + HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ + HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ + HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ + HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ + HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ + HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ + HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ + HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ + HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ + HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ + HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ + HH ( b, c, d, a, in[ 6], S34, UL( 76029189)); /* 44 */ + HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ + HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ + HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ + HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ + + /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ + II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ + II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ + II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ + II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ + II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ + II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ + II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ + II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ + II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ + II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ + II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ + II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ + II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ + II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ + II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +/* + *********************************************************************** + ** End of md5.c ** + ******************************** (cut) ******************************** + */ diff --git a/package/system/mtd/src/md5.h b/package/system/mtd/src/md5.h new file mode 100644 index 0000000..f7a0c96 --- /dev/null +++ b/package/system/mtd/src/md5.h @@ -0,0 +1,65 @@ +/* + *********************************************************************** + ** md5.h -- header file for implementation of MD5 ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm ** + ** Created: 2/17/90 RLR ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version ** + ** Revised (for MD5): RLR 4/27/91 ** + ** -- G modified to have y&~z instead of y&z ** + ** -- FF, GG, HH modified to add in last register done ** + ** -- Access pattern: round 2 works mod 5, round 3 works mod 3 ** + ** -- distinct additive constant for each step ** + ** -- round 4 added, working mod 7 ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved. ** + ** ** + ** License to copy and use this software is granted provided that ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message- ** + ** Digest Algorithm" in all material mentioning or referencing this ** + ** software or this function. ** + ** ** + ** License is also granted to make and use derivative works ** + ** provided that such works are identified as "derived from the RSA ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all ** + ** material mentioning or referencing the derived work. ** + ** ** + ** RSA Data Security, Inc. makes no representations concerning ** + ** either the merchantability of this software or the suitability ** + ** of this software for any particular purpose. It is provided "as ** + ** is" without express or implied warranty of any kind. ** + ** ** + ** These notices must be retained in any copies of any part of this ** + ** documentation and/or software. ** + *********************************************************************** + */ + +#ifndef __MD5_INCLUDE__ + +/* typedef a 32-bit type */ +#ifdef _LP64 +typedef unsigned int UINT4; +typedef int INT4; +#else +typedef unsigned long UINT4; +typedef long INT4; +#endif +#define _UINT4_T + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { + UINT4 i[2]; /* number of _bits_ handled mod 2^64 */ + UINT4 buf[4]; /* scratch buffer */ + unsigned char in[64]; /* input buffer */ + unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +void MD5_Init (); +void MD5_Update (); +void MD5_Final (); + +#define __MD5_INCLUDE__ +#endif /* __MD5_INCLUDE__ */ diff --git a/package/system/mtd/src/mtd.c b/package/system/mtd/src/mtd.c new file mode 100644 index 0000000..0247630 --- /dev/null +++ b/package/system/mtd/src/mtd.c @@ -0,0 +1,919 @@ +/* + * mtd - simple memory technology device manipulation tool + * + * Copyright (C) 2005 Waldemar Brodkorb , + * Copyright (C) 2005-2009 Felix Fietkau + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * The code is based on the linux-mtd examples. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fis.h" +#include "mtd.h" + +#include + +#define MAX_ARGS 8 +#define JFFS2_DEFAULT_DIR "" /* directory name without /, empty means root dir */ + +static char *buf = NULL; +static char *imagefile = NULL; +static char *jffs2file = NULL, *jffs2dir = JFFS2_DEFAULT_DIR; +static int buflen = 0; +int quiet; +int no_erase; +int mtdsize = 0; +int erasesize = 0; +int jffs2_skip_bytes=0; +int mtdtype = 0; + +int mtd_open(const char *mtd, bool block) +{ + FILE *fp; + char dev[PATH_MAX]; + int i; + int ret; + int flags = O_RDWR | O_SYNC; + char name[PATH_MAX]; + + snprintf(name, sizeof(name), "\"%s\"", mtd); + if ((fp = fopen("/proc/mtd", "r"))) { + while (fgets(dev, sizeof(dev), fp)) { + if (sscanf(dev, "mtd%d:", &i) && strstr(dev, name)) { + snprintf(dev, sizeof(dev), "/dev/mtd%s/%d", (block ? "block" : ""), i); + if ((ret=open(dev, flags))<0) { + snprintf(dev, sizeof(dev), "/dev/mtd%s%d", (block ? "block" : ""), i); + ret=open(dev, flags); + } + fclose(fp); + return ret; + } + } + fclose(fp); + } + + return open(mtd, flags); +} + +int mtd_check_open(const char *mtd) +{ + struct mtd_info_user mtdInfo; + int fd; + + fd = mtd_open(mtd, false); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + return -1; + } + + if(ioctl(fd, MEMGETINFO, &mtdInfo)) { + fprintf(stderr, "Could not get MTD device info from %s\n", mtd); + close(fd); + return -1; + } + mtdsize = mtdInfo.size; + erasesize = mtdInfo.erasesize; + mtdtype = mtdInfo.type; + + return fd; +} + +int mtd_block_is_bad(int fd, int offset) +{ + int r = 0; + loff_t o = offset; + + if (mtdtype == MTD_NANDFLASH) + { + r = ioctl(fd, MEMGETBADBLOCK, &o); + if (r < 0) + { + fprintf(stderr, "Failed to get erase block status\n"); + exit(1); + } + } + return r; +} + +int mtd_erase_block(int fd, int offset) +{ + struct erase_info_user mtdEraseInfo; + + mtdEraseInfo.start = offset; + mtdEraseInfo.length = erasesize; + ioctl(fd, MEMUNLOCK, &mtdEraseInfo); + if (ioctl (fd, MEMERASE, &mtdEraseInfo) < 0) + return -1; + + return 0; +} + +int mtd_write_buffer(int fd, const char *buf, int offset, int length) +{ + lseek(fd, offset, SEEK_SET); + write(fd, buf, length); + return 0; +} + + +static int +image_check(int imagefd, const char *mtd) +{ + int ret = 1; + if (trx_check) { + ret = trx_check(imagefd, mtd, buf, &buflen); + } + + return ret; +} + +static int mtd_check(const char *mtd) +{ + char *next = NULL; + char *str = NULL; + int fd; + + if (strchr(mtd, ':')) { + str = strdup(mtd); + mtd = str; + } + + do { + next = strchr(mtd, ':'); + if (next) { + *next = 0; + next++; + } + + fd = mtd_check_open(mtd); + if (fd < 0) + return 0; + + if (!buf) + buf = malloc(erasesize); + + close(fd); + mtd = next; + } while (next); + + if (str) + free(str); + + return 1; +} + +static int +mtd_unlock(const char *mtd) +{ + struct erase_info_user mtdLockInfo; + char *next = NULL; + char *str = NULL; + int fd; + + if (strchr(mtd, ':')) { + str = strdup(mtd); + mtd = str; + } + + do { + next = strchr(mtd, ':'); + if (next) { + *next = 0; + next++; + } + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } + + if (quiet < 2) + fprintf(stderr, "Unlocking %s ...\n", mtd); + + mtdLockInfo.start = 0; + mtdLockInfo.length = mtdsize; + ioctl(fd, MEMUNLOCK, &mtdLockInfo); + close(fd); + mtd = next; + } while (next); + + if (str) + free(str); + + return 0; +} + +static int +mtd_erase(const char *mtd) +{ + int fd; + struct erase_info_user mtdEraseInfo; + + if (quiet < 2) + fprintf(stderr, "Erasing %s ...\n", mtd); + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } + + mtdEraseInfo.length = erasesize; + + for (mtdEraseInfo.start = 0; + mtdEraseInfo.start < mtdsize; + mtdEraseInfo.start += erasesize) { + if (mtd_block_is_bad(fd, mtdEraseInfo.start)) { + if (!quiet) + fprintf(stderr, "\nSkipping bad block at 0x%x ", mtdEraseInfo.start); + } else { + ioctl(fd, MEMUNLOCK, &mtdEraseInfo); + if(ioctl(fd, MEMERASE, &mtdEraseInfo)) + fprintf(stderr, "Failed to erase block on %s at 0x%x\n", mtd, mtdEraseInfo.start); + } + } + + close(fd); + return 0; + +} + +static int +mtd_dump(const char *mtd, int part_offset, int size) +{ + int ret = 0, offset = 0; + int fd; + char *buf; + + if (quiet < 2) + fprintf(stderr, "Dumping %s ...\n", mtd); + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + return -1; + } + + if (!size) + size = mtdsize; + + if (part_offset) + lseek(fd, part_offset, SEEK_SET); + + buf = malloc(erasesize); + if (!buf) + return -1; + + do { + int len = (size > erasesize) ? (erasesize) : (size); + int rlen = read(fd, buf, len); + + if (rlen < 0) { + if (errno == EINTR) + continue; + ret = -1; + goto out; + } + if (!rlen || rlen != len) + break; + if (mtd_block_is_bad(fd, offset)) { + fprintf(stderr, "skipping bad block at 0x%08x\n", offset); + } else { + size -= rlen; + write(1, buf, rlen); + } + offset += rlen; + } while (size > 0); + +out: + close(fd); + return ret; +} + +static int +mtd_verify(const char *mtd, char *file) +{ + uint32_t f_md5[4], m_md5[4]; + struct stat s; + md5_ctx_t ctx; + int ret = 0; + int fd; + + if (quiet < 2) + fprintf(stderr, "Verifying %s against %s ...\n", mtd, file); + + if (stat(file, &s) || md5sum(file, f_md5) < 0) { + fprintf(stderr, "Failed to hash %s\n", file); + return -1; + } + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + return -1; + } + + md5_begin(&ctx); + do { + char buf[256]; + int len = (s.st_size > sizeof(buf)) ? (sizeof(buf)) : (s.st_size); + int rlen = read(fd, buf, len); + + if (rlen < 0) { + if (errno == EINTR) + continue; + ret = -1; + goto out; + } + if (!rlen) + break; + md5_hash(buf, rlen, &ctx); + s.st_size -= rlen; + } while (s.st_size > 0); + + md5_end(m_md5, &ctx); + + fprintf(stderr, "%08x%08x%08x%08x - %s\n", m_md5[0], m_md5[1], m_md5[2], m_md5[3], mtd); + fprintf(stderr, "%08x%08x%08x%08x - %s\n", f_md5[0], f_md5[1], f_md5[2], f_md5[3], file); + + ret = memcmp(f_md5, m_md5, sizeof(m_md5)); + if (!ret) + fprintf(stderr, "Success\n"); + else + fprintf(stderr, "Failed\n"); + +out: + close(fd); + return ret; +} + +static void +indicate_writing(const char *mtd) +{ + if (quiet < 2) + fprintf(stderr, "\nWriting from %s to %s ... ", imagefile, mtd); + + if (!quiet) + fprintf(stderr, " [ ]"); +} + +static int +mtd_write(int imagefd, const char *mtd, char *fis_layout, size_t part_offset) +{ + char *next = NULL; + char *str = NULL; + int fd, result; + ssize_t r, w, e; + ssize_t skip = 0; + uint32_t offset = 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]; + int n_new = 0, n_old = 0; + + if (fis_layout) { + const char *tmp = mtd; + char *word, *brkt; + int ret; + + memset(&old_parts, 0, sizeof(old_parts)); + memset(&new_parts, 0, sizeof(new_parts)); + + do { + next = strchr(tmp, ':'); + if (!next) + next = (char *) tmp + strlen(tmp); + + memcpy(old_parts[n_old].name, tmp, next - tmp); + + n_old++; + tmp = next + 1; + } while(*next); + + for (word = strtok_r(fis_layout, ",", &brkt); + word; + word = strtok_r(NULL, ",", &brkt)) { + + tmp = strtok(word, ":"); + strncpy((char *) new_parts[n_new].name, tmp, sizeof(new_parts[n_new].name) - 1); + + tmp = strtok(NULL, ":"); + if (!tmp) + goto next; + + new_parts[n_new].size = strtoul(tmp, NULL, 0); + + tmp = strtok(NULL, ":"); + if (!tmp) + goto next; + + new_parts[n_new].loadaddr = strtoul(tmp, NULL, 16); +next: + n_new++; + } + ret = fis_validate(old_parts, n_old, new_parts, n_new); + if (ret < 0) { + fprintf(stderr, "Failed to validate the new FIS partition table\n"); + exit(1); + } + if (ret == 0) + fis_layout = NULL; + } +#endif + + if (strchr(mtd, ':')) { + str = strdup(mtd); + mtd = str; + } + + r = 0; + +resume: + next = strchr(mtd, ':'); + if (next) { + *next = 0; + next++; + } + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } + if (part_offset > 0) { + fprintf(stderr, "Seeking on mtd device '%s' to: %zu\n", mtd, part_offset); + lseek(fd, part_offset, SEEK_SET); + } + + indicate_writing(mtd); + + w = e = 0; + for (;;) { + /* buffer may contain data already (from trx check or last mtd partition write attempt) */ + while (buflen < erasesize) { + r = read(imagefd, buf + buflen, erasesize - buflen); + if (r < 0) { + if ((errno == EINTR) || (errno == EAGAIN)) + continue; + else { + perror("read"); + break; + } + } + + if (r == 0) + break; + + buflen += r; + } + + if (buflen == 0) + break; + + if (buflen < erasesize) { + /* Pad block to eraseblock size */ + memset(&buf[buflen], 0xff, erasesize - buflen); + buflen = erasesize; + } + + if (skip > 0) { + skip -= buflen; + buflen = 0; + if (skip <= 0) + indicate_writing(mtd); + + continue; + } + + if (jffs2file && w >= jffs2_skip_bytes) { + if (memcmp(buf, JFFS2_EOF, sizeof(JFFS2_EOF) - 1) == 0) { + if (!quiet) + fprintf(stderr, "\b\b\b "); + if (quiet < 2) + fprintf(stderr, "\nAppending jffs2 data from %s to %s...", jffs2file, mtd); + /* got an EOF marker - this is the place to add some jffs2 data */ + skip = mtd_replace_jffs2(mtd, fd, e, jffs2file); + jffs2_replaced = 1; + + /* don't add it again */ + jffs2file = NULL; + + w += skip; + e += skip; + skip -= buflen; + buflen = 0; + offset = 0; + continue; + } + /* no EOF marker, make sure we figure out the last inode number + * before appending some data */ + mtd_parse_jffs2data(buf, jffs2dir); + } + + /* need to erase the next block before writing data to it */ + if(!no_erase) + { + while (w + buflen > e - skip_bad_blocks) { + if (!quiet) + fprintf(stderr, "\b\b\b[e]"); + + if (mtd_block_is_bad(fd, e)) { + if (!quiet) + fprintf(stderr, "\nSkipping bad block at 0x%08zx ", e); + + skip_bad_blocks += erasesize; + e += erasesize; + + // Move the file pointer along over the bad block. + lseek(fd, erasesize, SEEK_CUR); + continue; + } + + if (mtd_erase_block(fd, e) < 0) { + if (next) { + if (w < e) { + write(fd, buf + offset, e - w); + offset = e - w; + } + w = 0; + e = 0; + close(fd); + mtd = next; + fprintf(stderr, "\b\b\b \n"); + goto resume; + } else { + fprintf(stderr, "Failed to erase block\n"); + exit(1); + } + } + + /* erase the chunk */ + e += erasesize; + } + } + + if (!quiet) + fprintf(stderr, "\b\b\b[w]"); + + if ((result = write(fd, buf + offset, buflen)) < buflen) { + if (result < 0) { + fprintf(stderr, "Error writing image.\n"); + exit(1); + } else { + fprintf(stderr, "Insufficient space.\n"); + exit(1); + } + } + w += buflen; + + buflen = 0; + offset = 0; + } + + if (jffs2_replaced && trx_fixup) { + trx_fixup(fd, mtd); + } + + if (!quiet) + fprintf(stderr, "\b\b\b\b "); + + if (quiet < 2) + fprintf(stderr, "\n"); + +#ifdef FIS_SUPPORT + if (fis_layout) { + if (fis_remap(old_parts, n_old, new_parts, n_new) < 0) + fprintf(stderr, "Failed to update the FIS partition table\n"); + } +#endif + + close(fd); + return 0; +} + +static void usage(void) +{ + fprintf(stderr, "Usage: mtd [ ...] [ ...] [:...]\n\n" + "The device is in the format of mtdX (eg: mtd4) or its label.\n" + "mtd recognizes these commands:\n" + " unlock unlock the device\n" + " refresh refresh mtd partition\n" + " erase erase all data on device\n" + " verify |- verify (use - for stdin) to device\n" + " write |- write (use - for stdin) to device\n" + " jffs2write append to the jffs2 partition on the device\n"); + if (mtd_resetbc) { + fprintf(stderr, + " resetbc reset the uboot boot counter\n"); + } + if (mtd_fixtrx) { + fprintf(stderr, + " fixtrx fix the checksum in a trx header on first boot\n"); + } + if (mtd_fixseama) { + fprintf(stderr, + " fixseama fix the checksum in a seama header on first boot\n"); + } + fprintf(stderr, + "Following options are available:\n" + " -q quiet mode (once: no [w] on writing,\n" + " twice: no status messages)\n" + " -n write without first erasing the blocks\n" + " -r reboot after successful command\n" + " -f force write without trx checks\n" + " -e erase before executing the command\n" + " -d directory for jffs2write, defaults to \"tmp\"\n" + " -j integrate into jffs2 data when writing an image\n" + " -s skip the first n bytes when appending data to the jffs2 partiton, defaults to \"0\"\n" + " -p write beginning at partition offset\n" + " -l the length of data that we want to dump\n"); + if (mtd_fixtrx) { + fprintf(stderr, + " -o offset offset of the image header in the partition(for fixtrx)\n"); + } + fprintf(stderr, +#ifdef FIS_SUPPORT + " -F [:[:]][,...]\n" + " alter the fis partition table to create new partitions replacing\n" + " the partitions provided as argument to the write command\n" + " (only valid together with the write command)\n" +#endif + "\n" + "Example: To write linux.trx to mtd4 labeled as linux and reboot afterwards\n" + " mtd -r write linux.trx linux\n\n"); + exit(1); +} + +static void do_reboot(void) +{ + fprintf(stderr, "Rebooting ...\n"); + fflush(stderr); + + /* try regular reboot method first */ + system("/sbin/reboot"); + sleep(2); + + /* if we're still alive at this point, force the kernel to reboot */ + syscall(SYS_reboot,LINUX_REBOOT_MAGIC1,LINUX_REBOOT_MAGIC2,LINUX_REBOOT_CMD_RESTART,NULL); +} + +int main (int argc, char **argv) +{ + int ch, i, boot, imagefd = 0, force, unlocked; + char *erase[MAX_ARGS], *device = NULL; + char *fis_layout = NULL; + size_t offset = 0, part_offset = 0, dump_len = 0; + enum { + CMD_ERASE, + CMD_WRITE, + CMD_UNLOCK, + CMD_JFFS2WRITE, + CMD_FIXTRX, + CMD_FIXSEAMA, + CMD_VERIFY, + CMD_DUMP, + CMD_RESETBC, + } cmd = -1; + + erase[0] = NULL; + boot = 0; + force = 0; + buflen = 0; + quiet = 0; + no_erase = 0; + + while ((ch = getopt(argc, argv, +#ifdef FIS_SUPPORT + "F:" +#endif + "frnqe:d:s:j:p:o:l:")) != -1) + switch (ch) { + case 'f': + force = 1; + break; + case 'r': + boot = 1; + break; + case 'n': + no_erase = 1; + break; + case 'j': + jffs2file = optarg; + break; + case 's': + errno = 0; + jffs2_skip_bytes = strtoul(optarg, 0, 0); + if (errno) { + fprintf(stderr, "-s: illegal numeric string\n"); + usage(); + } + break; + case 'q': + quiet++; + break; + case 'e': + i = 0; + while ((erase[i] != NULL) && ((i + 1) < MAX_ARGS)) + i++; + + erase[i++] = optarg; + erase[i] = NULL; + break; + case 'd': + jffs2dir = optarg; + break; + case 'p': + errno = 0; + part_offset = strtoul(optarg, 0, 0); + if (errno) { + fprintf(stderr, "-p: illegal numeric string\n"); + usage(); + } + break; + case 'l': + errno = 0; + dump_len = strtoul(optarg, 0, 0); + if (errno) { + fprintf(stderr, "-l: illegal numeric string\n"); + usage(); + } + break; + case 'o': + errno = 0; + offset = strtoul(optarg, 0, 0); + if (errno) { + fprintf(stderr, "-o: illegal numeric string\n"); + usage(); + } + break; +#ifdef FIS_SUPPORT + case 'F': + fis_layout = optarg; + break; +#endif + case '?': + default: + usage(); + } + argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + if ((strcmp(argv[0], "unlock") == 0) && (argc == 2)) { + cmd = CMD_UNLOCK; + device = argv[1]; + } else if ((strcmp(argv[0], "erase") == 0) && (argc == 2)) { + cmd = CMD_ERASE; + device = argv[1]; + } else if (((strcmp(argv[0], "resetbc") == 0) && (argc == 2)) && mtd_resetbc) { + cmd = CMD_RESETBC; + device = argv[1]; + } else if (((strcmp(argv[0], "fixtrx") == 0) && (argc == 2)) && mtd_fixtrx) { + cmd = CMD_FIXTRX; + device = argv[1]; + } else if (((strcmp(argv[0], "fixseama") == 0) && (argc == 2)) && mtd_fixseama) { + cmd = CMD_FIXSEAMA; + device = argv[1]; + } else if ((strcmp(argv[0], "verify") == 0) && (argc == 3)) { + cmd = CMD_VERIFY; + imagefile = argv[1]; + device = argv[2]; + } else if ((strcmp(argv[0], "dump") == 0) && (argc == 2)) { + cmd = CMD_DUMP; + device = argv[1]; + } else if ((strcmp(argv[0], "write") == 0) && (argc == 3)) { + cmd = CMD_WRITE; + device = argv[2]; + + if (strcmp(argv[1], "-") == 0) { + imagefile = ""; + imagefd = 0; + } else { + imagefile = argv[1]; + if ((imagefd = open(argv[1], O_RDONLY)) < 0) { + fprintf(stderr, "Couldn't open image file: %s!\n", imagefile); + exit(1); + } + } + + if (!mtd_check(device)) { + fprintf(stderr, "Can't open device for writing!\n"); + exit(1); + } + /* check trx file before erasing or writing anything */ + if (!image_check(imagefd, device) && !force) { + fprintf(stderr, "Image check failed.\n"); + exit(1); + } + } else if ((strcmp(argv[0], "jffs2write") == 0) && (argc == 3)) { + cmd = CMD_JFFS2WRITE; + device = argv[2]; + + imagefile = argv[1]; + if (!mtd_check(device)) { + fprintf(stderr, "Can't open device for writing!\n"); + exit(1); + } + } else { + usage(); + } + + sync(); + + i = 0; + unlocked = 0; + while (erase[i] != NULL) { + mtd_unlock(erase[i]); + mtd_erase(erase[i]); + if (strcmp(erase[i], device) == 0) + unlocked = 1; + i++; + } + + switch (cmd) { + case CMD_UNLOCK: + if (!unlocked) + mtd_unlock(device); + break; + case CMD_VERIFY: + mtd_verify(device, imagefile); + break; + case CMD_DUMP: + mtd_dump(device, offset, dump_len); + break; + case CMD_ERASE: + if (!unlocked) + mtd_unlock(device); + mtd_erase(device); + break; + case CMD_WRITE: + if (!unlocked) + mtd_unlock(device); + mtd_write(imagefd, device, fis_layout, part_offset); + break; + case CMD_JFFS2WRITE: + if (!unlocked) + mtd_unlock(device); + mtd_write_jffs2(device, imagefile, jffs2dir); + break; + case CMD_FIXTRX: + if (mtd_fixtrx) { + mtd_fixtrx(device, offset); + } + case CMD_RESETBC: + if (mtd_resetbc) { + mtd_resetbc(device); + } + case CMD_FIXSEAMA: + if (mtd_fixseama) + mtd_fixseama(device, 0); + break; + } + + sync(); + + if (boot) + do_reboot(); + + return 0; +} diff --git a/package/system/mtd/src/mtd.h b/package/system/mtd/src/mtd.h new file mode 100644 index 0000000..fb37b8b --- /dev/null +++ b/package/system/mtd/src/mtd.h @@ -0,0 +1,31 @@ +#ifndef __mtd_h +#define __mtd_h + +#include + +#ifdef target_brcm47xx +#define target_brcm 1 +#endif + +#define JFFS2_EOF "\xde\xad\xc0\xde" + +extern int quiet; +extern int mtdsize; +extern int erasesize; + +extern int mtd_open(const char *mtd, bool block); +extern int mtd_check_open(const char *mtd); +extern int mtd_block_is_bad(int fd, int offset); +extern int mtd_erase_block(int fd, int offset); +extern int mtd_write_buffer(int fd, const char *buf, int offset, int length); +extern int mtd_write_jffs2(const char *mtd, const char *filename, const char *dir); +extern int mtd_replace_jffs2(const char *mtd, int fd, int ofs, const char *filename); +extern void mtd_parse_jffs2data(const char *buf, const char *dir); + +/* target specific functions */ +extern int trx_fixup(int fd, const char *name) __attribute__ ((weak)); +extern int trx_check(int imagefd, const char *mtd, char *buf, int *len) __attribute__ ((weak)); +extern int mtd_fixtrx(const char *mtd, size_t offset) __attribute__ ((weak)); +extern int mtd_fixseama(const char *mtd, size_t offset) __attribute__ ((weak)); +extern int mtd_resetbc(const char *mtd) __attribute__ ((weak)); +#endif /* __mtd_h */ diff --git a/package/system/mtd/src/seama.c b/package/system/mtd/src/seama.c new file mode 100644 index 0000000..b0c8bf3 --- /dev/null +++ b/package/system/mtd/src/seama.c @@ -0,0 +1,179 @@ +/* + * seama.c + * + * Copyright (C) 2011-2012 Gabor Juhos + * + * Based on the trx fixup code: + * Copyright (C) 2005 Mike Baker + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "mtd.h" +#include "seama.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 + +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); + +int +seama_fix_md5(char *buf, size_t len) +{ + struct seama_hdr *shdr; + char *data; + size_t msize; + size_t isize; + MD5_CTX ctx; + unsigned char digest[16]; + int i; + + if (len < sizeof(struct seama_hdr)) + return -1; + + shdr = (struct seama_hdr *) buf; + if (shdr->magic != htonl(SEAMA_MAGIC)) { + fprintf(stderr, "no SEAMA header found\n"); + return -1; + } + + isize = ntohl(shdr->size); + msize = ntohs(shdr->metasize); + if (isize == 0) { + /* the image contains no checksum */ + return -1; + } + + len -= sizeof(struct seama_hdr) + sizeof(digest) + msize; + if (isize > len) + isize = len; + + data = buf + sizeof(struct seama_hdr) + sizeof(digest) + msize; + + MD5_Init(&ctx); + MD5_Update(&ctx, data, isize); + MD5_Final(digest, &ctx); + + if (!memcmp(digest, &buf[sizeof(struct seama_hdr)], sizeof(digest))) { + if (quiet < 2) + fprintf(stderr, "the header is fixed already\n"); + return -1; + } + + if (quiet < 2) { + fprintf(stderr, "new size:%u, new MD5: ", isize); + for (i = 0; i < sizeof(digest); i++) + fprintf(stderr, "%02x", digest[i]); + + fprintf(stderr, "\n"); + } + + /* update the size in the image */ + shdr->size = htonl(isize); + + /* update the checksum in the image */ + for (i = 0; i < sizeof(digest); i++) + buf[sizeof(struct seama_hdr) + i] = digest[i]; + + return 0; +} + +int +mtd_fixseama(const char *mtd, size_t offset) +{ + int fd; + char *buf; + ssize_t res; + size_t block_offset; + + if (quiet < 2) + fprintf(stderr, "Trying to fix SEAMA header in %s at 0x%x...\n", + mtd, offset); + + block_offset = offset & ~(erasesize - 1); + offset -= block_offset; + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } + + if (block_offset + erasesize > mtdsize) { + fprintf(stderr, "Offset too large, device size 0x%x\n", + mtdsize); + exit(1); + } + + buf = malloc(mtdsize); + if (!buf) { + perror("malloc"); + exit(1); + } + + res = pread(fd, buf, mtdsize, block_offset); + if (res != mtdsize) { + perror("pread"); + exit(1); + } + + if (seama_fix_md5(buf, mtdsize)) + goto out; + + if (mtd_erase_block(fd, block_offset)) { + fprintf(stderr, "Can't erease block at 0x%x (%s)\n", + block_offset, strerror(errno)); + exit(1); + } + + if (quiet < 2) + fprintf(stderr, "Rewriting block at 0x%x\n", block_offset); + + if (pwrite(fd, buf, erasesize, block_offset) != erasesize) { + fprintf(stderr, "Error writing block (%s)\n", strerror(errno)); + exit(1); + } + + if (quiet < 2) + fprintf(stderr, "Done.\n"); + +out: + close (fd); + sync(); + + return 0; +} + diff --git a/package/system/mtd/src/seama.h b/package/system/mtd/src/seama.h new file mode 100644 index 0000000..02683b6 --- /dev/null +++ b/package/system/mtd/src/seama.h @@ -0,0 +1,108 @@ +/* vi: set sw=4 ts=4: */ +/* + * (SEA)ttle i(MA)ge is the image which used in project seattle. + * + * Created by David Hsieh + * Copyright (C) 2008-2009 Alpha Networks, Inc. + * + * This file is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either' + * version 2.1 of the License, or (at your option) any later version. + * + * The GNU C Library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with the GNU C Library; if not, write to the Free + * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + */ + +#ifndef __SEAMA_HEADER_FILE__ +#define __SEAMA_HEADER_FILE__ + +#include + +#define SEAMA_MAGIC 0x5EA3A417 + +/* + * SEAMA looks like the following map. + * All the data of the header should be in network byte order. + * + * +-------------+-------------+------------ + * | SEAMA magic | ^ + * +-------------+-------------+ | + * | reserved | meta size | | + * +-------------+-------------+ header + * | image size (0 bytes) | | + * +-------------+-------------+ | + * ~ Meta data ~ v + * +-------------+-------------+------------ + * | SEAMA magic | ^ ^ + * +-------------+-------------+ | | + * | reserved | meta size | | | + * +-------------+-------------+ | | + * | image size | | | + * +-------------+-------------+ header | + * | | | | + * | 16 bytes of MD5 digest | | | + * | | | | + * | | | | + * +-------------+-------------+ | | + * ~ Meta data ~ v | + * +-------------+-------------+------- | + * | | | + * | Image of the 1st entity | | + * ~ ~ 1st entity + * | | | + * | | v + * +-------------+-------------+------------- + * | SEAMA magic | ^ ^ + * +-------------+-------------+ | | + * | reserved | meta size | | | + * +-------------+-------------+ | | + * | image size | | | + * +-------------+-------------+ header | + * | | | | + * | 16 bytes of MD5 digest | | | + * | | | | + * | | | | + * +-------------+-------------+ | | + * ~ Meta data ~ v | + * +-------------+-------------+------- | + * | | | + * | Image of the 2nd entity | | + * ~ ~ 2nd entity + * | | | + * | | v + * +-------------+-------------+------------- + */ + + +/* + * SEAMA header + * + * |<-------- 32 bits -------->| + * +-------------+-------------+ + * | SEAMA magic | + * +-------------+-------------+ + * | reserved | meta size | + * +-------------+-------------+ + * | image size | + * +-------------+-------------+ + */ +/* seama header */ +typedef struct seama_hdr seamahdr_t; +struct seama_hdr +{ + uint32_t magic; /* should always be SEAMA_MAGIC. */ + uint16_t reserved; /* reserved for */ + uint16_t metasize; /* size of the META data */ + uint32_t size; /* size of the image */ +} __attribute__ ((packed)); + + +#endif diff --git a/package/system/mtd/src/trx.c b/package/system/mtd/src/trx.c new file mode 100644 index 0000000..245ee76 --- /dev/null +++ b/package/system/mtd/src/trx.c @@ -0,0 +1,223 @@ +/* + * trx.c + * + * Copyright (C) 2005 Mike Baker + * Copyright (C) 2008 Felix Fietkau + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "mtd.h" +#include "crc32.h" + +#define TRX_MAGIC 0x30524448 /* "HDR0" */ +struct trx_header { + uint32_t magic; /* "HDR0" */ + uint32_t len; /* Length of file including header */ + uint32_t crc32; /* 32-bit CRC from flag_version to end of file */ + uint32_t flag_version; /* 0:15 flags, 16:31 version */ + uint32_t offsets[3]; /* Offsets of partitions from start of header */ +}; + +#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 + +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); + +int +trx_fixup(int fd, const char *name) +{ + struct mtd_info_user mtdInfo; + unsigned long len; + struct trx_header *trx; + void *ptr, *scan; + int bfd; + + if (ioctl(fd, MEMGETINFO, &mtdInfo) < 0) { + fprintf(stderr, "Failed to get mtd info\n"); + goto err; + } + + len = mtdInfo.size; + if (mtdInfo.size <= 0) { + fprintf(stderr, "Invalid MTD device size\n"); + goto err; + } + + bfd = mtd_open(name, true); + ptr = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, bfd, 0); + if (!ptr || (ptr == (void *) -1)) { + perror("mmap"); + goto err1; + } + + trx = ptr; + if (trx->magic != TRX_MAGIC) { + fprintf(stderr, "TRX header not found\n"); + goto err; + } + + scan = ptr + offsetof(struct trx_header, flag_version); + trx->crc32 = crc32buf(scan, trx->len - (scan - ptr)); + msync(ptr, sizeof(struct trx_header), MS_SYNC|MS_INVALIDATE); + munmap(ptr, len); + close(bfd); + return 0; + +err1: + close(bfd); +err: + fprintf(stderr, "Error fixing up TRX header\n"); + return -1; +} + +#ifndef target_ar71xx +int +trx_check(int imagefd, const char *mtd, char *buf, int *len) +{ + const struct trx_header *trx = (const struct trx_header *) buf; + int fd; + + if (strcmp(mtd, "firmware") != 0) + return 1; + + *len = read(imagefd, buf, 32); + if (*len < 32) { + fprintf(stdout, "Could not get image header, file too small (%d bytes)\n", *len); + return 0; + } + + if (trx->magic != TRX_MAGIC || trx->len < sizeof(struct trx_header)) { + if (quiet < 2) { + fprintf(stderr, "Bad trx header\n"); + fprintf(stderr, "This is not the correct file format; refusing to flash.\n" + "Please specify the correct file or use -f to force.\n"); + } + return 0; + } + + /* check if image fits to mtd device */ + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } + + if(mtdsize < trx->len) { + fprintf(stderr, "Image too big for partition: %s\n", mtd); + close(fd); + return 0; + } + + close(fd); + return 1; +} +#endif + +int +mtd_fixtrx(const char *mtd, size_t offset) +{ + int fd; + struct trx_header *trx; + char *buf; + ssize_t res; + size_t block_offset; + + if (quiet < 2) + fprintf(stderr, "Trying to fix trx header in %s at 0x%x...\n", mtd, offset); + + fd = mtd_check_open(mtd); + if(fd < 0) { + fprintf(stderr, "Could not open mtd device: %s\n", mtd); + exit(1); + } + + block_offset = offset & ~(erasesize - 1); + offset -= block_offset; + + if (block_offset + erasesize > mtdsize) { + fprintf(stderr, "Offset too large, device size 0x%x\n", mtdsize); + exit(1); + } + + buf = malloc(erasesize); + if (!buf) { + perror("malloc"); + exit(1); + } + + res = pread(fd, buf, erasesize, block_offset); + if (res != erasesize) { + perror("pread"); + exit(1); + } + + trx = (struct trx_header *) (buf + offset); + if (trx->magic != STORE32_LE(0x30524448)) { + fprintf(stderr, "No trx magic found\n"); + exit(1); + } + + if (trx->len == STORE32_LE(erasesize - offset)) { + if (quiet < 2) + fprintf(stderr, "Header already fixed, exiting\n"); + close(fd); + return 0; + } + + trx->len = STORE32_LE(erasesize - offset); + + trx->crc32 = STORE32_LE(crc32buf((char*) &trx->flag_version, erasesize - offset - 3*4)); + if (mtd_erase_block(fd, block_offset)) { + fprintf(stderr, "Can't erease block at 0x%x (%s)\n", block_offset, strerror(errno)); + exit(1); + } + + if (quiet < 2) + fprintf(stderr, "New crc32: 0x%x, rewriting block\n", trx->crc32); + + if (pwrite(fd, buf, erasesize, block_offset) != erasesize) { + fprintf(stderr, "Error writing block (%s)\n", strerror(errno)); + exit(1); + } + + if (quiet < 2) + fprintf(stderr, "Done.\n"); + + close (fd); + sync(); + return 0; + +} + -- cgit v1.2.3