FreeCalypso > hg > freecalypso-reveng
comparison mpffs/Description @ 28:c9f7a4afccc9
Mokopir-FFS: verbal description finished
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sun, 30 Jun 2013 04:15:00 +0000 |
parents | 343b6b2f178b |
children | 86a494a5f2b0 |
comparison
equal
deleted
inserted
replaced
27:343b6b2f178b | 28:c9f7a4afccc9 |
---|---|
58 and the exact binary byte content of all files contained therein. | 58 and the exact binary byte content of all files contained therein. |
59 | 59 |
60 However, the knowledge possessed by the present hacker (and conveyed in this | 60 However, the knowledge possessed by the present hacker (and conveyed in this |
61 document and the accompanying source code) is NOT sufficient for constructing a | 61 document and the accompanying source code) is NOT sufficient for constructing a |
62 valid Mokopir-FFS image "in vitro" given a tree of directories and files, or | 62 valid Mokopir-FFS image "in vitro" given a tree of directories and files, or |
63 for making modifications to the file or directory content on an existing image | 63 for making modifications to the file or directory content of an existing image |
64 and producing a content-modified image that is also valid; valid as in suitable | 64 and producing a content-modified image that is also valid; valid as in suitable |
65 for the original proprietary firmware to make its normal read and write | 65 for the original proprietary firmware to make its normal read and write |
66 operations without noticing anything amiss. | 66 operations without noticing anything amiss. |
67 | 67 |
68 Constructing "de novo" Mokopir-FFS images or modifying existing images in such | 68 Constructing "de novo" Mokopir-FFS images or modifying existing images in such |
69 a way that they remain 100% valid for all read and write operations of the | 69 a way that they remain 100% valid for all read and write operations of the |
70 original proprietary firmware would, at the very minimum, require an | 70 original proprietary firmware would, at the very minimum, require an |
71 understanding of the meaning of *all* fields on the on-media FFS format. Some | 71 understanding of the meaning of *all* fields of the on-media FFS format. Some |
72 of these fields are still left as "non-understood" for now though: a read-only | 72 of these fields are still left as "non-understood" for now though: a read-only |
73 implementation can get away with simply ignoring them, but a writer/generator | 73 implementation can get away with simply ignoring them, but a writer/generator |
74 would have to put *something* in those fields. | 74 would have to put *something* in those fields. |
75 | 75 |
76 As you read the "read-only" description of the Mokopir-FFS on-media format in | 76 As you read the "read-only" description of the Mokopir-FFS on-media format in |
228 name of the directory itself, padded with FFs to a 16-byte boundary. For | 228 name of the directory itself, padded with FFs to a 16-byte boundary. For |
229 example, an FFS directory named /gsm would be represented by an object | 229 example, an FFS directory named /gsm would be represented by an object |
230 consisting of two flash writes: a 16-byte entry in the active index block, with | 230 consisting of two flash writes: a 16-byte entry in the active index block, with |
231 the object type byte set to F2, and a corresponding 16-byte chunk in one of the | 231 the object type byte set to F2, and a corresponding 16-byte chunk in one of the |
232 data sectors, with the 16 bytes containing "gsm", a terminating NUL byte, and | 232 data sectors, with the 16 bytes containing "gsm", a terminating NUL byte, and |
233 12 FF bytes to pad up to 16. In the case of files, this name may be following | 233 12 FF bytes to pad up to 16. In the case of files, this name may be followed |
234 by the first chunk of file data content, as explained further down. | 234 by the first chunk of file data content, as explained further down. |
235 | 235 |
236 In order to parse the FFS directory tree (whether the objective is to dump the | 236 In order to parse the FFS directory tree (whether the objective is to dump the |
237 whole thing recursively or to find a specific file given a pathname), one needs | 237 whole thing recursively or to find a specific file given a pathname), one needs |
238 to first (well, after finding the active AB block) find the root directory node. | 238 to first (well, after finding the active AB block) find the root directory node. |
276 chunks to a new flash sector, invalidating the old copies - turning the latter | 276 chunks to a new flash sector, invalidating the old copies - turning the latter |
277 into deleted objects. The root node will be among them. Then at some point | 277 into deleted objects. The root node will be among them. Then at some point |
278 the active index block is going to fill up too, and will need to be rewritten | 278 the active index block is going to fill up too, and will need to be rewritten |
279 into a new sector - at which point the previously-deleted index entries are | 279 into a new sector - at which point the previously-deleted index entries are |
280 omitted and the root node becomes #1 again...] | 280 omitted and the root node becomes #1 again...] |
281 | |
282 Tree structure | |
283 | |
284 Once the root node has been found, the descendant and sibling pointers are used | |
285 to traverse the tree structure. For each directory object, including the root | |
286 node, the descendant pointer points to the first child object of this directory: | |
287 the first file or subdirectory contained therein. (Descendant and sibling | |
288 pointers take the form of index numbers in the active index block. A "nil" | |
289 pointer is indicated by all 1s (FFFF) - the usual all-0s NULL pointer convention | |
290 couldn't be used because it's flash, where the blank state is all 1s.) If the | |
291 descendant pointer of a directory object is nil, that means an empty directory. | |
292 The sibling pointer of each file or directory points to its next sibling, i.e., | |
293 the next member of the same parent directory. The sibling pointer of the root | |
294 node is nil. | |
295 | |
296 Data content of files | |
297 | |
298 Objects of type F1 are the head chunks of files. Each file has a head chunk, | |
299 and may or may not have continuation chunks. More precisely, the head chunk | |
300 may contain only the name (or viewed alternatively, 0 bytes of data), or it may | |
301 contain a nonzero number of payload bytes; orthogonally to this variability, | |
302 there may or may not be continuation chunk(s) present. | |
303 | |
304 Continuation chunks | |
305 | |
306 The descendant pointer of each file head object (the object of type F1, the one | |
307 reached by traversing the directory tree) indicates whether or not there are | |
308 any continuation chunks present. If this descendant pointer is nil, there are | |
309 no continuation chunks; otherwise it points to the first continuation chunk | |
310 object. File continuation objects have type F4, don't have any siblings (the | |
311 sibling pointer is nil), and the descendant pointer of each continuation object | |
312 points to the next continuation object, if there is one - nil otherwise. | |
313 | |
314 Payload data delineation | |
315 | |
316 Each chunk, whether head or continuation, always has a length that is a nonzero | |
317 multiple of 16 bytes. The length of the chunk here means the amount of flash | |
318 space it occupies in its data sector - which is NOT equal to the payload data | |
319 length. | |
320 | |
321 The head chunk of each file begins with the filename, terminated by a NUL byte. | |
322 If there are any payload data bytes present in this head chunk (I'll explain | |
323 momentarily how you would tell), the byte immediately after the NUL that | |
324 terminates the filename is the first byte of the payload. In the case of a | |
325 continuation chunk, there is no filename and the first byte of the chunk is the | |
326 first byte of that chunk's portion of the user data payload. | |
327 | |
328 Each data-containing chunk (head or continuation) has the following termination | |
329 after the last byte of that chunk's payload data: one byte of 00, followed by | |
330 however many bytes are needed ([0,15] range) of FFs to pad to a 16-byte | |
331 boundary. A file head chunk that has no payload data has the same format as a | |
332 directory name chunk: filename followed by its terminating NUL followed by | |
333 [0,15] bytes of FFs to pad to the next 16-byte boundary. | |
334 | |
335 When working with a head chunk, find the beginning of possible payload data (1 | |
336 byte after the filename terminating NUL) and find the end per the standard | |
337 termination logic: scanning from the end of the chunk, skip FFs until 00 is | |
338 found (encountering anything else is an error). If the head chunk has no data, | |
339 the effective data length (end_pointer - start_pointer) will be 0 or -1. (The | |
340 latter possibility is the most likely, as there will normally be a "shared" 00 | |
341 byte, serving as both the filename terminator and the 00 before the padding | |
342 FF bytes.) | |
343 | |
344 ------------------------------------------------------------------------------- | |
345 | |
346 That's all I can think of right now. If anything is unclear, see the | |
347 accompanying source code for the listing/extraction utilities: with the general | |
348 explanation given by this document, it should be clear what my code does and | |
349 why. And if a given piece of knowledge is found neither in this document nor | |
350 in my source code, then I don't know it myself either, and my read-only | |
351 Mokopir-FFS implementation makes do without it. | |
352 | |
353 All knowledge contained herein has been recovered by reverse engineering. | |
354 Believe it or not, I have figured it out by staring at the hex dump of FFS | |
355 sectors, reasoning about how one could possibly implement an FFS given the | |
356 requirement of dynamic writability and the physical constraints of flash memory, | |
357 and writing listing/extraction test code iteratively until I got something that | |
358 appears to correctly parse all FFS images available to me - the result is the | |
359 code in this package. | |
360 | |
361 I never got as far as attempting to locate the FFS implementation routines | |
362 within the proprietary firmware binary code images, and I most certainly don't | |
363 have anything from TI that would help in this case. (The TSM30 code doesn't | |
364 seem to be of any use as its FFS appears to be totally different, and I haven't | |
365 looked at the FFS code in the more recently found LoCosto code leak because I | |
366 assumed from the documentation in the latter that the FFS implemented there is | |
367 different as well.) | |
368 | |
369 Michael Spacefalcon | |
370 SE 52 Mes 11 |