From 3fcaccd9b37b6ed2e2fedf3d0ebbc88d9a072100 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Sat, 12 Dec 2009 02:00:50 +0000 Subject: [PATCH] add a hacked up version of upslug2 which is able to flash a wrt350nv2 in recovery mode SVN-Revision: 18765 --- tools/Makefile | 4 +- tools/upslug2/Makefile | 35 +++ tools/upslug2/patches/100-libpcap_fix.patch | 153 ++++++++++ .../patches/110-wrt350nv2_support.patch | 279 ++++++++++++++++++ 4 files changed, 469 insertions(+), 2 deletions(-) create mode 100644 tools/upslug2/Makefile create mode 100644 tools/upslug2/patches/100-libpcap_fix.patch create mode 100644 tools/upslug2/patches/110-wrt350nv2_support.patch diff --git a/tools/Makefile b/tools/Makefile index 272c625435..276233ef57 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -16,7 +16,7 @@ endif tools-y += m4 autoconf automake bison pkg-config sed mklibs tools-y += sstrip ipkg-utils genext2fs mtd-utils mkimage tools-y += firmware-utils patch-cmdline quilt yaffs2 -tools-y += wrt350nv2-builder +tools-$(CONFIG_TARGET_orion) += wrt350nv2-builder upslug2 ifneq ($(CONFIG_LINUX_2_4)$(CONFIG_LINUX_2_6_21)$(CONFIG_LINUX_2_6_25)$(CONFIG_LINUX_2_6_28),) tools-y += squashfs lzma-old else @@ -89,5 +89,5 @@ $(curdir)//compile = $(STAGING_DIR)/.prepared $(STAGING_DIR_HOST)/.prepared $($( $(curdir)/ := .config prereq $(curdir)//install = $(1)/compile -$(eval $(call stampfile,$(curdir),tools,install,,CONFIG_CCACHE CONFIG_powerpc CONFIG_GCC_VERSION_4_3 CONFIG_GCC_USE_GRAPHITE)) +$(eval $(call stampfile,$(curdir),tools,install,,CONFIG_CCACHE CONFIG_powerpc CONFIG_GCC_VERSION_4_3 CONFIG_GCC_USE_GRAPHITE CONFIG_TARGET_orion)) $(eval $(call subdir,$(curdir))) diff --git a/tools/upslug2/Makefile b/tools/upslug2/Makefile new file mode 100644 index 0000000000..6a73853f3c --- /dev/null +++ b/tools/upslug2/Makefile @@ -0,0 +1,35 @@ +# +# Copyright (C) 2009 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# +include $(TOPDIR)/rules.mk + +PKG_NAME:=upslug2 +PKG_VERSION:=20071227 + +PKG_SOURCE_URL:=http://svn.nslu2-linux.org/svnroot/upslug2/trunk +PKG_SOURCE_PROTO:=svn +PKG_SOURCE_SUBDIR:=upslug2-$(PKG_VERSION) +PKG_SOURCE_VERSION:=41 +PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 + +include $(INCLUDE_DIR)/host-build.mk + +unexport CFLAGS + +define Host/Configure + (cd $(HOST_BUILD_DIR); \ + aclocal && autoconf && \ + autoheader && \ + automake --add-missing; \ + ) + $(Host/Configure/Default) +endef + +ifneq ($(HOST_OS),Linux) + HOST_CONFIGURE_ARGS += --with-libpcap +endif + +$(eval $(call HostBuild)) diff --git a/tools/upslug2/patches/100-libpcap_fix.patch b/tools/upslug2/patches/100-libpcap_fix.patch new file mode 100644 index 0000000000..1e14de4519 --- /dev/null +++ b/tools/upslug2/patches/100-libpcap_fix.patch @@ -0,0 +1,153 @@ +--- a/pcap_wire.cc ++++ b/pcap_wire.cc +@@ -18,6 +18,7 @@ + + #include + #include ++#include + + /* Ways of finding the hardware MAC on this machine... */ + /* This is the Linux only fallback. */ +@@ -130,20 +131,18 @@ namespace NSLU2Upgrade { + * non-static (real) Handler. + */ + void Handler(const struct pcap_pkthdr *packet_header, const u_char *packet) { +- /* This should only be called once... */ +- if (captured) +- throw std::logic_error("Handler called twice"); +- + /* Verify the protocol and originating address of the packet, then + * return this packet. + */ ++ if (captured) ++ return; + if (packet_header->caplen > 14 && (broadcast || + std::memcmp(packet+6, header, 6) == 0)) { +- /* Record the address and copy the data */ +- std::memcpy(source, packet+6, 6); + const size_t len(packet_header->caplen - 14); + if (len > captureSize) +- throw std::logic_error("packet too long"); ++ return; ++ /* Record the address and copy the data */ ++ std::memcpy(source, packet+6, 6); + std::memcpy(captureBuffer, packet+14, len); + captureSize = len; + captured = true; +@@ -156,7 +155,7 @@ namespace NSLU2Upgrade { + * packet and the buffer should be big enough. + */ + if (packet_header->caplen < packet_header->len) +- throw std::logic_error("truncated packet"); ++ return; + + /*IGNORE EVIL: known evil cast */ + reinterpret_cast(user)->Handler(packet_header, packet); +@@ -173,56 +172,24 @@ namespace NSLU2Upgrade { + virtual void Receive(void *buffer, size_t &size, unsigned long timeout) { + /* Now try to read packets until the timeout has been consumed. + */ +- struct timeval tvStart; +- if (timeout > 0 && gettimeofday(&tvStart, 0) != 0) +- throw OSError(errno, "gettimeofday(base)"); ++ int time_count; + + captureBuffer = buffer; + captureSize = size; + captured = false; ++ time_count = timeout / 2000; /* 2 ms intervals */ ++ time_count++; + do { + /*IGNORE EVIL: known evil cast */ +- int count(pcap_dispatch(pcap, 1, PCapHandler, +- reinterpret_cast(this))); ++ int count = pcap_dispatch(pcap, 1, PCapHandler, ++ reinterpret_cast(this)); + +- if (count > 0) { +- /* Were any packets handled? */ +- if (captured) { +- size = captureSize; +- return; +- } +- /* else try again. */ +- } else if (count == 0) { +- /* Nothing to handle - do the timeout, do this +- * by waiting a bit then trying again, the trick +- * to this is to work out how long to wait each +- * time, for the moment a 10ms delay is used. +- */ +- if (timeout == 0) +- break; +- +- struct timeval tvNow; +- if (gettimeofday(&tvNow, 0) != 0) +- throw OSError(errno, "gettimeofday(now)"); +- +- unsigned long t(tvNow.tv_sec - tvStart.tv_sec); +- t *= 1000000; +- t += tvNow.tv_usec; +- t -= tvStart.tv_usec; +- if (t > timeout) +- break; +- +- tvNow.tv_sec = 0; +- tvNow.tv_usec = timeout-t; +- if (tvNow.tv_usec > 10000) +- tvNow.tv_usec = 10000; +- +- /* Delay, may be interrupted - this should +- * be portable to the BSDs (since the +- * technique originates in BSD.) +- */ +- (void)select(0, 0, 0, 0, &tvNow); +- } else { ++ /* Were any packets handled? */ ++ if (captured) { ++ size = captureSize; ++ return; ++ } ++ if (count < 0) { + /* Error condition. */ + if (count == -1) { + if (errno != EINTR) +@@ -232,7 +199,8 @@ namespace NSLU2Upgrade { + } else + throw std::logic_error("pcap unexpected result"); + } +- } while (timeout != 0); ++ time_count--; ++ } while (time_count > 0); + + /* Here on timeout. */ + size = 0; +@@ -288,6 +256,7 @@ NSLU2Upgrade::Wire *NSLU2Upgrade::Wire:: + const unsigned char *mac, const unsigned char *address, int uid) { + /* This is used to store the error passed to throw. */ + static char PCapErrbuf[PCAP_ERRBUF_SIZE]; ++ struct bpf_program fp; + + /* Check the device name. If not given use 'DEFAULT_ETHERNET_IF'. */ + if (device == NULL) +@@ -301,20 +270,12 @@ NSLU2Upgrade::Wire *NSLU2Upgrade::Wire:: + * for other ethernet MACs. (Because the code above does not + * check that the destination matches the device in use). + */ +- pcap = pcap_open_live(device, 1540, false/*promiscuous*/, 1/*ms*/, PCapErrbuf); ++ pcap = pcap_open_live(device, 1540, false/*promiscuous*/, 2/*ms*/, PCapErrbuf); + + if (pcap == NULL) + throw WireError(errno, PCapErrbuf); + } + +- /* Always do a non-blocking read, because the 'timeout' above +- * doesn't work on Linux (return is immediate) and on OSX (and +- * maybe other BSDs) the interface tends to hang waiting for +- * the timeout to expire even after receiving a single packet. +- */ +- if (pcap_setnonblock(pcap, true, PCapErrbuf)) +- throw WireError(errno, PCapErrbuf); +- + try { + /* The MAC of the transmitting device is needed - without + * this the return packet won't go to the right place! diff --git a/tools/upslug2/patches/110-wrt350nv2_support.patch b/tools/upslug2/patches/110-wrt350nv2_support.patch new file mode 100644 index 0000000000..eea7cc4d00 --- /dev/null +++ b/tools/upslug2/patches/110-wrt350nv2_support.patch @@ -0,0 +1,279 @@ +--- a/nslu2_image.cc ++++ b/nslu2_image.cc +@@ -54,28 +54,44 @@ namespace NSLU2Image { + int &address, int &length) { + address = image.tellg(); + length = buffer_length; +- if (address+length > NSLU2Protocol::FlashSize) +- length = NSLU2Protocol::FlashSize-address; ++ if (address+length > EndAddress) ++ length = EndAddress-address; + if (length > 0) + SafeRead(&image, buffer, length, "image (read)"); + } + ++ virtual void GetBoundaries(int &start, int &end) ++ { ++ start = BaseAddress; ++ end = EndAddress; ++ } ++ + /* Rewind to the start of the image (or the Kernel if not + * doing a complete reprogram). + */ + virtual void Rewind(void) { +- SafeSeek(&image, reprogram ? 0 : NSLU2Protocol::BaseAddress, ++ SafeSeek(&image, reprogram ? 0 : BaseAddress, + "image (seek)"); + } + + private: ++ int BaseAddress; ++ int EndAddress; ++ + /* Validate that this really is an image file. */ + void Validate(const char *i) { + char signature[8]; + + SafeSeek(&image, -8, i, std::ios::end); + SafeRead(&image, signature, 8, i); +- if (memcmp(signature, "eRcOmM", 6) != 0) ++ ++ if (memcmp(signature, "eRcOmM", 6) == 0) { ++ BaseAddress = NSLU2Protocol::BaseAddress; ++ EndAddress = NSLU2Protocol::FlashSize; ++ } else if (memcmp(signature + 1, "sErCoMm", 7) == 0) { ++ BaseAddress = 0; ++ EndAddress = NSLU2Protocol::FlashSize - 0x40000; ++ } else + throw NSLU2Image::FileError(DataError, i, 0); + } + +@@ -93,6 +109,12 @@ namespace NSLU2Image { + virtual ~SynthesiseImage() { + } + ++ void GetBoundaries(int &start, int &end) ++ { ++ start = NSLU2Protocol::BaseAddress; ++ end = NSLU2Protocol::FlashSize; ++ } ++ + /* Get the next block of bytes, returns an address and length, false if + * there is a problem. + */ +--- a/nslu2_image.h ++++ b/nslu2_image.h +@@ -35,6 +35,8 @@ namespace NSLU2Image { + virtual ~Image() { + } + ++ virtual void GetBoundaries(int &start, int &end) = 0; ++ + /* Get the next block of bytes, returns an address and length. + */ + virtual void GetBytes(char *buffer, size_t buffer_length, +--- a/nslu2_upgrade.cc ++++ b/nslu2_upgrade.cc +@@ -95,7 +95,7 @@ namespace NSLU2Upgrade { + + class RealDoUpgrade : public DoUpgrade { + public: +- RealDoUpgrade(Wire *w, Progress *p, bool r) : ++ RealDoUpgrade(Wire *w, Progress *p, bool r, int start, int end) : + wire(w), progress(p), sequenceError(-1), reprogram(r), + lastType(NSLU2Protocol::InvalidType) { + if (reprogram) { +@@ -105,6 +105,8 @@ namespace NSLU2Upgrade { + NSLU2Protocol::UpgradeStartPacket packet(seq); + wire->Send(packet.PacketBuffer(), packet.PacketLength()); + } ++ BaseAddress = start; ++ EndAddress = end; + } + + virtual ~RealDoUpgrade() { +@@ -205,8 +207,8 @@ namespace NSLU2Upgrade { + + }; + +- DoUpgrade *DoUpgrade::MakeDoUpgrade(Wire *wire, Progress *progress, bool reprogram) { +- return new RealDoUpgrade(wire, progress, reprogram); ++ DoUpgrade *DoUpgrade::MakeDoUpgrade(Wire *wire, Progress *progress, bool reprogram, int start, int end) { ++ return new RealDoUpgrade(wire, progress, reprogram, start, end); + } + }; + +@@ -421,13 +423,18 @@ void NSLU2Upgrade::RealDoUpgrade::Upgrad + /* Simple upgrade programs only the addresses beyound BaseAddress, + * reprogram overwrites the whole flash. + */ +- if (!reprogram && address < NSLU2Protocol::BaseAddress) { ++ if (!reprogram && address < BaseAddress) { + length += address; +- if (length <= NSLU2Protocol::BaseAddress) ++ if (length <= BaseAddress) + return; /* nothing to do. */ +- address = NSLU2Protocol::BaseAddress; ++ address = BaseAddress; + length -= address; + } ++ if (!reprogram && address + length > EndAddress) { ++ if (address >= EndAddress) ++ return; /* nothing to do. */ ++ length -= EndAddress - address; ++ } + + #if 1 + /* Skip blocks of 255 valued bytes - the erase clears the flash to this +@@ -495,11 +502,11 @@ void NSLU2Upgrade::RealDoUpgrade::Verify + Finish(); + + /* Verify never verifies anything below BaseAddress. */ +- if (address < NSLU2Protocol::BaseAddress) { ++ if (address < BaseAddress) { + length += address; +- if (length <= NSLU2Protocol::BaseAddress) ++ if (length <= BaseAddress) + return; /* nothing to do. */ +- address = NSLU2Protocol::BaseAddress; ++ address = BaseAddress; + length -= address; + } + +--- a/nslu2_upgrade.h ++++ b/nslu2_upgrade.h +@@ -206,6 +206,8 @@ namespace NSLU2Upgrade { + + class DoUpgrade { + public: ++ int BaseAddress; ++ int EndAddress; + virtual ~DoUpgrade() { + } + +@@ -228,7 +230,7 @@ namespace NSLU2Upgrade { + virtual void Reboot(void) = 0; + /* Reboot the NSLU2. */ + +- static DoUpgrade *MakeDoUpgrade(Wire *wire, Progress *progress, bool reprogram); ++ static DoUpgrade *MakeDoUpgrade(Wire *wire, Progress *progress, bool reprogram, int start, int end); + /* Instantiate a real DoUpgrade, returns NULL if the object + * cannot be instantiated. + * +--- a/upslug2.cc ++++ b/upslug2.cc +@@ -21,8 +21,8 @@ + + class ProgressBar : public UpSlug2::CharacterProgressBar<80> { + public: +- ProgressBar(bool reprogram, const unsigned char *t) : +- UpSlug2::CharacterProgressBar<80>(reprogram, 64), ++ ProgressBar(bool reprogram, const unsigned char *t, int start, int end) : ++ UpSlug2::CharacterProgressBar<80>(reprogram, 64, start, end), + target(t), displayed(false), ticker(0) { + } + +@@ -95,7 +95,7 @@ private: + else if (seen == -1) { + seen = 0; + if (!reprogram) +- sent -= NSLU2Protocol::BaseAddress; ++ sent -= NSLU2Protocol::FlashSize - (EndAddress - BaseAddress); + } else + sent -= seen; + +@@ -423,7 +423,7 @@ int main(int argc, char **argv) { + { 0, 0, 0, 0 } + }; + +- do switch (getopt_long(argc, argv, "he:d:t:f:vUni:Ck:r:R:j:p:P:T:F:E:", options, 0)) { ++ do switch (getopt_long(argc, argv, "he:d:t:f:vUni:Ck:r:R:j:op:P:T:F:E:", options, 0)) { + case -1: if (optind < argc) { + std::fprintf(stderr, "%s: unrecognised option\n", argv[optind]); + std::exit(1); +@@ -523,16 +523,22 @@ done: + + if (mac && got_kernel) { + Pointer wire(NSLU2Upgrade::Wire::MakeWire(device, fromMac, mac, euid)); +- ProgressBar progress(reprogram, mac); ++ int BaseAddress = NSLU2Protocol::BaseAddress; ++ int EndAddress = NSLU2Protocol::FlashSize; + + if (full_image) { /* complete image. */ + /* The full image case allows a complete reprogram. */ ++ NSLU2Image::Image *image_p; + Pointer image( + NSLU2Image::Image::MakeImage( + reprogram, full_image)); ++ image_p = image.p; ++ image_p->GetBoundaries(BaseAddress, EndAddress); ++ ProgressBar progress(reprogram, mac, BaseAddress, EndAddress); + Pointer upgrade( + NSLU2Upgrade::DoUpgrade::MakeDoUpgrade( +- wire.p, &progress, reprogram)); ++ wire.p, &progress, reprogram, ++ BaseAddress, EndAddress)); + progress.FirstDisplay(); + Upgrade(upgrade.p, image.p, no_upgrade, no_verify); + progress.EndDisplay(); +@@ -551,9 +557,11 @@ done: + fis_payload, + product_id, protocol_id, + firmware_version, extra_version)); ++ ProgressBar progress(reprogram, mac, BaseAddress, EndAddress); + Pointer upgrade( + NSLU2Upgrade::DoUpgrade::MakeDoUpgrade( +- wire.p, &progress, false)); ++ wire.p, &progress, false, ++ BaseAddress, EndAddress)); + progress.FirstDisplay(); + Upgrade(upgrade.p, image.p, no_upgrade, no_verify); + progress.EndDisplay(); +--- a/upslug2_progress.h ++++ b/upslug2_progress.h +@@ -161,15 +161,19 @@ namespace UpSlug2 { + Timedout, /* *: timeout on a sent packet for this address. */ + NumberOfStates + } Status; +- ++ int BaseAddress; ++ int EndAddress; ++ + /* reprogram says whether this is a full reprogram (the entire + * flash will be erased) or not (the leading, RedBoot, SysConf + * partitions are not erased). + * resolution should be about 6 for a command line (character) + * progress bar and 8 for a GUI (pixel) progress bar. + */ +- ProgressBar(bool r) : ++ ProgressBar(bool r, int start, int end) : + reprogram(r), timeout(false), retransmit(false), status(Init) { ++ BaseAddress = start; ++ EndAddress = end; + } + + /* lowWaterMark..(highWaterMark-1) bytes are in state 'st', +@@ -179,8 +183,8 @@ namespace UpSlug2 { + /* These initial settings cover the majority of cases + * correctly. + */ +- lowWaterMark = reprogram ? 0 : NSLU2Protocol::BaseAddress; +- highWaterMark = status >= st ? NSLU2Protocol::FlashSize-1 : 0; ++ lowWaterMark = reprogram ? 0 : BaseAddress; ++ highWaterMark = status >= st ? EndAddress-1 : 0; + switch (st) { + case Init: + /* Everything has an initial value... */ +@@ -286,9 +290,9 @@ namespace UpSlug2 { + */ + template class CharacterProgressBar : public ProgressBar { + public: +- CharacterProgressBar(bool reprogram, int n, const char ind[NumberOfStates] = 0) : ++ CharacterProgressBar(bool reprogram, int n, int start, int end, const char ind[NumberOfStates] = 0) : + numberOfCharacters(n > characters || n < 1 ? characters : n), +- ProgressBar(reprogram) { ++ ProgressBar(reprogram, start, end) { + if (ind) + std::memcpy(indicators, ind, NumberOfStates); + else