Difference between revisions of "Stage2"

From DSiBrew
Jump to navigation Jump to search
(WRAMCNT setting in stage2 header)
 
(13 intermediate revisions by 5 users not shown)
Line 1: Line 1:
== Stage 1 ==
 
 
[[Image:boot-stage1-error.jpeg|frame|When the Stage 1 bootloader (in ROM) fails, it displays a 32-bit hexadecimal number on the top screen.]]
 
 
The first stage of the DSi's bootloader lives in ROM, presumably on the CPU die. It loads further encrypted+signed stages from [[NAND]] flash, starting with a plaintext offset table in the sector at offset 0x200.
 
 
Not much is known about this bootloader yet, but it presumably knows how to:
 
# Initialize the encryption hardware
 
# Read the contents of [[NVRAM]]
 
# Initialize both LCDs
 
# Read blocks (but not files) from the [[NAND]] flash
 
# Perform some variety of integrity check on all data it reads (signature, CRC, ?)
 
# Display basic hexadecimal error codes
 
# Possibly factory-programming the [[NAND]] flash?
 
# Might also do basic power-on self test of peripherals
 
 
Known error codes:
 
 
{| border="1" cellpadding="3" cellspacing="0"
 
! Error Code  !!  Description
 
|-
 
| 0000FE00 || Error communicating with NAND chip. (It's missing, CLK is shorted, etc.)
 
|-
 
| 0000FEFC || Integrity error in first block of Stage 2 (address at 0x220)
 
|-
 
| 0000FEFD || Integrity error in second block of Stage 2 (address at 0x230)
 
|-
 
| 0000FEFE || Boot sector integrity error (Sector 0x200 not valid), or error in [[NVRAM]] contents.
 
|}
 
 
== Stage 2 ==
 
 
 
[[Image:boot-stage2-error.jpeg|frame|This may have been a Stage 2 bootloader error.]]
 
[[Image:boot-stage2-error.jpeg|frame|This may have been a Stage 2 bootloader error.]]
  
Unlike the stage1 bootloader, which must be small enough to fit in ROM (probably several kilobytes), the stage2 bootloader has about a megabyte of NAND flash reserved for it. The stage2 bootloader understands partitions and filesystems, and it is capable of loading the DSi menu. It also must understand the encryption used on filesystem blocks in the NAND, and it must understand how to load and validate title metadata.
+
Unlike the stage1 bootloader, which must be small enough to fit in ROM (32 kilobytes per core), the stage2 bootloader has about a megabyte of NAND flash reserved for it. The stage2 bootloader understands partitions and filesystems, and it is capable of loading the DSi menu. It also must understand the encryption used on filesystem blocks in the NAND, and it must understand how to load and validate title metadata.
  
The Stage 2 loader was not modified by the [[System Menu 1.4]] update. This is still earlier in the boot process than the "Health and Safety" warning(that warning is displayed by the sysmenu).
+
The Stage 2 loader was not modified by the [[System Menu 1.4]] update. This is still earlier in the boot process than the "Health and Safety" warning (that warning is displayed by the sysmenu).
  
The first stage bootloader reads the sector at offset 0x200 in order to find a table of offsets to the Stage 2 bootloader:
+
The [[stage1|first stage bootloader]] reads the sector at offset 0x200 in order to find a table of offsets to the Stage 2 bootloader:
  
 
  00000220  00 08 00 00 10 64 02 00  00 80 7b 03 00 66 02 00  |.....d....{..f..|
 
  00000220  00 08 00 00 10 64 02 00  00 80 7b 03 00 66 02 00  |.....d....{..f..|
 
  00000230  00 6e 02 00 88 75 02 00  00 80 7b 03 00 76 02 00  |.n...u....{..v..|
 
  00000230  00 6e 02 00 88 75 02 00  00 80 7b 03 00 76 02 00  |.n...u....{..v..|
 
  00000240  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 
  00000240  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
 +
 +
There's two header sectors [[NAND|following]] this, however stage1 ignores these.
  
 
This is describing two chunks of the stage2 loader: the ARM9-binary 0x26410 bytes in length at address 0x800, and the ARM7-binary 0x27588 bytes at address 0x26e00.
 
This is describing two chunks of the stage2 loader: the ARM9-binary 0x26410 bytes in length at address 0x800, and the ARM7-binary 0x27588 bytes at address 0x26e00.
Line 61: Line 31:
 
| 0x24
 
| 0x24
 
| 0x4
 
| 0x4
| ARM9 Bootcode, Size "Actual binary size"
+
| ARM9 Bootcode, Size "Actual decompressed binary size"
 
|-
 
|-
 
| 0x28
 
| 0x28
Line 69: Line 39:
 
| 0x2C
 
| 0x2C
 
| 0x4
 
| 0x4
| ARM9 Bootcode, Size rounded up to multiple of 0x200
+
| ARM9 Bootcode, Size (compressed, if compression is used) rounded up to multiple of 0x200
 
|-
 
|-
 
| 0x30
 
| 0x30
Line 77: Line 47:
 
| 0x34
 
| 0x34
 
| 0x4
 
| 0x4
| ARM7 Bootcode, Size "Actual binary size"
+
| ARM7 Bootcode, Size "Actual decompressed binary size"
 
|-
 
|-
 
| 0x38
 
| 0x38
Line 85: Line 55:
 
| 0x3C
 
| 0x3C
 
| 0x4
 
| 0x4
| ARM7 Bootcode, Size rounded up to multiple of 0x200
+
| ARM7 Bootcode, Size (compressed, if compression is used) rounded up to multiple of 0x200
 
|-
 
|-
 
| 0x40
 
| 0x40
Line 93: Line 63:
 
| 0xFF
 
| 0xFF
 
| 0x1
 
| 0x1
| Unknown, value 0xFF? (actually, this is appears to be always 0Ch, not FFh?)
+
| Option flags (see below). Mostly used for NAND and NVRAM boots, only a single bit is checked for game cartridge boots! Typically 0x0C for NAND boots. NVRAM sets this to 0x80 to signal a NAND boot.
 
|-
 
|-
 
| 0x100
 
| 0x100
Line 112: Line 82:
 
|-
 
|-
 
| 0x1AC
 
| 0x1AC
| 0x4
+
| 0x3
 
| Global MBK9 Slot Master Setting
 
| Global MBK9 Slot Master Setting
 +
|-
 +
| 0x1AF
 +
| 0x1
 +
| Global WRAMCNT Setting
 
|-
 
|-
 
| 0x1B0
 
| 0x1B0
Line 120: Line 94:
 
|}
 
|}
  
Below is some interesting info on the RSA Data Block, but it's unclear if or how that data block has been decrypted, and if it has been done on DSi or 3DS (or both).
+
Note that the above format roughly resembles the [[DSi Cartridge Header]] (entries 0x20-0x3F are roughly similar, and entries 0x180-0x1AF appear to be same as in cart header).
  
In practice, bootcode decryption isn't possible because the RSA key is unknown, keyY is also unknown (when not knowing the RSA key), and keyX is also unknown (it's said to be same as for Tad; which is unknown, it isn't included in the "srl extract" utility), and the "binblksize" value for CTR is also unclear (it might be same as "'''binblk->'''binbl'''oc'''ksize" though).
+
The option byte at +0xff has the following flags:
 +
{| border="1" cellpadding="3" cellspacing="0"
 +
! Bit
 +
! Mask
 +
! Description
 +
|-
 +
| 0
 +
| 0x01
 +
| Use LZ77 decompression for the ARM9 binary (game cartridge boots ignore this flag and always treat binaries as uncompressed)
 +
|-
 +
| 1
 +
| 0x02
 +
| Use LZ77 decompression for the ARM7 binary (game cartridge boots ignore this flag and always treat binaries as uncompressed)
 +
|-
 +
| 2
 +
| 0x04
 +
| Run the ARM9 at 133 MHz when performing RSA verification and SHA1 hash calculation (it starts out at 66 MHz). This is the only flag checked during a game cartridge boot.
 +
|-
 +
| 3
 +
| 0x08
 +
| Use the IPC FIFO to send compressed payloads to the ARM9, and have the ARM9 decompress them. If not selected, the ARM7 will decompress the payload, then map it to the ARM9 using the MBK registers. Has no effect for uncompressed payloads (and thus game cartridge boots).
 +
|-
 +
| 4
 +
| 0x10
 +
| Unknown, doesn't seem to be used. Always 0.
 +
|-
 +
| 5
 +
| 0x20
 +
| Unknown, doesn't seem to be used. Always 0.
 +
|-
 +
| 6
 +
| 0x40
 +
| When booting from NVRAM, use an 8 MHz SPI clock. If 0, use a 4 MHz SPI clock. Not used for non-NVRAM boots.
 +
|-
 +
| 7
 +
| 0x80
 +
| Boot medium selection flag: if 1, boot from NAND. If 0, boot from NVRAM. Not applicable for game cartridge boots (which use a magic key combination).
 +
|}
 +
 
 +
The RSA public keys (the one for 3DS and the other one for DSi) for the below signature _for NAND boots_ can be obtained from 3DS TWL_FIRM Process9 (this is required for getting the binaries' keyY). It is also found in the DSi's ARM9 boot ROM, but this is never copied to some place outside the boot ROM. (The bootroms copy _some_ keys to WRAM/ITCM, but not this one.) Public keys for NVRAM and game cartridge boots are only available from the DSi ARM9 boot ROM, and all differ from the NAND RSA public key.
  
 
Structure of the 0x74-byte "hash-data" stored in the RSA message:
 
Structure of the 0x74-byte "hash-data" stored in the RSA message:
Line 136: Line 149:
 
| 0x10
 
| 0x10
 
| 0x14
 
| 0x14
| SHA1 hash. Going by 3DS TWL_FIRM this seems to calculated over the first 0x28-bytes of [[NAND]], then the first 0x100-bytes of the header, then the last 0x80-bytes of the header(following the signature). This works with the bootloader contained in TWL_FIRM, however it's unknown how the first part is handled on DSi.
+
| SHA1 hash, calculated over the first 0x28-bytes of [[NVRAM]], then the first 0x100-bytes of the header, then the last 0x80-bytes of the header (following the signature). The bootloader contained in TWL_FIRM uses the first 0x28-bytes from NAND. For non-NAND boot mediums, this hash is calculated the same except there's no 0x28-byte block.
 
|-
 
|-
 
| 0x24
 
| 0x24
Line 148: Line 161:
 
| 0x4C
 
| 0x4C
 
| 0x14
 
| 0x14
| Unknown, not used by 3DS TWL_FIRM. Normally all-zero.
+
| Unknown, not used by 3DS TWL_FIRM. Normally all-zero. Copied to 0x01FFC880 by ARM9 [[Stage1]].
 
|-
 
|-
 
| 0x60
 
| 0x60
 
| 0x14
 
| 0x14
| Unknown, not used by 3DS TWL_FIRM.
+
| SHA1 of all previous fields in the RSA message, used to prevent RSA signature forgery. Not used by 3DS TWL_FIRM(?).
 
|}
 
|}
  
 
Note that this sector (and two similar ones at 0x400 and 0x600) appear to be the only unencrypted blocks on the NAND flash.
 
Note that this sector (and two similar ones at 0x400 and 0x600) appear to be the only unencrypted blocks on the NAND flash.
  
After loading+verifying the the above header, the ARM7 binary is loaded+verified, then the ARM9 binary is loaded+verified.
+
After loading+verifying the the above header, the ARM7 binary is loaded+verified, then the ARM9 binary is loaded+verified (see [[stage1]]).
  
 
Whereas the filesystem data in NAND is encrypted using a unique key for every DSi, the stage2 bootloader is identical on every DSi tested so far. The stage2 bootloader binaries are not encrypted with any console-unique keys.
 
Whereas the filesystem data in NAND is encrypted using a unique key for every DSi, the stage2 bootloader is identical on every DSi tested so far. The stage2 bootloader binaries are not encrypted with any console-unique keys.
  
Stage1 uses the [[AES_Engine]] to decrypt each ARM9/ARM7 binary, where keyY is from the above signature. The [[AES_Engine]] keyslot used here is the same one used for the shared areas for [[Tad]], therefore the keyX is the same as the one used for that. The following is used for the CTR, where "binblk->binblocksize" is the actual binary size:
+
Stage1 uses the [[AES_Engine]] with mode AES-CTR to decrypt each ARM9/ARM7 binary, where keyY is from the above signature. The [[AES_Engine]] keyslot used here is the same one used for the shared areas for [[Tad]], therefore the keyX is the same as the one used for that. The following is used for the CTR, where "binblk->binblocksize" is the above binary size aligned to 0x200-bytes:
  
 
   unsigned int ctr[4];
 
   unsigned int ctr[4];
Line 167: Line 180:
 
    
 
    
 
   ctr[0] = binblk->binblocksize;
 
   ctr[0] = binblk->binblocksize;
   ctr[1] = (unsigned int)(-binblksize);
+
   ctr[1] = (unsigned int)(-binblk->binblocksize);
 
   ctr[2] = ~binblk->binblocksize;
 
   ctr[2] = ~binblk->binblocksize;
 +
  ctr[3] = AES block offset (starts at 0)
  
 
=== Stage2 operations ===
 
=== Stage2 operations ===
 +
 
After Stage 2 is loaded:
 
After Stage 2 is loaded:
 +
# Main RAM (aka FCRAM aka DRAM) is allowed bus access (using the EXMEMCNT MMIO register) and initialized.
 +
# The status registers of the BPTWL are read to check whether this is a warmboot. The powerbutton action of the BPTWL is reset as well.
 
# The NAND flash is partially re-initialized
 
# The NAND flash is partially re-initialized
# Sector 0 is read from the NAND. This appears to be an (encrypted) DOS-style MBR.
+
# Various hardware components, such as the touchscreen/sound controller, Wifi chip, etc. are initialized. (Cameras aren't initialized, though.)
 +
# Sector 0 is read from the NAND. This is an (encrypted) DOS-style MBR.
 
# The MBR signature and the type of the first partition are verified.
 
# The MBR signature and the type of the first partition are verified.
 
# Filesystem metadata is read from sectors starting around 0x100000. The metadata is in FAT16 format with long filenames.
 
# Filesystem metadata is read from sectors starting around 0x100000. The metadata is in FAT16 format with long filenames.
Line 184: Line 202:
 
|-
 
|-
 
| "Error: 1-2435-8325" || Invalid signature or partition type in MBR, invalid starting LBA.
 
| "Error: 1-2435-8325" || Invalid signature or partition type in MBR, invalid starting LBA.
 +
|-
 +
| "Error: 2-2435-8325" || Invalid Firmware
 
|-
 
|-
 
| "Error: 3-2435-8325" || DSi Menu integrity checks failed
 
| "Error: 3-2435-8325" || DSi Menu integrity checks failed
 
|-
 
|-
 
|}
 
|}

Latest revision as of 17:11, 7 January 2023

This may have been a Stage 2 bootloader error.

Unlike the stage1 bootloader, which must be small enough to fit in ROM (32 kilobytes per core), the stage2 bootloader has about a megabyte of NAND flash reserved for it. The stage2 bootloader understands partitions and filesystems, and it is capable of loading the DSi menu. It also must understand the encryption used on filesystem blocks in the NAND, and it must understand how to load and validate title metadata.

The Stage 2 loader was not modified by the System Menu 1.4 update. This is still earlier in the boot process than the "Health and Safety" warning (that warning is displayed by the sysmenu).

The first stage bootloader reads the sector at offset 0x200 in order to find a table of offsets to the Stage 2 bootloader:

00000220  00 08 00 00 10 64 02 00  00 80 7b 03 00 66 02 00  |.....d....{..f..|
00000230  00 6e 02 00 88 75 02 00  00 80 7b 03 00 76 02 00  |.n...u....{..v..|
00000240  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|

There's two header sectors following this, however stage1 ignores these.

This is describing two chunks of the stage2 loader: the ARM9-binary 0x26410 bytes in length at address 0x800, and the ARM7-binary 0x27588 bytes at address 0x26e00.

Structure of this header:

Offset Size Description
0x0 0x20 Reserved (zerofilled)
0x20 0x4 ARM9 Bootcode, eMMC Source Offset
0x24 0x4 ARM9 Bootcode, Size "Actual decompressed binary size"
0x28 0x4 ARM9 Bootcode, RAM Destination Address and Entrypoint
0x2C 0x4 ARM9 Bootcode, Size (compressed, if compression is used) rounded up to multiple of 0x200
0x30 0x4 ARM7 Bootcode, eMMC Source Offset
0x34 0x4 ARM7 Bootcode, Size "Actual decompressed binary size"
0x38 0x4 ARM7 Bootcode, RAM Destination Address and Entrypoint
0x3C 0x4 ARM7 Bootcode, Size (compressed, if compression is used) rounded up to multiple of 0x200
0x40 0xBF Reserved (zerofilled)
0xFF 0x1 Option flags (see below). Mostly used for NAND and NVRAM boots, only a single bit is checked for game cartridge boots! Typically 0x0C for NAND boots. NVRAM sets this to 0x80 to signal a NAND boot.
0x100 0x80 RSA-1024 Data Block
0x180 0x14 Global MBK1..MBK5 Slot Settings
0x194 0xC Local MBK6..MBK8 Settings for ARM9 Side
0x1A0 0xC Local MBK6..MBK8 Settings for ARM7 Side
0x1AC 0x3 Global MBK9 Slot Master Setting
0x1AF 0x1 Global WRAMCNT Setting
0x1B0 0x50 Reserved (zerofilled)

Note that the above format roughly resembles the DSi Cartridge Header (entries 0x20-0x3F are roughly similar, and entries 0x180-0x1AF appear to be same as in cart header).

The option byte at +0xff has the following flags:

Bit Mask Description
0 0x01 Use LZ77 decompression for the ARM9 binary (game cartridge boots ignore this flag and always treat binaries as uncompressed)
1 0x02 Use LZ77 decompression for the ARM7 binary (game cartridge boots ignore this flag and always treat binaries as uncompressed)
2 0x04 Run the ARM9 at 133 MHz when performing RSA verification and SHA1 hash calculation (it starts out at 66 MHz). This is the only flag checked during a game cartridge boot.
3 0x08 Use the IPC FIFO to send compressed payloads to the ARM9, and have the ARM9 decompress them. If not selected, the ARM7 will decompress the payload, then map it to the ARM9 using the MBK registers. Has no effect for uncompressed payloads (and thus game cartridge boots).
4 0x10 Unknown, doesn't seem to be used. Always 0.
5 0x20 Unknown, doesn't seem to be used. Always 0.
6 0x40 When booting from NVRAM, use an 8 MHz SPI clock. If 0, use a 4 MHz SPI clock. Not used for non-NVRAM boots.
7 0x80 Boot medium selection flag: if 1, boot from NAND. If 0, boot from NVRAM. Not applicable for game cartridge boots (which use a magic key combination).

The RSA public keys (the one for 3DS and the other one for DSi) for the below signature _for NAND boots_ can be obtained from 3DS TWL_FIRM Process9 (this is required for getting the binaries' keyY). It is also found in the DSi's ARM9 boot ROM, but this is never copied to some place outside the boot ROM. (The bootroms copy _some_ keys to WRAM/ITCM, but not this one.) Public keys for NVRAM and game cartridge boots are only available from the DSi ARM9 boot ROM, and all differ from the NAND RSA public key.

Structure of the 0x74-byte "hash-data" stored in the RSA message:

Offset Size Description
0x0 0x10 AES_Engine keyY used for the ARM9/ARM7 binaries crypto.
0x10 0x14 SHA1 hash, calculated over the first 0x28-bytes of NVRAM, then the first 0x100-bytes of the header, then the last 0x80-bytes of the header (following the signature). The bootloader contained in TWL_FIRM uses the first 0x28-bytes from NAND. For non-NAND boot mediums, this hash is calculated the same except there's no 0x28-byte block.
0x24 0x14 SHA1 hash over the plaintext ARM9 binary, with the actual binary size.
0x38 0x14 SHA1 hash over the plaintext ARM7 binary, with the actual binary size.
0x4C 0x14 Unknown, not used by 3DS TWL_FIRM. Normally all-zero. Copied to 0x01FFC880 by ARM9 Stage1.
0x60 0x14 SHA1 of all previous fields in the RSA message, used to prevent RSA signature forgery. Not used by 3DS TWL_FIRM(?).

Note that this sector (and two similar ones at 0x400 and 0x600) appear to be the only unencrypted blocks on the NAND flash.

After loading+verifying the the above header, the ARM7 binary is loaded+verified, then the ARM9 binary is loaded+verified (see stage1).

Whereas the filesystem data in NAND is encrypted using a unique key for every DSi, the stage2 bootloader is identical on every DSi tested so far. The stage2 bootloader binaries are not encrypted with any console-unique keys.

Stage1 uses the AES_Engine with mode AES-CTR to decrypt each ARM9/ARM7 binary, where keyY is from the above signature. The AES_Engine keyslot used here is the same one used for the shared areas for Tad, therefore the keyX is the same as the one used for that. The following is used for the CTR, where "binblk->binblocksize" is the above binary size aligned to 0x200-bytes:

 unsigned int ctr[4];
 memset(ctr, 0, 16);
 
 ctr[0] = binblk->binblocksize;
 ctr[1] = (unsigned int)(-binblk->binblocksize);
 ctr[2] = ~binblk->binblocksize;
 ctr[3] = AES block offset (starts at 0)

Stage2 operations

After Stage 2 is loaded:

  1. Main RAM (aka FCRAM aka DRAM) is allowed bus access (using the EXMEMCNT MMIO register) and initialized.
  2. The status registers of the BPTWL are read to check whether this is a warmboot. The powerbutton action of the BPTWL is reset as well.
  3. The NAND flash is partially re-initialized
  4. Various hardware components, such as the touchscreen/sound controller, Wifi chip, etc. are initialized. (Cameras aren't initialized, though.)
  5. Sector 0 is read from the NAND. This is an (encrypted) DOS-style MBR.
  6. The MBR signature and the type of the first partition are verified.
  7. Filesystem metadata is read from sectors starting around 0x100000. The metadata is in FAT16 format with long filenames.
  8. Multiple files are loaded from the filesystem. The exact read addresses will vary depending on your DSi's firmware version and the state of its filesystem when you performed the last firmware update. On a brand new DSi, it appears that the DSi Menu itself is loaded from 0xb20000 after two small metadata files are read from 0xb1c000 and 0x7a0000.

All errors show before the health and safety screen. It appears that stage2 errors from a cold power-on always cause the DSi to hang at a black screen, whereas stage2 errors after reset (pressing but not holding the power button) will give an error message screen. Known errors:

Text Description
"Error: 1-2435-8325" Invalid signature or partition type in MBR, invalid starting LBA.
"Error: 2-2435-8325" Invalid Firmware
"Error: 3-2435-8325" DSi Menu integrity checks failed