FreeCalypso > hg > freecalypso-reveng
comparison mpffs/Description @ 41:86a494a5f2b0
MPFFS description: documented relocated chunks and the journal file
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Fri, 05 Jul 2013 03:26:06 +0000 |
parents | c9f7a4afccc9 |
children |
comparison
equal
deleted
inserted
replaced
40:7ceab8bfacb3 | 41:86a494a5f2b0 |
---|---|
4 "proper" name for this FFS, and needing _some_ identifier to refer to it, I | 4 "proper" name for this FFS, and needing _some_ identifier to refer to it, I |
5 have named it Mokopir-FFS, from "Moko" and "Pirelli" - sometimes abbreviated | 5 have named it Mokopir-FFS, from "Moko" and "Pirelli" - sometimes abbreviated |
6 further to MPFFS. | 6 further to MPFFS. |
7 | 7 |
8 (I have previously called the FFS in question MysteryFFS; but now that I've | 8 (I have previously called the FFS in question MysteryFFS; but now that I've |
9 successfully reverse-engineered it, it isn't such a mystery any more :-) | 9 successfully reverse-engineered it, it isn't as much of a mystery any more :-) |
10 | 10 |
11 At a high functional level, Mokopir-FFS presents the following features: | 11 At a high functional level, Mokopir-FFS presents the following features: |
12 | 12 |
13 * Has a directory tree structure like UNIX file systems; | 13 * Has a directory tree structure like UNIX file systems; |
14 | 14 |
306 The descendant pointer of each file head object (the object of type F1, the one | 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 | 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 | 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 | 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 | 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 | 311 sibling pointer is nil - but see below regarding relocated chunks), and the |
312 points to the next continuation object, if there is one - nil otherwise. | 312 descendant pointer of each continuation object points to the next continuation |
313 object, if there is one - nil otherwise. | |
313 | 314 |
314 Payload data delineation | 315 Payload data delineation |
315 | 316 |
316 Each chunk, whether head or continuation, always has a length that is a nonzero | 317 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 multiple of 16 bytes. The length of the chunk here means the amount of flash |
339 the effective data length (end_pointer - start_pointer) will be 0 or -1. (The | 340 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 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 byte, serving as both the filename terminator and the 00 before the padding |
342 FF bytes.) | 343 FF bytes.) |
343 | 344 |
345 Relocated chunks | |
346 | |
347 Let's go back to the scenario in which a particular data sector is full (no more | |
348 usable free space left) and contains a mixture of active and dirty (deleted or | |
349 invalidated) data. How does the dirty flash space get reclaimed, so that the | |
350 amount of available space (blank flash ready to hold new data) becomes equal to | |
351 the total FFS size minus the total size of active files and overhead? It can | |
352 only be done by relocating the still-active objects from the full sector to a | |
353 new one, invalidating the old copies, and once the old sector consists of | |
354 nothing but invalidated data, subjecting it to flash erasure. | |
355 | |
356 So how do the active FFS objects get relocated from a "condemned" sector to a | |
357 new one? If the object is a directory, a new index entry is created, pointing | |
358 to the newly relocated name chunk, but it is then made to fit into the old tree | |
359 structure without disrupting the latter: the new index entry is added at the | |
360 tail of the sibling-chain of the parent directory's descendants, the old index | |
361 entry for the same directory is invalidated (as if the directory were rmdir'ed), | |
362 and the descendant pointer of the newly written index entry is set to a copy of | |
363 the descendant pointer from the old index entry for the same directory. The | |
364 same approach is used when the head chunk of a file needs to be relocated; in | |
365 both cases a read-only FFS implementation doesn't need to do anything special to | |
366 support reading file and directory objects that have been relocated in this | |
367 manner. | |
368 | |
369 However, if the relocated object is a file continuation chunk, then the manner | |
370 in which such objects get relocated does affect file reading code. What if a | |
371 chunk in the middle of a chain linked by "descend" pointers needs to be moved? | |
372 What happens in this case is that the old copy of the chunk gets invalidated | |
373 (the object type byte turned to 00) like in the other object relocating cases, | |
374 and the sibling pointer of that old index entry (which was originally FFFF as | |
375 continuation objects have no siblings) is set to point to the new index entry | |
376 for the same chunk. The "descend" pointer in the new index entry is a copy of | |
377 that pointer from the old index entry. | |
378 | |
379 The manner of chunk relocation just described has been observed in the FFS | |
380 images read out of my most recent batch of Pirelli phones - the same ones in | |
381 which the root directory object is not at index #1. Thinking about it as I | |
382 write this, I've realized that the way in which continuation objects get | |
383 relocated is exactly the same as for other object types - thus the compaction | |
384 code in the firmware doesn't need to examine what object type it is moving. | |
385 However, the case of continuation chunk relocation deserves special attention | |
386 because it affects a read-only implementation like ours - the utilities whose | |
387 source accompanies this document used to fail on these FFS images until I | |
388 implemented the following additional handling: | |
389 | |
390 When following the chunk chain of a file, normally the only object type that's | |
391 expected is F4 - any other object type is an error. However, as a result of | |
392 chunk relocation, one can also encounter deleted objects, i.e., type == 00. | |
393 If such a deleted object is encountered, follow its sibling pointer, which must | |
394 be non-nil. | |
395 | |
396 Journal file | |
397 | |
398 Every Mokopir-FFS image I've seen so far contains a special file named | |
399 /.journal; this file is special in the following ways: | |
400 | |
401 * The object type byte is E1 instead of F1; | |
402 * Unlike regular files, this special file is internally-writable. | |
403 | |
404 What I mean by the above is that regular files are mostly immutable: once a | |
405 file has been created with some data content in the head chunk, it can only be | |
406 either appended to (one or more continuation chunks added), or overwritten by | |
407 creating a new file with the same name at the same level in the tree hierarchy | |
408 and invalidating the old one. But the special /.journal file is different: I | |
409 have never observed it to consist of more than the head chunk, and this head | |
410 chunk is pre-allocated with some largish and apparently fixed length (4 KiB on | |
411 my GTA02, 16 KiB on the Pirelli). This pre-allocated chunk contains what look | |
412 like 16-byte records at the beginning (on the first 4-byte boundary after the | |
413 NUL terminating the ".journal" name), followed by blank flash for the remainder | |
414 of the pre-allocated chunk - so it surely looks like new flash writes happen | |
415 within this chunk. | |
416 | |
417 I do not currently know the purpose of this /.journal file or the meaning of the | |
418 records it seems to contain. This understanding would surely be needed if one | |
419 wanted to create FFS images from scratch or to implement FFS write operations, | |
420 but I reason that a read-only implementation can get away with simply ignoring | |
421 this file. I reason that this file can't be necessary in order to parse an FFS | |
422 image for reading because one needs to parse the tree structure first in order | |
423 to locate this journal file itself. | |
424 | |
344 ------------------------------------------------------------------------------- | 425 ------------------------------------------------------------------------------- |
345 | 426 |
346 That's all I can think of right now. If anything is unclear, see the | 427 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 | 428 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 | 429 explanation given by this document, it should be clear what my code does and |
357 and writing listing/extraction test code iteratively until I got something that | 438 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 | 439 appears to correctly parse all FFS images available to me - the result is the |
359 code in this package. | 440 code in this package. |
360 | 441 |
361 I never got as far as attempting to locate the FFS implementation routines | 442 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 | 443 within the proprietary firmware binary code images, and I haven't found an |
363 have anything from TI that would help in this case. (The TSM30 code doesn't | 444 implementation of this particular FFS in any of the leaked sources yet either. |
364 seem to be of any use as its FFS appears to be totally different, and I haven't | 445 The TSM30 code doesn't seem to be of any use as its FFS appears to be totally |
365 looked at the FFS code in the more recently found LoCosto code leak because I | 446 different. As to the more recently found LoCosto code leak, I found that one a |
366 assumed from the documentation in the latter that the FFS implemented there is | 447 few days *after* I got the Moko/Pirelli "MysteryFFS" reverse-engineered on my |
367 different as well.) | 448 own, and when I did look at the FFS in the LoCosto code later, I saw what seems |
449 to be a different FFS as well. | |
368 | 450 |
369 Michael Spacefalcon | 451 Michael Spacefalcon |
370 SE 52 Mes 11 | 452 SE 52 Mes 16 |