DGND3700 V1 Transmission Firmware Reverse Decompile 2

=adsl_phy.bin swapping=

This may have been a lot easier to someone good with C and assembler skills, unfortunately that isn't me. Without the old source this would have been impossible.

Interesting info here, http://bcm63xx.sipsolutions.net/AdslPhy

=At the beginning in 2013=

Unfortunately A2pv6C035m [obtained from the beta .20 firmware] is the last version that will load for some reason. (Several older ones I tried all seem to load ok.)

I have tried these three newer ones with same error, which comes from adsldd.ko, so presume they are only as swappable as this kernel module can manage to support.


 * A2pv6C037h
 * A2pv6C038h
 * A2pv6C038k1

BcmAdsl_Initialize=0xC012CA10, g_pFnNotifyCallback=0xC0160FD4 Clocks for QPROC and AFE are being aligned with step through ... AFE is aligned, i = 080, PhaseValue = -050, PhaseCntl = 0x3B6D3D9B QPROC is aligned, i = 001, PhaseValue = 0050, PhaseCntl = 0x3B6D7D9C Clocks for QPROC and AFE are aligned with syn_status AFE = 0x70, QPROC = 0x78 AFE phase control reg @0xb0f570f8 default actual = 0x0021C38F, exp = 0x0021c38f QPRC phase control reg @0xb0f5f0c0 default actual = 0x0421C38F, exp = 0x0421c38f Failed to read SDRAM image from '/etc/adsl/adsl_phy.bin'. AdslCoreHwReset: Failed to load ADSL PHY image (0) Clocks for QPROC and AFE are being aligned with step through ... AFE is aligned, i = 080, PhaseValue = -050, PhaseCntl = 0x3ACD3D4B QPROC is aligned, i = 001, PhaseValue = 0050, PhaseCntl = 0x3ACD7D4C Clocks for QPROC and AFE are aligned with syn_status AFE = 0x70, QPROC = 0x78 AFE phase control reg @0xb0f570f8 default actual = 0x0021C38F, exp = 0x0021c38f QPRC phase control reg @0xb0f5f0c0 default actual = 0x0421C38F, exp = 0x0421c38f Failed to read SDRAM image from '/etc/adsl/adsl_phy.bin'. AdslCoreHwReset: Failed to load ADSL PHY image (0) dgasp: kerSysRegisterDyingGaspHandler: dsl0 registered
 * XfaceOffset: 0x5FF90 => 0x5FF90 ***
 * XfaceOffset: 0x5FF90 => 0x5FF90 ***

The key part should look like this (35m) pSdramPHY=0xA7FFFFF8, 0x3B1 0xDEADBEEF AdslCoreSharedMemInit: shareMemAvailable=3504
 * XfaceOffset: 0x5FF90 => 0x5FF90 ***
 * PhySdramSize got adjusted: 0xC8B38 => 0xFF230 ***

Update Feb 2015
I spent a few weeks reverse engineering this using the DG834G source code (DG834GBv4_V5.01.01_src) and looking at the kernel module (of the DGND3700 and HG612). Looking at the MIPS assembled and disassembled code, most of it was same/very similar as far as I could tell [assume really]. (Just to add to the confusion I initially was comparing with the hd612 'enlargened' code but then did screenshots with the enlargened 3800 code, although it was about the same I think)

Understanding the size definitions
Dump first 32 bye header of the PHY to see the sizes of the lmem and sdram parts.

hexdump -C -n 32 adsl_phy_A2pv6C035m.bin 00000000 41 20 00 00 00 00 00 20  00 00 5f 88 00 00 5f a8  |A ..... .._..._.| 00000010 00 0c 8b 38 00 00 00 00  00 00 00 00 00 00 00 00  |...8............|

0x04	32 bit	lmemImageOffset	[offset of the adsl mips part in the file]	00 00 00 20 0x08	32 bit	lmemImageLen	[length of the adsl mips part]			00 00 5f 88 <	0x5F88 (24456) 0x0c	32 bit	sdramImageOffset	[offset of the shared part in the file]	00 00 5f a8 0x10	32 bit	sdramImageLength	[length of the shared part]		00 0c 8b 38 < aka, *** PhySdramSize got adjusted: 0xC8B38 (822072)

This is the flow in adsldd.ko that controls the PHY loading, as per DG834GBv4_V5.01.01_src source code. Most of the function names are the same. adsl_init (adsldrv.c) [module entrant] BcmAdsl_Initialize (adsl.c) BcmAdslCoreInit (BcmAdslcore.c) [from source comment : called by ADSL driver to init core, ADSL PHY] ADSLCoreInit (Adslcore.c)   AdslCoreHwReset (Adslcore.c) [If true returns *** PhySdramSize got adjusted: 0xXXXXX => 0xXXXXXX ***, this not present in source.] __AdslCoreHwReset (Adslcore.c) [called 3 times in a loop, why failed PHY loading happens thrice, function seems merged in new adsldd.ko] AdslCoreLoadImage (Adslcore.c) [If this returns false it gives error "AdslCoreHwReset: Failed to load ADSL PHY image (0)" AdslFileLoadImage (AdslFile.c) [loads PHY into buffer] [If AdslCoreSetSdramImageAddr returns false, errors "Failed to read SDRAM image from '/etc/adsl/adsl_phy.bin'."] AdslCoreSetSdramImageAddr (Adslcore.c) [Prints 'pSdramPHY=0xA7FFFFF8, 0xXXXX 0xDEADBEEF' if successful.] If above returns true to __AdslCoreHwReset, it then calls AdslCoreSharedMemInit [does calloc] [gived AdslCoreSharedMemInit: shareMemAvailable=xxxxxxxxx]

Call Trace: [ ] AdslFileLoadImage+0x44/0x210 [adsldd] [ ] AdslCoreHwReset+0x518/0xb80 [adsldd] [ ] AdslCoreInit+0x2d8/0x2ec [adsldd] [ ] BcmAdslCoreInit+0x12c/0x1d0 [adsldd] [ ] BcmAdsl_Initialize+0x12c/0x17c [adsldd] [ ] DoInitialize+0xe0/0x150 [adsldd] [ ] adsl_ioctl+0x9c/0xac [adsldd] [ ] vfs_ioctl+0x2d8/0x308 [ ] sys_ioctl+0x50/0x90 [ ] stack_done+0x20/0x3c
 * Note Also while testing something later (by removing the phy altogether when it tried to load) I got this stacktrace of the real thing which is helpful

The nub of the problem is that the space tested for an allocatable is 0xFFFFF, which will load a ~ 850kb PHY, anything newer than 35m is bigger. (you can see only 3504 bytes are free after loading 35m). I never worked out the math behind this. There are various macro defines in the source this could relate to, the most likely seemed to be ADSL_SDRAM_TOTAL_SIZE. Sadly there are also lots of random values in the source that aren't defined as macros relating to god knows what too. This is most obvious function this played a part in is AdslCoreSetSdramImageAddr (as adslCorePhyDesc.sdramPageAddr)

This led to

3 things to patch
Three 32 bit values need to be changed. In MIPS these are done in two steps, high 16 (lui) then low 16 (ori)

(These opcode patch offsets below are relative to the default adsldd.ko [adslddDGND3700.o_save] in the DGND3700)

AdslCoreSetSdramImageAddr
Success: pSdramPHY=0xA7FFFFF8, 0xXXXX 0xDEADBEEF, error causes 'Failed to read SDRAM image from /etc/adsl/adsl_file.bin' in AdslFileLoadImage

New PHY: Reduced threshold value of logic branch from 0x0fffff to 0x0cdfff = 0x3200 = 204800

Error stems from this in Adslfile.c (this is the old DG834g source)

AdslFile.c, Function AdslFileLoadImage pAdslSDRAM = AdslCoreSetSdramImageAddr(((ulong*)pAdslLMem)[2], phyHdr.sdramSize); adslf_lseek(fd, phyHdr.sdramOffset, 0); if (adslf_read(fd, pAdslSDRAM, phyHdr.sdramSize) != phyHdr.sdramSize) { printk("Failed to read SDRAM image from '%s'.\n", fname); adslf_close(fd); return 0; }	adslf_close(fd); set_fs(fs); return phyHdr.lmemSize + phyHdr.sdramSize; } If pAdslSDRAM is returned too small the read will fail to load everything, [phyHdr.sdramSize is read from the adls_phy.bin file header size.]

This is from AdslCore.c void * AdslCoreSetSdramImageAddr(ulong lmem2, ulong sdramSize) {	if (0 == lmem2) { lmem2 = (sdramSize > 0x40000) ? 0x20000 : 0x40000; adslCorePhyDesc.sdramPhyImageAddr = ADSL_PHY_SDRAM_START + lmem2; }	else adslCorePhyDesc.sdramPhyImageAddr = lmem2; lmem2 &= (ADSL_PHY_SDRAM_PAGE_SIZE-1); adslCorePhyDesc.sdramImageAddr = adslCorePhyDesc.sdramPageAddr + lmem2; if ((lmem2 & 0x00FFFFFF) < 0x100000)	/* old 256K PHY over orig. 2M */ adslCorePhyDesc.sdramImageAddr += (0x200000 - 0x80000); adslCorePhyDesc.sdramImageSize = (sdramSize+0xF) & ~0xF; pSdramReserved = (void *) (adslCorePhyDesc.sdramPageAddr + ADSL_PHY_SDRAM_PAGE_SIZE - sizeof(sdramReservedAreaStruct)); AdslDrvPrintf(TEXT("pSdramPHY=0x%X, 0x%X 0x%X\n"), (int) pSdramReserved, pSdramReserved->timeCnt, pSdramReserved->initMark); adslCoreEcUpdateMask = 0;
 * 1) if (ADSL_PHY_SDRAM_PAGE_SIZE == 0x200000)
 * 1) endif

softdsl/AdslCoreDefs.h adslCorePhyDesc.sdramPageAddr = macro ADSL_SDRAM_TOTAL_SIZE
 * 1) define ADSL_SDRAM_TOTAL_SIZE			0x00800000

Looking at the MIPS I can sort of see the change is before and relating to what goes on in the second branch (bne) i.e. "if ((lmem2 & 0x00FFFFFF) < 0x100000)". I presume it revolves around either how lmem2 is being defined above it or altering what equates to 0x100000 in the old source? I cant get my head round what is actually happening. Is it perhaps ADSL_SDRAM_TOTAL_SIZE being altered which is changing lmem2?





Opcode change

00003ca4 3c 02 00 0f 34 42 ff ff  00003ca4  3c 02 00 0c 34 42 df ff
 * 1) from
 * to

Patch

echo 'Patch adsldd.ko AdslCoreSetSdramImageAddr lets it load the SDRAM phy in the firstplace, else error Failed to read SDRAM image from..' printf '\x00\x0c' | dd of="$ROOT/DGND3700/bcmdrivers/broadcom/char/adsl/impl1/adslddDGND3700.o_save" bs=1 seek=$((0x3ca6)) count=2 conv=notrunc printf '\xdf\xff' | dd of="$ROOT/DGND3700/bcmdrivers/broadcom/char/adsl/impl1/adslddDGND3700.o_save" bs=1 seek=$((0x3caa)) count=2 conv=notrunc

AdslCoreHWReset
Performs: *** PhySdramSize got adjusted: 0xXXXXX => 0xXXXXXX ***

New PHY: Space to load in is approx doubled up from 0xfffff to 0x1fffff = 0x100000 = 1048576

The source code for this looks different (all this stuff is in __AdslCoreHwReset in the source in fact) and I found this initialy by looking for the opcodes as changed in the AdslCoreSharedMemInit alteration, then double checking by comparing the original and HG612 PHY. This is the vaguest of the changes.





Note the new code adds 0x200000 into the mix over the old code, not sure what this is doing.

Opcode change

00006818 3c 02 00 0f 34 42 ff ff 00006818  3c 02 00 1f 34 42 ff ff
 * 1) from
 * to

Patch

echo 'Patch adsldd.ko AdslCoreHWReset - responsible for allowing PhySdramSize got adjusted.' printf '\x00\x1f' | dd of="$ROOT/DGND3700/bcmdrivers/broadcom/char/adsl/impl1/adslddDGND3700.o_save" bs=1 seek=$((0x681a)) count=2 conv=notrunc

