- See also: Hardware/NAND Interface
| This article may require cleanup to meet WiiBrew's quality standards.
Reason: Needs cleanup
The Wii contains 512 MiB of NAND flash storage, which is used to store "system software", channels (including Virtual Console titles), game saves, and system settings.
The NAND flash device is divided into 4096 blocks of 8 clusters. Each cluster is 8 pages. Each page is 2048 bytes of data and 64 bytes of "spare data" (used for error-correction (ECC) data and HMAC signatures on individual clusters).
- Block 0 (pages 0-0x3F): boot1
- Blocks 1-7 (Pages 0x40 - 0x1ff) : boot2 (two copies and blockmaps)
- boot2 is the third-stage bootloader; it is stored in a modified WAD format, including a ticket that is encrypted with the common key and signed.
- Block 8 / Cluster 0x40 / Page 0x200: beginning of per-console unique data
- Clusters 0x40 - 0x7EFF: Encrypted filesystem data. Data is encrypted with a per-console AES key, and then signed with a (separate, per-console) HMAC key.
- Clusters 0x7F00-0x7FFF: Filesystem metadata (SFFS, unencrypted). There are 16 superblocks contained therein — one every 16 clusters.
The authoritative source of information about the Wii's metadata layout is Segher's zestig.c, but here is an attempt to describe that in English.
Each metadata "superblock" starts with the 4 magic bytes "SFFS", followed by a 4-byte "generation number" and another 4-byte number (always 0x10?). When accessing the FS, IOS will choose the superblock with the highest generation number and use it; whenever it modifies the filesystem in any way, it will increment the generation number by 1 and write out an entirely new superblock in the next slot (in round-robin order).
The next 0x10000 bytes (bytes 0xc:0x1000c within the superblock) are 0x8000 2-byte cluster numbers, and comprise the FAT. The FAT is followed by the FST — the tree structure containing the directory hierarchy and (plaintext!) filenames.
The FAT contains cluster chain / allocation information for the entire NAND chip, including parts of it which are not technically part of the filesystem!
The first 64 entries will always be 0xFFFC, which indicates that this cluster is "reserved". These correspond to the first 64 clusters or 8 blocks — which is where boot1 and boot2 are stored.
Special values include:
- 0xFFFB - last cluster within a chain
- 0xFFFC - reserved cluster
- 0xFFFD - bad block (marked at factory) — you should always see these in groups of 8 (8 clusters per NAND block)
- 0xFFFE - empty (unused / available) space
Otherwise, the value stored within a slot in the FAT for a given cluster points to the next cluster in the chain, similar to the FAT used in DOS. Therefore, in order to figure out what clusters belong to what file, you must use the information in the FST to find the starting cluster for each file, and then follow each cluster chain.
Each entry in the FST is 0x20 bytes. Here is a typical entry for a leaf node (regular file):
0000000: 4e41 4e44 424f 4f54 494e 464f fd00 2714 NANDBOOTINFO..'. 0000010: 0035 0000 1020 0000 1000 0001 0000 0000 .5... ..........
|0x0C||0x0C||1||0xfd||File access "mode"
|0x0E||0x0F||2||0x2714||"sub" -- for a file, this is the starting cluster for the file. For a directory, this points to the index into the FST of the first child of this tree node|
|0x10||0x11||2||0x0035||"sib" -- this points to the index into the FST of the next sibling node|
|0x1B||0x1F||4||0||x3 (unknown, but see below)|
The filesystem data and metadata clusters are "signed" with an HMAC to prevent tampering. The HMAC key is a 20-byte key stored in OTP, but each cluster is also seeded with a non-standard "salt". This 0x40-byte piece of data is generated in memory and then fed into the HMAC algorithm, and then the unencrypted contents of a cluster is fed through the HMAC algorithm. Two copies of the resulting 20-byte HMAC value is stored in the spare / OOB area of the cluster, in the 7th and 8th pages within that cluster.
Salt format for file data:
|0x10||0x13||0x04||index (which cluster in the chain this is; for the first cluster, this will be 0, for the second cluster, 1, etc)|
|0x14||0x17||0x04||fst_pos (index into FST)|
|0x18||0x1b||0x04||x3 (unknown field above)|
|0x1c||0x3f||0x24||padding (all zero)|
Salt format for metadata:
|0x00||0x11||0x12||padding (all zero)|
|0x12||0x13||2||cluster (starting cluster number of this metadata block, e.g. 0x7F00)|
|0x14||0x3f||0x2b||padding (all zero)|
The NAND flash driver inside boot2 and IOS supports the following chip IDs:
Hynix: ad 76 / ad f1 / ad dc (64MB = HY27US0812(1/2)B, 128MB = HY27UF081G2A, 512MB = HY27UF084G2M or HY27UG084G2M) Samsung: ec 76 / ec f1 / ec da / ec dc (64M K9F1208U0C /128 K9F1G08U0B/256 K9F2G08U0A/512 = K9F4G08U0A) Toshiba: 98 76 / 98 f1 / 98 da (64/128 = TC58NVG0S3AFT05 or TC58NVG0S3ATG05 or TC58NVG0S3BFT00/256 = TC58NVG1D4BTG00 (?!))
It is not known why the IOS driver supports chips smaller than 512MB.
[USEFUL LINKS @samsung]