CM CPE, both the CopperRocket and the Netopia SDSL WAN module, has a very peculiar firmware structure. Specifically, the flash memory on the board stores two complete copies of the firmware image. Image 1 at the beginning of flash remains unchanged from the factory, whereas image 2 is subject to field updates. The MC68LC302 processor always fetches the reset vector from the beginning of flash, so image 1 always runs at least initially. It starts initializing the board and at some points checks the flash and decides whether to keep running or to transfer control to image 2. If image 2 gains control, it completely takes over. Both images proceed with normal functionality past the image selection logic: bring up the SDSL link, etc.

Dual firmware images are common in embedded system with field firmware update capability. The goal is for the device to remain functional and allow recovery even if the firmware field update doesn't go smoothly, e.g., if a power failure occurs in the middle of writing to flash. However, CM's implementation of this common trick is rather peculiar due to constraints imposed by the modest hardware.

The system's vital stats are quite modest. Each firmware image weighs about 90 KB. The flash memory on the CopperRocket consists of two Am29F010 (128K x 8) chips covering MC68LC302's 16-bit data bus, for a total size of 256 KB. The first and second 128 KB halves store images 1 and 2, respectively. The Netopia SDSL module apparently runs the MC68LC302 in 8-bit data bus mode (I guess they didn't do the same on the CopperRocket because of Ethernet) and has only one 8-bit flash chip. On our unit this chip has turned out to be an Am29F040 (512K x 8), but only the first 256 KB are used, storing two images well under 128 KB exactly as on the CopperRocket. Why a 4 Mbit chip then? Well, there are no 2 Mbit flash chips in this family, only 1 Mbit and 4 Mbit, and I guess the savings from having just one chip outweighed the cost of using twice the necessary capacity.

The RAM is also very modest: 64 KB on the CopperRocket and 128 KB on the Netopia SDSL module. (It's all SRAM, no DRAM.) On the CopperRocket which we've reverse-engineered more thoroughly, most of this RAM is used for packet buffers, with a little room set aside at the end for variables and a small stack. As expected for a system of this size there is no embedded operating system, not even a small RTOS, and the code runs directly on the hardware without any scheduling or memory management and the like. It also executes directly from flash; copying to RAM is obviously not possible with such tiny RAM capacity.

One implication of executing directly from flash is that the two firmware images are not interchangeable, i.e., a given image can work either in image 1 position only or in image 2 position only. The CPU core in the MC68LC302 is the original M68000, no 68020 and later luxuries, and is not very PIC-friendly. Writing position-independent code for M68000 is a royal pain and it's understandable that CM didn't do it. The code uses absolute addresses and is linked either for the flash address of image 1 or for that of image 2. And since the build is different anyway, a few additional gratuitous changes are also made.

The thing is clearly designed for firmware field updates to be done over the SDSL link commanded by the DSLAM, i.e., involuntary firmware updates from the user's perspective. It is instructive to consider how this mechanism has to work. Although we haven't delved into the code that implements it, some conclusions can be drawn just from logical reasoning.

Suppose that the device powers on, image 2 runs as usual, brings up the SDSL link, and one bright summer day gets a command from the DSLAM to download new firmware (say, a new image has been released and installed on the DSLAM). How would it go about the procedure? Normally it would be done by receiving the new firmware image into a RAM buffer, validating it there (checksum etc.), then disabling all interrupts, erasing and reprogramming the flash, and rebooting. But this can't be done on CM CPE hardware, at least on the CopperRocket, because there isn't enough RAM to hold a complete firmware image during this process. It would have to erase the flash first before it has the new image downloaded, then program the new image in chunks as it's received over the line. But how can you do it if you are executing directly from the same flash?

The only way I can think of for this to work is to require image 1 to be running while a new image 2 is being downloaded. The flash sectors that store image 2 can be erased and programmed while those with image 1 remain intact. Code can't be running from anywhere in the same flash chip during the actual erase and program operations, but the routines to do those can be small enough to be copied to RAM and executed there. But what if image 2 is already running when the firmware download command is received from the DSLAM? The only solution I can think of is that it probably then marks itself as invalid and reboots, expecting the image selection logic in image 1 not to transfer control to it this time. The implication is that the firmware field update process may involve temporarily running a firmware version that's even older than the pre-update image 2, and this old firmware version has to bring up the SDSL link and run it well enough to download the new firmware image over it.

Which brings us to the following observation. Reverse engineering of our CopperRocket (image 1 version 1.20.8 from the factory, image 2 version 5.0.95 downloaded by the DSLAM when it was last in service) has revealed that firmware version 1.20.8 which we have in image 1 does not support the 1568 kbps data rate (the new one of course does). This wouldn't matter for us because our SDSL line was 416 kbps (I assume; it was billed as 384 kbps). But what if we had a 1568 kbps line? How would the DSLAM perform its remote firmware updates then? The logical conclusion is that CM DSLAMs probably switch to a lower data rate (likely 160 kbps) during these maintenance operations and expect CM-style autoconfiguring CPE to pick it up by counting the speed code pulses. Definitely something that one needs to be aware of when connecting to CM SDSL lines with open source CPE — read about CMCP.