[lantiq] Support booting the Speedport W502V using BRN-BOOT.
While the disadvantage is less available flash space, it's easy and safe to flash without opening the device. Going back to the original firmware is also possible. This patch add two firmware utilities, mkbrncmdline and mkbrnboot. mkbrncmdline patches the uncompressed kernel so the registeres a0 to a3 are initialized and the memory size is passed in. mkbrnboot takes the lzma compressed kernel and squashfs images and creates a firmware image that can be flashed using the BRN-BOOT recovery kernel, which is booted by holding both buttons when powering up the device and will listen on http://192.168.2.1. The firmware file from bin/lantiq/ to use is openwrt-lantiq-danube-ARV4525PW-BRNDTW502-brnImage The BRN-BOOT recovery kernel does size-check the image, so if it's too big to fit into flash it will complain accordingly. A second patch is needed to make the wired network interface work since there is no u-boot to pre-initialise it. Signed-off-by: Tobias Diedrich <ranma+openwrt@tdiedrich.de> git-svn-id: svn://svn.openwrt.org/openwrt/trunk@30532 3c298f89-4303-0410-b956-a3cf2f4a3e73master
parent
b90d992cc7
commit
f7b9691687
|
@ -78,6 +78,35 @@ static struct mtd_partition arv45xx_partitions[] =
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct mtd_partition arv45xx_brnboot_partitions[] =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
.name = "brn-boot",
|
||||||
|
.offset = 0x0,
|
||||||
|
.size = 0x20000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "config",
|
||||||
|
.offset = 0x20000,
|
||||||
|
.size = 0x30000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "linux",
|
||||||
|
.offset = 0x50000,
|
||||||
|
.size = 0x390000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "reserved", /* 12-byte signature at 0x3efff4 :/ */
|
||||||
|
.offset = 0x3e0000,
|
||||||
|
.size = 0x010000,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
.name = "eeprom",
|
||||||
|
.offset = 0x3f0000,
|
||||||
|
.size = 0x10000,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static struct mtd_partition arv7525_partitions[] =
|
static struct mtd_partition arv7525_partitions[] =
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
@ -136,6 +165,11 @@ static struct physmap_flash_data arv45xx_flash_data = {
|
||||||
.parts = arv45xx_partitions,
|
.parts = arv45xx_partitions,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct physmap_flash_data arv45xx_brnboot_flash_data = {
|
||||||
|
.nr_parts = ARRAY_SIZE(arv45xx_brnboot_partitions),
|
||||||
|
.parts = arv45xx_brnboot_partitions,
|
||||||
|
};
|
||||||
|
|
||||||
static struct physmap_flash_data arv7525_flash_data = {
|
static struct physmap_flash_data arv7525_flash_data = {
|
||||||
.nr_parts = ARRAY_SIZE(arv7525_partitions),
|
.nr_parts = ARRAY_SIZE(arv7525_partitions),
|
||||||
.parts = arv7525_partitions,
|
.parts = arv7525_partitions,
|
||||||
|
@ -244,13 +278,22 @@ arv452cpw_gpio_leds[] __initdata = {
|
||||||
|
|
||||||
static struct gpio_led
|
static struct gpio_led
|
||||||
arv4525pw_gpio_leds[] __initdata = {
|
arv4525pw_gpio_leds[] __initdata = {
|
||||||
{ .name = "soc:green:fxs1", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
|
{ .name = "soc:green:dsl", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
|
||||||
{ .name = "soc:green:fxs2", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
|
|
||||||
{ .name = "soc:red:dsl", .gpio = 6, .active_low = 1, .default_trigger = "default-on" },
|
|
||||||
{ .name = "soc:green:wifi", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
|
{ .name = "soc:green:wifi", .gpio = 8, .active_low = 1, .default_trigger = "default-on" },
|
||||||
{ .name = "soc:green:online", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
|
{ .name = "soc:green:online", .gpio = 9, .active_low = 1, .default_trigger = "default-on" },
|
||||||
|
{ .name = "soc:green:fxs-internet", .gpio = 5, .active_low = 1, .default_trigger = "default-on" },
|
||||||
|
{ .name = "soc:green:fxs-festnetz", .gpio = 4, .active_low = 1, .default_trigger = "default-on" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define ARV4525PW_PHYRESET 13
|
||||||
|
#define ARV4525PW_RELAY 31
|
||||||
|
|
||||||
|
static struct gpio arv4525pw_gpios[] __initdata = {
|
||||||
|
{ ARV4525PW_PHYRESET, GPIOF_OUT_INIT_HIGH, "phyreset" },
|
||||||
|
{ ARV4525PW_RELAY, GPIOF_OUT_INIT_HIGH, "relay" },
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
static struct gpio_led
|
static struct gpio_led
|
||||||
arv752dpw22_gpio_leds[] __initdata = {
|
arv752dpw22_gpio_leds[] __initdata = {
|
||||||
{ .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
|
{ .name = "soc:blue:power", .gpio = 3, .active_low = 1, .default_trigger = "default-on" },
|
||||||
|
@ -521,16 +564,24 @@ MIPS_MACHINE(LANTIQ_MACH_ARV452CPW,
|
||||||
"ARV452CPW - Arcor A801",
|
"ARV452CPW - Arcor A801",
|
||||||
arv452Cpw_init);
|
arv452Cpw_init);
|
||||||
|
|
||||||
|
|
||||||
static void __init
|
static void __init
|
||||||
arv4525pw_init(void)
|
arv4525pw_init(void)
|
||||||
{
|
{
|
||||||
#define ARV4525PW_MADWIFI_ADDR 0xb07f0400
|
#define ARV4525PW_MADWIFI_ADDR 0xb03f0400
|
||||||
|
if (ltq_brn_boot)
|
||||||
|
ltq_register_nor(&arv45xx_brnboot_flash_data);
|
||||||
|
else
|
||||||
|
ltq_register_nor(&arv45xx_flash_data);
|
||||||
|
|
||||||
ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv4525pw_gpio_leds), arv4525pw_gpio_leds);
|
ltq_add_device_gpio_leds(-1, ARRAY_SIZE(arv4525pw_gpio_leds), arv4525pw_gpio_leds);
|
||||||
ltq_register_nor(&arv45xx_flash_data);
|
gpio_request_array(arv4525pw_gpios, ARRAY_SIZE(arv4525pw_gpios));
|
||||||
|
gpio_export(ARV4525PW_RELAY, false);
|
||||||
|
gpio_export(ARV4525PW_PHYRESET, false);
|
||||||
ltq_pci_data.clock = PCI_CLOCK_INT;
|
ltq_pci_data.clock = PCI_CLOCK_INT;
|
||||||
ltq_register_pci(<q_pci_data);
|
ltq_register_pci(<q_pci_data);
|
||||||
ltq_register_madwifi_eep(ARV4525PW_MADWIFI_ADDR);
|
ltq_register_madwifi_eep(ARV4525PW_MADWIFI_ADDR);
|
||||||
|
arv45xx_register_ath5k();
|
||||||
|
ltq_register_ath5k(arv45xx_ath5k_eeprom_data, arv45xx_ath5k_eeprom_mac);
|
||||||
ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII;
|
ltq_eth_data.mii_mode = PHY_INTERFACE_MODE_MII;
|
||||||
arv45xx_register_ethernet();
|
arv45xx_register_ethernet();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,12 @@ define PatchKernelLzma
|
||||||
$(call CompressLzma,$(KDIR)/vmlinux-$(1),$(KDIR)/vmlinux-$(1).lzma)
|
$(call CompressLzma,$(KDIR)/vmlinux-$(1),$(KDIR)/vmlinux-$(1).lzma)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
|
define MkBrnImage
|
||||||
|
mkbrncmdline -i $(KDIR)/vmlinux-$(4) -o $(KDIR)/vmlinux-$(4)-brn BRN-BOOT $(6)
|
||||||
|
$(call CompressLzma,$(KDIR)/vmlinux-$(4)-brn,$(KDIR)/vmlinux-$(4)-brn.lzma)
|
||||||
|
mkbrnimg -s $(1) -m $(2) -o $(3) $(KDIR)/vmlinux-$(4)-brn.lzma $(KDIR)/root.$(5)
|
||||||
|
endef
|
||||||
|
|
||||||
define MkImageLzma
|
define MkImageLzma
|
||||||
mkimage -A mips -O linux -T kernel -a 0x80002000 -C lzma \
|
mkimage -A mips -O linux -T kernel -a 0x80002000 -C lzma \
|
||||||
-e 0x80002000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
|
-e 0x80002000 -n 'MIPS OpenWrt Linux-$(LINUX_VERSION)' \
|
||||||
|
@ -32,6 +38,7 @@ endef
|
||||||
define Image/Build/squashfs
|
define Image/Build/squashfs
|
||||||
cat $(KDIR)/uImage-$(2) $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image
|
cat $(KDIR)/uImage-$(2) $(KDIR)/root.$(1) > $(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image
|
||||||
$(call prepare_generic_squashfs,$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image)
|
$(call prepare_generic_squashfs,$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(1).image)
|
||||||
|
$(if $(3),$(call MkBrnImage,$(3),$(4),$(BIN_DIR)/$(IMG_PREFIX)-$(2)-$(3)-brnImage,$(2),$(1),$(5)))
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Image/Build/jffs2-64k
|
define Image/Build/jffs2-64k
|
||||||
|
@ -109,7 +116,7 @@ define Image/BuildKernel/Profile/ARV4525PW
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Image/Build/Profile/ARV4525PW
|
define Image/Build/Profile/ARV4525PW
|
||||||
$(call Image/Build/$(1),$(1),ARV4525PW)
|
$(call Image/Build/$(1),$(1),ARV4525PW,BRNDTW502,0x12345678,memsize=32)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Image/BuildKernel/Profile/ARV7525PW
|
define Image/BuildKernel/Profile/ARV7525PW
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
Index: linux-3.1.9/drivers/mtd/mtdpart.c
|
||||||
|
===================================================================
|
||||||
|
--- linux-3.1.9.orig/drivers/mtd/mtdpart.c 2012-01-29 22:55:30.295904157 +0100
|
||||||
|
+++ linux-3.1.9/drivers/mtd/mtdpart.c 2012-01-29 22:55:30.395904294 +0100
|
||||||
|
@@ -899,6 +899,38 @@
|
||||||
|
return le32_to_cpu(temp) == SQUASHFS_MAGIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static unsigned long find_brnimage_size(struct mtd_info *mtd,
|
||||||
|
+ unsigned long offset)
|
||||||
|
+{
|
||||||
|
+ unsigned long buf[4];
|
||||||
|
+ // Assume at most 2MB of kernel image
|
||||||
|
+ unsigned long end = offset + (2 << 20);
|
||||||
|
+ unsigned long ptr = offset + 0x400 - 12;
|
||||||
|
+ size_t len;
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ while (ptr < end) {
|
||||||
|
+ long size_min = ptr - 0x400 - 12 - offset;
|
||||||
|
+ long size_max = ptr + 12 - offset;
|
||||||
|
+ ret = mtd->read(mtd, ptr, 16, &len, (void *)buf);
|
||||||
|
+ if (ret || len != 16)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ if (le32_to_cpu(buf[0]) < size_min ||
|
||||||
|
+ le32_to_cpu(buf[0]) > size_max) {
|
||||||
|
+ ptr += 0x400;
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (le32_to_cpu(buf[3]) == SQUASHFS_MAGIC)
|
||||||
|
+ return ptr + 12 - offset;
|
||||||
|
+
|
||||||
|
+ ptr += 0x400;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int split_uimage(struct mtd_info *mtd,
|
||||||
|
const struct mtd_partition *part)
|
||||||
|
{
|
||||||
|
@@ -916,8 +948,11 @@
|
||||||
|
|
||||||
|
split_partitions[0].size = find_uimage_size(mtd, part->offset);
|
||||||
|
if (!split_partitions[0].size) {
|
||||||
|
- printk(KERN_NOTICE "no uImage found in linux partition\n");
|
||||||
|
- return -1;
|
||||||
|
+ split_partitions[0].size = find_brnimage_size(mtd, part->offset);
|
||||||
|
+ if (!split_partitions[0].size) {
|
||||||
|
+ printk(KERN_NOTICE "no uImage or brnImage found in linux partition\n");
|
||||||
|
+ return -1;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!detect_squashfs_partition(mtd,
|
||||||
|
Index: linux-3.1.9/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h
|
||||||
|
===================================================================
|
||||||
|
--- linux-3.1.9.orig/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-01-29 22:55:30.195904014 +0100
|
||||||
|
+++ linux-3.1.9/arch/mips/include/asm/mach-lantiq/xway/lantiq_soc.h 2012-01-29 22:55:30.395904294 +0100
|
||||||
|
@@ -149,6 +149,7 @@
|
||||||
|
|
||||||
|
extern __iomem void *ltq_ebu_membase;
|
||||||
|
extern __iomem void *ltq_cgu_membase;
|
||||||
|
+extern long ltq_brn_boot;
|
||||||
|
|
||||||
|
/* request a non-gpio and set the PIO config */
|
||||||
|
extern int ltq_gpio_request(unsigned int pin, unsigned int alt0,
|
||||||
|
Index: linux-3.1.9/arch/mips/lantiq/setup.c
|
||||||
|
===================================================================
|
||||||
|
--- linux-3.1.9.orig/arch/mips/lantiq/setup.c 2012-01-29 22:55:30.095903875 +0100
|
||||||
|
+++ linux-3.1.9/arch/mips/lantiq/setup.c 2012-01-29 22:59:28.686237119 +0100
|
||||||
|
@@ -20,6 +20,8 @@
|
||||||
|
|
||||||
|
/* assume 16M as default incase uboot fails to pass proper ramsize */
|
||||||
|
unsigned long physical_memsize = 16L;
|
||||||
|
+/* set to 1 if the bootloader is BRN-BOOT instead of u-boot */
|
||||||
|
+unsigned long ltq_brn_boot = 0;
|
||||||
|
|
||||||
|
void __init plat_mem_setup(void)
|
||||||
|
{
|
||||||
|
@@ -39,6 +41,10 @@
|
||||||
|
if (strict_strtoul(e, 0, &physical_memsize))
|
||||||
|
pr_warn("bad memsize specified\n");
|
||||||
|
}
|
||||||
|
+ if (!strncmp(e, "BRN-BOOT", 8)){
|
||||||
|
+ pr_info("Found BRN-BOOT instead of u-boot\n");
|
||||||
|
+ ltq_brn_boot = 1;
|
||||||
|
+ }
|
||||||
|
envp++;
|
||||||
|
}
|
||||||
|
physical_memsize *= 1024 * 1024;
|
|
@ -55,6 +55,8 @@ define Host/Compile
|
||||||
$(call cc,buffalo-tftp buffalo-lib, -Wall)
|
$(call cc,buffalo-tftp buffalo-lib, -Wall)
|
||||||
$(call cc,mkwrgimg md5, -Wall)
|
$(call cc,mkwrgimg md5, -Wall)
|
||||||
$(call cc,mkedimaximg)
|
$(call cc,mkedimaximg)
|
||||||
|
$(call cc,mkbrncmdline)
|
||||||
|
$(call cc,mkbrnimg)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
define Host/Install
|
define Host/Install
|
||||||
|
|
|
@ -0,0 +1,168 @@
|
||||||
|
/*
|
||||||
|
* mkbrncmdline.c - partially based on OpenWrt's wndr3700.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Tobias Diedrich <ranma+openwrt@tdiedrich.de>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
static void usage(const char *) __attribute__ (( __noreturn__ ));
|
||||||
|
|
||||||
|
static void usage(const char *mess)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: %s\n", mess);
|
||||||
|
fprintf(stderr, "Usage: mkbrncmdline -i input_file -o output_file [-a loadaddress] arg1 [argx ...]\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *input_file = NULL;
|
||||||
|
static char *output_file = NULL;
|
||||||
|
static unsigned loadaddr = 0x80002000;
|
||||||
|
|
||||||
|
static void parseopts(int *argc, char ***argv)
|
||||||
|
{
|
||||||
|
char *endptr;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
while ((res = getopt(*argc, *argv, "a:i:o:")) != -1) {
|
||||||
|
switch (res) {
|
||||||
|
default:
|
||||||
|
usage("Unknown option");
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
loadaddr = strtoul(optarg, &endptr, 0);
|
||||||
|
if (endptr == optarg || *endptr != 0)
|
||||||
|
usage("loadaddress must be a decimal or hexadecimal 32-bit value");
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
input_file = optarg;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
output_file = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*argc -= optind;
|
||||||
|
*argv += optind;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void emitload(int outfd, int reg, unsigned value)
|
||||||
|
{
|
||||||
|
char buf[8] = {
|
||||||
|
0x3c, 0x04 + reg,
|
||||||
|
value >> 24, value >> 16,
|
||||||
|
0x34, 0x84 + reg + (reg << 5),
|
||||||
|
value >> 8, value,
|
||||||
|
};
|
||||||
|
if (write(outfd, buf, sizeof(buf)) != sizeof(buf)) {
|
||||||
|
fprintf(stderr, "write: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int outfd;
|
||||||
|
int i;
|
||||||
|
int fd;
|
||||||
|
size_t len, skip, buf_len;
|
||||||
|
unsigned cmdline_addr;
|
||||||
|
unsigned s_ofs;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
parseopts(&argc, &argv);
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
usage("must specify at least one kernel cmdline argument");
|
||||||
|
|
||||||
|
if (input_file == NULL || output_file == NULL)
|
||||||
|
usage("must specify input and output file");
|
||||||
|
|
||||||
|
if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// mmap input_file
|
||||||
|
if ((fd = open(input_file, O_RDONLY)) < 0
|
||||||
|
|| (len = lseek(fd, 0, SEEK_END)) < 0
|
||||||
|
|| (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
|
||||||
|
|| close(fd) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error mapping file '%s': %s\n", input_file, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
cmdline_addr = loadaddr + len;
|
||||||
|
|
||||||
|
// Kernel args are passed in registers a0,a1,a2 and a3
|
||||||
|
emitload(outfd, 0, 0); /* a0 = 0 */
|
||||||
|
emitload(outfd, 1, 0); /* a1 = 0 */
|
||||||
|
emitload(outfd, 2, cmdline_addr); /* a2 = &cmdline */
|
||||||
|
emitload(outfd, 3, 0); /* a3 = 0 */
|
||||||
|
skip = lseek(outfd, 0, SEEK_END);
|
||||||
|
|
||||||
|
// write the kernel
|
||||||
|
if (write(outfd, input_file + skip, len - skip) != len -skip) {
|
||||||
|
fprintf(stderr, "write: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// write cmdline structure
|
||||||
|
buf_len = (argc + 1) * 4;
|
||||||
|
for (i=0; i<argc; i++) {
|
||||||
|
buf_len += strlen(argv[i]) + 1;
|
||||||
|
}
|
||||||
|
buf = malloc(buf_len + 16);
|
||||||
|
if (!buf) {
|
||||||
|
fprintf(stderr, "Could not allocate memory for cmdline buffer\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
memset(buf, 0, buf_len);
|
||||||
|
|
||||||
|
s_ofs = 4 * (argc + 1);
|
||||||
|
for (i=0; i<argc; i++) {
|
||||||
|
unsigned s_ptr = cmdline_addr + s_ofs;
|
||||||
|
buf[i * 4 + 0] = s_ptr >> 24;
|
||||||
|
buf[i * 4 + 1] = s_ptr >> 16;
|
||||||
|
buf[i * 4 + 2] = s_ptr >> 8;
|
||||||
|
buf[i * 4 + 3] = s_ptr >> 0;
|
||||||
|
memcpy(&buf[s_ofs], argv[i], strlen(argv[i]));
|
||||||
|
s_ofs += strlen(argv[i]) + 1;
|
||||||
|
}
|
||||||
|
if (write(outfd, buf, buf_len) != buf_len) {
|
||||||
|
fprintf(stderr, "write: %s\n", strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
munmap(input_file, len);
|
||||||
|
close(outfd);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* mkbrnimg.c - partially based on OpenWrt's wndr3700.c
|
||||||
|
*
|
||||||
|
* Copyright (C) 2011 Tobias Diedrich <ranma+openwrt@tdiedrich.de>
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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 <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define BPB 8 /* bits/byte */
|
||||||
|
|
||||||
|
static uint32_t crc32[1<<BPB];
|
||||||
|
|
||||||
|
static void init_crc32()
|
||||||
|
{
|
||||||
|
const uint32_t poly = ntohl(0x2083b8ed);
|
||||||
|
int n;
|
||||||
|
|
||||||
|
for (n = 0; n < 1<<BPB; n++) {
|
||||||
|
uint32_t crc = n;
|
||||||
|
int bit;
|
||||||
|
|
||||||
|
for (bit = 0; bit < BPB; bit++)
|
||||||
|
crc = (crc & 1) ? (poly ^ (crc >> 1)) : (crc >> 1);
|
||||||
|
crc32[n] = crc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t crc32buf(unsigned char *buf, size_t len)
|
||||||
|
{
|
||||||
|
uint32_t crc = 0xFFFFFFFF;
|
||||||
|
|
||||||
|
for (; len; len--, buf++)
|
||||||
|
crc = crc32[(uint8_t)crc ^ *buf] ^ (crc >> BPB);
|
||||||
|
return ~crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void usage(const char *) __attribute__ (( __noreturn__ ));
|
||||||
|
|
||||||
|
static void usage(const char *mess)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error: %s\n", mess);
|
||||||
|
fprintf(stderr, "Usage: mkbrnimg [-o output_file] [-m magic] [-s signature] kernel_file [additional files]\n");
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *output_file = "default-brnImage";
|
||||||
|
static uint32_t magic = 0x12345678;
|
||||||
|
static char *signature = "BRNDTW502";
|
||||||
|
|
||||||
|
static void parseopts(int *argc, char ***argv)
|
||||||
|
{
|
||||||
|
char *endptr;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
while ((res = getopt(*argc, *argv, "o:m:s:")) != -1) {
|
||||||
|
switch (res) {
|
||||||
|
default:
|
||||||
|
usage("Unknown option");
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
output_file = optarg;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
magic = strtoul(optarg, &endptr, 0);
|
||||||
|
if (endptr == optarg || *endptr != 0)
|
||||||
|
usage("magic must be a decimal or hexadecimal 32-bit value");
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
signature = optarg;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*argc -= optind;
|
||||||
|
*argv += optind;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void appendfile(int outfd, char *path, int kernel) {
|
||||||
|
int fd;
|
||||||
|
size_t len, padded_len;
|
||||||
|
char *input_file;
|
||||||
|
uint32_t crc;
|
||||||
|
char padding[0x400];
|
||||||
|
char footer[12];
|
||||||
|
|
||||||
|
memset(padding, 0xff, sizeof(padding));
|
||||||
|
|
||||||
|
// mmap input_file
|
||||||
|
if ((fd = open(path, O_RDONLY)) < 0
|
||||||
|
|| (len = lseek(fd, 0, SEEK_END)) < 0
|
||||||
|
|| (input_file = mmap(0, len, PROT_READ, MAP_SHARED, fd, 0)) == (void *) (-1)
|
||||||
|
|| close(fd) < 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error mapping file '%s': %s\n", path, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// kernel should be lzma compressed image, not uImage
|
||||||
|
if (kernel &&
|
||||||
|
(input_file[0] != (char)0x5d ||
|
||||||
|
input_file[1] != (char)0x00 ||
|
||||||
|
input_file[2] != (char)0x00 ||
|
||||||
|
input_file[3] != (char)0x80)) {
|
||||||
|
fprintf(stderr, "lzma signature not found on kernel image.\n");
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
init_crc32();
|
||||||
|
crc = crc32buf(input_file, len);
|
||||||
|
fprintf(stderr, "crc32 for '%s' is %08x.\n", path, crc);
|
||||||
|
|
||||||
|
// write the file
|
||||||
|
write(outfd, input_file, len);
|
||||||
|
|
||||||
|
// write padding
|
||||||
|
padded_len = ((len + sizeof(footer) + sizeof(padding) - 1) & ~(sizeof(padding) - 1)) - sizeof(footer);
|
||||||
|
fprintf(stderr, "len=%08x padded_len=%08x\n", len, padded_len);
|
||||||
|
write(outfd, padding, padded_len - len);
|
||||||
|
|
||||||
|
// write footer
|
||||||
|
footer[0] = (len >> 0) & 0xff;
|
||||||
|
footer[1] = (len >> 8) & 0xff;
|
||||||
|
footer[2] = (len >> 16) & 0xff;
|
||||||
|
footer[3] = (len >> 24) & 0xff;
|
||||||
|
footer[4] = (magic >> 0) & 0xff;
|
||||||
|
footer[5] = (magic >> 8) & 0xff;
|
||||||
|
footer[6] = (magic >> 16) & 0xff;
|
||||||
|
footer[7] = (magic >> 24) & 0xff;
|
||||||
|
footer[8] = (crc >> 0) & 0xff;
|
||||||
|
footer[9] = (crc >> 8) & 0xff;
|
||||||
|
footer[10] = (crc >> 16) & 0xff;
|
||||||
|
footer[11] = (crc >> 24) & 0xff;
|
||||||
|
write(outfd, footer, sizeof(footer));
|
||||||
|
|
||||||
|
munmap(input_file, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int outfd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
parseopts(&argc, &argv);
|
||||||
|
|
||||||
|
if (argc < 1)
|
||||||
|
usage("wrong number of arguments");
|
||||||
|
|
||||||
|
if ((outfd = open(output_file, O_WRONLY|O_CREAT|O_TRUNC, 0644)) == -1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Error opening '%s' for writing: %s\n", output_file, strerror(errno));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i=0; i<argc; i++) {
|
||||||
|
appendfile(outfd, argv[i], i == 0);
|
||||||
|
}
|
||||||
|
write(outfd, signature, strlen(signature)+1);
|
||||||
|
close(outfd);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue