Sansa AMS Porting Status

Firmware recovery procedures have been found on the e200, but no other AMS device yet, however some buttons have been enabled allowing edited firmware to be carefully loaded.

As raised on the forums, it could probably be possible to create a development firmware replacing the Firmware block (block 1) in a first pass, thus allowing development without completely understanding library and resource blocks. To be confirmed.

Overview

All AMS devices use the same SoC as their main processing unit: the AS3525.

The AMS firmware file is divided in a bunch of blocks. The M200v2 v4.1.08A firmware has been used for analysis, but it seems that the file format is (almost) the same for other models.

In the M200 firmware, there seem to be 32 blocks. The following table shows the firmware file blocks details for that specific firmware version:

Blocks Description

This section describes the actual firmware file blocks.

Every block has fixed length, but the effective code or data it contains can be smaller than this. There are 2 different padding types used in the firmware file: 0xFF paddings and 0xDEADBEEF paddings. Every byte following the effective block length is padded as 0xFF up to a 0x200 size boundary. Starting from that boundary up to the complete block size, 0xDEADBEEF padding is used.

Firmware Header (Block 0)

The firmware header is present at the very beginning of the firmware file. Numbers are represented in little endian. There are only 2 structures in this header, the first one being at 0x00000000, and the second one at 0x00000200. The second one is a mirror on the first one with a single exception, the FWHeaderIndex field is 1 while it was 0 in the first copy. The FirmwareHeader structure is as follow:

Number that, multiplied by 0x200, gives the size of the main firmware block

0x0C

4

FirmwareSize

Effective size of the firmware block

Effective size of the firmware block

0x10

4

Unknown1

3

Still unknown

0x14

1

Unknown2

Variable

Still unknown

0x15

1

ModelId

0x22: Clip, 0x23: C200, 0x24: E200, 0x1e: Fuze, 0x25: M200

Sansa model identifier

0x16

2

Zero

0

Unknown, but seems to always be 0

0x18

4

FourthyHex

0x40

Unknown, but seems to always be 0x40

0x1C

4

One

1

Unknown, but seems to always be 1

0x3C

4

FiveThousandHex

0x5000

Unknown, but present in the E200 firmwares only. Seems to always be 0x5000

Every byte not included in the above structure is 0xFF.

Firmware (Block 1)

The firmware block is the block that is loaded at address 0x00000000 in ROM/FLASH/whatever non-volatile memory in the device. The actual code hasn't been thoroughly analyzed, but we can deduce that it contains all the code needed for the device operation, except for specific libraries contained in library blocks.

It seems that the Firmware block actually contains the usual ARM vector table right off at the block's beginning (0x400 offset from beginning of firmware file). In the M200 firmware, only the reset, IRQ and FIQ seems to be handled though. The reserved vector is simply a NOP, while all the (four) others are simply infinite loops, so if they ever happen, the device is frozen. The following table shows the vector table of the specific analyzed firmware file:

Resources (Block 20 to 26)

These blocks are still mostly misunderstood, but they seems to contain various resources (localized strings, etc.). Resource blocks size is understood to be the next 0x200 bytes boundary after the block effective size. For example, a resource block with an effective size of 0x1234 would end 0x1400 bytes after the block beginning.

Whole-file checksum

In addition to the checksums in the Firmware Header, the last four bytes of the firmware file contains a whole-file checksum. This checksum is not present in the M200 firmware.

This is simply calculated as a 32-bit sum of all the 32-bit words in the firmware file, excluding the last four bytes.

Firmware Comprehension (M200 V2 series, 4.1.8a specific revision)

Form what we understand, the firmware file is directly loaded into ROM/FLASH/whatever and is booted directly by the uC. There is, however, one little thing. The firmware file as download by the sansa updater contains a firmware header which seems to be discarded when loaded into the non-volatile memory. So in fact, every addresses in there are relocated by 0x400 bytes. It also seems that only the first block (up to 0x1CC00) is loaded into non-volatile memory at first, then other blocks are loaded by the firmware at will.

All addresses referred in here are "true" firmware addresses, that is with the 0x400 bytes header removed. The first thing you should do to analyze the firmware is to discard the first 0x400 bytes and everything after 0x1C6AC (which is after the effective firmware instructions and data).

int strncmp(char *s1, char *s2, int n)

There is function at 0x0011668 that compares two strings up to a specific number of characters. Its signature looks like it is an implementation of the well-known strncmp function. It is frequently used to compare a string with predefined "library names" strings, and as expected, n in those cases is 11 (or 0xB) as is the length of those "library names". An usage example can be seen at 0x000078E4.

File type recognition

There is a very interesting function at 0x00010A08 which seems to recognize the audio file type and load the appropriate decoder for it.

[graph to be done]

Library block loading

At 0x0000782C, there is a function (that is called from the file type recognition function) that seems to dynamically load a library block in memory at a specified address, with specified length, etc. At 0x00007852, there is a comparison with 18 (or 0x12) which is also one more than the number of library blocks in the firmware file. Coincidence? Probably not...

At 0x00007882, there is a function call to 0x00007440, which seems to be a sub-function of the loading function. It is interesting to note that in this sub-function, there is a call to 0x00007364 which directly exposes a parameter value of 0x1E000, which is the library blocks size. In this same sub-function (0x00007440), there is calls at 0x00007498 and 0x000074C4 to a function at 0x00011878 which is evidently a block copy routine with the following signature: void block_copy(void *dest, void *src, int size).

For the records, there also seems to be some sort of critical region or something like that in this function, which is protected with the use of a particular variable stored 0x1F840. This is to be verified though.

[graph to be done]

Firmware naming conventions

The name of the firmware file affects the functionality of the device, for example flashing the Sansa Clip with a firmware renamed from m300f.bin to m300t.bin enables extra functionality like more languages and a diagnosis mode.

More information is available here in the sansa AMS thread.
See also this thread on the anythingbutipod forums.