Changes

Jump to navigation Jump to search
7,334 bytes added ,  06:03, 21 May 2017
Fix typo.
Line 4: Line 4:     
== Boot ROM ==
 
== Boot ROM ==
Upon boot, parts of the ARM9 and ARM11 boot ROMs are protected by writing to [[CONFIG#CFG_SYSPROT9|CFG_SYSPROT9]] and [[CONFIG#CFG_SYSPROT11|CFG_SYSPROT11]], respectively. The non-protected areas of the ARM9 and ARM11 boot ROMs are identical for launch-day regular Old3DS, 2DS, and regular New3DS.
+
Upon boot, parts of the ARM9 and ARM11 boot ROMs are protected by writing to [[CONFIG#CFG_SYSPROT9|CFG_SYSPROT9]] and [[CONFIG#CFG_SYSPROT11|CFG_SYSPROT11]], respectively. The ARM9 and ARM11 boot ROMs are identical for all Old 3DS, 2DS and New 3DS consoles.
    
== NAND FIRM boot ==
 
== NAND FIRM boot ==
Line 14: Line 14:  
Boot9 can also boot from non-NAND. For this a different set of RSA pubks are used(separate pubks for retail/devunit like NAND). The spiflash FIRM image for this is also encrypted with AES-CBC using a normalkey stored in prot_boot9(separate for retail/devunit). This encryption is basically used instead of what is used for NAND-firm-partitions. This encryption is only used for the FIRM sections, the FIRM header is used raw. The AES keyslot for this is only overwritten afterwards when booting from non-NAND fails. AES keyslot 0x3F is used for this.
 
Boot9 can also boot from non-NAND. For this a different set of RSA pubks are used(separate pubks for retail/devunit like NAND). The spiflash FIRM image for this is also encrypted with AES-CBC using a normalkey stored in prot_boot9(separate for retail/devunit). This encryption is basically used instead of what is used for NAND-firm-partitions. This encryption is only used for the FIRM sections, the FIRM header is used raw. The AES keyslot for this is only overwritten afterwards when booting from non-NAND fails. AES keyslot 0x3F is used for this.
   −
   CTR_word[0] = firmimageoffset;
+
   CTR_word[0] = firmimageoffset;//FIRM section offset from FIRM header
   CTR_word[1] = outbufaddr;
+
   CTR_word[1] = outbufaddr;//FIRM section load addr
   CTR_word[2] = readsize;
+
   CTR_word[2] = readsize;//FIRM section size
   CTR_word[3] = readsize;
+
   CTR_word[3] = readsize;//FIRM section size
   −
When booting from NAND fails, boot9 will then attempt to boot from Wifi SPI-flash(this only triggers when the wifi module hw is properly accessible/connected, which is normally the case). The base offset for spiflash FIRM is 0x400. Note that this region is write-protected by the spiflash.
+
When booting from NAND fails, boot9 will then attempt to boot from Wifi SPI-flash(this only triggers when the wifi module hw is properly accessible/connected, which is normally the case). The base offset for spiflash FIRM is 0x400. Note that this region(all data prior to offset 0x1F300) is write-protected by the spiflash(not writable from 3DS-mode / DS-mode).
 +
 
 +
Additionally, if the shell is closed and a special key combination (Start + Select + X) is held, boot9 will attempt to boot from an inserted NTR cartridge before booting from NAND. Note: While normally on O3DS/2DS the console will not turn on if the shell is closed (or this is faked by holding a magnet to the console), when this special key combination is held holding down the power button will cause boot to occur anyway.
    
For non-NAND booting, NCSD / FIRM-backup is not used.
 
For non-NAND booting, NCSD / FIRM-backup is not used.
Line 25: Line 27:  
== SDMMC ==
 
== SDMMC ==
   −
Boot9 has code implemented for using SD(HC) cards, but the input deviceids used by boot9 for those functions are hard-coded for NAND.
+
Boot9 has code implemented for using SD(HC) cards, but the input deviceids used by boot9 for those functions are hard-coded for NAND. However, it is possible to use an SD(HC) card in place of the NAND if the NAND chip is first disconnected, and a SD card connected to the bus. Due to the CID being different, partitions will need to be re-encrypted and TWL mode will not work, due to the MBR being in the NCSD header. Using sighax, it may be possible to replace the NCSD header.
    
== Boot9 RSA keyslots ==
 
== Boot9 RSA keyslots ==
Line 101: Line 103:     
For an issue with console-unique key-init, see [[OTP_Registers|here]].
 
For an issue with console-unique key-init, see [[OTP_Registers|here]].
 +
 +
== BootROM Errors ==
 +
Sample error-screen(where firm0+firm1 RSA signatures were corrupted):
 +
 +
  BOOTROM 8046
 +
  ERRCODE: 00F800FF
 +
  DEDEFFFF FFFFFFFF
 +
  00000000 00000000
 +
 +
* 1st line is: <code>print_string(..., "BOOTROM %X", 0x8046);//This last param comes from the .pool.</code>
 +
* 2nd line is: <code>print_string(..., "ERRCODE:    %08X", *((unsigned int*)(0x1FFFE000+0xC)));//See below memory notes.</code>
 +
* 3rd line is: <code>print_string(..., "%08X %08X", *((unsigned int*)(0x1FFFE000+0x10))`, `*((unsigned int*)(0x1fffe000+0x14)));//See below memory notes.</code>
 +
* 4th line is: <code>print_string(..., "%08X %08X",*((unsigned int*)(0x1FFFE000+0x18))`, `*((unsigned int*)(0x1fffe000+0x1C)));//See below memory notes.</code>
 +
 +
== 0x1FFFE000 memory ==
 +
This memory is used by boot9 mainly for sending info to the arm11 for the error-screen. The data in this region is still stored in memory by the time the ARM9+ARM11 jumps to FIRM.
 +
 +
Among boot9/boot11, the 3 words at 0x1FFFE000 seem to be ''only'' accessed by the boot11 function initializing those words.
 +
 +
* u32 0x1FFFE000+0: ARM11 MPCore "Cycle Counter Register (CCNT)".
 +
* u32 0x1FFFE000+4: ARM11 MPCore "Count Register 0 (PMN0)".
 +
* u32 0x1FFFE000+8: ARM11 MPCore "Count Register 1 (PMN0)".
 +
* 8bit-entry-array 0x1FFFE000+0xC: 8bit status-codes initialized by boot9 main(), for the FIRM-boot devices. +0 is NAND and +2 is wifi-spiflash.
 +
* ...
 +
* 8bit-entry-array 0x1FFFE000+0x10: Status-codes originally from nand_findfirmpartition_loadfirm(), for each of the 8 NCSD partitions.
 +
 +
== BootROM Status Codes ==
 +
{| class="wikitable" border="1"
 +
|-
 +
!  Value
 +
!  Description
 +
|-
 +
| 0x00
 +
| Success
 +
|-
 +
| 0xEE(~17)
 +
| NCSD header validation function failed: NCSD magicnum is invalid or RSA verification failed.
 +
|-
 +
| 0xDE(~33)
 +
| FIRM header validation function failed: FIRM magicnum is invalid or RSA verification failed.
 +
|-
 +
| 0xDF(~32)
 +
| Failed to read sector data from the device.
 +
|-
 +
| 0xCF(~48)
 +
| FIRM section validation function failed: FIRM section is invalid.
 +
|-
 +
| 0xF7(~8)
 +
| A NAND FIRM from another partition was already found with a priority(firmhdr+4) >= to the value for the current partition's FIRM priority.
 +
|-
 +
| 0xF8(~7)
 +
| The FIRM magicnum(firmhdr+0) is invalid.
 +
|-
 +
| 0xFF(~0)
 +
| Initial value for each entry in the 8-entry array of status-codes for the NAND NCSD partitions. Indicates that the partition is not a FIRM partition(partition fs type isn't 0x3 or partition fs crypt-type isn't 0x2).
 +
|}
    
== Boot9 startup ==
 
== Boot9 startup ==
    
0xffff0000 jumps to 0xffff8000. 0xffff8000 is crt0:
 
0xffff0000 jumps to 0xffff8000. 0xffff8000 is crt0:
* Very first thing this does is clear u8 register 0x10000002 bit0 to zero.
+
* Very first thing this does is clear u8 register 0x10000002 ([[CONFIG_Registers#CFG_RST11|CFG_RST11]]) bit 0 to zero.
 
* Then sp is initialized for each cpumode, IRQs/FIQs are disabled during the first mode-switch.
 
* Then sp is initialized for each cpumode, IRQs/FIQs are disabled during the first mode-switch.
 
* Order of mode-switches + sp initialization: svc-mode = 0xfff04000, irq-mode = 0xfff03f00, system-mode = 0xfff03b00. Hence, the rest of the code following this runs in system-mode.
 
* Order of mode-switches + sp initialization: svc-mode = 0xfff04000, irq-mode = 0xfff03f00, system-mode = 0xfff03b00. Hence, the rest of the code following this runs in system-mode.
Line 122: Line 180:  
* Then the instruction/data access permissions for the MPU regions are setup.
 
* Then the instruction/data access permissions for the MPU regions are setup.
 
* Lastly bitmask 0x0005707d is orred in the cp15 control register.
 
* Lastly bitmask 0x0005707d is orred in the cp15 control register.
 +
 +
== Boot9 main() ==
 +
 +
  The following functions are called: LT_ffff2024(), LT_ffff1ff8(), pxi_init(), rsa_init(), initialize_rsakeyslots_pubk(), crypto_initialize(), and aesengine_reset().
 +
  Then AES keyslot 0x3F is setup: aesengine_setnormalkey(0x3f, 5, ptr) is called. ptr on retail(CFG_UNITINFO check) is 0xffffd6e0, 0xffffd700 for devunit. Then essentially, aesengine_setctr(5, ptr+0x10) is executed.
 +
  Then AES keyslot 0x3f is selected.
 +
  When calling the following functions, if any of them return zero, it will immediately jump to setting ptr to 0x10012000(otp), otherwise when all of them return non-zero ptr = sp+0x94. otp_decrypt(sp+4), otp_verify(sp+4), initialize_consoleunique_itcm(sp+4, 0x07ffb800).
 +
  Then the following is executed: initialize_aeskeys_wrap(ptr, 0x70);
 +
  Then sp+4 size 0x100 is cleared to zero.
 +
 
 +
  ...
 +
 
 +
  NAND firm-boot code-block, is described below. Note that boot9 is basically hard-coded to use deviceid NAND, not SD.
 +
  {
 +
  timer_updatestoredstate() is called, then the AES keyslot for NAND-FIRM is selected(0x6).
 +
  Then LT_ffff56c8() is called, if that returns non-zero the statuscode variable is set to ~2 then it jumps to NAND_BOOTEND.
 +
  Then LT_ffff5774(0x201) is called, if that returns non-zero the statuscode variable is set to ~1 then it jumps to NAND_BOOTEND.
 +
  Then fsdriver_setup_mmc() is called. Then nand_findfirmpartition_loadfirm(0) is called, with the statuscode variable set to the retval.
 +
  Executes a loop which runs 8 times: write the output from get_errorcode_arrayentry_xfff005e8(loopindex) to u8 0x1fffe000+0x10+loopindex(copy the array of 32bit error-codes for all 8 NCSD partitions initialized by nand_findfirmpartition_loadfirm() to the array of 8bit entries at 0x1fffe000+0x10).
 +
 
 +
  NAND_BOOTEND:
 +
  Then the statuscode variable is written to u8 0x1fffe000+0xc.
 +
  Then LT_ffff5690(0x201, 0x1fffe018, 0x1fffe01c) is called.
 +
  Then LT_ffff5644() is called.
 +
  Then timer_updatestoredstate() is called.
 +
  When statuscode==0 for success, it jumps to FIRMLOAD_END. Otherwise, it continues to the next code-block.
 +
  }
 +
 
 +
  Wifi spi-flash firm-boot code-block, executed when no FIRM was loaded successfully so far.
 +
  {
 +
  timer_updatestoredstate() is called.
 +
 
 +
  Then spi_wififlash_cmdgetstatusreg(sp+0x100) is executed. When bit0 of the output u8 at sp+0x100 is clear, it will continue this code-block, otherwise it will set the statuscode variable to ~1 then jump to SPIFLASH_BOOTEND.
 +
  Then fsdriver_setup_wififlash() is called.
 +
  Here read_firmhdr_validate_loadfirm(0, 2) is called, with the statuscode variable set to the retval.
 +
 
 +
  SPIFLASH_BOOTEND:
 +
  Then the statuscode variable is written to u8 0x1fffe000+0xe.
 +
  Then timer_updatestoredstate() is called.
 +
  When statuscode==0 for success, it jumps to FIRMLOAD_END. Otherwise, it executes writenormalkey_keyslot3f(), then jumps to FIRMLOAD_FAILURE.
 +
  }
 +
 
 +
  FIRMLOAD_END:
 +
  Here it calls firmhdr_getarm11_entrypoint() and firmhdr_getarm9_entrypoint(). Immediately after calling each function it checks if the retval is 0, if so it then jumps to FIRMLOAD_FAILURE.
 +
  After calling initialize_x07ffbd00_x07ffc100_rsakeyslotsprivk(), it jumps to FIRMLOAD_EXIT.
 +
 
 +
  FIRMLOAD_FAILURE:
 +
  Here it clears 0x07ffb800 size 0x3c70 to zero, endaddr = 0x07fff470.
 +
  Then it continues to FIRMLOAD_EXIT.
 +
 
 +
  FIRMLOAD_EXIT:
 +
  Here firmboot() is called, which should never return. The instruction after this bl is a call for panic().
 +
 +
== Boot11 ==
 +
 +
* ...
 +
 +
main():
 +
  LT_1263c();
 +
  ...
 +
  LT_13944()
 +
  ...
 +
  pxi_init();
 +
  initializefuncptr_firmboot_start(firmbootbegin_funcptr);
 +
  firmboot();
 +
  return;
 +
 +
LT_12220/initializefuncptr_firmboot_start
 +
  inr0=funcptr
 +
  This writes inr0 to address 0x1ffe8028, then returns.
 +
  This initializes the funcptr which firmboot() can call after the very first func-call.
 +
 +
LT_13944
 +
  if([[I2C_Registers|i2cmcu_readregf]](sp+0)==0)
 +
  {
 +
  return (*((u8*)0x10147000) >> 4) & 1;//Reads [[GPIO_Registers|GPIO]] when reading I2C fails.
 +
  }
 +
  Here it basically does "return <byte loaded from sp+0> ^ 0x2". Hence in this case, it will return 0x2 when the system shell is closed(sleep-mode), otherwise 0x0 is returned.
 +
 +
LT_12454/firmboot
 +
  This is the arm11 version of the boot9 firmboot() function, like boot9 this is the final function called from main(). The functionality for these two functions are identical, minus addresses.
 +
  ptr = firmboot_loadentrypoint11();
 +
  funcptr = *(0x1ffe8028);
 +
  if(funcptr)funcptr(ptr);
 +
  LT_11ffc(ptr);
 +
  return;
    
== Boot Procedure ==
 
== Boot Procedure ==
    
* 0 seconds - unit is powered on. The ARM9 and ARM11 [[Memory_layout|bootroms]] begin execution.
 
* 0 seconds - unit is powered on. The ARM9 and ARM11 [[Memory_layout|bootroms]] begin execution.
 
+
* <= ~1 second - BootROMs fully run, load FIRM, etc. The loaded FIRM begins running.
* 2 seconds - ARM9 bootrom attempts to initialize the NAND.
+
**The ARM11 sysmodules included with FIRM are launched by ARM11-kernel, etc.
**If the NAND is successfully initialized:
+
**The [[Process_Manager_Services|PM]] module launches [[NS]].
***the ARM9 bootrom loads the [[FIRM|firmware]] stored in the NAND [[FIRM]] partition which handles booting the rest of the system (if verification for NAND firm0 fails, the ARM9 bootrom will attempt to use firm1 instead).
  −
***The ARM11 kernel loaded from FIRM then launches the [[NCCH#CXI|CXI]] ARM11 system modules loaded from FIRM (i.e. sm, fs, pm, loader, and pxi). (Note that the ARM11 kernel does not handle any encryption/RSA verification, this is handled by the [[FIRM|ARM9]].)
  −
**If the NAND cannot be initialized (i.e. the NAND chip is not connected/damaged/etc), a [[Bootloader#Error_Codes|blue error screen]] appears.
  −
 
  −
* 3 seconds - all essential hardware is active.
  −
**The [[Process_Manager_Services|PM]] module launches [[NS]]
   
**If [[Home_Menu#Auto-Boot_Function|auto-booting]] is needed, NS will [[NS#Auto-boot|auto-boot]] titles.
 
**If [[Home_Menu#Auto-Boot_Function|auto-booting]] is needed, NS will [[NS#Auto-boot|auto-boot]] titles.
 
**Otherwise, NS will instead launch [[ErrDisp]] and the [[Configuration Memory#ACTIVEMENUTID|current active menu]] via the PM module. For retail units, this menu is usually the [[Home Menu]]. Note that the PM module first launches the module dependencies when launching a process, prior to actually launching the process.
 
**Otherwise, NS will instead launch [[ErrDisp]] and the [[Configuration Memory#ACTIVEMENUTID|current active menu]] via the PM module. For retail units, this menu is usually the [[Home Menu]]. Note that the PM module first launches the module dependencies when launching a process, prior to actually launching the process.
**The further Home Menu startup process is described [[Home_Menu#Home_Menu_startup|here]].
+
**The further Home Menu startup process is described [[Home_Menu#Home_Menu_startup|here]]. This includes Home Menu manually launching various sysmodules.
    
* 4 seconds - the LCD screens are initialized.
 
* 4 seconds - the LCD screens are initialized.
29

edits

Navigation menu