The Rockbox Sansa AMS Firmware
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:
Block Index |
Address |
Description |
0 |
0x000000 |
Firmware header |
1 |
0x000400 |
Main firmware |
2 to 18 |
0x400 + (Index * 0x1E000) |
Library blocks |
19 |
0x21AC00 |
Empty library block (filled with 0xFF) |
20 to 26 |
Unregular, read below |
Resource blocks |
27 |
0x4D5400 |
Empty resource block (filled with DEADBEEF) |
28 |
0x4D5600 |
Unknown data block |
29 |
0x4D5800 |
Unknown data block 2 (only contains 0xDF0 at 0x4D5800) |
30 |
0x4D5A00 |
Unicode certificate data |
31 |
0x4D6800 |
Empty ending block (filled with DEADBEEF) |
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:
Structure Offset |
Size |
Name |
Value |
Description |
0x00 |
4 |
FirmwareHeaderIndex |
0 for the first copy, 1 for the second |
FirmwareHeader structure index |
0x04 |
4 |
FirmwareChecksum |
Sum of all dwords present in block 1 effective section |
Firmware checksum |
0x08 |
4 |
FirmwareBlockSizeMultiplier |
0xE4, 0xE8, 0xEA, 0xEC, 0xED, or 0xF0 |
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:
Address |
Function |
Handler summary |
0x400 |
Reset |
Main code at 0x4B8 |
0x404 |
Undefined instruction |
Infinite loop |
0x408 |
Software Interrupt |
Infinite loop |
0x40C |
Prefetch Abort |
Infinite loop |
0x410 |
Data Abort |
Infinite loop |
0x414 |
Reserved |
NOP, effectively calling the IRQ handler |
0x418 |
Interrupt Request |
Interrupt handler at 0x8468 |
0x41C |
Fast Interrupt Request |
Interrupt handler at 0x8468 |
In short, this is a "standard" image file for a processor to execute.
Libraries (Block 2 to 18)
The following table describes the library blocks header (offsets are relative to each block base address):
Offset |
Value(s) |
Description |
0x00 |
LibraryName |
Offset to the library name |
0x04 |
LibraryBaseAddress |
Base address of the library |
0x08 |
LibraryEndAddress |
Seems to be the library end address, but seems to include extra space(?) |
0x0C |
LibraryBlockSize |
Size of effective data in this block |
0x10 |
Unknown1 |
Still unknown. Needed space for variables? |
0x14 |
ExportCount |
Number of publicly exported functions |
0x18 |
Exports |
An array of ExportCount addresses which points to library functions |
The 17 library blocks from the M200 firmware are tagged with the following "library names":
Block Index |
Library Name |
2 |
usb_functio |
3 |
mp3_decoder |
4 |
otg_functio |
5 |
wav_codec |
6 |
acp_decoder |
7 |
aud_decoder |
8 |
drm10_nonpk |
9 |
drm10_pkcpt |
10 |
drm10__Init |
11 |
wma_decoder |
12 |
wma_decInit |
13 |
wma_decPlay |
14 |
drm10_InitT |
15 |
drm10_host_ |
16 |
wmaPDDRMini |
17 |
wmaPDDRMper |
18 |
sd_reload__ |
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.
The resource blocks have the following header:
Offset |
Value(s) |
Description |
0x00 |
ResourceBlockSize |
Size of effective data in this block |
0x04 |
ResourceId |
The more plausible signification is a resource ID number |
0x08 |
"HEADER" |
The "HEADER" ascii string |
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).
GPIOs Usage
This is, in the firmware, all known GPIOs usage:
GPIO |
Usage |
A0 |
Keypad pattern scanner input |
A1 |
Keypad pattern scanner input |
A2 |
Keypad pattern scanner input |
A3 |
Keypad pattern scanner input |
A4 |
Keypad pattern scanner output |
A5 |
Keypad pattern scanner output |
A6 |
Keypad pattern scanner output |
A7 |
Keypad pattern scanner output |
B0 |
DBOP (LCD display) |
B1 |
DBOP (LCD display) |
B2 |
DBOP (LCD display) |
B3 |
DBOP (LCD display) |
B4 |
Output in some LCD display routines |
B6 |
Output in the routine at 0x00006B38 |
C0 |
DBOP (LCD display) |
C1 |
DBOP (LCD display), but also used as an input in 0x00006B38 before being used in LCD display routines |
C2 |
DBOP (LCD display) |
C3 |
DBOP (LCD display) |
C4 |
DBOP (LCD display) |
C5 |
DBOP (LCD display) |
C6 |
DBOP (LCD display) |
C7 |
DBOP (LCD display) |
D1 |
Output in some LCD display routines |
D3 |
Output in some LCD display routines |
Interrupt Handlers
Reset Handler
The reset handler is located at 0x000000B8 in the firmware. It is quite simple and does the following:
DirectedGraph Error (25): *DirectedGraphPlugin error:* $GV_FILE_PATH environment variable set; exiting
01:
02: This sandboxing mechanism is no longer supported
03: Problem executing /usr/bin/dot: '/usr/bin/dot /home/rockbox/foswiki/working/tmp/DiGraphPluginS1KRp12CKq.dot -Tcmapx -o/home/rockbox/foswiki/working/tmp/DGP61bfOiach8.cmapx -Tpng -o/home/rockbox/foswiki/working/tmp/DGP4drkp9thfs.png 2> /home/rockbox/foswiki/working/tmp/DiGraphPluginS1KRp12CKq.dot.err ', got:
04: /usr/bin/dot exited with rc=1
05:
IRQ Handler
The IRQ handler, in the M200 firmware, is called for both the IRQ and FIQ interrupts. It is located at 0x00008068 and does the following:
DirectedGraph Error (25): *DirectedGraphPlugin error:* $GV_FILE_PATH environment variable set; exiting
01:
02: This sandboxing mechanism is no longer supported
03: Problem executing /usr/bin/dot: '/usr/bin/dot /home/rockbox/foswiki/working/tmp/DiGraphPluginN0PFoNHApC.dot -Tcmapx -o/home/rockbox/foswiki/working/tmp/DGPHxThN2sYXT.cmapx -Tpng -o/home/rockbox/foswiki/working/tmp/DGPhkUv1Pe0Nv.png 2> /home/rockbox/foswiki/working/tmp/DiGraphPluginN0PFoNHApC.dot.err ', got:
04: /usr/bin/dot exited with rc=1
05:
Functions
void main(void)
The main function (which is located at 0x0000019C) is as follow:
DirectedGraph Error (25): *DirectedGraphPlugin error:* $GV_FILE_PATH environment variable set; exiting
01:
02: This sandboxing mechanism is no longer supported
03: Problem executing /usr/bin/dot: '/usr/bin/dot /home/rockbox/foswiki/working/tmp/DiGraphPluginUSuH4WWXXt.dot -Tcmapx -o/home/rockbox/foswiki/working/tmp/DGPDB4BhA_3hp.cmapx -Tpng -o/home/rockbox/foswiki/working/tmp/DGPwt2W8gXXPG.png 2> /home/rockbox/foswiki/working/tmp/DiGraphPluginUSuH4WWXXt.dot.err ', got:
04: /usr/bin/dot exited with rc=1
05:
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.
References and Links
Copyright © by the contributing authors.