Linksys EA8500 uboot damaged after wrongly flashing with empty $loadaddr

Hi, couple days ago I finally can recover my EA7500v1.
Thanks for guy who developed https://pypi.org/project/qcom-nandc-pagify/ and described how SBL partitions works.

What I have done.

Need direct connection to NAND flash. On EA7500v1/EA8500 it is possible by using testpoints on PCB, which is even labeled by manufacturer.
I've superglued pinheaders onto PCB, and after that soldering wires between them and testpoints.
On this picture I've labeled which is which.

If you have programmer capable to flash 8bit parallel NAND flash, it is easy.
I've try to do it on cheap and used for this purpose raspberry pi b+ which just laying around.
I found project which is implemented bitbang nand flasher. I forked and adapted for my particular Spansion S34MS01G2 nand flash.

Connections described in source file. GPIO layout can be found there https://pinout.xyz/

BUSY GPIO3
ALE  GPIO4
CLE  GPIO5
RE   GPIO6
CS   GND
WE   GPIO7
IO0:IO7  GPIO8:GPIO15

And of course ground from RPI needs to be connected to router's GND. In my case it can be accessed on UART pinheaders.
About power supply, NAND should be supplied by 1.8V, but RPI is a 3.3V.
From electrical point of view it is wrong, but in my case I didn't connect any power to router at all, I discovered that NAND seems to be powered through pull-up resistors from RPI, and 1.8 rail on router was about 1.9v, seems reasonable.
Reading and writing operation was remarkably well, and I decided to leave it without additional supply.

After wiring you can check connection by running

./rpi-raw-nand-v3 150 read_id

Program reads ID from flash and should recognize it as S34MS01G2
If all works fine you should dump existing content of flash, just in case.

./rpi-raw-nand-v3 150 read_full 0 7936 backup.bin

This dumps from mtd0 up to mtd12

You should always use read_full instead read_data, at least for qualcomm propietary partitions, as OOB contains actual data.

Recovering process is a bit messy, as you need dumps from someone who can dump mtd0-mtd12 from working router, but qualcomm nand driver in 5.4 kernel has a bug. Driver removes ECC from dump, but not all, leaves some chunks of it. I've wrote script for recovering actual data and stripping all unnecessary parts.
On the other hand nand driver in 5.10 kernel can correctly dump from mtd0 to mtd8, but corrupts mtd9 (u-boot). So in my case preferred method was get full dumps from 5.4 kernel router.
On working router you need to install nand-utils package and run commands

nanddump -f /tmp/dumpmtd0.bin -o -n /dev/mtd0
nanddump -f /tmp/dumpmtd1.bin -o -n /dev/mtd1
nanddump -f /tmp/dumpmtd2.bin -o -n /dev/mtd2
nanddump -f /tmp/dumpmtd3.bin -o -n /dev/mtd3
... and so on

Then feed this dumps into strip_ecc.py script and you've got clean data.

After that we need to prepare raw data for flasher by adding ECC and other Qualcomm specific things.

qcom-nandc-pagify --infile mtd0_strip.bin --outfile mtd0_ecc.bin --ecc rs_sbl
qcom-nandc-pagify --infile mtd1_strip.bin --outfile mtd1_ecc.bin --ecc rs_sbl
qcom-nandc-pagify --infile mtd2_strip.bin --outfile mtd2_ecc.bin --ecc rs_sbl
... and so on

Flashing new data.
You should always try to save your mtd8 (ART) partition as it contains unique calibration data for this particular device.
As wel as mtd12 which contains serial number and other no so important stuff.

Before you can write into NAND it needs to be erased. Erasing performed by big blocks, in this case by 64 pages. Each page is a 2048 byte.
For example if you need restore SBL1, you need to erase pages from 0 to 127. Is is first two blocks.

./rpi-raw-nand-v3 150 erase_blocks 0 2

Then you can write new data onto it

./rpi-raw-nand-v3 150 write_full 0 128 mtd0_ecc.bin

Partitions table from EA7500v1

No	Name		Start		Start page	Start block		Size		Size pages	Size blocks	ECC
0	SBL1		0			0			0				0x40000		128			2	 		RS_SBL
1	MIBIB		0x40000		128			2				0x140000	640			10	 		RS_SBL
2	SBL2		0x180000	768			12				0x140000	640			10	 		RS_SBL
3	SBL3		0x2c0000	1408		22				0x280000	1280		20	 		RS_SBL
4	DDRCONFIG	0x540000	2688		42				0x120000	576			9	 		RS_SBL
5	SSD			0x660000	3264		51				0x120000	576			9	 		RS_SBL
6	TZ			0x780000	3840		60				0x280000	1280		20	 		RS_SBL
7	RPM			0xa00000	5120		80				0x280000	1280		20	 		RS_SBL
8	ART			0xc80000	6400		100				0x140000	640			10	 		RS
9	APPSBL		0xdc0000	7040		110				0x100000	512			8	 		RS_SBL
10	u_env		0xec0000	7552		118				0x40000		128			2	 		RS
11	s_env		0xf00000	7680		120				0x40000		128			2	 		RS
12	devinfo		0xf40000	7808		122				0x40000		128			2	 		RS

In this table I place page and blocks numbers, for writing and erasing.
Don't substitute page numbers in erase_blocks command!
In ECC column shown which format was used in partition. Description and differences between them, you can find in qcom-nandc-pagify docs.

For successfully boot in U-Boot you need all chain from SBL1 up to RPM plus APPSBL.

Recovering process can be observed by hooking logic analyzer/oscilloscope up to one of the nand's data pin.

This is a chart I've captured on my router and marked what partitions loading. If boot process fails after some stage, you can figure which is caused.

In my repo https://github.com/iglooom/rpi-tsop48-nand/tree/master/qca-sbl-dumps/raw-nand-dumps you can find raw NAND dumps which I've dumped from working router after recovery. You can simply flash it by external flasher.
I can't check is this dumps can work on 8500, but as I upgraded RAM on my 7500 I've flash mtd4 exactly from 8500 dump and it recognized 512M. So, it seems to be should work on real 8500 too.

And after all of that I've performed some tests, and it seems to be impossible to correctly flash this partitions from OpenWRT, it always corrupted by driver in some way.
Read-only flag on those not a coincidence, don't try this at home :slight_smile:

4 Likes