From bbb8942009badc1594ab187a36dac8877137c929 Mon Sep 17 00:00:00 2001 From: John Crispin Date: Mon, 16 Jun 2014 18:57:20 +0000 Subject: [PATCH] ramips: RT-N56U support fixes and factory image creation Signed-off-by: Mikko Hissa git-svn-id: svn://svn.openwrt.org/openwrt/trunk@41224 3c298f89-4303-0410-b956-a3cf2f4a3e73 --- ...sh_checksumming => 04_handle_checksumming} | 17 +- target/linux/ramips/dts/RTN56U.dts | 8 + target/linux/ramips/image/Makefile | 8 +- .../0135-mtd-add-rtn56u-support.patch | 28 ++ tools/firmware-utils/Makefile | 1 + tools/firmware-utils/src/mkrtn56uimg.c | 294 ++++++++++++++++++ 6 files changed, 353 insertions(+), 3 deletions(-) rename target/linux/ramips/base-files/lib/preinit/{04_disable_wnce2001_flash_checksumming => 04_handle_checksumming} (62%) create mode 100644 target/linux/ramips/patches-3.10/0135-mtd-add-rtn56u-support.patch create mode 100644 tools/firmware-utils/src/mkrtn56uimg.c diff --git a/target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming b/target/linux/ramips/base-files/lib/preinit/04_handle_checksumming similarity index 62% rename from target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming rename to target/linux/ramips/base-files/lib/preinit/04_handle_checksumming index 67a1746f1d..fd06d20c99 100644 --- a/target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming +++ b/target/linux/ramips/base-files/lib/preinit/04_handle_checksumming @@ -5,7 +5,7 @@ # this, so we make sure to zero checksum and size to be checksummed before # that happens, so this needs to run very early during boot. -do_wnce2001_checksumming_disable() { +do_checksumming_disable() { . /lib/ramips.sh local board=$(ramips_board_name) @@ -35,9 +35,22 @@ do_wnce2001_checksumming_disable() { echo "Checksum is already zero, nothing to do." fi ;; + rt-n56u) + echo "Board is ASUS RT-N56U, replacing uImage header..." + local firmware_mtd=$(find_mtd_part firmware) + local rootfs_mtd=$(find_mtd_part rootfs) + local rootfs_data_mtd=$(find_mtd_part rootfs_data) + local rootfs_len=$(grep \"rootfs\" /proc/mtd | awk -F' ' '{print "0x"$2}') + local rootfs_data_len=$(grep \"rootfs_data\" /proc/mtd | awk -F' ' '{print "0x"$2}') + local offset=$(echo "$rootfs_len $rootfs_data_len 0x40" | awk -F' ' '{printf "%i",$1-$2-$3}') + local signature=$(dd if=$rootfs_mtd skip=$offset bs=1 count=4 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"') + if [ "$signature" == "27051956" ]; then + dd conv=notrunc if=$rootfs_mtd skip=$offset of=$firmware_mtd bs=1 count=64 2>/dev/null + fi + ;; esac return 0 } -boot_hook_add preinit_main do_wnce2001_checksumming_disable +boot_hook_add preinit_main do_checksumming_disable diff --git a/target/linux/ramips/dts/RTN56U.dts b/target/linux/ramips/dts/RTN56U.dts index b962aa0d23..305e36e85b 100644 --- a/target/linux/ramips/dts/RTN56U.dts +++ b/target/linux/ramips/dts/RTN56U.dts @@ -43,12 +43,20 @@ host-bridge { pci-bridge@1 { status = "okay"; + wmac@0,0 { + compatible = "ralink,rt2880-pci", "pciclass060400", "pciclass0604"; + reg = < 0x10000 0 0 0 0 >; + ralink,eeprom = "rt2x00pci_1_0.eeprom"; + }; + }; }; }; wmac@10180000 { + status = "okay"; ralink,2ghz = <0>; + ralink,eeprom = "soc_wmac.eeprom"; }; ehci@101c0000 { diff --git a/target/linux/ramips/image/Makefile b/target/linux/ramips/image/Makefile index 58a54773c2..1b342deb7a 100644 --- a/target/linux/ramips/image/Makefile +++ b/target/linux/ramips/image/Makefile @@ -665,7 +665,13 @@ Image/Build/Profile/DIR645=$(call BuildFirmware/Seama/$(1),$(1),dir-645,DIR-645, omniembhpm_mtd_size=16449536 Image/Build/Profile/OMNIEMBHPM=$(call BuildFirmware/CustomFlash/$(1),$(1),omni-emb-hpm,OMNI-EMB-HPM,$(omniembhpm_mtd_size)) -Image/Build/Profile/RTN56U=$(call BuildFirmware/Default8M/$(1),$(1),rt-n56u,RTN56U) +define BuildFirmware/RTN56U/squashfs + $(call BuildFirmware/Default8M/$(1),$(1),rt-n56u,RTN56U) + -mkrtn56uimg -s $(call sysupname,$(1),rt-n56u) + -cp $(call sysupname,$(1),rt-n56u) $(call imgname,$(1),rt-n56u)-factory.bin + -mkrtn56uimg -f $(call imgname,$(1),rt-n56u)-factory.bin +endef +Image/Build/Profile/RTN56U=$(call BuildFirmware/RTN56U/$(1),$(1),rt-n56u,RTN56U) Image/Build/Profile/TEW691GR=$(call BuildFirmware/UMedia/$(1),$(1),tew-691gr,TEW-691GR,0x026910) diff --git a/target/linux/ramips/patches-3.10/0135-mtd-add-rtn56u-support.patch b/target/linux/ramips/patches-3.10/0135-mtd-add-rtn56u-support.patch new file mode 100644 index 0000000000..52379916b9 --- /dev/null +++ b/target/linux/ramips/patches-3.10/0135-mtd-add-rtn56u-support.patch @@ -0,0 +1,28 @@ +--- a/drivers/mtd/mtdpart.c 2014-04-27 10:09:21.566294160 +0300 ++++ b/drivers/mtd/mtdpart.c 2014-06-09 11:27:48.952211672 +0300 +@@ -793,8 +793,11 @@ + { + struct { + __be32 magic; +- __be32 pad[2]; ++ __be32 pad0[2]; + __be32 size; ++ __be32 pad1[4]; ++ __be32 name[7]; ++ __be32 kern_size; + } hdr; + size_t len; + +@@ -804,7 +807,11 @@ + if (len != sizeof(hdr) || hdr.magic != cpu_to_be32(UBOOT_MAGIC)) + return; + +- len = be32_to_cpu(hdr.size) + 0x40; ++ if (hdr.kern_size != 0 && hdr.name[0] == 0) ++ len = be32_to_cpu(hdr.kern_size); ++ else ++ len = be32_to_cpu(hdr.size) + 0x40; ++ + __mtd_add_partition(master, "rootfs", part->offset + len, + part->mtd.size - len, false); + } diff --git a/tools/firmware-utils/Makefile b/tools/firmware-utils/Makefile index 3be80e77ab..8f17c3e923 100644 --- a/tools/firmware-utils/Makefile +++ b/tools/firmware-utils/Makefile @@ -67,6 +67,7 @@ define Host/Compile #$(call cc,mkhilinkfw, -lcrypto) $(call cc,mkdcs932, -Wall) $(call cc,mkheader_gemtek,-lz) + $(call cc,mkrtn56uimg, -lz) endef define Host/Install diff --git a/tools/firmware-utils/src/mkrtn56uimg.c b/tools/firmware-utils/src/mkrtn56uimg.c new file mode 100644 index 0000000000..973ab28d06 --- /dev/null +++ b/tools/firmware-utils/src/mkrtn56uimg.c @@ -0,0 +1,294 @@ +/* + * + * Copyright (C) 2014 OpenWrt.org + * Copyright (C) 2014 Mikko Hissa + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published + * by the Free Software Foundation. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IH_MAGIC 0x27051956 +#define IH_NMLEN 32 +#define IH_PRODLEN 23 + +#define IH_TYPE_INVALID 0 +#define IH_TYPE_STANDALONE 1 +#define IH_TYPE_KERNEL 2 +#define IH_TYPE_RAMDISK 3 +#define IH_TYPE_MULTI 4 +#define IH_TYPE_FIRMWARE 5 +#define IH_TYPE_SCRIPT 6 +#define IH_TYPE_FILESYSTEM 7 + +/* + * Compression Types + */ +#define IH_COMP_NONE 0 +#define IH_COMP_GZIP 1 +#define IH_COMP_BZIP2 2 +#define IH_COMP_LZMA 3 + +typedef struct { + uint8_t major; + uint8_t minor; +} version_t; + +typedef struct { + version_t kernel; + version_t fs; + uint8_t productid[IH_PRODLEN]; + uint8_t sub_fs; + uint32_t ih_ksz; +} asus_t; + +typedef struct image_header { + uint32_t ih_magic; + uint32_t ih_hcrc; + uint32_t ih_time; + uint32_t ih_size; + uint32_t ih_load; + uint32_t ih_ep; + uint32_t ih_dcrc; + uint8_t ih_os; + uint8_t ih_arch; + uint8_t ih_type; + uint8_t ih_comp; + union { + uint8_t ih_name[IH_NMLEN]; + asus_t asus; + } tail; +} image_header_t; + +typedef struct squashfs_sb { + uint32_t s_magic; + uint32_t pad0[9]; + uint64_t bytes_used; +} squashfs_sb_t; + +typedef enum { + NONE, FACTORY, SYSUPGRADE, +} op_mode_t; + +void +calc_crc(image_header_t *hdr, void *data, uint32_t len) +{ + /* + * Calculate payload checksum + */ + hdr->ih_dcrc = htonl(crc32(0, data, len)); + hdr->ih_size = htonl(len); + /* + * Calculate header checksum + */ + hdr->ih_hcrc = 0; + hdr->ih_hcrc = htonl(crc32(0, hdr, sizeof(image_header_t))); +} + + +static void +usage(const char *progname, int status) +{ + FILE *stream = (status != EXIT_SUCCESS) ? stderr : stdout; + int i; + + fprintf(stream, "Usage: %s [OPTIONS...]\n", progname); + fprintf(stream, "\n" + "Options:\n" + " -f generate a factory flash image \n" + " -s generate a sysupgrade flash image \n" + " -h show this screen\n"); + exit(status); +} + +int +process_image(char *progname, char *filename, op_mode_t opmode) +{ + int fd, len; + void *data, *ptr; + char namebuf[IH_NMLEN]; + struct stat sbuf; + uint32_t checksum, offset_kernel, offset_sqfs, offset_end, + offset_sec_header, offset_eb, offset_image_end; + squashfs_sb_t *sqs; + image_header_t *hdr; + + if ((fd = open(filename, O_RDWR, 0666)) < 0) { + fprintf (stderr, "%s: Can't open %s: %s\n", + progname, filename, strerror(errno)); + return (EXIT_FAILURE); + } + + if (fstat(fd, &sbuf) < 0) { + fprintf (stderr, "%s: Can't stat %s: %s\n", + progname, filename, strerror(errno)); + return (EXIT_FAILURE); + } + + if ((unsigned)sbuf.st_size < sizeof(image_header_t)) { + fprintf (stderr, + "%s: Bad size: \"%s\" is no valid image\n", + progname, filename); + return (EXIT_FAILURE); + } + + ptr = (void *)mmap(0, sbuf.st_size, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, 0); + + if ((caddr_t)ptr == (caddr_t)-1) { + fprintf (stderr, "%s: Can't read %s: %s\n", + progname, filename, strerror(errno)); + return (EXIT_FAILURE); + } + + hdr = ptr; + + if (ntohl(hdr->ih_magic) != IH_MAGIC) { + fprintf (stderr, + "%s: Bad Magic Number: \"%s\" is no valid image\n", + progname, filename); + return (EXIT_FAILURE); + } + + if (opmode == FACTORY) { + strncpy(&namebuf, (char *)&hdr->tail.ih_name, IH_NMLEN); + hdr->tail.asus.kernel.major = 0; + hdr->tail.asus.kernel.minor = 0; + hdr->tail.asus.fs.major = 0; + hdr->tail.asus.fs.minor = 0; + strncpy((char *)&hdr->tail.asus.productid, "RT-N56U", IH_PRODLEN); + } + + if (hdr->tail.asus.ih_ksz == 0) + hdr->tail.asus.ih_ksz = htonl(ntohl(hdr->ih_size) + sizeof(image_header_t)); + + offset_kernel = sizeof(image_header_t); + offset_sqfs = ntohl(hdr->tail.asus.ih_ksz); + sqs = ptr + offset_sqfs; + offset_sec_header = offset_sqfs + sqs->bytes_used; + + /* + * Reserve space for the second header. + */ + offset_end = offset_sec_header + sizeof(image_header_t); + offset_eb = ((offset_end>>16)+1)<<16; + + if (opmode == FACTORY) + offset_image_end = offset_eb + 4; + else + offset_image_end = sbuf.st_size; + /* + * Move the second header at the end of the image. + */ + offset_end = offset_sec_header; + offset_sec_header = offset_eb - sizeof(image_header_t); + + /* + * Remove jffs2 markers between squashfs and eb boundary. + */ + if (opmode == FACTORY) + memset(ptr+offset_end, 0xff ,offset_eb - offset_end); + + /* + * Grow the image if needed. + */ + if (offset_image_end > sbuf.st_size) { + (void) munmap((void *)ptr, sbuf.st_size); + ftruncate(fd, offset_image_end); + ptr = (void *)mmap(0, offset_image_end, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, 0); + /* + * jffs2 marker + */ + if (opmode == FACTORY) { + *(uint8_t *)(ptr+offset_image_end-4) = 0xde; + *(uint8_t *)(ptr+offset_image_end-3) = 0xad; + *(uint8_t *)(ptr+offset_image_end-2) = 0xc0; + *(uint8_t *)(ptr+offset_image_end-1) = 0xde; + } + } + + /* + * Calculate checksums for the second header to be used after flashing. + */ + if (opmode == FACTORY) { + hdr = ptr+offset_sec_header; + memcpy(hdr, ptr, sizeof(image_header_t)); + strncpy((char *)&hdr->tail.ih_name, &namebuf, IH_NMLEN); + calc_crc(hdr, ptr+offset_kernel, offset_sqfs - offset_kernel); + calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_image_end - offset_kernel); + } else { + calc_crc((image_header_t *)ptr, ptr+offset_kernel, offset_sqfs - offset_kernel); + } + + if (sbuf.st_size > offset_image_end) + (void) munmap((void *)ptr, sbuf.st_size); + else + (void) munmap((void *)ptr, offset_image_end); + + ftruncate(fd, offset_image_end); + (void) close (fd); + + return EXIT_SUCCESS; +} + +int +main(int argc, char **argv) +{ + int opt; + char *filename, *progname; + op_mode_t opmode = NONE; + + progname = argv[0]; + + while ((opt = getopt(argc, argv,":s:f:h?")) != -1) { + switch (opt) { + case 's': + opmode = SYSUPGRADE; + filename = optarg; + break; + case 'f': + opmode = FACTORY; + filename = optarg; + break; + case 'h': + opmode = NONE; + default: + usage(progname, EXIT_FAILURE); + opmode = NONE; + } + } + + if(filename == NULL) + opmode = NONE; + + switch (opmode) { + case NONE: + usage(progname, EXIT_FAILURE); + break; + case FACTORY: + case SYSUPGRADE: + return process_image(progname, filename, opmode); + break; + } + + return EXIT_SUCCESS; +} +