Contents

Physical layout

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

boot1 is the second-stage bootloader; it is decrypted by boot0, which resides on a read-only mask ROM inside the Starlet coprocessor. Its primary function is to load and decrypt boot2.

Block 0 is guaranteed by the manufacturer to be valid, so there is no bad block map necessary.

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.

Metadata layout

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.

FAT

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.

FST

Each entry in the FST is 0x20 bytes. Here is a typical entry for a leaf node (regular file):

"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

0x12

0x14

4

0x1020

filesize

0x15

0x18

4

0x1000

uid

0x19

0x1A

2

0x1

gid

0x1B

0x1F

4

0

x3 (unknown, but see below)

HMAC info

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:

Start

End

Length

Description

0x00

0x03

4

uid

0x04

0x0f

0x0b

filename

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:

Start

End

Length

Description

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)

Supported chips

The NAND flash driver inside boot2 and IOS supports the following chip IDs: