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 |
