ramips: RT-N56U support fixes and factory image creation
authorJohn Crispin <john@openwrt.org>
Mon, 16 Jun 2014 18:57:20 +0000 (18:57 +0000)
committerJohn Crispin <john@openwrt.org>
Mon, 16 Jun 2014 18:57:20 +0000 (18:57 +0000)
Signed-off-by: Mikko Hissa <mikko.hissa@werzek.com>
SVN-Revision: 41224

target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming [deleted file]
target/linux/ramips/base-files/lib/preinit/04_handle_checksumming [new file with mode: 0644]
target/linux/ramips/dts/RTN56U.dts
target/linux/ramips/image/Makefile
target/linux/ramips/patches-3.10/0135-mtd-add-rtn56u-support.patch [new file with mode: 0644]
tools/firmware-utils/Makefile
tools/firmware-utils/src/mkrtn56uimg.c [new file with mode: 0644]

diff --git a/target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming b/target/linux/ramips/base-files/lib/preinit/04_disable_wnce2001_flash_checksumming
deleted file mode 100644 (file)
index 67a1746..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-#!/bin/sh
-
-# Netgear WNCE2001 has does a checksum check on boot and goes into recovery
-# tftp mode when the check fails.  Initializing the JFFS2 partition triggers
-# 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() {
-       . /lib/ramips.sh
-
-       local board=$(ramips_board_name)
-
-       case "$board" in
-       wnce2001)
-               echo "Board is WNCE2001, updating checksum partition..."
-               local zeroes=/dev/zero
-               local tmpfile=/tmp/wnce2001_checksum
-               local partname=checksum
-               local mtd=$(find_mtd_part $partname)
-               dd if=$mtd of=$tmpfile bs=80 count=1 2>/dev/null
-               signature=$(dd if=$tmpfile bs=1 skip=24 count=20 2>/dev/null)
-               checksum=$(dd if=$tmpfile bs=1 count=4 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"')
-               if [ "$signature" != "RT3052-AP-WNCE2001-3" ]; then
-                       echo "Signature of checksum partition is wrong, bailing."
-                       return 0
-               fi
-               if [ "$checksum" != "00000000" ]; then
-                       echo "Checksum is set, zeroing."
-                       # zero out checksum
-                       dd if=$zeroes of=$tmpfile conv=notrunc bs=1 seek=0 count=4 2>/dev/null
-                       # zero out bytecount to be checksummed
-                       dd if=$zeroes of=$tmpfile conv=notrunc bs=1 seek=60 count=4 2>/dev/null
-                       mtd write $tmpfile $partname
-               else
-                       echo "Checksum is already zero, nothing to do."
-               fi
-       ;;
-       esac
-
-       return 0
-}
-
-boot_hook_add preinit_main do_wnce2001_checksumming_disable
diff --git a/target/linux/ramips/base-files/lib/preinit/04_handle_checksumming b/target/linux/ramips/base-files/lib/preinit/04_handle_checksumming
new file mode 100644 (file)
index 0000000..fd06d20
--- /dev/null
@@ -0,0 +1,56 @@
+#!/bin/sh
+
+# Netgear WNCE2001 has does a checksum check on boot and goes into recovery
+# tftp mode when the check fails.  Initializing the JFFS2 partition triggers
+# 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_checksumming_disable() {
+       . /lib/ramips.sh
+
+       local board=$(ramips_board_name)
+
+       case "$board" in
+       wnce2001)
+               echo "Board is WNCE2001, updating checksum partition..."
+               local zeroes=/dev/zero
+               local tmpfile=/tmp/wnce2001_checksum
+               local partname=checksum
+               local mtd=$(find_mtd_part $partname)
+               dd if=$mtd of=$tmpfile bs=80 count=1 2>/dev/null
+               signature=$(dd if=$tmpfile bs=1 skip=24 count=20 2>/dev/null)
+               checksum=$(dd if=$tmpfile bs=1 count=4 2>/dev/null | hexdump -v -n 4 -e '1/1 "%02x"')
+               if [ "$signature" != "RT3052-AP-WNCE2001-3" ]; then
+                       echo "Signature of checksum partition is wrong, bailing."
+                       return 0
+               fi
+               if [ "$checksum" != "00000000" ]; then
+                       echo "Checksum is set, zeroing."
+                       # zero out checksum
+                       dd if=$zeroes of=$tmpfile conv=notrunc bs=1 seek=0 count=4 2>/dev/null
+                       # zero out bytecount to be checksummed
+                       dd if=$zeroes of=$tmpfile conv=notrunc bs=1 seek=60 count=4 2>/dev/null
+                       mtd write $tmpfile $partname
+               else
+                       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_checksumming_disable
index b962aa0..305e36e 100644 (file)
                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 {
index 58a5477..1b342de 100644 (file)
@@ -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 (file)
index 0000000..5237991
--- /dev/null
@@ -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);
+ }
index 3be80e7..8f17c3e 100644 (file)
@@ -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 (file)
index 0000000..973ab28
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *
+ *  Copyright (C) 2014 OpenWrt.org
+ *  Copyright (C) 2014 Mikko Hissa <mikko.hissa@werzek.com>
+ *
+ *  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 <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <unistd.h>
+#include <zlib.h>
+
+#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 <file>            generate a factory flash image <file>\n"
+                       "  -s <file>            generate a sysupgrade flash image <file>\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;
+}
+