AdslCoreSharedMemInit
Performs: AdslCoreSharedMemInit: shareMemAvailable=xxxxxxxxx

Without this you will get negative values like AdslCoreSharedMemInit: shareMemAvailable=-119168

New PHY: Space to load in is approx doubled up from 0xfffe0 to 0x1fffff = 0x10001f = 1048607

AdslCore.c
 * 1) define ADSL_PHY_SDRAM_SHARED_START		(adslCorePhyDesc.sdramPageAddr + ADSL_PHY_SDRAM_PAGE_SIZE - ADSL_SDRAM_RESERVED)

int	adslPhyShareMemIsCalloc		= 0; int	adslPhyShareMemSizeAllow		= 0; void * adslPhyShareMemStart			= NULL;
 * 1) define SHARE_MEM_REQUIRE 			2048	/* 936 bytes worst case, but will use 2KB */

void AdslCoreSharedMemInit(void) {	int shareMemAvailable = ADSL_SDRAM_IMAGE_SIZE - ADSL_SDRAM_RESERVED - AdslCoreGetSdramImageSize; if( adslPhyShareMemIsCalloc == 0 ) { /* If calloc earlier, then will continure to use it; might be from Diags download */ if( shareMemAvailable < SHARE_MEM_REQUIRE ) { adslPhyShareMemStart = calloc(1,SHARE_MEM_REQUIRE); adslPhyShareMemStart = (void *)(0xA0000000 | ((ulong)adslPhyShareMemStart + SHARE_MEM_REQUIRE)); adslPhyShareMemIsCalloc = 1; adslPhyShareMemSizeAllow = SHARE_MEM_REQUIRE; }		else { adslPhyShareMemStart = (void *) ADSL_PHY_SDRAM_SHARED_START; adslPhyShareMemSizeAllow = shareMemAvailable; }			}

pAdslSharedMemAlloc = adslPhyShareMemStart; }

This allocates the memory it loads the phy into, I couldn't follow this either but it seems likely if enough isn't allocated it cant load! You would think ADSL_SDRAM_RESERVED is the likely thing altered but seems defined as '32' which seems very odd? I assume the value of 'int shareMemAvailable' is what is being edited here.

AdslCore.c
 * 1) define			ADSL_SDRAM_RESERVED			32

The other possibility maybe from ADSL_SDRAM_IMAGE_SIZE, but the page size and bias I think are the same. Odd. softdsl/AdslCoreDefs.h:#define ADSL_SDRAM_IMAGE_SIZE			(ADSL_PHY_SDRAM_PAGE_SIZE - ADSL_PHY_SDRAM_BIAS) softdsl/AdslCoreDefs.h:#define ADSL_SDRAM_IMAGE_SIZE			(256*1024) AdslCore.c:	int shareMemAvailable = ADSL_SDRAM_IMAGE_SIZE - ADSL_SDRAM_RESERVED - AdslCoreGetSdramImageSize; The change seemed the only obvious difference in the function comparing the mips code.





Note the new code adds 0x200000 into the mix over the old code, not sure what this is doing.

Opcode change

00003e24 3c 02 00 0f 34 42 ff e0 00003e24  3c 02 00 1f 34 42 ff ff
 * 1) from
 * to

Patch echo 'Patch adsldd.ko AdslCoreSharedMemInit does AdslCoreSharedMemInit: shareMemAvailable increase.' printf '\x00\x1f' | dd of="$ROOT/DGND3700/bcmdrivers/broadcom/char/adsl/impl1/adslddDGND3700.o_save" bs=1 seek=$((0x3e26)) count=2 conv=notrunc printf '\xff\xff' | dd of="$ROOT/DGND3700/bcmdrivers/broadcom/char/adsl/impl1/adslddDGND3700.o_save" bs=1 seek=$((0x3e2a)) count=2 conv=notrunc

Outcome
Although the PHY would then load, it caused kernel to crash when xdslctl starts, DOH!

I sort of gave up on that and took another approach after finding the new DGND3800 kernel moule was already 'enlargened'. I had to 'fix' (hexed it to point at vprintf instead, cough) an unamed symbol error and then this promptly did exactly the same thing qhwn xdslctl started!...so maybe my fixes had worked afterall.

=Comments=