<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://switchbrew.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Motezazer</id>
	<title>Nintendo Switch Brew - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://switchbrew.org/w/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Motezazer"/>
	<link rel="alternate" type="text/html" href="https://switchbrew.org/wiki/Special:Contributions/Motezazer"/>
	<updated>2026-05-17T04:12:34Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.43.1</generator>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=5626</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=5626"/>
		<updated>2018-11-25T13:20:23Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Keyblobs are dead&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== BootROM ==&lt;br /&gt;
The bootrom initializes two keyslots in the hardware engine:&lt;br /&gt;
&lt;br /&gt;
* the SBK (Secure Boot Key) in keyslot 14&lt;br /&gt;
* the SSK (Secure Storage Key) in keyslot 15.&lt;br /&gt;
&lt;br /&gt;
Reads from both of these keyslots are disabled by the bootROM.&lt;br /&gt;
The SBK is stored in [[Fuses#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY]], which are locked to read out only FFs after the bootrom finishes.&lt;br /&gt;
&lt;br /&gt;
SBK is &#039;&#039;&#039;unique&#039;&#039;&#039; per console, and not shared among consoles as originally believed.&lt;br /&gt;
&lt;br /&gt;
The SSK is derived on boot via the SBK, the 32-bit console-unique &amp;quot;Device Key&amp;quot;, and hardware information stored in fuses.&lt;br /&gt;
&lt;br /&gt;
Pseudocode for the derivation is as follows:&lt;br /&gt;
  void generateSSK() {&lt;br /&gt;
      char keyBuffer[0x10]; // Used to store keydata&lt;br /&gt;
      uint hwInfoBuffer[4]; // Used to store info about hardware from fuses&lt;br /&gt;
      uint deviceKey = getDeviceKey(); // Reads 32-bit device key from FUSE_PRIVATE_KEY4.&lt;br /&gt;
      for (int i = 0; i &amp;lt; 4; i++) { // Keybuffer = deviceKey || deviceKey || deviceKey || deviceKey&lt;br /&gt;
          ((uint *)keyBuffer)[i] = deviceKey;&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, deviceKey || {...})&lt;br /&gt;
      &lt;br /&gt;
      // Set up Hardware info buffer&lt;br /&gt;
      uint vendor_code = *((uint *)0x7000FA00) &amp;amp; 0x0000000F; // FUSE_VENDOR_CODE&lt;br /&gt;
      uint fab_code    = *((uint *)0x7000FA04) &amp;amp; 0x0000003F; // FUSE_FAB_CODE&lt;br /&gt;
      uint lot_code_0  = *((uint *)0x7000FA08) &amp;amp; 0xFFFFFFFF; // FUSE_LOT_CODE_0&lt;br /&gt;
      uint lot_code_1  = *((uint *)0x7000FA0C) &amp;amp; 0x0FFFFFFF; // FUSE_LOT_CODE_1&lt;br /&gt;
      uint wafer_id    = *((uint *)0x7000FA10) &amp;amp; 0x0000003F; // FUSE_WAFER_ID&lt;br /&gt;
      uint x_coord     = *((uint *)0x7000FA14) &amp;amp; 0x000001FF; // FUSE_X_COORDINATE&lt;br /&gt;
      uint y_coord     = *((uint *)0x7000FA18) &amp;amp; 0x000001FF; // FUSE_Y_COORDINATE&lt;br /&gt;
      uint unk_hw_fuse = *((uint *)0x7000FA20) &amp;amp; 0x0000003F; // Unknown cached fuse.&lt;br /&gt;
      &lt;br /&gt;
      // HARDWARE_INFO_BUFFER = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID&lt;br /&gt;
      hwInfoBuffer[0] = (lot_code_1 &amp;lt;&amp;lt; 30) | (wafer_id &amp;lt;&amp;lt; 24) | (x_coord &amp;lt;&amp;lt; 15) | (y_coord &amp;lt;&amp;lt; 6) | unk_hw_fuse;&lt;br /&gt;
      hwInfoBuffer[1] = (lot_code_0 &amp;lt;&amp;lt; 26) | (lot_code_1 &amp;gt;&amp;gt; 2);&lt;br /&gt;
      hwInfoBuffer[2] = (fab_code &amp;lt;&amp;lt; 26) | (lot_code_0 &amp;gt;&amp;gt; 6);&lt;br /&gt;
      hwInfoBuffer[3] = vendor_code;&lt;br /&gt;
      &lt;br /&gt;
      for (int i = 0; i &amp;lt; 0x10; i++) { // keyBuffer = XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER)&lt;br /&gt;
          keyBuffer[i] ^= ((char *)hwInfoBuffer)[i];&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER))&lt;br /&gt;
      &lt;br /&gt;
      setKeyslot(KEYSLOT_SSK, keyBuffer); // SSK = keyBuffer.&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
The falcon processor (TSEC) generates a special console-unique key (that will be referred to as the &amp;quot;tsec key&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This is presumably using data stored in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
== Package1ldr ==&lt;br /&gt;
&lt;br /&gt;
=== Key table during package1ldr ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Package1Key&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [1.0.0-3.0.2] Key table after package1ldr ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [4.0.0]+ Key table after package1ldr (Secure Monitor boot) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKeyForFirmwareSpecificPerConsoleKeyGen&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| StaticKeyForFirmwareSpecificPerConsoleKeyGen&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [4.0.0]+ Key table after package1ldr (Secure Monitor runtime) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| FirmwareSpecificPerConsoleKey&lt;br /&gt;
| Secure Monitor init&lt;br /&gt;
| Yes&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [6.2.0]+ Key table after package1ldr/TSEC Payload (Secure Monitor boot) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| TsecKey&lt;br /&gt;
| [[TSEC#Payload|Package1ldr TSEC Firmware]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| TsecRootKey&lt;br /&gt;
| [[TSEC#Payload|Package1ldr TSEC Firmware]]&lt;br /&gt;
| No&lt;br /&gt;
| Unknown&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
Note: aes_unwrap(wrapped_key, wrap_key) is just another name for a single AES-128 block decryption.&lt;br /&gt;
&lt;br /&gt;
If bit0 of 0x7000FB94 is clear, it will initialize keys like this (probably used for internal development units only):&lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = aes_unwrap(f5b1eadb.., sbk)&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x11 ? simpleseed_dev0 : simpleseed_dev1, aes_unwrap(5ff9c2d9.., sbk))&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e..., aes_unwrap(6e4a9592.., ssk))&lt;br /&gt;
&lt;br /&gt;
[4.0.0+] Above method was removed.&lt;br /&gt;
&lt;br /&gt;
Normal key generation looks like this on 1.0.0/2.0.0:&lt;br /&gt;
&lt;br /&gt;
  keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key    /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 3.0.0, they moved keyslots around a little to generate the same per-console key as 1.0.0:&lt;br /&gt;
&lt;br /&gt;
  old_keyblob_key /* slot10 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  keyblob_key     /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key        /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 4.0.0 it was further moved around:&lt;br /&gt;
&lt;br /&gt;
  keyblob_key     /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key        /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key        /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key          /* slot12 */ = aes_unwrap(normalseed_retail, keyblob+0x20)&lt;br /&gt;
  new_master_key      /* slot14 */ = aes_unwrap(2dc1f48d.., keyblob+0x20)&lt;br /&gt;
  new_per_console_key /* slot13 */ = aes_unwrap(0c9109db.., old_keyblob_key)&lt;br /&gt;
  per_console_key     /* slot15 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 6.2.0, they moved key generation out of package1ldr, and into the Secure Monitor&#039;s boot section:&lt;br /&gt;
&lt;br /&gt;
  clear_keyslots_other_than_12_13_and_14()&lt;br /&gt;
  &lt;br /&gt;
  old_keyblob_key /* slot15 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot12 */), sbk /* slot14 */)&lt;br /&gt;
  /* Previously, master_kek was stored at keyblob+0x20) */&lt;br /&gt;
  master_kek      /* slot13 */ = aes_unwrap(374b7729.. /* probably firmware specific */, tsec_root_key /* slot13 */) &lt;br /&gt;
  &lt;br /&gt;
  clear_keyslot(12)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  new_master_key      /* slot12 */ = aes_unwrap(2dc1f48d.., master_kek)        &lt;br /&gt;
  master_key          /* slot13 */ = aes_unwrap(normalseed_retail, master_kek) &lt;br /&gt;
  new_per_console_key /* slot14 */ = aes_unwrap(0c9109db.., old_keyblob_key)&lt;br /&gt;
  per_console_key     /* slot15 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
SBK and SSK keyslots are cleared after keys have been generated.&lt;br /&gt;
&lt;br /&gt;
See table above for which keys are console unique.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the hardcoded constants for the keyblob used in the current revision. Nintendo are withholding all the future hardcoded constants.&lt;br /&gt;
&lt;br /&gt;
This means that if you have an attack on the bootloader, you need to re-preform it every time they move to a new keyblob.&lt;br /&gt;
&lt;br /&gt;
Dumping the SBK and TSEC key of any single system should be enough to derive all key material on the system, prior to 6.2.0.&lt;br /&gt;
&lt;br /&gt;
The key-derivation is described in more detail [[Package1#Key_generation|here]].&lt;br /&gt;
&lt;br /&gt;
==== Keyblob ====&lt;br /&gt;
There are 32 keyblobs written to NAND at factory, with each keyblob encrypted with a console-unique key derived from the console&#039;s SBK, the console&#039;s tsec key, and a constant specific to each keyblob.&lt;br /&gt;
&lt;br /&gt;
Despite being encrypted with console unique keys, though, the decrypted keyblob contents are shared for all consoles.&lt;br /&gt;
&lt;br /&gt;
==== Seeds ====&lt;br /&gt;
  normalseed_retail = d8a2410a...&lt;br /&gt;
  &lt;br /&gt;
  [1.0.0] wrapped_keyblob_key = df206f59...&lt;br /&gt;
  [1.0.0] simpleseed_dev0   = aff11423...&lt;br /&gt;
  [1.0.0] simpleseed_dev1   = 5e177ee1...&lt;br /&gt;
  [1.0.0] normalseed_dev    = 0542a0fd...&lt;br /&gt;
  &lt;br /&gt;
  [3.0.0] wrapped_keyblob_key = 0c25615d...  &lt;br /&gt;
  [3.0.0] simpleseed_dev0   = de00216a...&lt;br /&gt;
  [3.0.0] simpleseed_dev1   = 2db7c0a1...&lt;br /&gt;
  [3.0.0] normalseed_dev    = 678c5a03...&lt;br /&gt;
  &lt;br /&gt;
  [3.0.1] wrapped_keyblob_key = 337685ee...  &lt;br /&gt;
  [3.0.1] simpleseed_dev0   = e045f5ba...&lt;br /&gt;
  [3.0.1] simpleseed_dev1   = 84d92e0d...&lt;br /&gt;
  [3.0.1] normalseed_dev    = cd88155b...&lt;br /&gt;
  &lt;br /&gt;
  [4.0.0] wrapped_keyblob_key = 2d1f4880...&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1-3.0.2&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0-4.1.0&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 5.0.0-5.1.0&lt;br /&gt;
| 5&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 6.0.0-6.1.0&lt;br /&gt;
| 6&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Starting from 6.2.0, key generation no longer uses keyblobs.&lt;br /&gt;
&lt;br /&gt;
== Secure Monitor Init ==&lt;br /&gt;
On all versions, the key to decrypt [[Package2]] is generated by decrypting a constant seed with the master key. The key is erased after use.   &lt;br /&gt;
&lt;br /&gt;
Additionally, starting from 4.0.0, the Secure Monitor init will decrypt another constant seed successively with a special per console key and a special static key passed by package1loader, to generate the firmware specific per-console key. The operation will erase these special keys passed by package1loader. &lt;br /&gt;
&lt;br /&gt;
== Secure Monitor ==&lt;br /&gt;
The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=4515</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=4515"/>
		<updated>2018-04-23T20:39:31Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Fun stuff part two&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
System Flaws are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of known and public Switch System Flaws.&lt;br /&gt;
&lt;br /&gt;
=List of Switch System Flaws=&lt;br /&gt;
&lt;br /&gt;
== Hardware == &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
&lt;br /&gt;
[5.0.0+] Works around this hardware flaw by using memory pool partitioning. You can no longer escalate into sysmodules with GPU DMA because all their memory is allocated using heap that&#039;s carved out.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Weak Security Engine context validation&lt;br /&gt;
| The Tegra X1 supports a &amp;quot;deep sleep&amp;quot; feature, where everything but DRAM and the PMC registers lose their content (and the SoC loses power). Upon awaking, the bootrom re-executes, restoring system state. Among these stored states is the Security Engine&#039;s saved state, which uses AES-128-CBC with a random key and all-zeroes IV. However, the bootrom doesn&#039;t perform a MAC on this data, and only validates the last block. This allows one to control most of security engine&#039;s state upon wakeup, if one has a way to modify the encrypted state buffer.&lt;br /&gt;
&lt;br /&gt;
With a way to modify the encrypted state buffer, one can thus dump keys from &amp;quot;write-only&amp;quot; keyslots, etc.&lt;br /&gt;
&lt;br /&gt;
This also bypasses the SBK protection of the bootROM: indeed, at warmboot, bootROM will always clear keyslot 0xE to prevent malicious code from saving the SBK. Moving the SBK to another keyslot in the saved context renders this protection moot.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| December 2017&lt;br /&gt;
| January 20, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
| Security Engine keyslots vulnerable to partial overwrite attack&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 security engine supports writing keyslot data to the engine with syntax as follows: &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_ADDR = (keyslot &amp;lt;&amp;lt; 4) | (dword_index_in_keyslot); &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_DATA = readle32(key, dword_index_in_keyslot * 4); &lt;br /&gt;
&lt;br /&gt;
However, the Security Engine flushes writes to the internal key tables immediately when AES_KEYTABLE_DATA is written -- this allows one to overwrite a single dword of a key at a time, and thus brute force the contents of keyslots in time (2^32 * 8) = 2^35 instead of 2^256.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| Theorized Summer 2017 due to suggestive syntax, confirmed April 9, 2018&lt;br /&gt;
| April 9, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], almost surely others (independently).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== System software ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Stage 1 Bootloader ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;s stage 1 bootloader, on panic(), clears the stack and then attempts to clear the Security Engine. However, it does so by dereferencing a pointer to the SE in .bss (initially NULL), and this pointer doesn&#039;t get initialized until partway into the bootloader&#039;s main() after several functions that might panic() are called. Thus, a panic() caused prior to SE initialization would result in the SE pointer still being NULL when dereferenced. &lt;br /&gt;
The BPMP doesn&#039;t have an active MPU and the bus won&#039;t data abort on an invalid address, so no exception will be entered: it&#039;ll end up overwriting some exception vectors with NULL before halting.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Some exception vectors overwritten with NULL, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|  FUSE_DIS_PGM not written by package1 &lt;br /&gt;
|  The switch&#039;s hardware fuse driver contains a write-once bit in a register called &amp;quot;FUSE_DIS_PGM&amp;quot;, which disables burning fuses until the next reboot. While Nintendo&#039;s bootloader code for waking up from sleep writes this on all firmware, the actual package1 initial bootloader forgets to write to it on cold reboot. &lt;br /&gt;
&lt;br /&gt;
This isn&#039;t too big of a problem because another fuse is burnt on retail devices (production mode), which prevents burning *all* fuses other than ODM_RESERVED ones in hardware.&lt;br /&gt;
&lt;br /&gt;
This was fixed in 3.0.0 by writing to the register on cold boot (although the write happens in TZ instead of package1 where it should take place, possibly to obfuscate the fact that they made this mistake).&lt;br /&gt;
|  Burning arbitrary ODM reserved fuses with TZ code execution, which should never be possible for non-bootloader code.&lt;br /&gt;
&lt;br /&gt;
Warning: one could irreparably brick one&#039;s console by playing with this.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Late summer/early fall 2017&lt;br /&gt;
|  December 31, 2017&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Non-atomic mutexes&lt;br /&gt;
|  When an [[SMC]] is called, TrustZone sets a global variable to mark that an SMC is in progress, so that two SMCs using shared resources (like the security engine) do not trample on one another. On 1.0.0, this global variable was written using non-atomic writes, and thus a race condition is possible.&lt;br /&gt;
&lt;br /&gt;
However, the SMC handler enforces that all SMCs must be called from core #3, unless the top-level handler ID is 1 (SMCs internal to the kernel). Thus, the only SMCs that can be run side-by-side are [any userland smc] and smcGetRandomBytesForKernel, and this turns out to not really be abusable.&lt;br /&gt;
| Mostly useless. Maybe some oob-write into unused (and thus useless) memory if running smcGetRandomBytesForKernel and smcGetRandomBytesForUser at the same time.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| December 2017 (Probably earlier by others)&lt;br /&gt;
| January 18, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], probably others.&lt;br /&gt;
|-&lt;br /&gt;
|  jamais vu (non-secure world access to PMC MMIO and pre-deep sleep firmware)&lt;br /&gt;
|  On [[1.0.0]], one could map in the PMC registers in userland. In addition, [[AM_services|am]] ran a little-kernel based firmware on the BPMP at runtime. With code execution under am, one could modify the BPMP&#039;s little-kernel firmware to hook deep sleep entry, and modify TrustZone/Security engine state. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry.&lt;br /&gt;
|  Arbitrary TrustZone code execution.&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  December, 2017&lt;br /&gt;
|  January 20, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  Missed BPMP Exception Vector Writes&lt;br /&gt;
|  Starting in [[2.0.0]], the BPMP is asleep at runtime, and is turned on by TrustZone during [[SMC|smcCpuSuspend]] in order to initiate the deep sleep process. When it does so, it is held in RESET, and TrustZone attempts to write to the BPMP exception vectors at 0x6000F200 to register EVP_RESET = lp0_entry_fw_crt0, and all other EVPs to a function that simply reboots. However, while they successfully write EVP_RESET, they miss all the other vectors, accidentally writing to the 0x6000F004-0x6000F020 region instead of the 0x6000F204-0x6000F220 region they want to write to. This results in all the exception vectors for the BPMP other than RESET being &amp;quot;undefined&amp;quot; (attacker controlled).&lt;br /&gt;
&lt;br /&gt;
With some way of causing an exception vector to be taken at the right time, this would give pre-sleep code execution (and thus arbitrary TrustZone code execution, via the security engine flaw). However, none of the abort vectors are really triggerable, and interrupts are disabled for the BPMP when it is taken out of reset. Thus, this is useless in practice.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by writing to the correct registers.&lt;br /&gt;
|  Theoretically: Arbitrary TrustZone code execution. In practice: Useless.&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  January, 2018&lt;br /&gt;
|  February 23, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]], [[User:Naehrwert|naehrwert]], [[User:Hexkyz|hexkyz]], probably others, independently.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| svcWaitSynchronization/svcReplyAndReceive bad cleanup on error&lt;br /&gt;
| If there is a page fault when fetching handles from the userspace array, it cleans up by dereferencing all objects despite having only loaded first N. Allows the attacker to make arbitrary decrefs on any kernel synchronization object, and thus can be used to get UAF. Haven&#039;t actually been tried on real HW though, but should work (tm).&lt;br /&gt;
| Kernel code execution&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| &lt;br /&gt;
| 24 April&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| GetLastThreadInfo UAF&lt;br /&gt;
| GetLastThreadInfo syscall gets last-scheduled-KThread pointer from KScheduler object. This pointer is not reference counted, and can be pointing to a freed KThread.&lt;br /&gt;
| Nothing. There is a theoretical race that might leak from a KThread from a different process, but it&#039;s impossible to trigger practically.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| &lt;br /&gt;
| 15 October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Memory Controller not properly secured&lt;br /&gt;
| The Switch OS originally had the memory controller not set to be accessible only by the secure-world, which was problematic because insecure access can compromise the kernel.&lt;br /&gt;
&lt;br /&gt;
This was fixed partially in [[2.0.0]] by blacklisting the memory controller from being mapped by user-processes, and was fixed entirely in [[4.0.0]] by making the memory controller TZ-only and making all kernel accesses go through [[SMC|smcReadWriteRegister]].&lt;br /&gt;
| With some way to access the memory controller MMIO, arbitrary kernel code execution.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| January 2018&lt;br /&gt;
| January 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], [[User:Yellows8|yellows8]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) service serves as an interface between the rest of the system and the secure monitor. Prior to [[4.0.0]], spl exposed only a single service &amp;quot;spl:&amp;quot;, which provided all TrustZone wrapper functions to all sysmodules with access to it. Thus anyone with access to the spl: service (via smhax or by pwning a sysmodule with access) could do crypto with any access keys they knew. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders (like expLDR): dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| nspwn&lt;br /&gt;
| fsp-ldr command 0 &amp;quot;MountCode&amp;quot; takes in a Content Path (retrieved from NCM by Loader), and returns an IFileSystem for the resulting ExeFS. These content paths, are normally NCAs, but MountCode also supports a number of other formats, including &amp;quot;.nsp&amp;quot; -- which is just a PFS0.&lt;br /&gt;
&lt;br /&gt;
When a path ending in &amp;quot;.nsp&amp;quot; is parsed by MountCode, the PFS0 is treated as a raw ExeFS. Because there is no NCA header, the ACID signatures are not validated -- and because there are no other signatures in a PFS0, this results in no signature checking happening at all.&lt;br /&gt;
&lt;br /&gt;
The actual .nsp handling is eventually done by {content mounting function} called by MountCode and other FS commands.&lt;br /&gt;
&lt;br /&gt;
Thus, by placing an ExeFS (NSOs + &amp;quot;main.npdm&amp;quot;) and setting one&#039;s desired title ID to &amp;quot;@Sdcard:/some_title.nsp&amp;quot; or &amp;quot;@User:/some_title.nsp&amp;quot; etc one can launch arbitrary unsigned code, with arbitrary unsigned NPDMs.&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: Arbitrary code execution with full system privileges.&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| Late 2017&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| The [[BCAT_Content_Container]] secret-data index is not validated at all. This is handled before the RSA-signature(?) is ever used. Since the field is an u8, a total of 0x800-bytes relative to the array start can be accessed.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  Prior to [[3.0.0]], pl:u (Shared Font services implemented in the NS sysmodule) service commands 1,2,3 took in a signed 32-bit index and returned that index of an array but did not check that index at all. This allowed for an arbitrary read within a 34-bit range (33-bit signed) from NS .bss. In [[3.0.0]], sending out of range indexes causes error code 0x60A to be returned.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], Reswitched team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|domain messages]] are not bounds checked. This out-of-bounds read could be exploited to brute-force ASLR and get PC control in some services that support domain messages.&lt;br /&gt;
|&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|-&lt;br /&gt;
| expLDR (sysmodule handle table exhaustion)&lt;br /&gt;
| Most sysmodules share common template code to handle IPC control messages. The command DuplicateSession (type 5 command 2)&#039;s template code will abort() if it fails to duplicate a session&#039;s handle for the requester. Because many sysmodules have limited handle table size (smaller than the browser/other entrypoints), repeatedly requesting to duplicate one&#039;s session will cause the sysmodule to run out of handle table space and abort, causing the service to release all its handles cleanly.&lt;br /&gt;
| Sysmodule crashes.  Most usefully, crashing ldr allows access to fsp-ldr and crashing pm allows access to fsp-pr. Useless after [[4.0.0]], which mitigated a number of single-session service access issues.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| 4.1.0&lt;br /&gt;
| 24 June 2017&lt;br /&gt;
| 8 March 2018&lt;br /&gt;
| [[User:daeken|daeken]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=4514</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=4514"/>
		<updated>2018-04-23T20:33:04Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Fun stuff&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
System Flaws are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of known and public Switch System Flaws.&lt;br /&gt;
&lt;br /&gt;
=List of Switch System Flaws=&lt;br /&gt;
&lt;br /&gt;
== Hardware == &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
&lt;br /&gt;
[5.0.0+] Works around this hardware flaw by using memory pool partitioning. You can no longer escalate into sysmodules with GPU DMA because all their memory is allocated using heap that&#039;s carved out.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Weak Security Engine context validation&lt;br /&gt;
| The Tegra X1 supports a &amp;quot;deep sleep&amp;quot; feature, where everything but DRAM and the PMC registers lose their content (and the SoC loses power). Upon awaking, the bootrom re-executes, restoring system state. Among these stored states is the Security Engine&#039;s saved state, which uses AES-128-CBC with a random key and all-zeroes IV. However, the bootrom doesn&#039;t perform a MAC on this data, and only validates the last block. This allows one to control most of security engine&#039;s state upon wakeup, if one has a way to modify the encrypted state buffer.&lt;br /&gt;
&lt;br /&gt;
With a way to modify the encrypted state buffer, one can thus dump keys from &amp;quot;write-only&amp;quot; keyslots, etc.&lt;br /&gt;
&lt;br /&gt;
This also bypasses the SBK protection of the bootROM: indeed, at warmboot, bootROM will always clear keyslot 0xE to prevent malicious code from saving the SBK. Moving the SBK to another keyslot in the saved context renders this protection moot.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| December 2017&lt;br /&gt;
| January 20, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
| Security Engine keyslots vulnerable to partial overwrite attack&lt;br /&gt;
| &lt;br /&gt;
The Tegra X1 security engine supports writing keyslot data to the engine with syntax as follows: &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_ADDR = (keyslot &amp;lt;&amp;lt; 4) | (dword_index_in_keyslot); &lt;br /&gt;
&lt;br /&gt;
SECURITY_ENGINE-&amp;gt;AES_KEYTABLE_DATA = readle32(key, dword_index_in_keyslot * 4); &lt;br /&gt;
&lt;br /&gt;
However, the Security Engine flushes writes to the internal key tables immediately when AES_KEYTABLE_DATA is written -- this allows one to overwrite a single dword of a key at a time, and thus brute force the contents of keyslots in time (2^32 * 8) = 2^35 instead of 2^256.&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| Theorized Summer 2017 due to suggestive syntax, confirmed April 9, 2018&lt;br /&gt;
| April 9, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], almost surely others (independently).&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== System software ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Stage 1 Bootloader ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;s stage 1 bootloader, on panic(), clears the stack and then attempts to clear the Security Engine. However, it does so by dereferencing a pointer to the SE in .bss (initially NULL), and this pointer doesn&#039;t get initialized until partway into the bootloader&#039;s main() after several functions that might panic() are called. Thus, a panic() caused prior to SE initialization would result in the SE pointer still being NULL when dereferenced. This would cause a data abort, causing the bootloader to clear the stack and then try to clear the security engine...dereferencing NULL again, over and over in a loop.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Infinite clear-the-stack-then-data-abort loop very early in boot, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|  FUSE_DIS_PGM not written by package1 &lt;br /&gt;
|  The switch&#039;s hardware fuse driver contains a write-once bit in a register called &amp;quot;FUSE_DIS_PGM&amp;quot;, which disables burning fuses until the next reboot. While Nintendo&#039;s bootloader code for waking up from sleep writes this on all firmware, the actual package1 initial bootloader forgets to write to it on cold reboot. &lt;br /&gt;
&lt;br /&gt;
This isn&#039;t too big of a problem because another fuse is burnt on retail devices (production mode), which prevents burning *all* fuses other than ODM_RESERVED ones in hardware.&lt;br /&gt;
&lt;br /&gt;
This was fixed in 3.0.0 by writing to the register on cold boot (although the write happens in TZ instead of package1 where it should take place, possibly to obfuscate the fact that they made this mistake).&lt;br /&gt;
|  Burning arbitrary ODM reserved fuses with TZ code execution, which should never be possible for non-bootloader code.&lt;br /&gt;
&lt;br /&gt;
Warning: one could irreparably brick one&#039;s console by playing with this.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Late summer/early fall 2017&lt;br /&gt;
|  December 31, 2017&lt;br /&gt;
|  [[User:SciresM|SciresM]], [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Non-atomic mutexes&lt;br /&gt;
|  When an [[SMC]] is called, TrustZone sets a global variable to mark that an SMC is in progress, so that two SMCs using shared resources (like the security engine) do not trample on one another. On 1.0.0, this global variable was written using non-atomic writes, and thus a race condition is possible.&lt;br /&gt;
&lt;br /&gt;
However, the SMC handler enforces that all SMCs must be called from core #3, unless the top-level handler ID is 1 (SMCs internal to the kernel). Thus, the only SMCs that can be run side-by-side are [any userland smc] and smcGetRandomBytesForKernel, and this turns out to not really be abusable.&lt;br /&gt;
| Mostly useless. Maybe some oob-write into unused (and thus useless) memory if running smcGetRandomBytesForKernel and smcGetRandomBytesForUser at the same time.&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| December 2017 (Probably earlier by others)&lt;br /&gt;
| January 18, 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], probably others.&lt;br /&gt;
|-&lt;br /&gt;
|  jamais vu (non-secure world access to PMC MMIO and pre-deep sleep firmware)&lt;br /&gt;
|  On [[1.0.0]], one could map in the PMC registers in userland. In addition, [[AM_services|am]] ran a little-kernel based firmware on the BPMP at runtime. With code execution under am, one could modify the BPMP&#039;s little-kernel firmware to hook deep sleep entry, and modify TrustZone/Security engine state. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[2.0.0]] by making the PMC secure-world only, blacklisting the BPMP&#039;s exception vectors from being mapped, and thoroughly checking for malicious behavior on deep sleep entry.&lt;br /&gt;
|  Arbitrary TrustZone code execution.&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  [[2.0.0]]&lt;br /&gt;
|  December, 2017&lt;br /&gt;
|  January 20, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]]&lt;br /&gt;
|-&lt;br /&gt;
|  Missed BPMP Exception Vector Writes&lt;br /&gt;
|  Starting in [[2.0.0]], the BPMP is asleep at runtime, and is turned on by TrustZone during [[SMC|smcCpuSuspend]] in order to initiate the deep sleep process. When it does so, it is held in RESET, and TrustZone attempts to write to the BPMP exception vectors at 0x6000F200 to register EVP_RESET = lp0_entry_fw_crt0, and all other EVPs to a function that simply reboots. However, while they successfully write EVP_RESET, they miss all the other vectors, accidentally writing to the 0x6000F004-0x6000F020 region instead of the 0x6000F204-0x6000F220 region they want to write to. This results in all the exception vectors for the BPMP other than RESET being &amp;quot;undefined&amp;quot; (attacker controlled).&lt;br /&gt;
&lt;br /&gt;
With some way of causing an exception vector to be taken at the right time, this would give pre-sleep code execution (and thus arbitrary TrustZone code execution, via the security engine flaw). However, none of the abort vectors are really triggerable, and interrupts are disabled for the BPMP when it is taken out of reset. Thus, this is useless in practice.&lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by writing to the correct registers.&lt;br /&gt;
|  Theoretically: Arbitrary TrustZone code execution. In practice: Useless.&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  [[4.0.0]]&lt;br /&gt;
|  January, 2018&lt;br /&gt;
|  February 23, 2018&lt;br /&gt;
|  [[User:SciresM|SciresM]] and [[User:motezazer|motezazer]], [[User:Naehrwert|naehrwert]], [[User:Hexkyz|hexkyz]], probably others, independently.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| svcWaitSynchronization/svcReplyAndReceive bad cleanup on error&lt;br /&gt;
| If there is a page fault when fetching handles from the userspace array, it cleans up by dereferencing all objects despite having only loaded first N. Allows the attacker to make arbitrary decrefs on any kernel synchronization object, and thus can be used to get UAF. Haven&#039;t actually been tried on real HW though, but should work (tm).&lt;br /&gt;
| Kernel code execution&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| &lt;br /&gt;
| 24 April&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| GetLastThreadInfo UAF&lt;br /&gt;
| GetLastThreadInfo syscall gets last-scheduled-KThread pointer from KScheduler object. This pointer is not reference counted, and can be pointing to a freed KThread.&lt;br /&gt;
| Nothing. There is a theoretical race that might leak from a KThread from a different process, but it&#039;s impossible to trigger practically.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| &lt;br /&gt;
| 15 October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Memory Controller not properly secured&lt;br /&gt;
| The Switch OS originally had the memory controller not set to be accessible only by the secure-world, which was problematic because insecure access can compromise the kernel.&lt;br /&gt;
&lt;br /&gt;
This was fixed partially in [[2.0.0]] by blacklisting the memory controller from being mapped by user-processes, and was fixed entirely in [[4.0.0]] by making the memory controller TZ-only and making all kernel accesses go through [[SMC|smcReadWriteRegister]].&lt;br /&gt;
| With some way to access the memory controller MMIO, arbitrary kernel code execution.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| January 2018&lt;br /&gt;
| January 2018&lt;br /&gt;
| [[User:SciresM|SciresM]], [[User:Yellows8|yellows8]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) service serves as an interface between the rest of the system and the secure monitor. Prior to [[4.0.0]], spl exposed only a single service &amp;quot;spl:&amp;quot;, which provided all TrustZone wrapper functions to all sysmodules with access to it. Thus anyone with access to the spl: service (via smhax or by pwning a sysmodule with access) could do crypto with any access keys they knew. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders (like expLDR): dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|-&lt;br /&gt;
| nspwn&lt;br /&gt;
| fsp-ldr command 0 &amp;quot;MountCode&amp;quot; takes in a Content Path (retrieved from NCM by Loader), and returns an IFileSystem for the resulting ExeFS. These content paths, are normally NCAs, but MountCode also supports a number of other formats, including &amp;quot;.nsp&amp;quot; -- which is just a PFS0.&lt;br /&gt;
&lt;br /&gt;
When a path ending in &amp;quot;.nsp&amp;quot; is parsed by MountCode, the PFS0 is treated as a raw ExeFS. Because there is no NCA header, the ACID signatures are not validated -- and because there are no other signatures in a PFS0, this results in no signature checking happening at all.&lt;br /&gt;
&lt;br /&gt;
The actual .nsp handling is eventually done by {content mounting function} called by MountCode and other FS commands.&lt;br /&gt;
&lt;br /&gt;
Thus, by placing an ExeFS (NSOs + &amp;quot;main.npdm&amp;quot;) and setting one&#039;s desired title ID to &amp;quot;@Sdcard:/some_title.nsp&amp;quot; or &amp;quot;@User:/some_title.nsp&amp;quot; etc one can launch arbitrary unsigned code, with arbitrary unsigned NPDMs.&lt;br /&gt;
| With access to &amp;quot;lr&amp;quot;: Arbitrary code execution with full system privileges.&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| [[5.0.0]]&lt;br /&gt;
| Late 2017&lt;br /&gt;
| April 23, 2018&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| The [[BCAT_Content_Container]] secret-data index is not validated at all. This is handled before the RSA-signature(?) is ever used. Since the field is an u8, a total of 0x800-bytes relative to the array start can be accessed.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  Prior to [[3.0.0]], pl:u (Shared Font services implemented in the NS sysmodule) service commands 1,2,3 took in a signed 32-bit index and returned that index of an array but did not check that index at all. This allowed for an arbitrary read within a 34-bit range (33-bit signed) from NS .bss. In [[3.0.0]], sending out of range indexes causes error code 0x60A to be returned.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], Reswitched team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|domain messages]] are not bounds checked. This out-of-bounds read could be exploited to brute-force ASLR and get PC control in some services that support domain messages.&lt;br /&gt;
|&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|-&lt;br /&gt;
| expLDR (sysmodule handle table exhaustion)&lt;br /&gt;
| Most sysmodules share common template code to handle IPC control messages. The command DuplicateSession (type 5 command 2)&#039;s template code will abort() if it fails to duplicate a session&#039;s handle for the requester. Because many sysmodules have limited handle table size (smaller than the browser/other entrypoints), repeatedly requesting to duplicate one&#039;s session will cause the sysmodule to run out of handle table space and abort, causing the service to release all its handles cleanly.&lt;br /&gt;
| Sysmodule crashes.  Most usefully, crashing ldr allows access to fsp-ldr and crashing pm allows access to fsp-pr. Useless after [[4.0.0]], which mitigated a number of single-session service access issues.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| 4.1.0&lt;br /&gt;
| 24 June 2017&lt;br /&gt;
| 8 March 2018&lt;br /&gt;
| [[User:daeken|daeken]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Gamecard&amp;diff=4274</id>
		<title>Gamecard</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Gamecard&amp;diff=4274"/>
		<updated>2018-03-24T21:42:36Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;For the Gamecard partitions that can be [[Filesystem_services|mounted]], see [[Gamecard_Partition|here]].&lt;br /&gt;
&lt;br /&gt;
For the format of the Gamecard image, see [[Gamecard_Format|here]].&lt;br /&gt;
&lt;br /&gt;
= Gamecard controller =&lt;br /&gt;
&lt;br /&gt;
The gamecard controller (a separate chip on the gamecard reader board) is responsible for communicating with the Gamecard.&lt;br /&gt;
[[Filesystem_services|FS]], to access the gamecard data, will communicate with the gamecard controller. At each boot, firmware blobs (with a fixed size of 0x7800 bytes) are sent by FS to the gamecard controller.&lt;br /&gt;
&lt;br /&gt;
The gamecard controller firmware is encrypted, signed and follows the format below.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x100&lt;br /&gt;
| RSA-PKCS#1 signature&lt;br /&gt;
|-&lt;br /&gt;
| 0x100&lt;br /&gt;
| 0x4&lt;br /&gt;
| Magic (&amp;quot;LAFW&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x104&lt;br /&gt;
| 0x4&lt;br /&gt;
| Unknown (0xFF000000, 0xFFFF0000 or 0xFFFFFF00)&lt;br /&gt;
|-&lt;br /&gt;
| 0x108&lt;br /&gt;
| 0x4&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
| 0x10C&lt;br /&gt;
| 0x4&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 0x110&lt;br /&gt;
| 0x4&lt;br /&gt;
| Version (0, 1 or 3)&lt;br /&gt;
|-&lt;br /&gt;
| 0x114&lt;br /&gt;
| 0x4&lt;br /&gt;
| Unknown (0x80000000)&lt;br /&gt;
|-&lt;br /&gt;
| 0x118&lt;br /&gt;
| 0x4&lt;br /&gt;
| Data size&lt;br /&gt;
|-&lt;br /&gt;
| 0x11C&lt;br /&gt;
| 0x4&lt;br /&gt;
| &lt;br /&gt;
|-&lt;br /&gt;
| 0x120&lt;br /&gt;
| 0x10&lt;br /&gt;
| Data hash&lt;br /&gt;
|-&lt;br /&gt;
| 0x130&lt;br /&gt;
| 0x10&lt;br /&gt;
| Placeholder string (&amp;quot;IDIDIDIDIDIDIDID&amp;quot;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x140&lt;br /&gt;
| 0x40&lt;br /&gt;
| Empty&lt;br /&gt;
|-&lt;br /&gt;
| 0x180&lt;br /&gt;
| 0x7680&lt;br /&gt;
| Encrypted data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Hardware =&lt;br /&gt;
{|  style=&amp;quot;float:right; margin-left: 0px;&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| [[File:ZeldaFront.jpg|200px|thumb|right|A Switch game cartridge, frontside]] &lt;br /&gt;
| [[File:ZeldaBack.jpg|200px|thumb|right|A Switch game cartridge, backside]] &lt;br /&gt;
|-&lt;br /&gt;
| [[File:CartridgeFront.jpeg|200px|thumb|right|Close-up of frontside PCB]]&lt;br /&gt;
|rowspan=&amp;quot;2&amp;quot;|[[File:CartridgeBack.jpeg|200px|thumb|right|Close-up of backside PCB]]&lt;br /&gt;
|-&lt;br /&gt;
|[[File:CartridgeFrontBare.jpeg|200px|thumb|right|Close-up of stripped frontside PCB]]&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Pinout ==&lt;br /&gt;
[[File:Gamecard-pinout.png|400px]]&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Pin&lt;br /&gt;
! Name&lt;br /&gt;
! Direction&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 &lt;br /&gt;
| IRQ?&lt;br /&gt;
| Output&lt;br /&gt;
| Always wired to GND inside game cartridge; Possibly used for interrupt signaling&lt;br /&gt;
|- &lt;br /&gt;
| 1 &lt;br /&gt;
| RCLK&lt;br /&gt;
| Output&lt;br /&gt;
| Return clock; Game cartridge sends back CLK signal delayed by a few ns&lt;br /&gt;
|- &lt;br /&gt;
| 2 &lt;br /&gt;
| CLK &lt;br /&gt;
| Input&lt;br /&gt;
| Clock, 25MHz&lt;br /&gt;
|- &lt;br /&gt;
| 3 &lt;br /&gt;
| CS&lt;br /&gt;
| Input&lt;br /&gt;
| Chip select; Switch pulls this LOW during a transfer&lt;br /&gt;
|- &lt;br /&gt;
| 4&lt;br /&gt;
| DAT0 &lt;br /&gt;
| Inout&lt;br /&gt;
| Data bus pin 0&lt;br /&gt;
|- &lt;br /&gt;
| 5 &lt;br /&gt;
| DAT1 &lt;br /&gt;
| Inout&lt;br /&gt;
| Data bus pin 1&lt;br /&gt;
|- &lt;br /&gt;
| 6 &lt;br /&gt;
| VCC 3.3v &lt;br /&gt;
| Input&lt;br /&gt;
|&lt;br /&gt;
|- &lt;br /&gt;
| 7 &lt;br /&gt;
| DAT2 &lt;br /&gt;
| Inout&lt;br /&gt;
| Data bus pin 2&lt;br /&gt;
|- &lt;br /&gt;
| 8 &lt;br /&gt;
| DAT3 &lt;br /&gt;
| Inout&lt;br /&gt;
| Data bus pin 3&lt;br /&gt;
|- &lt;br /&gt;
| 9 &lt;br /&gt;
| VCC 1.8v &lt;br /&gt;
| Input&lt;br /&gt;
|&lt;br /&gt;
|- &lt;br /&gt;
| 10 &lt;br /&gt;
| DAT4 &lt;br /&gt;
| Inout&lt;br /&gt;
| Data bus pin 4&lt;br /&gt;
|- &lt;br /&gt;
| 11 &lt;br /&gt;
| DAT5&lt;br /&gt;
| Inout&lt;br /&gt;
| Data bus pin 5&lt;br /&gt;
|- &lt;br /&gt;
| 12 &lt;br /&gt;
| DAT6&lt;br /&gt;
| Inout&lt;br /&gt;
| Data bus pin 6&lt;br /&gt;
|- &lt;br /&gt;
| 13 &lt;br /&gt;
| DAT7&lt;br /&gt;
| Inout&lt;br /&gt;
| Data bus pin 7&lt;br /&gt;
|- &lt;br /&gt;
| 14 &lt;br /&gt;
| GND&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
|- &lt;br /&gt;
| 15 &lt;br /&gt;
| RST&lt;br /&gt;
| Input&lt;br /&gt;
| Reset, active LOW.&lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All IO use 1.8V for logic HIGH and 0V for logic LOW.&lt;br /&gt;
&lt;br /&gt;
== Protocol ==&lt;br /&gt;
Switch game cartridges use a simple (but Nintendo proprietery) SPI-like bus with 8-bit width (DAT7..0). It is very similar to the bus interface of 3DS game cartridges, except with very different commands.&lt;br /&gt;
&lt;br /&gt;
The Switch host starts a transfer by first pulling CS low, followed by clocking a byte each clock cycle. The bus data will always be ready before the rising edge of the CLK signal, so that it can be captured on the rising edge.&lt;br /&gt;
After command bytes are written to the bus, the direction of the bus implicitly changes and the game cartridge responds. The Switch host keeps clocking while the game cartridge responds.&lt;br /&gt;
After the transfer is ended, the CS line is pulled high again.&lt;br /&gt;
&lt;br /&gt;
Commands are 16 bytes long, and followed immediately by a 4-byte CRC-32 over the command bytes. After this, the Switch stops driving the data bus, and the bus will be &#039;floating&#039;. Due to the pull-ups on the bus, it will slowly converge to logic HIGH state. The Switch will clock 2 cycles to allow the bus to settle a direction change. The Switch host will then clock another cycle and if the game cartridge didn&#039;t receive the CRC OK, it will respond with &amp;quot;01&amp;quot;. Otherwise it will respond with &amp;quot;00&amp;quot; and pull DAT0 low on the next cycle to signal it is busy. The Switch host will then keep clocking until the cartridge is ready.&lt;br /&gt;
&lt;br /&gt;
When the game cartridge is ready to send the actual data response, it will pull the DAT0 pin high for 2 cycles to let the Switch host know. After this, the game cartridge will send the actual data response bytes.&lt;br /&gt;
&lt;br /&gt;
The actual response bytes are also followed immediately by a 4-byte CRC-32 over the actual data response bytes.&lt;br /&gt;
&lt;br /&gt;
== Commands ==&lt;br /&gt;
A typical boot up sequence of a game cartridge (in this case, the game &amp;quot;1,2 Switch&amp;quot;) looks like this:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Command&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;5B000000000000010000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x200&lt;br /&gt;
| Read sector 0, contains &amp;quot;HEAD&amp;quot; blob&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;5B000000000000010000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x200&lt;br /&gt;
| Read sector 0, contains &amp;quot;HEAD&amp;quot; blob&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;56000000000000000000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x4&lt;br /&gt;
| Read card id &amp;quot;AE F8 01 21&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;28000000000000000000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x4&lt;br /&gt;
| Read ??? &amp;quot;02 00 00 00&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;A5000000000000000000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x4&lt;br /&gt;
| Read ??? &amp;quot;00 00 00 00&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;56000000000000000000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x4&lt;br /&gt;
| Read card id &amp;quot;AE F8 01 21&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;28000000000000000000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x4&lt;br /&gt;
| Read ??? &amp;quot;02 00 00 00&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;5B000000380000010000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x200&lt;br /&gt;
| Read sector 0x38, contains &amp;quot;CERT&amp;quot; blob&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;E2000000000000000000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x4&lt;br /&gt;
| Read ??? &amp;quot;01 00 00 00&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;E0000000000000000000000000000000&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x200&lt;br /&gt;
| Read crypto-challenge header&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;200838A25A344F818ABB6456694D4E8D&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0&lt;br /&gt;
| Enter crypto mode1 with HOST-RANDOM &amp;quot;0838A25A344F818ABB6456694D4E8D&amp;quot;&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;7EE41FDF12C01C157CC899910673A0CF&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x40&lt;br /&gt;
| Encrypted crypto mode1 command, reads CART-RANDOM&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;263C8230EC15FAE3CE79365BD850F4BD&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x0&lt;br /&gt;
| Encrypted mode1 command, enters crypto mode2 with (HOST-RANDOM, CART-RANDOM)&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;B6FDA6F37FFA29E18831D0B217DFBDBE&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x4&lt;br /&gt;
| Encrypted mode2 command, possibly read card id?&lt;br /&gt;
|- &lt;br /&gt;
| &amp;lt;code&amp;gt;7B97F7DF07240AA9870E1C974336FA8A&amp;lt;/code&amp;gt;&lt;br /&gt;
| 0x4&lt;br /&gt;
| Encrypted mode2 command&lt;br /&gt;
|- &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The meaning of some these commands are currently unknown.&lt;br /&gt;
&lt;br /&gt;
== Observations ==&lt;br /&gt;
* The &amp;quot;update&amp;quot; and &amp;quot;normal&amp;quot; partitions can be dumped using the plaintext 5B commands&lt;br /&gt;
* The &amp;quot;secure&amp;quot; partition can only be read from encrypted mode.&lt;br /&gt;
&lt;br /&gt;
== Encryption ==&lt;br /&gt;
After a few initial plaintext commands, the Switch instructs the game cartridge to enter into encrypted mode. From that point on, commands and responses are sent encrypted over the bus. The encryption algorithm used is currently unknown.&lt;br /&gt;
&lt;br /&gt;
There appear to be 2 kinds of crypto mode. &lt;br /&gt;
&lt;br /&gt;
Crypto mode1 is initiated solely by the HOST-RANDOM as random session seed. In that mode, the Switch host requests for the game cartridge random seed, and then sends a command to enter crypto mode2.&lt;br /&gt;
&lt;br /&gt;
Crypto mode2 takes into account the CART-RANDOM seed generated by the cartridge, and possibly the previous HOST-RANDOM.&lt;br /&gt;
The game cartridge will always send a different CART-RANDOM even if the exact same command sequence is replayed and thus with this scheme replay attacks are not possible.&lt;br /&gt;
&lt;br /&gt;
== Manufacturers ==&lt;br /&gt;
;Macronix (MX)&lt;br /&gt;
: Uses package: LGA&lt;br /&gt;
: Uses card id: 0xC2&lt;br /&gt;
;OKI Semiconductor &lt;br /&gt;
: Uses package: TSOP-48&lt;br /&gt;
: Uses card id: 0xAE&lt;br /&gt;
;SanDisk?&lt;br /&gt;
: Uses package: ??&lt;br /&gt;
: Uses card id: 0x45 ?&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=3995</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=3995"/>
		<updated>2018-03-12T23:39:19Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: New update + clarifications&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== BootROM ==&lt;br /&gt;
The bootrom initializes two keyslots in the hardware engine:&lt;br /&gt;
&lt;br /&gt;
* the SBK (Secure Boot Key) in keyslot 14&lt;br /&gt;
* the SSK (Secure Storage Key) in keyslot 15.&lt;br /&gt;
&lt;br /&gt;
Reads from both of these keyslots are disabled by the bootROM.&lt;br /&gt;
The SBK is stored in [[Fuses#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY]], which are locked to read out only FFs after the bootrom finishes.&lt;br /&gt;
&lt;br /&gt;
SBK is &#039;&#039;&#039;unique&#039;&#039;&#039; per console, and not shared among consoles as originally believed.&lt;br /&gt;
&lt;br /&gt;
The SSK is derived on boot via the SBK, the 32-bit console-unique &amp;quot;Device Key&amp;quot;, and hardware information stored in fuses.&lt;br /&gt;
&lt;br /&gt;
Pseudocode for the derivation is as follows:&lt;br /&gt;
  void generateSSK() {&lt;br /&gt;
      char keyBuffer[0x10]; // Used to store keydata&lt;br /&gt;
      uint hwInfoBuffer[4]; // Used to store info about hardware from fuses&lt;br /&gt;
      uint deviceKey = getDeviceKey(); // Reads 32-bit device key from FUSE_PRIVATE_KEY4.&lt;br /&gt;
      for (int i = 0; i &amp;lt; 4; i++) { // Keybuffer = deviceKey || deviceKey || deviceKey || deviceKey&lt;br /&gt;
          ((uint *)keyBuffer)[i] = deviceKey;&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, deviceKey || {...})&lt;br /&gt;
      &lt;br /&gt;
      // Set up Hardware info buffer&lt;br /&gt;
      uint vendor_code = *((uint *)0x7000FA00) &amp;amp; 0x0000000F; // FUSE_VENDOR_CODE&lt;br /&gt;
      uint fab_code    = *((uint *)0x7000FA04) &amp;amp; 0x0000003F; // FUSE_FAB_CODE&lt;br /&gt;
      uint lot_code_0  = *((uint *)0x7000FA08) &amp;amp; 0xFFFFFFFF; // FUSE_LOT_CODE_0&lt;br /&gt;
      uint lot_code_1  = *((uint *)0x7000FA0C) &amp;amp; 0x0FFFFFFF; // FUSE_LOT_CODE_1&lt;br /&gt;
      uint wafer_id    = *((uint *)0x7000FA10) &amp;amp; 0x0000003F; // FUSE_WAFER_ID&lt;br /&gt;
      uint x_coord     = *((uint *)0x7000FA14) &amp;amp; 0x000001FF; // FUSE_X_COORDINATE&lt;br /&gt;
      uint y_coord     = *((uint *)0x7000FA18) &amp;amp; 0x000001FF; // FUSE_Y_COORDINATE&lt;br /&gt;
      uint unk_hw_fuse = *((uint *)0x7000FA20) &amp;amp; 0x0000003F; // Unknown cached fuse.&lt;br /&gt;
      &lt;br /&gt;
      // HARDWARE_INFO_BUFFER = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID&lt;br /&gt;
      hwInfoBuffer[0] = (lot_code_1 &amp;lt;&amp;lt; 30) | (wafer_id &amp;lt;&amp;lt; 24) | (x_coord &amp;lt;&amp;lt; 15) | (y_coord &amp;lt;&amp;lt; 6) | unk_hw_fuse;&lt;br /&gt;
      hwInfoBuffer[1] = (lot_code_0 &amp;lt;&amp;lt; 26) | (lot_code_1 &amp;gt;&amp;gt; 2);&lt;br /&gt;
      hwInfoBuffer[2] = (fab_code &amp;lt;&amp;lt; 26) | (lot_code_0 &amp;gt;&amp;gt; 6);&lt;br /&gt;
      hwInfoBuffer[3] = vendor_code;&lt;br /&gt;
      &lt;br /&gt;
      for (int i = 0; i &amp;lt; 0x10; i++) { // keyBuffer = XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER)&lt;br /&gt;
          keyBuffer[i] ^= ((char *)hwInfoBuffer)[i];&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER))&lt;br /&gt;
      &lt;br /&gt;
      setKeyslot(KEYSLOT_SSK, keyBuffer); // SSK = keyBuffer.&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
The falcon processor (TSEC) generates a special console-unique key (that will be referred to as the &amp;quot;tsec key&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This is presumably using data stored in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
== Package1ldr ==&lt;br /&gt;
&lt;br /&gt;
=== Key table during package1ldr ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Package1Key&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [1.0.0-3.0.2] Key table after package1ldr ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [4.0.0]+ Key table after package1ldr (Secure Monitor boot) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKeyForFirmwareSpecificPerConsoleKeyGen&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| StaticKeyForFirmwareSpecificPerConsoleKeyGen&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [4.0.0]+ Key table after package1ldr (Secure Monitor runtime) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| FirmwareSpecificPerConsoleKey&lt;br /&gt;
| Secure Monitor init&lt;br /&gt;
| Yes&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1#Package1ldr|Package1ldr]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
Note: aes_unwrap(wrapped_key, wrap_key) is just another name for a single AES-128 block decryption.&lt;br /&gt;
&lt;br /&gt;
If bit0 of 0x7000FB94 is clear, it will initialize keys like this (probably used for internal development units only):&lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = aes_unwrap(f5b1eadb.., sbk)&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x11 ? simpleseed_dev0 : simpleseed_dev1, aes_unwrap(5ff9c2d9.., sbk))&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e..., aes_unwrap(6e4a9592.., ssk))&lt;br /&gt;
&lt;br /&gt;
[4.0.0+] Above method was removed.&lt;br /&gt;
&lt;br /&gt;
Normal key generation looks like this on 1.0.0/2.0.0:&lt;br /&gt;
&lt;br /&gt;
  keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key    /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 3.0.0, they moved keyslots around a little to generate the same per-console key as 1.0.0:&lt;br /&gt;
&lt;br /&gt;
  old_keyblob_key /* slot10 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  keyblob_key     /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key        /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 4.0.0 it was further moved around:&lt;br /&gt;
&lt;br /&gt;
  old_keyblob_key /* slot15 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  keyblob_key     /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key        /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key        /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key          /* slot12 */ = aes_unwrap(normalseed_retail, keyblob+0x20)&lt;br /&gt;
  new_master_key      /* slot14 */ = aes_unwrap(2dc1f48d.., keyblob+0x20)&lt;br /&gt;
  new_per_console_key /* slot13 */ = aes_unwrap(0c9109db.., old_keyblob_key)&lt;br /&gt;
  per_console_key     /* slot15 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
SBK and SSK keyslots are cleared after keys have been generated.&lt;br /&gt;
&lt;br /&gt;
See table above for which keys are console unique.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the hardcoded constants for the keyblob used in the current revision. Nintendo are withholding all the future hardcoded constants.&lt;br /&gt;
&lt;br /&gt;
This means that if you have an attack on the bootloader, you need to re-preform it every time they move to a new keyblob.&lt;br /&gt;
&lt;br /&gt;
Dumping the SBK and TSEC key of any single system should be enough to derive all key material on the system.&lt;br /&gt;
&lt;br /&gt;
The key-derivation is described in more detail [[Package1#Key_generation|here]].&lt;br /&gt;
&lt;br /&gt;
==== Keyblob ====&lt;br /&gt;
There are 32 keyblobs written to NAND at factory, with each keyblob encrypted with a console-unique key derived from the console&#039;s SBK, the console&#039;s tsec key, and a constant specific to each keyblob.&lt;br /&gt;
&lt;br /&gt;
Despite being encrypted with console unique keys, though, the decrypted keyblob contents are shared for all consoles.&lt;br /&gt;
&lt;br /&gt;
==== Seeds ====&lt;br /&gt;
  normalseed_retail = d8a2410a...&lt;br /&gt;
  &lt;br /&gt;
  [1.0.0] wrapped_keyblob_key = df206f59...&lt;br /&gt;
  [1.0.0] simpleseed_dev0   = aff11423...&lt;br /&gt;
  [1.0.0] simpleseed_dev1   = 5e177ee1...&lt;br /&gt;
  [1.0.0] normalseed_dev    = 0542a0fd...&lt;br /&gt;
  &lt;br /&gt;
  [3.0.0] wrapped_keyblob_key = 0c25615d...  &lt;br /&gt;
  [3.0.0] simpleseed_dev0   = de00216a...&lt;br /&gt;
  [3.0.0] simpleseed_dev1   = 2db7c0a1...&lt;br /&gt;
  [3.0.0] normalseed_dev    = 678c5a03...&lt;br /&gt;
  &lt;br /&gt;
  [3.0.1] wrapped_keyblob_key = 337685ee...  &lt;br /&gt;
  [3.0.1] simpleseed_dev0   = e045f5ba...&lt;br /&gt;
  [3.0.1] simpleseed_dev1   = 84d92e0d...&lt;br /&gt;
  [3.0.1] normalseed_dev    = cd88155b...&lt;br /&gt;
  &lt;br /&gt;
  [4.0.0] wrapped_keyblob_key = 2d1f4880...&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1-3.0.2&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0-4.1.0&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 5.0.0&lt;br /&gt;
| 5&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Secure Monitor Init ==&lt;br /&gt;
On all versions, the key to decrypt [[Package2]] is generated by decrypting a constant seed with the master key. The key is erased after use.   &lt;br /&gt;
&lt;br /&gt;
Additionally, starting from 4.0.0, the Secure Monitor init will decrypt another constant seed successively with a special per console key and a special static key passed by package1loader, to generate the firmware specific per-console key. The operation will erase these special keys passed by package1loader. &lt;br /&gt;
&lt;br /&gt;
== Secure Monitor ==&lt;br /&gt;
The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Fuses&amp;diff=3993</id>
		<title>Fuses</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Fuses&amp;diff=3993"/>
		<updated>2018-03-12T23:35:42Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: New update&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Nintendo Switch makes use of Tegra&#039;s fuse driver for a number of operations. This driver is mapped to physical address 0x7000F800 with a total size of 0x400 bytes and exposes several registers for fuse programming.&lt;br /&gt;
&lt;br /&gt;
Registers from 0x7000F800 to 0x7000F800 + 0xFF can be used to directly program the hardware fuse array, while registers from 0x7000F800 + 0x100 (FUSE_CHIP_REG_START_OFFSET) to 0x7000F800 + 0x3FC (FUSE_CHIP_REG_END_OFFSET) represent cached values read from certain fuses.&lt;br /&gt;
&lt;br /&gt;
== Registers ==&lt;br /&gt;
Below is a list of fuse driver registers used by the Switch&#039;s bootloaders.&lt;br /&gt;
&lt;br /&gt;
=== Driver registers ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Name&lt;br /&gt;
!  Address&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_CTRL|FUSE_CTRL]]&lt;br /&gt;
| 0x7000F800&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_REG_ADDR|FUSE_REG_ADDR]]&lt;br /&gt;
| 0x7000F804&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_REG_READ|FUSE_REG_READ]]&lt;br /&gt;
| 0x7000F808&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_REG_WRITE|FUSE_REG_WRITE]]&lt;br /&gt;
| 0x7000F80C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TIME_RD1&lt;br /&gt;
| 0x7000F810&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TIME_RD2&lt;br /&gt;
| 0x7000F814&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TIME_PGM1&lt;br /&gt;
| 0x7000F818&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_TIME_PGM2|FUSE_TIME_PGM2]]&lt;br /&gt;
| 0x7000F81C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_PRIV2INTFC&lt;br /&gt;
| 0x7000F820&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_FUSEBYPASS&lt;br /&gt;
| 0x7000F824&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_PRIVATEKEYDISABLE&lt;br /&gt;
| 0x7000F828&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_DIS_PGM|FUSE_DIS_PGM]]&lt;br /&gt;
| 0x7000F82C&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_WRITE_ACCESS|FUSE_WRITE_ACCESS]]&lt;br /&gt;
| 0x7000F830&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_PWR_GOOD_SW&lt;br /&gt;
| 0x7000F834&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== FUSE_CTRL ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 0-1&lt;br /&gt;
| Fuse command (1 = FUSE_READ; 2 = FUSE_WRITE; 3 = FUSE_SENSE)&lt;br /&gt;
|-&lt;br /&gt;
| 26&lt;br /&gt;
| Fuse power down mode flag (FUSE_CTRL_PD)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Before fuse reading/writing the power down mode must be disabled.&lt;br /&gt;
FUSE_SENSE mode flushes programmed values into the [[Fuses#Cache_registers|cache registers]].&lt;br /&gt;
&lt;br /&gt;
==== FUSE_REG_ADDR ====&lt;br /&gt;
This register takes the address of the fuse to be read/written/sensed.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_REG_READ ====&lt;br /&gt;
This register receives the value read from the fuse.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_REG_WRITE ====&lt;br /&gt;
This register takes the value to be written to the fuse.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_TIME_PGM2 ====&lt;br /&gt;
This register takes the fuse programming pulse (0xC0 == 19200 kHz).&lt;br /&gt;
&lt;br /&gt;
==== FUSE_DIS_PGM ====&lt;br /&gt;
If set to 0x01, this register disables fuse programming.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_WRITE_ACCESS ====&lt;br /&gt;
If set to 0x01, this register disables software writes to the fuse driver registers.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Cache registers ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Name&lt;br /&gt;
!  Address&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_PRODUCTION_MODE&lt;br /&gt;
| 0x7000F900&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_SKU_INFO|FUSE_SKU_INFO]]&lt;br /&gt;
| 0x7000F910&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CPU_SPEEDO_0&lt;br /&gt;
| 0x7000F914&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CPU_IDDQ&lt;br /&gt;
| 0x7000F918&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_FT_REV&lt;br /&gt;
| 0x7000F928&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CPU_SPEEDO_1&lt;br /&gt;
| 0x7000F92C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CPU_SPEEDO_2&lt;br /&gt;
| 0x7000F930&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SOC_SPEEDO_0&lt;br /&gt;
| 0x7000F934&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_SOC_SPEEDO_1|FUSE_SOC_SPEEDO_1]]&lt;br /&gt;
| 0x7000F938&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SOC_SPEEDO_2&lt;br /&gt;
| 0x7000F93C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SOC_IDDQ&lt;br /&gt;
| 0x7000F940&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_FA|FUSE_FA]]&lt;br /&gt;
| 0x7000F948&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY0]]&lt;br /&gt;
| 0x7000F964&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY1]]&lt;br /&gt;
| 0x7000F968&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY2]]&lt;br /&gt;
| 0x7000F96C&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY3]]&lt;br /&gt;
| 0x7000F970&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY4]]&lt;br /&gt;
| 0x7000F974&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY5]]&lt;br /&gt;
| 0x7000F978&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY6]]&lt;br /&gt;
| 0x7000F97C&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY7]]&lt;br /&gt;
| 0x7000F980&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_1&lt;br /&gt;
| 0x7000F984&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_2&lt;br /&gt;
| 0x7000F988&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CP_REV&lt;br /&gt;
| 0x7000F990&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_0&lt;br /&gt;
| 0x7000F998&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_FIRST_BOOTROM_PATCH_SIZE_REG&lt;br /&gt;
| 0x7000F99C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SECURITY_MODE&lt;br /&gt;
| 0x7000F9A0&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY0]]&lt;br /&gt;
| 0x7000F9A4&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY1]]&lt;br /&gt;
| 0x7000F9A8&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY2]]&lt;br /&gt;
| 0x7000F9AC&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY3]]&lt;br /&gt;
| 0x7000F9B0&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY4]]&lt;br /&gt;
| 0x7000F9B4&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_RESERVED_SW|FUSE_RESERVED_SW]]&lt;br /&gt;
| 0x7000F9C0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_VP8_ENABLE&lt;br /&gt;
| 0x7000F9C4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM0&lt;br /&gt;
| 0x7000F9C8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM1&lt;br /&gt;
| 0x7000F9CC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM2&lt;br /&gt;
| 0x7000F9D0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM3&lt;br /&gt;
| 0x7000F9D4&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_RESERVED_ODM4|FUSE_RESERVED_ODM4]]&lt;br /&gt;
| 0x7000F9D8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM5&lt;br /&gt;
| 0x7000F9DC&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_RESERVED_ODM6|FUSE_RESERVED_ODM6]]&lt;br /&gt;
| 0x7000F9E0&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]]&lt;br /&gt;
| 0x7000F9E4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SKU_USB_CALIB&lt;br /&gt;
| 0x7000F9F0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SKU_DIRECT_CONFIG&lt;br /&gt;
| 0x7000F9F4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_VENDOR_CODE&lt;br /&gt;
| 0x7000FA00&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_FAB_CODE&lt;br /&gt;
| 0x7000FA04&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_LOT_CODE_0&lt;br /&gt;
| 0x7000FA08&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_LOT_CODE_1&lt;br /&gt;
| 0x7000FA0C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_WAFER_ID&lt;br /&gt;
| 0x7000FA10&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_X_COORDINATE&lt;br /&gt;
| 0x7000FA14&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_Y_COORDINATE&lt;br /&gt;
| 0x7000FA18&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SATA_CALIB&lt;br /&gt;
| 0x7000FA24&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_GPU_IDDQ&lt;br /&gt;
| 0x7000FA28&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_3&lt;br /&gt;
| 0x7000FA2C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_OPT_SUBREVISION&lt;br /&gt;
| 0x7000FA48&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_4&lt;br /&gt;
| 0x7000FA54&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_5&lt;br /&gt;
| 0x7000FA58&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_6&lt;br /&gt;
| 0x7000FA5C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_7&lt;br /&gt;
| 0x7000FA60&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_OPT_PRIV_SEC_DIS&lt;br /&gt;
| 0x7000FA64&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PKC_DISABLE|FUSE_PKC_DISABLE]]&lt;br /&gt;
| 0x7000FA68&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_COMMON&lt;br /&gt;
| 0x7000FA80&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_DEBUG_AUTH_OVERRIDE&lt;br /&gt;
| 0x7000FA9C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_8&lt;br /&gt;
| 0x7000FAD4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_CALIB&lt;br /&gt;
| 0x7000FB04&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_9&lt;br /&gt;
| 0x7000FB1C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_USB_CALIB_EXT&lt;br /&gt;
| 0x7000FB50&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_0&lt;br /&gt;
| 0x7000FB80&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_1&lt;br /&gt;
| 0x7000FB84&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_2&lt;br /&gt;
| 0x7000FB88&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_3&lt;br /&gt;
| 0x7000FB8C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_4&lt;br /&gt;
| 0x7000FB90&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_SPARE_BIT_5|FUSE_SPARE_BIT_5]]&lt;br /&gt;
| 0x7000FB94&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_6&lt;br /&gt;
| 0x7000FB98&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_7&lt;br /&gt;
| 0x7000FB9C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_8&lt;br /&gt;
| 0x7000FBA0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_9&lt;br /&gt;
| 0x7000FBA4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_10&lt;br /&gt;
| 0x7000FBA8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_11&lt;br /&gt;
| 0x7000FBAC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_12&lt;br /&gt;
| 0x7000FBB0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_13&lt;br /&gt;
| 0x7000FBB4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_14&lt;br /&gt;
| 0x7000FBB8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_15&lt;br /&gt;
| 0x7000FBBC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_16&lt;br /&gt;
| 0x7000FBC0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_17&lt;br /&gt;
| 0x7000FBC4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_18&lt;br /&gt;
| 0x7000FBC8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_19&lt;br /&gt;
| 0x7000FBCC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_20&lt;br /&gt;
| 0x7000FBD0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_21&lt;br /&gt;
| 0x7000FBD4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_22&lt;br /&gt;
| 0x7000FBD8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_23&lt;br /&gt;
| 0x7000FBDC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_24&lt;br /&gt;
| 0x7000FBE0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_25&lt;br /&gt;
| 0x7000FBE4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_26&lt;br /&gt;
| 0x7000FBE8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_27&lt;br /&gt;
| 0x7000FBEC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_28&lt;br /&gt;
| 0x7000FBF0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_29&lt;br /&gt;
| 0x7000FBF4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_30&lt;br /&gt;
| 0x7000FBF8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_31&lt;br /&gt;
| 0x7000FBFC&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== FUSE_SKU_INFO ====&lt;br /&gt;
Stores the SKU ID (must be 0x83).&lt;br /&gt;
&lt;br /&gt;
==== FUSE_FA ====&lt;br /&gt;
Stores failure analysis mode.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_SOC_SPEEDO_1 ====&lt;br /&gt;
Stores the bootrom patch version.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_RESERVED_ODM4 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 0-1&lt;br /&gt;
| Unit type (3 = debug; 0 = retail)&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Unknown config (must be 1 on retail)&lt;br /&gt;
|-&lt;br /&gt;
| 3-5&lt;br /&gt;
| DRAM id&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Unknown config mask (must be 0 on retail)&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Unit type mask (0 = debug; 1 = retail)&lt;br /&gt;
|-&lt;br /&gt;
| 10&lt;br /&gt;
| [4.0.0+] Unknown, returned by smcGetConfig(14)&lt;br /&gt;
|-&lt;br /&gt;
| 16-19&lt;br /&gt;
| [4.0.0+] Unknown config (hardware-type-related)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This stores some device configuration parameters.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_RESERVED_ODM6 ====&lt;br /&gt;
This register returns the value programmed into index 0x3A of the fuse array. &lt;br /&gt;
&lt;br /&gt;
==== FUSE_RESERVED_ODM7 ====&lt;br /&gt;
This register returns the value programmed into index 0x3C of the fuse array.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_SPARE_BIT_5 ====&lt;br /&gt;
Must be non-zero on retail units, otherwise the first bootloader panics.&lt;br /&gt;
On debug units it can be zero, which tells the bootloader to choose from two debug master key seeds. If set to non-zero on a debug unit, it tells the bootloader to choose from two retail master key seeds (only the last one matches the retail master key seed).&lt;br /&gt;
&lt;br /&gt;
==== FUSE_PRIVATE_KEY ====&lt;br /&gt;
This stores the 160-bit private key (128 bit SBK + 32-bit device key).&lt;br /&gt;
Reads to these registers after the SBK is locked out produce all-FF output.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_PUBLIC_KEY ====&lt;br /&gt;
This stores the SHA256 hash of the 2048-bit RSA key expected at BCT+0x210.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_RESERVED_SW ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 5&lt;br /&gt;
| ENABLE_WATCHDOG&lt;br /&gt;
|-&lt;br /&gt;
| 6&lt;br /&gt;
| Forced RCM two button mode (0 = Only VOLUME_UP; 1 = VOLUME_UP + HOME)&lt;br /&gt;
|-&lt;br /&gt;
| 7&lt;br /&gt;
| RCM USB controller mode (0 = USB 2.0; 1 = XUSB)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This caches the value of the sw_reserved fuse from the hardware array.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_PKC_DISABLE ====&lt;br /&gt;
This caches the value of the pkc_disable fuse from the hardware array.&lt;br /&gt;
&lt;br /&gt;
== eFuses ==&lt;br /&gt;
The actual hardware fuses can be programmed through the fuse driver after enabling fuse programming.&lt;br /&gt;
&lt;br /&gt;
Below is a list of common fuse indexes used by Tegra devices (and applicable to the Switch).&lt;br /&gt;
Note that the indexes are relative to the start of the fuse array and each element is a 4 byte word. A single fuse write operation always writes the same word at both fuse_array + 0 (PRIMARY_ALIAS) and fuse_array + 1 (REDUNDANT_ALIAS).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Name&lt;br /&gt;
!  Index&lt;br /&gt;
!  Bits&lt;br /&gt;
|-&lt;br /&gt;
| jtag_disable&lt;br /&gt;
| 0x00&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| odm_production_mode&lt;br /&gt;
| 0x00&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| odm_lock&lt;br /&gt;
| 0x00&lt;br /&gt;
| 4&lt;br /&gt;
|-&lt;br /&gt;
| public_key&lt;br /&gt;
| 0x0C&lt;br /&gt;
| 256&lt;br /&gt;
|-&lt;br /&gt;
| secure_boot_key&lt;br /&gt;
| 0x22&lt;br /&gt;
| 128&lt;br /&gt;
|-&lt;br /&gt;
| device_key&lt;br /&gt;
| 0x2A&lt;br /&gt;
| 32&lt;br /&gt;
|-&lt;br /&gt;
| sec_boot_dev_cfg&lt;br /&gt;
| 0x2C&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| sec_boot_dev_sel&lt;br /&gt;
| 0x2C&lt;br /&gt;
| 3&lt;br /&gt;
|-&lt;br /&gt;
| sw_reserved&lt;br /&gt;
| 0x2E&lt;br /&gt;
| 12&lt;br /&gt;
|-&lt;br /&gt;
| ignore_dev_sel_straps&lt;br /&gt;
| 0x2E&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| [[#odm_reserved|odm_reserved]]&lt;br /&gt;
| 0x2E&lt;br /&gt;
| 256&lt;br /&gt;
|-&lt;br /&gt;
| pkc_disable&lt;br /&gt;
| 0x52&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| [[#bootrom_ipatch|bootrom_ipatch]]&lt;br /&gt;
| 0x72&lt;br /&gt;
| 624&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== odm_reserved ===&lt;br /&gt;
The first bootloader only burns fuses in this region.&lt;br /&gt;
Both fuse indexes 0x3A (odm_reserved + 0x0C) and 0x3C (odm_reserved + 0x0E) are used for anti-downgrade control. These fuses will have their values cached into [[#FUSE_RESERVED_ODM6|FUSE_RESERVED_ODM6]] and [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]].&lt;br /&gt;
&lt;br /&gt;
=== bootrom_ipatch ===&lt;br /&gt;
Tegra210 based hardware such as the Switch provides support for bootrom patches. The patch data is burned to the hardware fuse array using a specific format (see [https://gist.github.com/shuffle2/f8728159da100e9df2606d43925de0af shuffle2&#039;s ipatch decoder]). The bootrom reads these fuses in order to initialize the IPATCH hardware, which allows overriding data returned for code and data fetches done by BPMP.&lt;br /&gt;
&lt;br /&gt;
The revision stored in FUSE_CP_REV indicates the unique set of values stored in ipatch fuses.&lt;br /&gt;
&lt;br /&gt;
The following represents the patch data dumped from a 2.0.0 Switch console:&lt;br /&gt;
 Patch address       Patch data &lt;br /&gt;
 0x001016AE          0xDF00    // svc #0x00 (offset 0x48)&lt;br /&gt;
 0x00103040          0xDF22    // svc #0x22 (offset 0x8c)&lt;br /&gt;
 0x00106F2E          0xDF26    // svc #0x26 (offset 0x94)&lt;br /&gt;
 0x0010FB3C          0x2000    // movs r0, #0x00&lt;br /&gt;
 0x00100856          0xDF2C    // svc #0x2c (offset 0xa0)&lt;br /&gt;
 0x00106F54          0xDF42    // svc #0x42 (offset 0xcc)&lt;br /&gt;
 0x001012E4          0xDF4B    // svc #0x4b (offset 0xde)&lt;br /&gt;
 0x00104526          0xDF54    // svc #0x54 (offset 0xf0)&lt;br /&gt;
 0x001043F4          0xDF5D    // svc #0x5d (offset 0x102)&lt;br /&gt;
 0x00117744          0xAC57    // data&lt;br /&gt;
 0x00117758          0x3D19    // data&lt;br /&gt;
 0x00103D2A          0x2001    // movs r0, #0x01&lt;br /&gt;
&lt;br /&gt;
The last 4 patches are exclusive to the Switch, while the remaining ones are often included in most Tegra210 based devices.&lt;br /&gt;
&lt;br /&gt;
== Anti-downgrade ==&lt;br /&gt;
The first bootloader verifies [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]] to prevent downgrading.&lt;br /&gt;
How many fuses are expected to be burnt depends the device&#039;s unit type as below.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Expected number of burnt fuses (retail)&lt;br /&gt;
! Expected number of burnt fuses (non-retail)&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0&lt;br /&gt;
| 1&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0-2.3.0&lt;br /&gt;
| 2&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1-3.0.2&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0-4.1.0&lt;br /&gt;
| 5&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 5.0.0&lt;br /&gt;
| 6&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If too many fuses are burnt the bootloader will panic immediately.&lt;br /&gt;
&lt;br /&gt;
If too few are burnt, the bootloader will enable fuse programming and write the expected value to fuse indexes 0x3A and 0x3C. Afterwards, fuse programming is disabled and the panic value 0x21 is written to PMC_SCRATCH200 register (0x7000EC40). Finally, the watchdog timer is initialized and programmed to force a reset.&lt;br /&gt;
&lt;br /&gt;
On a subsequent boot, after the anti-downgrade fuses are checked again, the PMC_RST_STATUS register (0x7000E5B4) is checked and if set to 0x01 (watchdog reset) the PMC_SCRATCH200 register (0x7000EC40) will be checked for the panic value 0x21.&lt;br /&gt;
PMC_RST_STATUS will only be set back to 0 (power on reset) if the fuse count matches the new expected value, otherwise the system will panic.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=3536</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=3536"/>
		<updated>2018-01-23T13:10:19Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Some updates&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== BootROM ==&lt;br /&gt;
The bootrom initializes two keyslots in the hardware engine:&lt;br /&gt;
&lt;br /&gt;
* the SBK (Secure Boot Key) in keyslot 14&lt;br /&gt;
* the SSK (Secure Storage Key) in keyslot 15.&lt;br /&gt;
&lt;br /&gt;
Reads from both of these keyslots are disabled by the bootROM.&lt;br /&gt;
The SBK is stored in [[Fuses#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY]], which are locked to read out only FFs after the bootrom finishes.&lt;br /&gt;
&lt;br /&gt;
SBK is &#039;&#039;&#039;unique&#039;&#039;&#039; per console, and not shared among consoles as originally believed.&lt;br /&gt;
&lt;br /&gt;
The SSK is derived on boot via the SBK, the 32-bit console-unique &amp;quot;Device Key&amp;quot;, and hardware information stored in fuses.&lt;br /&gt;
&lt;br /&gt;
Pseudocode for the derivation is as follows:&lt;br /&gt;
  void generateSSK() {&lt;br /&gt;
      char keyBuffer[0x10]; // Used to store keydata&lt;br /&gt;
      uint hwInfoBuffer[4]; // Used to store info about hardware from fuses&lt;br /&gt;
      uint deviceKey = getDeviceKey(); // Reads 32-bit device key from FUSE_PRIVATE_KEY4.&lt;br /&gt;
      for (int i = 0; i &amp;lt; 4; i++) { // Keybuffer = deviceKey || deviceKey || deviceKey || deviceKey&lt;br /&gt;
          ((uint *)keyBuffer)[i] = deviceKey;&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, deviceKey || {...})&lt;br /&gt;
      &lt;br /&gt;
      // Set up Hardware info buffer&lt;br /&gt;
      uint vendor_code = *((uint *)0x7000FA00) &amp;amp; 0x0000000F; // FUSE_VENDOR_CODE&lt;br /&gt;
      uint fab_code    = *((uint *)0x7000FA04) &amp;amp; 0x0000003F; // FUSE_FAB_CODE&lt;br /&gt;
      uint lot_code_0  = *((uint *)0x7000FA08) &amp;amp; 0xFFFFFFFF; // FUSE_LOT_CODE_0&lt;br /&gt;
      uint lot_code_1  = *((uint *)0x7000FA0C) &amp;amp; 0x0FFFFFFF; // FUSE_LOT_CODE_1&lt;br /&gt;
      uint wafer_id    = *((uint *)0x7000FA10) &amp;amp; 0x0000003F; // FUSE_WAFER_ID&lt;br /&gt;
      uint x_coord     = *((uint *)0x7000FA14) &amp;amp; 0x000001FF; // FUSE_X_COORDINATE&lt;br /&gt;
      uint y_coord     = *((uint *)0x7000FA18) &amp;amp; 0x000001FF; // FUSE_Y_COORDINATE&lt;br /&gt;
      uint unk_hw_fuse = *((uint *)0x7000FA20) &amp;amp; 0x0000003F; // Unknown cached fuse.&lt;br /&gt;
      &lt;br /&gt;
      // HARDWARE_INFO_BUFFER = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID&lt;br /&gt;
      hwInfoBuffer[0] = (lot_code_1 &amp;lt;&amp;lt; 30) | (wafer_id &amp;lt;&amp;lt; 24) | (x_coord &amp;lt;&amp;lt; 15) | (y_coord &amp;lt;&amp;lt; 6) | unk_hw_fuse;&lt;br /&gt;
      hwInfoBuffer[1] = (lot_code_0 &amp;lt;&amp;lt; 26) | (lot_code_1 &amp;gt;&amp;gt; 2);&lt;br /&gt;
      hwInfoBuffer[2] = (fab_code &amp;lt;&amp;lt; 26) | (lot_code_0 &amp;gt;&amp;gt; 6);&lt;br /&gt;
      hwInfoBuffer[3] = vendor_code;&lt;br /&gt;
      &lt;br /&gt;
      for (int i = 0; i &amp;lt; 0x10; i++) { // keyBuffer = XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER)&lt;br /&gt;
          keyBuffer[i] ^= ((char *)hwInfoBuffer)[i];&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER))&lt;br /&gt;
      &lt;br /&gt;
      setKeyslot(KEYSLOT_SSK, keyBuffer); // SSK = keyBuffer.&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
The falcon processor (TSEC) generates a special console-unique key (that will be referred to as the &amp;quot;tsec key&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This is presumably using data stored in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
== Package1 ==&lt;br /&gt;
&lt;br /&gt;
=== Key table during package1 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Package1Key&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| No&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [1.0.0-3.0.2] Key table after package1 ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [4.0.0]+ Key table after package1 (Secure Monitor boot) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKeyForNewPerConsoleKeyGen&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| StaticKeyForNewPerConsoleKeyGen&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== [4.0.0]+ Key table after package1 (Secure Monitor runtime) ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| NewPerConsoleKey&lt;br /&gt;
| Secure Monitor init&lt;br /&gt;
| Yes&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
Note: aes_unwrap(wrapped_key, wrap_key) is just another name for a single AES-128 block decryption.&lt;br /&gt;
&lt;br /&gt;
If bit0 of 0x7000FB94 is clear, it will initialize keys like this (probably used for internal development units only):&lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = aes_unwrap(f5b1eadb.., sbk)&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x11 ? simpleseed_dev0 : simpleseed_dev1, aes_unwrap(5ff9c2d9.., sbk))&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e..., aes_unwrap(6e4a9592.., ssk))&lt;br /&gt;
&lt;br /&gt;
[4.0.0+] Above method was removed.&lt;br /&gt;
&lt;br /&gt;
Normal key generation looks like this on 1.0.0/2.0.0:&lt;br /&gt;
&lt;br /&gt;
  keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key    /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 3.0.0, they moved keyslots around a little to generate the same per-console key as 1.0.0:&lt;br /&gt;
&lt;br /&gt;
  old_keyblob_key /* slot10 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  keyblob_key     /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key        /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x4f ? normalseed_dev : normalseed_retail, keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
.. and on 4.0.0 it was further moved around:&lt;br /&gt;
&lt;br /&gt;
  old_keyblob_key /* slot15 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  keyblob_key     /* slot13 */ = aes_unwrap(aes_unwrap(wrapped_keyblob_key, tsec_key /* slot13 */), sbk /* slot14 */)&lt;br /&gt;
  cmac_key        /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key        /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key          /* slot12 */ = aes_unwrap(normalseed_retail, keyblob+0x20)&lt;br /&gt;
  new_master_key      /* slot14 */ = aes_unwrap(2dc1f48d.., keyblob+0x20)&lt;br /&gt;
  new_per_console_key /* slot13 */ = aes_unwrap(0c9109db.., old_keyblob_key)&lt;br /&gt;
  per_console_key     /* slot15 */ = aes_unwrap(4f025f0e.., old_keyblob_key)&lt;br /&gt;
&lt;br /&gt;
SBK and SSK keyslots are cleared after keys have been generated.&lt;br /&gt;
&lt;br /&gt;
See table above for which keys are console unique.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the hardcoded constants for the keyblob used in the current revision. Nintendo are withholding all the future hardcoded constants.&lt;br /&gt;
&lt;br /&gt;
This means that if you have an attack on the bootloader, you need to re-preform it every time they move to a new keyblob.&lt;br /&gt;
&lt;br /&gt;
Dumping the SBK and TSEC key of any single system should be enough to derive all key material on the system.&lt;br /&gt;
&lt;br /&gt;
The key-derivation is described in more detail [[Package1#Key_generation|here]].&lt;br /&gt;
&lt;br /&gt;
==== Keyblob ====&lt;br /&gt;
There are 32 keyblobs written to NAND at factory, with each keyblob encrypted with a console-unique key derived from the console&#039;s SBK, the console&#039;s tsec key, and a constant specific to each keyblob.&lt;br /&gt;
&lt;br /&gt;
Despite being encrypted with console unique keys, though, the decrypted keyblob contents are shared for all consoles.&lt;br /&gt;
&lt;br /&gt;
==== Seeds ====&lt;br /&gt;
  normalseed_retail = d8a2410a...&lt;br /&gt;
  &lt;br /&gt;
  [1.0.0] wrapped_keyblob_key = df206f59...&lt;br /&gt;
  [1.0.0] simpleseed_dev0   = aff11423...&lt;br /&gt;
  [1.0.0] simpleseed_dev1   = 5e177ee1...&lt;br /&gt;
  [1.0.0] normalseed_dev    = 0542a0fd...&lt;br /&gt;
  &lt;br /&gt;
  [3.0.0] wrapped_keyblob_key = 0c25615d...  &lt;br /&gt;
  [3.0.0] simpleseed_dev0   = de00216a...&lt;br /&gt;
  [3.0.0] simpleseed_dev1   = 2db7c0a1...&lt;br /&gt;
  [3.0.0] normalseed_dev    = 678c5a03...&lt;br /&gt;
  &lt;br /&gt;
  [3.0.1] wrapped_keyblob_key = 337685ee...  &lt;br /&gt;
  [3.0.1] simpleseed_dev0   = e045f5ba...&lt;br /&gt;
  [3.0.1] simpleseed_dev1   = 84d92e0d...&lt;br /&gt;
  [3.0.1] normalseed_dev    = cd88155b...&lt;br /&gt;
  &lt;br /&gt;
  [4.0.0] wrapped_keyblob_key = 2d1f4880...&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1-3.0.2&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Secure Monitor Init ==&lt;br /&gt;
On all versions, the key to decrypt [[Package2]] is generated by decrypting a constant seed with the master key. The key is erased after use.   &lt;br /&gt;
&lt;br /&gt;
Additionally, starting from 4.0.0, the Secure Monitor init will decrypt another constant seed successively with a special per console key and a special static key passed by package1loader, to generate a new per-console key. The operation will erase these special keys passed by package1loader. &lt;br /&gt;
&lt;br /&gt;
== Secure Monitor ==&lt;br /&gt;
The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=3338</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=3338"/>
		<updated>2018-01-01T01:30:14Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Precision&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
System Flaws are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of known and public Switch System Flaws.&lt;br /&gt;
&lt;br /&gt;
=List of Switch System Flaws=&lt;br /&gt;
&lt;br /&gt;
== Hardware == &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== System software ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Stage 1 Bootloader ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;s stage 1 bootloader, on panic(), clears the stack and then attempts to clear the Security Engine. However, it does so by dereferencing a pointer to the SE in .bss (initially NULL), and this pointer doesn&#039;t get initialized until partway into the bootloader&#039;s main() after several functions that might panic() are called. Thus, a panic() caused prior to SE initialization would result in the SE pointer still being NULL when dereferenced. This would cause a data abort, causing the bootloader to clear the stack and then try to clear the security engine...dereferencing NULL again, over and over in a loop.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Infinite clear-the-stack-then-data-abort loop very early in boot, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|  FUSE_DIS_PGM not written by package1 &lt;br /&gt;
|  The switch&#039;s hardware fuse driver contains a write-once bit in a register called &amp;quot;FUSE_DIS_PGM&amp;quot;, which disables burning fuses until the next reboot. While Nintendo&#039;s bootloader code for waking up from sleep writes this on all firmware, the actual package1 initial bootloader forgets to write to it on cold reboot. &lt;br /&gt;
&lt;br /&gt;
This isn&#039;t too big of a problem because another fuse is burnt on retail devices (production mode), which prevents burning *all* fuses other than ODM_RESERVED ones in hardware.&lt;br /&gt;
&lt;br /&gt;
This was fixed in 3.0.0 by writing to the register on cold boot (although the write happens in TZ instead of package1 where it should take place, possibly to obfuscate the fact that they made this mistake).&lt;br /&gt;
|  Burning arbitrary ODM reserved fuses with TZ code execution, which should never be possible for non-bootloader code.&lt;br /&gt;
&lt;br /&gt;
Warning: one could irreparably brick one&#039;s console by playing with this.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  late summer/early fall 2017&lt;br /&gt;
|  December 31, 2017&lt;br /&gt;
|  SciresM, Motezazer&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  No public ARM TrustZone exploits &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| GetLastThreadInfo UAF&lt;br /&gt;
| GetLastThreadInfo syscall gets last-scheduled-KThread pointer from KScheduler object. This pointer is not reference counted, and can be pointing to a freed KThread.&lt;br /&gt;
| Nothing. There is a theoretical race that might leak from a KThread from a different process, but it&#039;s impossible to trigger practically.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| &lt;br /&gt;
| 15 October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) service serves as an interface between the rest of the system and the secure monitor. Prior to [[4.0.0]], spl exposed only a single service &amp;quot;spl:&amp;quot;, which provided all TrustZone wrapper functions to all sysmodules with access to it. Thus anyone with access to the spl: service (via smhax or by pwning a sysmodule with access) could do crypto with any access keys they knew. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders: dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| The [[BCAT_Content_Container]] secret-data index is not validated at all. This is handled before the RSA-signature(?) is ever used. Since the field is an u8, a total of 0x800-bytes relative to the array start can be accessed.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|Yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  Prior to [[3.0.0]], pl:u (Shared Font services implemented in the NS sysmodule) service commands 1,2,3 took in a signed 32-bit index and returned that index of an array but did not check that index at all. This allowed for an arbitrary read within a 34-bit range (33-bit signed) from NS .bss. In [[3.0.0]], sending out of range indexes causes error code 0x60A to be returned.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], Reswitched team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|domain messages]] are not bounds checked. This out-of-bounds read could be exploited to brute-force ASLR and get PC control in some services that support domain messages.&lt;br /&gt;
|&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=3307</id>
		<title>Switch System Flaws</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Switch_System_Flaws&amp;diff=3307"/>
		<updated>2017-12-30T19:08:59Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: It&amp;#039;s a hardware model, not a firmware version&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&lt;br /&gt;
System Flaws are used to execute unofficial code (homebrew) on the Nintendo Switch. This page is a list of known and public Switch System Flaws.&lt;br /&gt;
&lt;br /&gt;
=List of Switch System Flaws=&lt;br /&gt;
&lt;br /&gt;
== Hardware == &lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Fixed with hardware model/revision&lt;br /&gt;
!  Newest hardware model/revision this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| GMMU DMA attack&lt;br /&gt;
| The Switch&#039;s GPU includes a separate MMU (GMMU) that is allowed to bypass the system&#039;s IOMMU (SMMU). By accessing the GPU&#039;s MMIO region and manipulating the page table entries in the GMMU, an attacker can read/write any portion of the DRAM (except memory carveouts).&lt;br /&gt;
| None&lt;br /&gt;
| HAC-001&lt;br /&gt;
| Summer 2017&lt;br /&gt;
| December 28, 2017&lt;br /&gt;
| [[User:hexkyz|hexkyz]], [[User:SciresM|SciresM]] and [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== System software ==&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Stage 1 Bootloader ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  Null-dereference in panic()&lt;br /&gt;
|  The Switch&#039;s stage 1 bootloader, on panic(), clears the stack and then attempts to clear the Security Engine. However, it does so by dereferencing a pointer to the SE in .bss (initially NULL), and this pointer doesn&#039;t get initialized until partway into the bootloader&#039;s main() after several functions that might panic() are called. Thus, a panic() caused prior to SE initialization would result in the SE pointer still being NULL when dereferenced. This would cause a data abort, causing the bootloader to clear the stack and then try to clear the security engine...dereferencing NULL again, over and over in a loop.&lt;br /&gt;
&lt;br /&gt;
In 3.0.0, this was fixed by moving the security engine initialization earlier in main(), before the first function that could potentially panic().&lt;br /&gt;
|  Infinite clear-the-stack-then-data-abort loop very early in boot, before SBK/other keyslots are cleared. Probably useless for anything more interesting.&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  Early July, 2017&lt;br /&gt;
|  July 30, 2017&lt;br /&gt;
|  Everyone who diff&#039;d 2.3.0 and 3.0.0 Package1&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== TrustZone ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
|  No public ARM TrustZone exploits &lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Kernel ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Syscall Infoleaks&lt;br /&gt;
| Many syscalls leaked kernel pointers on sad paths (for example svcSetHeapSize and svcQueryMemory), until they landed a bunch of fixes in 2.0.0.&lt;br /&gt;
| Nothing really.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| &lt;br /&gt;
| &lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| GetLastThreadInfo UAF&lt;br /&gt;
| GetLastThreadInfo syscall gets last-scheduled-KThread pointer from KScheduler object. This pointer is not reference counted, and can be pointing to a freed KThread.&lt;br /&gt;
| Nothing. There is a theoretical race that might leak from a KThread from a different process, but it&#039;s impossible to trigger practically.&lt;br /&gt;
| Unfixed&lt;br /&gt;
| &lt;br /&gt;
| 15 October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Bad irq_id check in CreateInterruptEvent&lt;br /&gt;
| CreateInterruptEvent syscall is designed to work only for irq_id &amp;gt;= 32. All irq_ids &amp;lt; 32 are &amp;quot;per-core&amp;quot; and reserved for kernel use (watchdog/scheduling/core communications).&lt;br /&gt;
On 1.0.0 you could supply irq_id &amp;lt; 32 and it would write outside the SharedIrqs table.&lt;br /&gt;
| You can register irq&#039;s in the Core3Irqs table, and thus register per-core irqs for core3, that are normally reserved for kernel. Useless.&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~October&lt;br /&gt;
| 17 October&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
| Kernel .text mapped executable in usermode&lt;br /&gt;
| Prior to [[3.0.2]] the kernel .text was [[Memory_layout|mapped]] in usermode as executable. This can be used for usermode ROP for bypassing ASLR, but SVCs/IPC are not usable by running kernel .text in usermode.&lt;br /&gt;
| Executing kernel .text in usermode&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| [[3.0.2]]&lt;br /&gt;
| &lt;br /&gt;
| 34c3 (December 28, 2017)&lt;br /&gt;
| [[User:qlutoo|qlutoo]]&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FIRM-package System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Service access control bypass (sm:h, smhax, probably other names)&lt;br /&gt;
| Prior to [[3.0.1]], the &#039;&#039;service manager&#039;&#039; (sm) built-in system module treats a user as though it has full permissions if the user creates a new &amp;quot;sm:&amp;quot; port session but bypasses [[Services_API#Initialize|initialization]]. This is due to the other sm commands skipping the service ACL check for Pids &amp;lt;= 7 (i.e. all kernel bundled modules) and that skipping the initialization command leaves the Pid field uninitialized.&lt;br /&gt;
In [[3.0.1]], sm returns error code 0x415 if [[Services_API#Initialize|Initialize]] has not been called yet.&lt;br /&gt;
| Acquiring, registering, and unregistering arbitrary services&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| [[3.0.1]]&lt;br /&gt;
| May 2017&lt;br /&gt;
| August 17, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Overly permissive SPL service&lt;br /&gt;
| The concept behind the switch&#039;s [[SMC|Secure Monitor]] is that all cryptographic keydata is located in userspace, but stored as &amp;quot;access keys&amp;quot; encrypted with &amp;quot;keks&amp;quot; that never leave TrustZone. The [[SPL services|spl]] (&amp;quot;security processor liaison&amp;quot;?) service serves as an interface between the rest of the system and the secure monitor. Prior to [[4.0.0]], spl exposed only a single service &amp;quot;spl:&amp;quot;, which provided all TrustZone wrapper functions to all sysmodules with access to it. Thus anyone with access to the spl: service (via smhax or by pwning a sysmodule with access) could do crypto with any access keys they knew. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by splitting spl: into spl:, spl:mig, spl:ssl, spl:es, and spl:fs.&lt;br /&gt;
| Arbitrary spl: crypto with any access keys one knows. For example, one could use the SSL module&#039;s access keys to decrypt their console&#039;s SSL certificate private key without having to pwn the SSL sysmodule.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Summer 2017 (after smhax was discovered).&lt;br /&gt;
| December 23, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|-&lt;br /&gt;
| Single session services not really single session&lt;br /&gt;
| Several &amp;quot;critical&amp;quot; services (like fsp-ldr, fsp-pr, sm:m, etc) are meant to only ever hold a single session with a specific sysmodule. However, when a sysmodule dies, all its service session handles are released -- and thus killing the holder of a single session handle would allow one (via sm:hax etc) to get access to that service. &lt;br /&gt;
&lt;br /&gt;
This was fixed in [[4.0.0]] by adding a semaphore to these critical single-session services, so that even if one gets access to them an error code will be returned when attempting to use any of their commands.&lt;br /&gt;
| With some way to access these services and kill their session holders: dumping sysmodule code, arbitrary service access, elevated filesystem permissions, etc.&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| May/June 2017 (basically immediately after smhax was discovered)&lt;br /&gt;
| December 30, 2017&lt;br /&gt;
| Everyone&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== System Modules ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!  Summary&lt;br /&gt;
!  Description&lt;br /&gt;
!  Successful exploitation result&lt;br /&gt;
!  Fixed in system version&lt;br /&gt;
!  Last system version this flaw was checked for&lt;br /&gt;
!  Timeframe this was discovered&lt;br /&gt;
!  Public disclosure timeframe&lt;br /&gt;
!  Discovered by&lt;br /&gt;
|-&lt;br /&gt;
| Out-of-bounds array read for [[BCAT_Content_Container]] secret-data index&lt;br /&gt;
| The [[BCAT_Content_Container]] secret-data index is not validated at all. This is handled before the RSA-signature(?) is ever used. Since the field is an u8, a total of 0x800-bytes relative to the array start can be accessed.&lt;br /&gt;
This is not useful since the string loaded from this array is only involved with key-generation.&lt;br /&gt;
| &lt;br /&gt;
| Unknown&lt;br /&gt;
| [[2.0.0]]&lt;br /&gt;
| August 4, 2017&lt;br /&gt;
| August 6, 2017&lt;br /&gt;
| [[User: shinyquagsire23|Shiny Quagsire]], [[User:Yellows8|Yellows8]] (independently)&lt;br /&gt;
|-&lt;br /&gt;
|  OOB Read in NS system module (pl:utoohax, pl:utonium, maybe other names)&lt;br /&gt;
|  Prior to [[3.0.0]], pl:u (Shared Font services implemented in the NS sysmodule) service commands 1,2,3 took in a signed 32-bit index and returned that index of an array but did not check that index at all. This allowed for an arbitrary read within a 34-bit range (33-bit signed) from NS .bss. In [[3.0.0]], sending out of range indexes causes error code 0x60A to be returned.&lt;br /&gt;
|  Dumping full NS .text, .rodata and .data, infoleak, etc&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  [[3.0.0]]&lt;br /&gt;
|  April 2017&lt;br /&gt;
|  On exploit&#039;s fix in [[3.0.0]]&lt;br /&gt;
|  [[User:qlutoo|qlutoo]], Reswitched team (independently)&lt;br /&gt;
|-&lt;br /&gt;
| Unchecked domain ID in common IPC code&lt;br /&gt;
| Prior to [[2.0.0]], object IDs in [[IPC_Marshalling#Domain_message|domain messages]] are not bounds checked. This out-of-bounds read could be exploited to brute-force ASLR and get PC control in some services that support domain messages.&lt;br /&gt;
|&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| 2.0.0&lt;br /&gt;
| ~July 2017&lt;br /&gt;
| 20 July 2017‎&lt;br /&gt;
| [[User:hthh|hthh]]&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=SVC&amp;diff=3043</id>
		<title>SVC</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=SVC&amp;diff=3043"/>
		<updated>2017-11-21T17:45:27Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: /* svcReadWriteRegister */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;__NOTOC__&lt;br /&gt;
&lt;br /&gt;
= System calls =&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Id || Name || In || Out&lt;br /&gt;
|-&lt;br /&gt;
|  0x1 || [[#svcSetHeapSize]] || W1=size || W0=result, X1=outaddr&lt;br /&gt;
|-&lt;br /&gt;
|  0x2 || [[#svcSetMemoryPermission]] || X0=addr, X1=size, W2=prot || W0=result&lt;br /&gt;
|-&lt;br /&gt;
|  0x3 || [[#svcSetMemoryAttribute]] || X0=addr, X1=size, W2=state0, W3=state1 || W0=result&lt;br /&gt;
|-&lt;br /&gt;
|  0x4 || [[#svcMapMemory]] || X0=dstaddr, X1=srcaddr, X2=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
|  0x5 || [[#svcUnmapMemory]] || X0=dstaddr, X1=srcaddr, X2=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
|  0x6 || [[#svcQueryMemory]] || X0=MemoryInfo*, X2=addr || W0=result, W1=PageInfo                                                         &lt;br /&gt;
|-&lt;br /&gt;
|  0x7 || [[#svcExitProcess]] || None ||&lt;br /&gt;
|-&lt;br /&gt;
|  0x8 || [[#svcCreateThread]] || X1=entry, X2=arg, X3=stacktop, W4=prio, W5=processor_id  || W0=result, W1=handle&lt;br /&gt;
|-&lt;br /&gt;
|  0x9 || [[#svcStartThread]] || W0=thread_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
|  0xA || [[#svcExitThread]] || None ||                                                         &lt;br /&gt;
|-&lt;br /&gt;
|  0xB || [[#svcSleepThread]] || X0=nano || W0=result&lt;br /&gt;
|-&lt;br /&gt;
|  0xC || [[#svcGetThreadPriority]] || W1=thread_handle || W0=result, W1=prio&lt;br /&gt;
|-&lt;br /&gt;
|  0xD || [[#svcSetThreadPriority]] || W0=thread_handle, W1=prio || W0=result&lt;br /&gt;
|-&lt;br /&gt;
|  0xE || [[#svcGetThreadCoreMask]] || W2=thread_handle || W0=result, W1=out, X2=out&lt;br /&gt;
|-&lt;br /&gt;
|  0xF || [[#svcSetThreadCoreMask]] || W0=thread_handle, W1=in, X2=in2 || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || [[#svcGetCurrentProcessorNumber]] || None || W0/X0=cpuid&lt;br /&gt;
|-&lt;br /&gt;
| 0x11 || svcSignalEvent || W0=wevent_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x12 || svcClearEvent || W0=wevent_or_revent_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x13 || [[#svcMapSharedMemory]] || W0=shmem_handle, X1=addr, X2=size, W3=perm || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x14 || svcUnmapSharedMemory || W0=shmem_handle, X1=addr, X2=size || W0=result                                                 &lt;br /&gt;
|-&lt;br /&gt;
| 0x15 || [[#svcCreateTransferMemory]] || X1=addr, X2=size, W3=perm || W0=result, W1=tmem_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x16 || svcCloseHandle || W0=handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x17 || svcResetSignal || W0=revent_or_process_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x18 || [[#svcWaitSynchronization]] || X1=handles_ptr, W2=num_handles. X3=timeout || W0=result, W1=handle_idx&lt;br /&gt;
|-&lt;br /&gt;
| 0x19 || svcCancelSynchronization || W0=thread_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x1A || svcArbitrateLock || W0=cur_thread_handle, X1=ptr, W2=req_thread_handle ||                                     &lt;br /&gt;
|-&lt;br /&gt;
| 0x1B || svcArbitrateUnlock || X0=ptr ||&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C || svcWaitProcessWideKeyAtomic || X0=ptr0, X1=ptr, W2=thread_handle, X3=timeout || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x1D || svcSignalProcessWideKey || X0=ptr, W1=value || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x1E || svcGetSystemTick || None || X0={value of cntpct_el0}&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F || svcConnectToNamedPort || X1=port_name_str || W0=result, W1=handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || svcSendSyncRequestLight || W0=light_session_handle, X1=? || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x21 || svcSendSyncRequest || X0=normal_session_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x22 || [[#svcSendSyncRequestWithUserBuffer]] || X0=cmdbufptr, X1=size, X2=handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x23 || svcSendAsyncRequestWithUserBuffer || X1=cmdbufptr, X2=size, X3=handle || W0=result, W1=event_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x24 || svcGetProcessId || W1=thread_or_process_or_debug_handle || W0=result, X1=pid&lt;br /&gt;
|-&lt;br /&gt;
| 0x25 || svcGetThreadId || W0=thread_handle || W0=result, X1=out&lt;br /&gt;
|-&lt;br /&gt;
| 0x26 || svcBreak || X0,X1,X2=info || ?&lt;br /&gt;
|-&lt;br /&gt;
| 0x27 || svcOutputDebugString || X0=str, X1=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || svcReturnFromException || X0=result || &lt;br /&gt;
|-&lt;br /&gt;
| 0x29 || [[#svcGetInfo]] || X1=info_id, X2=handle, X3=info_sub_id || W0=result, X1=out&lt;br /&gt;
|-&lt;br /&gt;
| 0x2A || svcFlushEntireDataCache || None || None&lt;br /&gt;
|-&lt;br /&gt;
| 0x2B || svcFlushDataCache || X0=addr, X1=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x2C || [3.0.0+] svcMapPhysicalMemory ||  ||&lt;br /&gt;
|-&lt;br /&gt;
| 0x2D || [3.0.0+] svcUnmapPhysicalMemory||  ||&lt;br /&gt;
|- style=&amp;quot;border-top: double&amp;quot;&lt;br /&gt;
| 0x2F || svcGetLastThreadInfo || None || W0=result, W1,W2,W3,W4=unk, W5=truncated_u64, W6=bool&lt;br /&gt;
|-&lt;br /&gt;
| 0x30 || svcGetResourceLimitLimitValue || W1=reslimit_handle, W2=[[#LimitableResource]] || W0=result, X1=value&lt;br /&gt;
|-&lt;br /&gt;
| 0x31 || svcGetResourceLimitCurrentValue || W1=reslimit_handle, W2=[[#LimitableResource]] || W0=result, X1=value&lt;br /&gt;
|-&lt;br /&gt;
| 0x32 || svcSetThreadActivity || W0=thread_handle, W1=bool || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x33 || svcGetThreadContext3 || W0=thread_handle, W1=[[#ThreadContext]]* || W0=result&lt;br /&gt;
|- style=&amp;quot;border-top: double&amp;quot;&lt;br /&gt;
| 0x3C || svcDumpInfo ||  || &lt;br /&gt;
|- style=&amp;quot;border-top: double&amp;quot;&lt;br /&gt;
| 0x40 || svcCreateSession || W2=is_light, X3=? || W0=result, W1=client_handle, W2=server_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x41 || svcAcceptSession || W1=port_handle || W0=result, W1=session_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x42 || svcReplyAndReceiveLight || W0=light_session_handle || W0=result, W1,W2,W3,W4,W5,W6,W7=out&lt;br /&gt;
|-&lt;br /&gt;
| 0x43 || svcReplyAndReceive || X1=ptr_handles, W2=num_handles, X3=replytarget_handle(0=none), X4=timeout || W0=result, W1=handle_idx&lt;br /&gt;
|-&lt;br /&gt;
| 0x44 || svcReplyAndReceiveWithUserBuffer|| X1=buf, X2=sz, X3=ptr_handles, W4=num_handles, X5=replytarget_handle(0=none), X6=timeout || W0=result, W1=handle_idx&lt;br /&gt;
|-&lt;br /&gt;
| 0x45 || svcCreateEvent || None || W0=result, W1=client_handle ?, W2=server_handle ?&lt;br /&gt;
|- style=&amp;quot;border-top: double&amp;quot;&lt;br /&gt;
| 0x4D || svcSleepSystem || None || None&lt;br /&gt;
|-&lt;br /&gt;
| 0x4E || [[#svcReadWriteRegister]] || X1=reg_addr, W2=rw_mask, W3=in_val || W0=result, W1=out_val&lt;br /&gt;
|-&lt;br /&gt;
| 0x4F || svcSetProcessActivity || W0=process_handle, W1=bool || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x50 || [[#svcCreateSharedMemory]] || W1=size, W2=myperm, W3=otherperm || W0=result, W1=shmem_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x51 || [[#svcMapTransferMemory]] || X0=tmem_handle, X1=addr, X2=size, W3=perm || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x52 || [[#svcUnmapTransferMemory]] || W0=tmemhandle, X1=addr, X2=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x53 || svcCreateInterruptEvent || X1=irq_id, W2=flag || W0=result, W1=handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x54 || [[#svcQueryPhysicalAddress]] || X1=addr || W0=result, X1=out0, X2=out1, X3=out2&lt;br /&gt;
|-&lt;br /&gt;
| 0x55 || [[#svcQueryIoMapping]] || X1=physaddr, X2=size || W0=result, X1=virtaddr&lt;br /&gt;
|-&lt;br /&gt;
| 0x56 || [[#svcCreateDeviceAddressSpace]] || X1=dev_as_start_addr, X2=dev_as_end_addr || W0=result, W1=dev_as_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x57 || [[#svcAttachDeviceAddressSpace]] || W0=device, X1=dev_as_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x58 || [[#svcDetachDeviceAddressSpace]] || W0=device, X1=dev_as_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x59 || [[#svcMapDeviceAddressSpaceByForce]] || W0=dev_as_handle, W1=proc_handle, X2=dev_map_addr, X3=dev_as_size, X4=dev_as_addr, W5=perm || W0=result &lt;br /&gt;
|-&lt;br /&gt;
| 0x5A || [[#svcMapDeviceAddressSpaceAligned]] || W0=dev_as_handle, W1=proc_handle, X2=dev_map_addr, X3=dev_as_size, X4=dev_as_addr, W5=perm || W0=result &lt;br /&gt;
|-&lt;br /&gt;
| 0x5B || svcMapDeviceAddressSpace || || &lt;br /&gt;
|-&lt;br /&gt;
| 0x5C || [[#svcUnmapDeviceAddressSpace]] || W0=dev_as_handle, W1=proc_handle, X2=dev_map_addr, X3=dev_as_size, X4=dev_as_addr || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x5D || svcInvalidateProcessDataCache || W0=process_handle, X1=addr, X2=size || W0=size&lt;br /&gt;
|-&lt;br /&gt;
| 0x5E || svcStoreProcessDataCache || W0=process_handle, X1=addr, X2=size || W0=size&lt;br /&gt;
|-&lt;br /&gt;
| 0x5F || svcFlushProcessDataCache || W0=process_handle, X1=addr, X2=size || W0=size&lt;br /&gt;
|-&lt;br /&gt;
| 0x60 || svcDebugActiveProcess || X1=pid || W0=result, W1=debug_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x61 || svcBreakDebugProcess || W0=debug_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x62 || svcTerminateDebugProcess || W0=debug_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x63 || svcGetDebugEvent || X0=DebugEventInfo*, W1=debug_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x64 || svcContinueDebugEvent || W0=debug_handle, W1=[[#ContinueDebugFlags]], X2=thread_id || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x65 || svcGetProcessList || X1=pids_out_ptr, W2=max_out || W0=result, W1=num_out &lt;br /&gt;
|-&lt;br /&gt;
| 0x66 || svcGetThreadList || X1=tids_out_ptr, W2=max_out, W3=debug_handle_or_zero || W0=result, X1=num_out&lt;br /&gt;
|-&lt;br /&gt;
| 0x67 || svcGetDebugThreadContext || X0=ThreadContext*, X1=debug_handle, X2=thread_id, W3=[[#ThreadContextFlags]] || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x68 || svcSetDebugThreadContext || W0=debug_handle, W1=[[#ThreadContextFlags]], X2=ThreadContext* || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x69 || svcQueryDebugProcessMemory || X0=[[#MemoryInfo]]*, X2=debug_handle, X3=addr || W0=result, W1=PageInfo&lt;br /&gt;
|-&lt;br /&gt;
| 0x6A || svcReadDebugProcessMemory || X0=buffer*, X1=debug_handle, X2=src_addr, X3=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x6B || svcWriteDebugProcessMemory || X0=debug_handle, X1=buffer*, X2=dst_addr, X3=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x6C || svcSetHardwareBreakPoint || W0=HardwareBreakpointId, X1=watchpoint_flags, X2=watchpoint_value/debug_handle? || &lt;br /&gt;
|-&lt;br /&gt;
| 0x6D || svcGetDebugThreadParam || X2=debug_handle, X3=thread_id, W4=[[#DebugThreadParam]] || W0=result, X1=out0, W2=out1&lt;br /&gt;
|- style=&amp;quot;border-top: double&amp;quot;&lt;br /&gt;
| 0x70 || svcCreatePort || || &lt;br /&gt;
|-&lt;br /&gt;
| 0x71 || svcManageNamedPort || X1=name_ptr, W2=max_sessions(?) || W0=result, W1=serverport_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x72 || svcConnectToPort || W1=clientport_handle || W0=result, W1=session_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x73 || svcSetProcessMemoryPermission || X0=addr, X1=size, W2=perm || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x74 || [[#svcMapProcessMemory]] || X0=srcaddr, W1=process_handle, X2=dstaddr, X3=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x75 || [[#svcUnmapProcessMemory]] || W0=process_handle, X1=dstaddr, X2=srcaddr, X3=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x76 || [[#svcQueryProcessMemory]] || X0=meminfo_ptr, W2=process_handle, X3=addr || W0=result, W1=pageinfo&lt;br /&gt;
|-&lt;br /&gt;
| 0x77 || [[#svcMapProcessCodeMemory]] || W0=process_handle, X2=dstaddr, X2=srcaddr, X3=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x78 || [[#svcUnmapProcessCodeMemory]] || W0=process_handle, X1=dstaddr, X2=srcaddr, X3=size || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x79 || [[#svcCreateProcess]] || X1=procinfo_ptr, X2=caps_ptr, W3=cap_num ||  W0=result, W1=process_handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x7A || svcStartProcess || W0=process_handle, W1=main_thread_prio, W2=default_cpuid, W3=main_thread_stacksz || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x7B || svcTerminateProcess || W0=process_handle || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x7C || [[#svcGetProcessInfo]] || W0=process_handle || W0=result, X1=[[#ProcessState]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x7D || svcCreateResourceLimit || None || W0=result, W1=reslimit_handle &lt;br /&gt;
|-&lt;br /&gt;
| 0x7E || svcSetResourceLimitLimitValue || W0=reslimit_handle, W1=[[#LimitableResource]], X2=value || W0=result&lt;br /&gt;
|-&lt;br /&gt;
| 0x7F || svcCallSecureMonitor || || &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== svcSetHeapSize ==&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) X1 || u64 || &amp;lt;code&amp;gt;OutAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Set the process heap to a given &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;. It can both extend and shrink the heap.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt; must be a multiple of 0x2000000.&lt;br /&gt;
&lt;br /&gt;
On success, the heap base-address (which is fixed by kernel, aslr&#039;d) is written to &amp;lt;code&amp;gt;OutAddr&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
[2.0.0+] &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt; must be less than 0x18000000.&lt;br /&gt;
&lt;br /&gt;
== svcSetMemoryPermission ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || void* || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || [[#Permission]] || &amp;lt;code&amp;gt;Prot&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Change permission of page-aligned memory region.&lt;br /&gt;
&lt;br /&gt;
Bit2 of permission (exec) is not allowed. Setting write-only is not allowed either (bit1).&lt;br /&gt;
&lt;br /&gt;
This can be used to move back and forth between ---, r-- and rw-.&lt;br /&gt;
&lt;br /&gt;
== svcSetMemoryAttribute ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || void* || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || u32 || &amp;lt;code&amp;gt;State0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W3 || u32 || &amp;lt;code&amp;gt;State1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Change attribute of page-aligned memory region. &lt;br /&gt;
&lt;br /&gt;
This is used to turn on/off caching for a given memory area. Useful when talking to devices such as the GPU.&lt;br /&gt;
&lt;br /&gt;
What happens &amp;quot;under the hood&amp;quot; is the &amp;quot;Memory Attribute Indirection Register&amp;quot; index is changed from 2 to 3 in the MMU descriptor.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! State0 || State1 || Action&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 0 || Clear bit3 in [[#MemoryAttribute]].&lt;br /&gt;
|-&lt;br /&gt;
| 8 || 0 || Clear bit3 in [[#MemoryAttribute]].&lt;br /&gt;
|-&lt;br /&gt;
| 8 || 8 || Set bit3 in [[#MemoryAttribute]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== svcMapMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || void* || &amp;lt;code&amp;gt;DstAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || void* || &amp;lt;code&amp;gt;SrcAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Maps a memory range into a different range.&lt;br /&gt;
&lt;br /&gt;
Mainly used for adding guard pages around stack.&lt;br /&gt;
&lt;br /&gt;
Source range gets reprotected to --- (it can no longer be accessed), and bit0 is set in the source [[#MemoryAttribute]].&lt;br /&gt;
&lt;br /&gt;
If dstaddr &amp;gt;= LowerTreshold, the dst-range is enforced to be within the process&#039; &amp;quot;MapRegion&amp;quot;. Code can get the range of this region from [[#svcGetInfo]] id0=2,3.&lt;br /&gt;
&lt;br /&gt;
In this case, the mapped memory will have state &amp;lt;code&amp;gt;0x5C3C0B&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
As long as (dstaddr+size) &amp;lt; LowerThreshold, then you can map anywhere but the mapped memory will have state &amp;lt;code&amp;gt;0x482907&amp;lt;/code&amp;gt; instead.&lt;br /&gt;
&lt;br /&gt;
LowerTreshold is 0x80000000 for 36-bit address spaces, and 0x40000000 for 32-bit ones.&lt;br /&gt;
&lt;br /&gt;
[2.0.0+] Support for the &amp;lt;code&amp;gt;0x482907&amp;lt;/code&amp;gt; mappings outside the &amp;quot;MapRegion&amp;quot; were removed.&lt;br /&gt;
&lt;br /&gt;
== svcUnmapMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || void* || &amp;lt;code&amp;gt;DstAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || void* || &amp;lt;code&amp;gt;SrcAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Unmaps a region that was previously mapped with [[#svcMapMemory]].&lt;br /&gt;
&lt;br /&gt;
It&#039;s possible to unmap ranges partially, you don&#039;t need to unmap the entire range &amp;quot;in one go&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The srcaddr/dstaddr must match what was given when the pages were originally mapped.&lt;br /&gt;
&lt;br /&gt;
== svcQueryMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || [[#MemoryInfo]]* || &amp;lt;code&amp;gt;MemInfo&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || void* || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || PageInfo || &amp;lt;code&amp;gt;PageInfo&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Query information about an address. Will always fetch the lowest page-aligned mapping that contains the provided address.&lt;br /&gt;
&lt;br /&gt;
Outputs a [[#MemoryInfo]] struct.&lt;br /&gt;
&lt;br /&gt;
== svcExitProcess ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) None || || &lt;br /&gt;
|-&lt;br /&gt;
| (Out) None || ||&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Exits the current process.&lt;br /&gt;
&lt;br /&gt;
== svcCreateThread ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || void(*)(void*) || &amp;lt;code&amp;gt;Entry&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || void* || &amp;lt;code&amp;gt;Arg&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || void* || &amp;lt;code&amp;gt;StackTop&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W4 || u32 || &amp;lt;code&amp;gt;Priority&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W5 || u32 || &amp;lt;code&amp;gt;ProcessorId&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || Handle&amp;lt;Thread&amp;gt; || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Create a thread in the current process.&lt;br /&gt;
&lt;br /&gt;
Processor_id must be 0,1,2,3 or -2, where -2 uses the default cpuid for process.&lt;br /&gt;
&lt;br /&gt;
== svcStartThread ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;Thread&amp;gt; || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) None ||  ||&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Starts the thread for the provided handle.&lt;br /&gt;
&lt;br /&gt;
== svcExitThread ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) None || || &lt;br /&gt;
|-&lt;br /&gt;
| (Out) None || ||&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Exits the current thread.&lt;br /&gt;
&lt;br /&gt;
== svcSleepThread ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;Nano&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Sleep for a specified amount of time, or yield thread.&lt;br /&gt;
&lt;br /&gt;
Setting nano=0 means &amp;quot;yield thread&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== svcGetThreadPriority ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1|| Handle&amp;lt;Thread&amp;gt; || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || u64 || &amp;lt;code&amp;gt;Priority&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Get priority of provided thread handle.&lt;br /&gt;
&lt;br /&gt;
== svcSetThreadPriority ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0|| Handle&amp;lt;Thread&amp;gt; || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1|| u32 || &amp;lt;code&amp;gt;Priority&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Set priority of provided thread handle.&lt;br /&gt;
&lt;br /&gt;
Priority is a number 0-0x3F. Lower value means higher priority.&lt;br /&gt;
&lt;br /&gt;
== svcGetThreadCoreMask ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || Handle&amp;lt;Thread&amp;gt; || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || u32 || &amp;lt;code&amp;gt;Out0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) X2 || u64 || &amp;lt;code&amp;gt;Out1&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Get affinity mask of provided thread handle.&lt;br /&gt;
&lt;br /&gt;
== svcSetThreadCoreMask ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;Thread&amp;gt; || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1 || u32 || &amp;lt;code&amp;gt;In0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;In1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Set affinity mask of provided thread handle.&lt;br /&gt;
&lt;br /&gt;
== svcGetCurrentProcessorNumber ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) None || || &lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0/X0 || u64 || &amp;lt;code&amp;gt;CpuId&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Get which cpu is executing the current thread.&lt;br /&gt;
&lt;br /&gt;
Cpu-id is an integer in the range 0-3.&lt;br /&gt;
&lt;br /&gt;
== svcMapSharedMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;SharedMemory&amp;gt; || &amp;lt;code&amp;gt;MemHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || void* || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W3 || [[#Permission]] || &amp;lt;code&amp;gt;Permissions&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Maps the block supplied by the handle. The required permissions are different for the process that created the handle and all other processes.&lt;br /&gt;
&lt;br /&gt;
Increases reference count for the KSharedMemory object. Thus in order to release the memory associated with the object, all handles to it must be closed and all mappings must be unmapped.&lt;br /&gt;
&lt;br /&gt;
== svcCreateTransferMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || void* || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W3 || [[#Permission]] || &amp;lt;code&amp;gt;Permissions&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || Handle&amp;lt;TransferMemory&amp;gt; || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This one reprotects the src block with perms you give it. It also sets bit0 into [[#MemoryAttribute]].&lt;br /&gt;
&lt;br /&gt;
Executable bit perm not allowed.&lt;br /&gt;
&lt;br /&gt;
Closing all handles automatically causes the bit0 in [[#MemoryAttribute]] to clear, and the permission to reset.&lt;br /&gt;
&lt;br /&gt;
== svcWaitSynchronization ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || Handle* || &amp;lt;code&amp;gt;HandlesPtr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || u64 || &amp;lt;code&amp;gt;HandlesNum&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;Timeout&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || u64 || &amp;lt;code&amp;gt;HandleIndex&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Works with num_handles &amp;lt;= 0x40, error on num_handles == 0.&lt;br /&gt;
&lt;br /&gt;
Does not accept 0xFFFF8001 or 0xFFFF8000 as handles.&lt;br /&gt;
&lt;br /&gt;
== svcSendSyncRequestWithUserBuffer ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || void* || &amp;lt;code&amp;gt;CmdPtr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || Handle&amp;lt;Session&amp;gt; || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Size must be 0x1000-aligned.&lt;br /&gt;
&lt;br /&gt;
== svcBreak ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || u64 ||&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 ||&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Info&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) ? || ? || &amp;lt;code&amp;gt;?&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
When used on retail where inx0 bit31 is clear, the system will throw a [[Error_codes|fatal-error]]. Otherwise when bit31 is set, it will return 0.&lt;br /&gt;
&lt;br /&gt;
== svcGetInfo ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;InfoId&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || Handle || &amp;lt;code&amp;gt;Handle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;InfoSubId&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) X1 || u64 || &amp;lt;code&amp;gt;Out&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Handle type || Id0 || Id1 || Description&lt;br /&gt;
|-&lt;br /&gt;
| Process || 0 || 0 || AllowedCpuIdBitmask&lt;br /&gt;
|-&lt;br /&gt;
| Process || 1 || 0 || AllowedThreadPrioBitmask&lt;br /&gt;
|-&lt;br /&gt;
| Process || 2 || 0 || ReservedMapRegionBaseAddress&lt;br /&gt;
|-&lt;br /&gt;
| Process || 3 || 0 || ReservedMapRegionSize&lt;br /&gt;
|-&lt;br /&gt;
| Process || 4 || 0 || ReservedHeapRegionBaseAddress&lt;br /&gt;
|-&lt;br /&gt;
| Process || 5 || 0 || ReservedHeapRegionSize&lt;br /&gt;
|-&lt;br /&gt;
| Process || 6 || 0 || TotalMemoryUsage&lt;br /&gt;
|-&lt;br /&gt;
| Process || 7 || 0 || TotalHeapUsage&lt;br /&gt;
|-&lt;br /&gt;
| Zero    || 8 || 0 || IsCurrentProcessBeingDebugged&lt;br /&gt;
|-&lt;br /&gt;
| Zero    || 9 || 0 || Returns ResourceLimit handle for current process. Used by [[Process_Manager_services|PM]].&lt;br /&gt;
|-&lt;br /&gt;
| Zero    || 10 || -1, {current coreid} || Unknown. Output data changes each time this SVC is used. Global and core-specific tick-count?&lt;br /&gt;
|-&lt;br /&gt;
| Zero    || 11 || 0-3 || RandomEntropy from current process. TRNG. Used to seed usermode PRNGs.&lt;br /&gt;
|-&lt;br /&gt;
| Process || 12 || 0 || [2.0.0+] AddressSpaceStart&lt;br /&gt;
|-&lt;br /&gt;
| Process || 13 || 0 || [2.0.0+] AddressSpaceSize&lt;br /&gt;
|-&lt;br /&gt;
| Process || 14 || 0 || [2.0.0+] NewReservedRegionStartAddr&lt;br /&gt;
|-&lt;br /&gt;
| Process || 15 || 0 || [2.0.0+] NewReservedRegionSize&lt;br /&gt;
|-&lt;br /&gt;
| Process || 18 || 0 || [3.0.0+] Title-id.&lt;br /&gt;
|-&lt;br /&gt;
| Thread || 0xF0000002 || 0 || Performance counter related.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== svcDumpInfo ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) None || || &lt;br /&gt;
|-&lt;br /&gt;
| (Out) None || ||&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Does nothing, just returns with registers set to all-zero.&lt;br /&gt;
&lt;br /&gt;
== svcReadWriteRegister ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;RegAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || u64 || &amp;lt;code&amp;gt;RwMask&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W3 || u64 || &amp;lt;code&amp;gt;InValue&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1|| u64 || &amp;lt;code&amp;gt;OutValue&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Read/write IO registers with a hardcoded whitelist. Input address is physical-address and must be aligned to 4.&lt;br /&gt;
&lt;br /&gt;
rw_mask is 0 for reading and 0xffffffff for writing. You can also write individual bits by using a mask value.&lt;br /&gt;
&lt;br /&gt;
You can only write to registers inside physical pages 0x70019000 (MC), 0x7001C000 (MC0), 0x7001D000 (MC1), and they all share the same whitelist.&lt;br /&gt;
&lt;br /&gt;
The whitelist is same for writing as for reading.&lt;br /&gt;
&lt;br /&gt;
The whitelist is:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
0x054, 0x090, 0x094, 0x098, 0x09c, 0x0a0, 0x0a4, 0x0a8, 0x0ac, 0x0b0, 0x0b4, 0x0b8, 0x0bc, 0x0c0, 0x0c4, 0x0c8, 0x0d0, 0x0d4, 0x0d8, 0x0dc, 0x0e0, 0x100, 0x108, 0x10c, 0x118, 0x11c, 0x124, 0x128, 0x12c, 0x130, 0x134, 0x138, 0x13c, 0x158, 0x15c, 0x164, 0x168, 0x16c, 0x170, 0x174, 0x178, 0x17c, 0x200, 0x204, 0x2e4, 0x2e8, 0x2ec, 0x2f4, 0x2f8, 0x310, 0x314, 0x320, 0x328, 0x344, 0x348, 0x370, 0x374, 0x37c, 0x380, 0x390, 0x394, 0x398, 0x3ac, 0x3b8, 0x3bc, 0x3c0, 0x3c4, 0x3d8, 0x3e8, 0x41c, 0x420, 0x424, 0x428, 0x42c, 0x430, 0x44c, 0x47c, 0x480, 0x484, 0x50c, 0x554, 0x558, 0x55c, 0x670, 0x674, 0x690, 0x694, 0x698, 0x69c, 0x6a0, 0x6a4, 0x6c0, 0x6c4, 0x6f0, 0x6f4, 0x960, 0x970, 0x974, 0xa20, 0xa24, 0xb88, 0xb8c, 0xbc4, 0xbc8, 0xbcc, 0xbd0, 0xbd4, 0xbd8, 0xbdc, 0xbe0, 0xbe4, 0xbe8, 0xbec, 0xc00, 0xc5c, 0xcac&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[2.0.0+] Whitelist was extended with &amp;lt;code&amp;gt;0x4c4, 0x4c8, 0x4cc, 0x584, 0x588, 0x58c.&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
[2.0.0+] The IO registers in range 0x7000E400 (PMC) size 0xC00 skip the whitelist, and do a TrustZone call using [[SMC]] Id1 0xC3000008(ReadWriteRegister).&lt;br /&gt;
&lt;br /&gt;
Here is the whitelist imposed by that SMC, relative to the start of the PMC registers:&lt;br /&gt;
&amp;lt;code&amp;gt;&lt;br /&gt;
0x000, 0x00c, 0x010, 0x014, 0x01c, 0x020, 0x02c, 0x030, 0x034, 0x038, 0x03c, 0x040, 0x044, 0x048, 0x0dc, 0x0e0, 0x0e4, 0x160, 0x164, 0x168, 0x170, 0x1a8, 0x1b8, 0x1bc, 0x1c0, 0x1c4, 0x1c8, 0x2b4, 0x2d4, 0x440, 0x4d8&lt;br /&gt;
&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== svcCreateSharedMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || [[#Permission]] || &amp;lt;code&amp;gt;LocalPerm&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W3 || [[#Permission]] || &amp;lt;code&amp;gt;RemotePerm&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || Handle&amp;lt;SharedMemory&amp;gt; || &amp;lt;code&amp;gt;MemHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Other perm can be used to enforce permission 1, 3, or 0x10000000 if don&#039;t care.&lt;br /&gt;
&lt;br /&gt;
== svcMapTransferMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || Handle&amp;lt;TransferMemory&amp;gt; || &amp;lt;code&amp;gt;MemHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || void* || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W3 || [[#Permission]] || &amp;lt;code&amp;gt;Permissions&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The newly mapped pages will have [[#MemoryState]] type 0xE.&lt;br /&gt;
&lt;br /&gt;
You must pass same size and permissions as given in svcCreateMemoryMirror, otherwise error.&lt;br /&gt;
&lt;br /&gt;
== svcUnmapTransferMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || Handle&amp;lt;TransferMemory&amp;gt; || &amp;lt;code&amp;gt;MemHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || void* || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Size must match size given in map syscall, otherwise there&#039;s an invalid-size error.&lt;br /&gt;
&lt;br /&gt;
== svcQueryPhysicalAddress ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]]|| &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) X1 || u64 || &amp;lt;code&amp;gt;Out0&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) X2 || u64 || &amp;lt;code&amp;gt;Out1&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) X3 || u64 || &amp;lt;code&amp;gt;Out2&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The inverse operation of [[#svcQueryIoMapping]].&lt;br /&gt;
&lt;br /&gt;
== svcQueryIoMapping ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;PhysAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) X1 || void* || &amp;lt;code&amp;gt;VirtAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Returns a virtual address mapped to a given IO range.&lt;br /&gt;
&lt;br /&gt;
== svcCreateDeviceAddressSpace ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;StartAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;EndAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || Handle&amp;lt;DeviceAddressSpace&amp;gt; || &amp;lt;code&amp;gt;AddressSpaceHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Creates a virtual address space for binding device address spaces and returns a handle.&lt;br /&gt;
&lt;br /&gt;
dev_as_start_addr is normally set to 0 and dev_as_end_addr is normally set to 0xFFFFFFFF.&lt;br /&gt;
&lt;br /&gt;
== svcAttachDeviceAddressSpace ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || [[#DeviceName]] || &amp;lt;code&amp;gt;DeviceId&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || Handle&amp;lt;DeviceAddressSpace&amp;gt; || &amp;lt;code&amp;gt;DeviceAsHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Attaches a device address space to a [[#DeviceName|device]].&lt;br /&gt;
&lt;br /&gt;
== svcDetachDeviceAddressSpace ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || [[#DeviceName]] || &amp;lt;code&amp;gt;DeviceId&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || Handle&amp;lt;DeviceAddressSpace&amp;gt; || &amp;lt;code&amp;gt;DeviceAsHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Detaches a device address space from a [[#DeviceName|device]].&lt;br /&gt;
&lt;br /&gt;
== svcMapDeviceAddressSpaceByForce ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;DeviceAddressSpace&amp;gt; || &amp;lt;code&amp;gt;DeviceAsHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || void* || &amp;lt;code&amp;gt;SrcAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;DeviceAsSize&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X4 || u64 || &amp;lt;code&amp;gt;DeviceAsAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W5 || [[#Permission]] || &amp;lt;code&amp;gt;Permissions&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Maps an attached device address space to an userspace address.&lt;br /&gt;
&lt;br /&gt;
dev_map_addr is the userspace destination address, while dev_as_addr is the source address between dev_as_start_addr and dev_as_end_addr (passed to [[#svcCreateDeviceAddressSpace]]).&lt;br /&gt;
&lt;br /&gt;
The userspace destination address must have the [[SVC#MemoryState|MapDeviceAllowed]] bit set. Bit [[SVC#MemoryAttribute|IsDeviceMapped]] will be set after mapping.&lt;br /&gt;
&lt;br /&gt;
== svcMapDeviceAddressSpaceAligned ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;DeviceAddressSpace&amp;gt; || &amp;lt;code&amp;gt;DeviceAsHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || void* || &amp;lt;code&amp;gt;SrcAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;DeviceAsSize&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X4 || u64 || &amp;lt;code&amp;gt;DeviceAsAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W5 || [[#Permission]] || &amp;lt;code&amp;gt;Permissions&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Maps an attached device address space to an userspace address.&lt;br /&gt;
&lt;br /&gt;
Same as [[#svcMapDeviceAddressSpaceByForce]], but the userspace destination address must have the [[SVC#MemoryState|MapDeviceAlignedAllowed]] bit set instead.&lt;br /&gt;
&lt;br /&gt;
== svcUnmapDeviceAddressSpace ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;DeviceAddressSpace&amp;gt; || &amp;lt;code&amp;gt;DeviceAsHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || void* || &amp;lt;code&amp;gt;SrcAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;DeviceAsSize&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X4 || u64 || &amp;lt;code&amp;gt;DeviceAsAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Description:&#039;&#039;&#039; Unmaps an attached device address space from an userspace address.&lt;br /&gt;
&lt;br /&gt;
== svcMapProcessMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || u64 || &amp;lt;code&amp;gt;SrcAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W1 || u64 || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || void* || &amp;lt;code&amp;gt;DstAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Maps the src address from the supplied process handle into the current process.&lt;br /&gt;
&lt;br /&gt;
This allows mapping code and rodata with RW- permission.&lt;br /&gt;
&lt;br /&gt;
== svcUnmapProcessMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || void* || &amp;lt;code&amp;gt;DstAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;SrcAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unmaps what was mapped by [[#svcMapProcessMemory]].&lt;br /&gt;
&lt;br /&gt;
== svcQueryProcessMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X0 || [[#MemoryInfo]]* || &amp;lt;code&amp;gt;MemInfoPtr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) W2 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || PageInfo || &amp;lt;code&amp;gt;PageInfo&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Equivalent to [[#svcQueryMemory]] except takes a process handle.&lt;br /&gt;
&lt;br /&gt;
== svcMapProcessCodeMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;DstAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;SrcAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Takes a process handle, and maps normal heap in that process as executable code in that process. Used when loading NROs.&lt;br /&gt;
&lt;br /&gt;
== svcUnmapProcessCodeMemory ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || u64 || &amp;lt;code&amp;gt;DstAddr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;Src Addr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;Size&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Unmaps what was mapped by [[#svcMapProcessCodeMemory]].&lt;br /&gt;
&lt;br /&gt;
== svcCreateProcess ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) X1 || [[#CreateProcessInfo]]* || &amp;lt;code&amp;gt;InfoPtr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X2 || u64 || &amp;lt;code&amp;gt;CapabilitiesPtr&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (In) X3 || u64 || &amp;lt;code&amp;gt;CapibilitiesNum&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Takes a [[#CreateProcessInfo]] as input.&lt;br /&gt;
&lt;br /&gt;
== svcGetProcessInfo ==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div style=&amp;quot;display: inline-block;&amp;quot;&amp;gt;&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Argument || Type || Name&lt;br /&gt;
|-&lt;br /&gt;
| (In) W0 || Handle&amp;lt;Process&amp;gt; || &amp;lt;code&amp;gt;ProcessHandle&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W0 || [[#Result]] || &amp;lt;code&amp;gt;Ret&amp;lt;/code&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| (Out) W1 || [[#ProcessState]] || &amp;lt;code&amp;gt;State&amp;lt;/code&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Returns an enum with value 0-7.&lt;br /&gt;
&lt;br /&gt;
== Debugging ==&lt;br /&gt;
[2.0.0+] Exactly 6 debug SVCs require that [[SPL_services#GetConfig|IsDebugMode]] is non-zero. Error 0x4201 is returned otherwise.&lt;br /&gt;
* svcBreakDebugProcess&lt;br /&gt;
* svcContinueDebugEvent&lt;br /&gt;
* svcWriteDebugProcessMemory&lt;br /&gt;
* svcSetDebugThreadContext&lt;br /&gt;
* svcTerminateDebugProcess&lt;br /&gt;
* svcSetHardwareBreakPoint&lt;br /&gt;
&lt;br /&gt;
svcDebugActiveProcess stops execution of the target process, the normal method for resuming it requires svcContinueDebugEvent(see above). Closing the debug handle also results in execution being resumed.&lt;br /&gt;
&lt;br /&gt;
= Enum/Structures =&lt;br /&gt;
== ThreadContextRequestFlags ==&lt;br /&gt;
Bitfield of one of more of these:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Bit || Bitmask || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || NormalContext&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 2 ||&lt;br /&gt;
|-&lt;br /&gt;
| 2 || 4 ||&lt;br /&gt;
|-&lt;br /&gt;
| 3 || 8 ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== DeviceName ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || DeviceName_AFI&lt;br /&gt;
|-&lt;br /&gt;
| 1 || DeviceName_AVPC&lt;br /&gt;
|-&lt;br /&gt;
| 2 || DeviceName_DC&lt;br /&gt;
|-&lt;br /&gt;
| 3 || DeviceName_DCB&lt;br /&gt;
|-&lt;br /&gt;
| 4 || DeviceName_HC&lt;br /&gt;
|-&lt;br /&gt;
| 5 || DeviceName_HDA&lt;br /&gt;
|-&lt;br /&gt;
| 6 || DeviceName_ISP2&lt;br /&gt;
|-&lt;br /&gt;
| 7 || DeviceName_MSENCNVENC&lt;br /&gt;
|-&lt;br /&gt;
| 8 || DeviceName_NV&lt;br /&gt;
|-&lt;br /&gt;
| 9 || DeviceName_NV2&lt;br /&gt;
|-&lt;br /&gt;
| 10 || DeviceName_PPCS&lt;br /&gt;
|-&lt;br /&gt;
| 11 || DeviceName_SATA&lt;br /&gt;
|-&lt;br /&gt;
| 12 || DeviceName_VI&lt;br /&gt;
|-&lt;br /&gt;
| 13 || DeviceName_VIC&lt;br /&gt;
|-&lt;br /&gt;
| 14 || DeviceName_XUSB_HOST&lt;br /&gt;
|-&lt;br /&gt;
| 15 || DeviceName_XUSB_DEV&lt;br /&gt;
|-&lt;br /&gt;
| 16 || DeviceName_TSEC&lt;br /&gt;
|-&lt;br /&gt;
| 17 || DeviceName_PPCS1&lt;br /&gt;
|-&lt;br /&gt;
| 18 || DeviceName_DC1&lt;br /&gt;
|-&lt;br /&gt;
| 19 || DeviceName_SDMMC1A&lt;br /&gt;
|-&lt;br /&gt;
| 20 || DeviceName_SDMMC2A&lt;br /&gt;
|-&lt;br /&gt;
| 21 || DeviceName_SDMMC3A&lt;br /&gt;
|-&lt;br /&gt;
| 22 || DeviceName_SDMMC4A&lt;br /&gt;
|-&lt;br /&gt;
| 23 || DeviceName_ISP2B&lt;br /&gt;
|-&lt;br /&gt;
| 24 || DeviceName_GPU&lt;br /&gt;
|-&lt;br /&gt;
| 25 || DeviceName_GPUB&lt;br /&gt;
|-&lt;br /&gt;
| 26 || DeviceName_PPCS2&lt;br /&gt;
|-&lt;br /&gt;
| 27 || DeviceName_NVDEC&lt;br /&gt;
|-&lt;br /&gt;
| 28 || DeviceName_APE&lt;br /&gt;
|-&lt;br /&gt;
| 29 || DeviceName_SE&lt;br /&gt;
|-&lt;br /&gt;
| 30 || DeviceName_NVJPG&lt;br /&gt;
|-&lt;br /&gt;
| 31 || DeviceName_HC1&lt;br /&gt;
|-&lt;br /&gt;
| 32 || DeviceName_SE1&lt;br /&gt;
|-&lt;br /&gt;
| 33 || DeviceName_AXIAP&lt;br /&gt;
|-&lt;br /&gt;
| 34 || DeviceName_ETR&lt;br /&gt;
|-&lt;br /&gt;
| 35 || DeviceName_TSECB&lt;br /&gt;
|-&lt;br /&gt;
| 36 || DeviceName_TSEC1&lt;br /&gt;
|-&lt;br /&gt;
| 37 || DeviceName_TSECB1&lt;br /&gt;
|-&lt;br /&gt;
| 38 || DeviceName_NVDEC1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== LimitableResource ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || LimitableResource_Memory&lt;br /&gt;
|-&lt;br /&gt;
| 1 || LimitableResource_Threads&lt;br /&gt;
|-&lt;br /&gt;
| 2 || LimitableResource_Events&lt;br /&gt;
|-&lt;br /&gt;
| 3 || LimitableResource_TransferMemories&lt;br /&gt;
|-&lt;br /&gt;
| 4 || LimitableResource_Sessions&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ProcessEvent ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || ProcessEvent_Created&lt;br /&gt;
|-&lt;br /&gt;
| 1 || ProcessEvent_DebugAttached&lt;br /&gt;
|-&lt;br /&gt;
| 2 || ProcessEvent_DebugDetached&lt;br /&gt;
|-&lt;br /&gt;
| 3 || ProcessEvent_Crashed&lt;br /&gt;
|-&lt;br /&gt;
| 4 || ProcessEvent_Running&lt;br /&gt;
|-&lt;br /&gt;
| 5 || ProcessEvent_Exiting&lt;br /&gt;
|-&lt;br /&gt;
| 6 || ProcessEvent_Exited&lt;br /&gt;
|-&lt;br /&gt;
| 7 || ProcessEvent_DebugSuspended&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== DebugThreadParam ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || DebugThreadParam_ActualPriority&lt;br /&gt;
|-&lt;br /&gt;
| 1 ||&lt;br /&gt;
|-&lt;br /&gt;
| 2 || DebugThreadParam_CpuCore&lt;br /&gt;
|-&lt;br /&gt;
| 3 ||&lt;br /&gt;
|-&lt;br /&gt;
| 4 || DebugThreadParam_CoreMask&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== CreateProcessInfo ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Bits || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 12 || || ProcessName (doesn&#039;t have to be null-terminated)&lt;br /&gt;
|-&lt;br /&gt;
| 0xC || 4 || ||&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || 8 || || TitleId&lt;br /&gt;
|-&lt;br /&gt;
| 0x18 || 8 || || CodeAddr&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || 4 || || CodeNumPages&lt;br /&gt;
|-&lt;br /&gt;
| 0x24 || 4 || || MmuFlags&lt;br /&gt;
|-&lt;br /&gt;
| || || Bit0 || Is64bit&lt;br /&gt;
|-&lt;br /&gt;
| || || Bit3-1 || [[#AddressSpaceType]]&lt;br /&gt;
|-&lt;br /&gt;
| || || Bit4 ||&lt;br /&gt;
|-&lt;br /&gt;
| || || Bit5 || EnableAslr&lt;br /&gt;
|-&lt;br /&gt;
| || || Bit6 || IsSystem&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || 4 || || ResourceLimitHandle&lt;br /&gt;
|-&lt;br /&gt;
| 0x2C || 4 ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== AddressSpaceType ===&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Type || Name || Width || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 || Normal_32Bit || 32 ||&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Normal_36Bit || 36 ||&lt;br /&gt;
|-&lt;br /&gt;
| 2 || WithoutMap_32Bit || 32 || Appears to be missing map region [?]&lt;br /&gt;
|-&lt;br /&gt;
| 3 || [2.0.0+] Normal_39Bit || 39 ||&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MemoryInfo ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 8 || BaseAddress&lt;br /&gt;
|-&lt;br /&gt;
| 8 || 8 || Size&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || 4 || MemoryType: lower 8 bits of [[#MemoryState]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x14 || 4 || [[#MemoryAttribute]]&lt;br /&gt;
|-&lt;br /&gt;
| 0x18 || 4 || Permission (bit0: R, bit1: W, bit2: X)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C || 4 || IpcRefCount&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || 4 || DeviceRefCount&lt;br /&gt;
|-&lt;br /&gt;
| 0x24 || 4 || Padding: always zero&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MemoryAttribute ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Bits || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 || IsBorrowed&lt;br /&gt;
|-&lt;br /&gt;
| 1 || IsIpcMapped: when IpcRefCount &amp;gt; 0.&lt;br /&gt;
|-&lt;br /&gt;
| 2 || IsDeviceMapped: when DeviceRefCount &amp;gt; 0.&lt;br /&gt;
|-&lt;br /&gt;
| 3 || IsUncached&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== MemoryState ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Bits || Description&lt;br /&gt;
|-&lt;br /&gt;
| 7-0 || Type&lt;br /&gt;
|-&lt;br /&gt;
| 8 || [[#svcSetMemoryPermission|PermissionChangeAllowed]]&lt;br /&gt;
|-&lt;br /&gt;
| 9 || ForceReadWritableByDebugSyscalls&lt;br /&gt;
|-&lt;br /&gt;
| 10 || IpcSendAllowed_Type0&lt;br /&gt;
|-&lt;br /&gt;
| 11 || IpcSendAllowed_Type3&lt;br /&gt;
|-&lt;br /&gt;
| 12 || IpcSendAllowed_Type1&lt;br /&gt;
|-&lt;br /&gt;
| 14 || [[#svcSetProcessMemoryPermission|ProcessPermissionChangeAllowed]]&lt;br /&gt;
|-&lt;br /&gt;
| 15 || [[#svcMapMemory|MapAllowed]]&lt;br /&gt;
|-&lt;br /&gt;
| 16 || [[#svcUnmapProcessCodeMemory|UnmapProcessCodeMemoryAllowed]]&lt;br /&gt;
|-&lt;br /&gt;
| 17 || [[#svcCreateTransferMemory|TransferMemoryAllowed]]&lt;br /&gt;
|-&lt;br /&gt;
| 19 || MapDeviceAllowed ([[#svcMapDeviceAddressSpace]] and [[#svcMapDeviceAddressSpaceByForce]])&lt;br /&gt;
|-&lt;br /&gt;
| 20 || [[#svcMapDeviceAddressSpaceAligned|MapDeviceAlignedAllowed]]&lt;br /&gt;
|-&lt;br /&gt;
| 21 || [[#svcSendSyncRequestWithUserBuffer|IpcBufferAllowed]]&lt;br /&gt;
|-&lt;br /&gt;
| 22 || IsPoolAllocated/IsReferenceCounted&lt;br /&gt;
|-&lt;br /&gt;
| 23 || [[#svcMapProcessMemory|MapProcessAllowed]]&lt;br /&gt;
|-&lt;br /&gt;
| 24 || [[#svcSetMemoryAttribute|AttributeChangeAllowed]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Type || Meaning&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00000000&amp;lt;/code&amp;gt; || MemoryType_Unmapped ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00002001&amp;lt;/code&amp;gt; || MemoryType_Io || Mapped by kernel capability parsing in [[#svcCreateProcess]]. &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00042002&amp;lt;/code&amp;gt; || MemoryType_Normal || Mapped by kernel capability parsing in [[#svcCreateProcess]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00DC7E03&amp;lt;/code&amp;gt; || MemoryType_CodeStatic || Mapped during [[#svcCreateProcess]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01FEBD04&amp;lt;/code&amp;gt; || MemoryType_CodeMutable || Transition from 0xDC7E03 performed by [[#svcSetProcessMemoryPermission]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x017EBD05&amp;lt;/code&amp;gt; || MemoryType_Heap || Mapped using [[#svcSetHeapSize]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00402006&amp;lt;/code&amp;gt; || MemoryType_SharedMemory || Mapped using [[#svcMapSharedMemory]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00482907&amp;lt;/code&amp;gt; || [1.0.0] MemoryType_WeirdSharedMemory || Mapped using [[#svcMapMemory]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00DD7E08&amp;lt;/code&amp;gt; || MemoryType_ModuleCodeStatic || Mapped using [[#svcMapProcessCodeMemory]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x01FFBD09&amp;lt;/code&amp;gt; || MemoryType_ModuleCodeMutable || Transition from 0xDD7E08 performed by [[#svcSetProcessMemoryPermission]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x005C3C0A&amp;lt;/code&amp;gt; || [[IPC_Marshalling|MemoryType_IpcBuffer0]] || IPC buffers with descriptor flags=0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x005C3C0B&amp;lt;/code&amp;gt; || MemoryType_MappedMemory || Mapped using [[#svcMapMemory]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x0040200C&amp;lt;/code&amp;gt; || [[Thread Local Storage|MemoryType_ThreadLocal]] || Mapped during [[#svcCreateThread]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x015C3C0D&amp;lt;/code&amp;gt; || MemoryType_TransferMemoryIsolated || Mapped using [[#svcMapTransferMemory]] when the owning process has perm=0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x005C380E&amp;lt;/code&amp;gt; || MemoryType_TransferMemory || Mapped using [[#svcMapTransferMemory]] when the owning process has perm!=0.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x0040380F&amp;lt;/code&amp;gt; || MemoryType_ProcessMemory || Mapped using [[#svcMapProcessMemory]].&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00000010&amp;lt;/code&amp;gt; || MemoryType_Reserved ||&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x005C3811&amp;lt;/code&amp;gt; || [[IPC_Marshalling|MemoryType_IpcBuffer1]] || IPC buffers with descriptor flags=1.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x004C2812&amp;lt;/code&amp;gt; || [[IPC_Marshalling|MemoryType_IpcBuffer3]] || IPC buffers with descriptor flags=3.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;code&amp;gt;0x00002013&amp;lt;/code&amp;gt; || MemoryType_KernelStack || Mapped in kernel during [[#svcCreateThread]].&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== ContinueDebugFlags ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Bit || Bitmask || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 1 || SwallowException&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 2 ||&lt;br /&gt;
|-&lt;br /&gt;
| 2 || 4 || ResumeAllThreads&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== DebugEventInfo ==&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0 || u32 || EventType&lt;br /&gt;
|-&lt;br /&gt;
| 4 || u32 || Flags (bit0: NeedsContinue)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || u64 || ThreadId&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || || PerTypeSpecifics&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
AttachProcess specific:&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || u64 || TitleId&lt;br /&gt;
|-&lt;br /&gt;
| 0x18 || u64 || ProcessId&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || char[12] || ProcessName&lt;br /&gt;
|-&lt;br /&gt;
| 0x2C || u32 || MmuFlags&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
AttachThread specific:&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || u64 || ThreadId&lt;br /&gt;
|-&lt;br /&gt;
| 0x18 || u64 || TlsPtr&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || u64 || Entrypoint&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
ExitProcess/ExitThread specific:&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || u32 || ProcessId/ThreadId?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Exception specific:&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 || u64 || ExceptionType&lt;br /&gt;
|-&lt;br /&gt;
| 0x18 || u64 || FaultRegister&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || || PerExceptionSpecifics&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== DebugEventType ===&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || DebugEvent_AttachProcess&lt;br /&gt;
|-&lt;br /&gt;
| 1 || DebugEvent_AttachThread&lt;br /&gt;
|-&lt;br /&gt;
| 2 || DebugEvent_ExitProcess?&lt;br /&gt;
|-&lt;br /&gt;
| 3 || DebugEvent_ExitThread&lt;br /&gt;
|-&lt;br /&gt;
| 3 || DebugEvent_Exception&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== DebugExceptionType ===&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Name&lt;br /&gt;
|-&lt;br /&gt;
| 0 || Exception_UndefinedInstruction&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Exception_InstructionAbort&lt;br /&gt;
|-&lt;br /&gt;
| 2 || Exception_DataAbortMisc&lt;br /&gt;
|-&lt;br /&gt;
| 3 || Exception_PcSpAlignmentFault&lt;br /&gt;
|-&lt;br /&gt;
| 4 || Exception_DebuggerAttached&lt;br /&gt;
|-&lt;br /&gt;
| 5 || Exception_BreakPoint&lt;br /&gt;
|-&lt;br /&gt;
| 6 || Exception_UserBreak&lt;br /&gt;
|-&lt;br /&gt;
| 7 || Exception_DebuggerBreak&lt;br /&gt;
|-&lt;br /&gt;
| 8 || Exception_BadSvcId&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
UndefinedInstruction specifics:&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || u32 || Opcode&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
BreakPoint specifics:&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || u32 || IsWatchpoint&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
UserBreak specifics:&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || u32 || Info0&lt;br /&gt;
|-&lt;br /&gt;
| 0x28 || u64 || Info1&lt;br /&gt;
|-&lt;br /&gt;
| 0x30 || u64 || Info2&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
BadSvcId specifics:&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Offset || Length || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x20 || u32 || SvcId&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Exception handling =&lt;br /&gt;
There is userland code for handling exceptions, however this doesn&#039;t seem to be executed on retail mode.&lt;br /&gt;
&lt;br /&gt;
When a usermode exception occurs, it jumps to the main code binary entrypoint (main_binary_address + 0 == &#039;&#039;&#039;_start&#039;&#039;&#039;).&lt;br /&gt;
&lt;br /&gt;
During normal boot &#039;&#039;&#039;_start&#039;&#039;&#039; is invoked with X0=0 and X1=main_thread_handle (triggering normal crt0 setup).&lt;br /&gt;
During an usermode exception &#039;&#039;&#039;_start&#039;&#039;&#039; is invoked with X0=exception_info0_ptr and X1=exception_info1_ptr instead.&lt;br /&gt;
&lt;br /&gt;
The &#039;&#039;&#039;_start&#039;&#039;&#039; method determines whether to boot normally or handle an exception if X0 is set to 0 or not.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=2875</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=2875"/>
		<updated>2017-10-19T15:19:19Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: /* Key generation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== BootROM ==&lt;br /&gt;
The bootrom initializes two keyslots in the hardware engine:&lt;br /&gt;
&lt;br /&gt;
* the SBK (Secure Boot Key) in keyslot 14&lt;br /&gt;
* the SSK (Secure Storage Key) in keyslot 15.&lt;br /&gt;
&lt;br /&gt;
Reads from both of these keyslots are disabled by the bootROM.&lt;br /&gt;
The SBK is stored in [[Fuses#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY]], which are locked to read out only FFs after the bootrom finishes.&lt;br /&gt;
&lt;br /&gt;
SBK should be shared amongst all consoles, but we don&#039;t know this is the case.&lt;br /&gt;
&lt;br /&gt;
The SSK is derived on boot via the SBK, the 32-bit console-unique &amp;quot;Device Key&amp;quot;, and hardware information stored in fuses.&lt;br /&gt;
&lt;br /&gt;
Pseudocode for the derivation is as follows:&lt;br /&gt;
  void generateSSK() {&lt;br /&gt;
      char keyBuffer[0x10]; // Used to store keydata&lt;br /&gt;
      uint hwInfoBuffer[4]; // Used to store info about hardware from fuses&lt;br /&gt;
      uint deviceKey = getDeviceKey(); // Reads 32-bit device key from FUSE_PRIVATE_KEY4.&lt;br /&gt;
      for (int i = 0; i &amp;lt; 4; i++) { // Keybuffer = deviceKey || deviceKey || deviceKey || deviceKey&lt;br /&gt;
          ((uint *)keyBuffer)[i] = deviceKey;&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, deviceKey || {...})&lt;br /&gt;
      &lt;br /&gt;
      // Set up Hardware info buffer&lt;br /&gt;
      uint vendor_code = *((uint *)0x7000FA00) &amp;amp; 0x0000000F; // FUSE_VENDOR_CODE&lt;br /&gt;
      uint fab_code    = *((uint *)0x7000FA04) &amp;amp; 0x0000003F; // FUSE_FAB_CODE&lt;br /&gt;
      uint lot_code_0  = *((uint *)0x7000FA08) &amp;amp; 0xFFFFFFFF; // FUSE_LOT_CODE_0&lt;br /&gt;
      uint lot_code_1  = *((uint *)0x7000FA0C) &amp;amp; 0x0FFFFFFF; // FUSE_LOT_CODE_1&lt;br /&gt;
      uint wafer_id    = *((uint *)0x7000FA10) &amp;amp; 0x0000003F; // FUSE_WAFER_ID&lt;br /&gt;
      uint x_coord     = *((uint *)0x7000FA14) &amp;amp; 0x000001FF; // FUSE_X_COORDINATE&lt;br /&gt;
      uint y_coord     = *((uint *)0x7000FA18) &amp;amp; 0x000001FF; // FUSE_Y_COORDINATE&lt;br /&gt;
      uint unk_hw_fuse = *((uint *)0x7000FA20) &amp;amp; 0x0000003F; // Unknown cached fuse.&lt;br /&gt;
      &lt;br /&gt;
      // HARDWARE_INFO_BUFFER = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID&lt;br /&gt;
      hwInfoBuffer[0] = (lot_code_1 &amp;lt;&amp;lt; 30) | (wafer_id &amp;lt;&amp;lt; 24) | (x_coord &amp;lt;&amp;lt; 15) | (y_coord &amp;lt;&amp;lt; 6) | unk_hw_fuse;&lt;br /&gt;
      hwInfoBuffer[1] = (lot_code_0 &amp;lt;&amp;lt; 26) | (lot_code_1 &amp;gt;&amp;gt; 2);&lt;br /&gt;
      hwInfoBuffer[2] = (fab_code &amp;lt;&amp;lt; 26) | (lot_code_0 &amp;gt;&amp;gt; 6);&lt;br /&gt;
      hwInfoBuffer[3] = vendor_code;&lt;br /&gt;
      &lt;br /&gt;
      for (int i = 0; i &amp;lt; 0x10; i++) { // keyBuffer = XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER)&lt;br /&gt;
          keyBuffer[i] ^= ((char *)hwInfoBuffer)[i];&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER))&lt;br /&gt;
      &lt;br /&gt;
      setKeyslot(KEYSLOT_SSK, keyBuffer); // SSK = keyBuffer.&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
The falcon processor (TSEC) stores a special console-unique key (that will be referred to as the &amp;quot;tsec key&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This is presumably stored in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
The tsec key is the source of all per-console entropy, because SSK is not used on retail.&lt;br /&gt;
&lt;br /&gt;
== Package1 ==&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Cleared by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
! Introduced in&lt;br /&gt;
! Deprecated on&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Package1Key&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
| Never&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
| Never&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| OtherPerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| ?&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Never&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| No&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
| Never&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| OtherMasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| ?&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Never&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
| Never&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
| Never&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: aes_unwrap(wrapped_key, wrap_key) is just another name for a single AES-128 block decryption.&lt;br /&gt;
&lt;br /&gt;
If bit0 of 0x7000FB94 is clear, it will initialize keys like this (probably used for internal development units only):&lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = aes_unwrap(f5baeadb.., sbk)&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x11 ? aff11423.. : 5e177ee1.., aes_unwrap(5ff9c2d9.., sbk))&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e..., aes_unwrap(6e4a9592.., ssk))&lt;br /&gt;
&lt;br /&gt;
Normal key generation looks like this on 1.0.0/2.0.0:&lt;br /&gt;
  keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */, sbk /* slot14 */)&lt;br /&gt;
  cmac_key    /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(is_debug ? 0542a0fd.. : d8a2410a.., keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., keyblob_key)&lt;br /&gt;
&lt;br /&gt;
SBK and SSK keyslots are cleared after keys have been generated.&lt;br /&gt;
&lt;br /&gt;
See table above for which keys are console unique.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the hardcoded constants for the keyblob used in the current revision. Nintendo are withholding all the future hardcoded constants.&lt;br /&gt;
&lt;br /&gt;
This means that if you have an attack on the bootloader, you need to re-preform it every time they move to a new keyblob.&lt;br /&gt;
&lt;br /&gt;
Dumping the SBK and TSEC key of any single system should be enough to derive all key material on the system.&lt;br /&gt;
&lt;br /&gt;
The key-derivation is described in more detail [[Package1#Key_generation|here]].&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1-3.0.2&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 1 ==&lt;br /&gt;
It is currently unknown what key generation the stage 2 bootloader does.&lt;br /&gt;
&lt;br /&gt;
== Secure Monitor ==&lt;br /&gt;
The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=4.0.0&amp;diff=2873</id>
		<title>4.0.0</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=4.0.0&amp;diff=2873"/>
		<updated>2017-10-19T14:47:05Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: checkFuseCoherency&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Switch 4.0.0 system update was released on October 18, 2017. This Switch update was released for the following regions: ALL.&lt;br /&gt;
&lt;br /&gt;
Security flaws fixed: &amp;lt;fill this in manually later, see the updatedetails page from the ninupdates-report page(s) once available for now&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Change-log==&lt;br /&gt;
[http://en-americas-support.nintendo.com/app/answers/detail/a_id/22525/p/897 Official] ALL change-log:&lt;br /&gt;
* Added the following system functionality&lt;br /&gt;
* Capture video on select games&lt;br /&gt;
* To capture video, hold down the Capture Button during gameplay&lt;br /&gt;
* Up to maximum of the previous 30 seconds will be saved in the Album. You can trim the beginning and end of each clip, and post to Facebook and Twitter. &lt;br /&gt;
* As of October 18th, 2017, this feature is compatible with The Legend of Zelda: Breath of the Wild, Mario Kart 8 Deluxe, ARMS, and Splatoon 2&lt;br /&gt;
* Select from 12 new Super Mario Odyssey and The Legend of Zelda: Breath of the Wild icons for your user&lt;br /&gt;
* To edit your user icon, head to your My Page on the top left of the Home Menu &amp;gt; Profile &lt;br /&gt;
* Transfer user and save data to another system&lt;br /&gt;
* To transfer, head to System Settings &amp;gt; Users &amp;gt; Transfer Your User and Save Data&lt;br /&gt;
* Pre-purchase option on Nintendo eShop&lt;br /&gt;
* A pre-purchase option will be available for certain games. This option allows pre-load of the game to your system for quicker play when the game is released.&lt;br /&gt;
*  This feature will be supported by future game releases &lt;br /&gt;
* News channel updates&lt;br /&gt;
* The news feed has been updated with a new look. &lt;br /&gt;
*  Unfollowing a channel will remove that channel&#039;s content from the news feed and following the channel again will make it reappear.&lt;br /&gt;
* Match software version with a group of local users&lt;br /&gt;
* To create a group, head to the software&#039;s Options &amp;gt; Software Update &amp;gt; Match Version with Local Users&lt;br /&gt;
* Everyone&#039;s software will be updated to match the most recent version in the group&lt;br /&gt;
* All users must be on system menu version 4.0.0 or later to view and join a group &lt;br /&gt;
* General system stability improvements to enhance the user&#039;s experience, including:&lt;br /&gt;
* Changed the specification which hid wireless networks using TKIP security from the network search results.  Wireless networks using TKIP security will now display in search results as a grayed-out selection instead of not being displayed&lt;br /&gt;
* The Nintendo Switch console supports WEP, WPA-PSK(AES), and WPA2-PSK(AES). If your router is using a different security type (e.g. WPA-PSK(TKIP)), you will need to change this security type within your router&#039;s settings.&lt;br /&gt;
&lt;br /&gt;
==System Titles==&lt;br /&gt;
&amp;lt;fill this in (manually) later&amp;gt;&lt;br /&gt;
&lt;br /&gt;
* Every single system title was updated, except for: 0100000000000805(&amp;quot;Chinese and Korean dictionaries&amp;quot;), 0100000000000808(&amp;quot;European, English and Japanese dictionaries&amp;quot;), and 010000000000080C(&amp;quot;EULA&amp;quot;).&lt;br /&gt;
* 4 new sysmodules were added, and new FIRM-package title 010000000000081C was added.&lt;br /&gt;
&lt;br /&gt;
===FIRM===&lt;br /&gt;
Everything under RomFS was updated.&lt;br /&gt;
&lt;br /&gt;
The package1 entrypoint address specified by BCT was increased by 0x20-bytes, since there&#039;s now an additional 0x20-bytes at the start of package1. The additional data is identical to the 0x20-byte block before it.&lt;br /&gt;
&lt;br /&gt;
====Package1====&lt;br /&gt;
  setKeyslotFlags (LT_4001011a)&lt;br /&gt;
  Instead of writing ~flags directly to securityEngine-&amp;gt;KEYSLOT_FLAGS[keyslot], this now preserves the high bits of the existing flags.&lt;br /&gt;
  &lt;br /&gt;
  getOdmFuse4Type (LT_40010614)&lt;br /&gt;
  This func now includes bits 16-19 in the OR&#039;d flag used in the switch, and now returns 4 as a default invalid result instead of the low bit of [[Fuses|FUSE_SPARE_BIT_5]].&lt;br /&gt;
  &lt;br /&gt;
  checkFuseCoherency (LT_400106e4)&lt;br /&gt;
  This func was updated to take into account the new invalid retval for getOdmFuse4Type.&lt;br /&gt;
  Checks that were only enforced on retail prior to this update (bootROM patch must not be &amp;lt; 0x7F and EKS must be provisionned) are now enforced for dev too.&lt;br /&gt;
  The now redundant bootROM &amp;lt; 0x1F check was removed.&lt;br /&gt;
    &lt;br /&gt;
  decryptAndParsePK11 (LT_40010734)&lt;br /&gt;
  The entrypoint calculation code no longer adds *(package11Header + 0x4) to the address.&lt;br /&gt;
  &lt;br /&gt;
  generateKeys (LT_400107a2)&lt;br /&gt;
  setKeyslotFlags(keyslot, 0x15) is now additionally called on keyslots 14 and 15.&lt;br /&gt;
  The code for switching key generation method depending on fuses (unit type) and last byte of PKC modulus has been removed, and replaced with a call to a single key generation function.&lt;br /&gt;
  The code block inbetween the keyslot-config code was replaced with just a call to LT_40011264(same function mentioned above).&lt;br /&gt;
  setKeyslotFlags(keyslot, 0xFF) is now used on keyslots 12 and 15 instead of 12 and 13.&lt;br /&gt;
  &lt;br /&gt;
  downgradeFuseCheck (LT_400111cc)&lt;br /&gt;
  The burnt fuse information stored in .rodata now expects 5 fuses to be burnt for retail units, instead of 4.&lt;br /&gt;
  &lt;br /&gt;
  generateKeysFromBITAddress (LT_40011264)&lt;br /&gt;
  Instead of calling generateKeysLegacyMethod, this now calls generateKeysFromKeyblobAndKeyseeds (the main key generation function). Legacy key generation code has been removed.&lt;br /&gt;
  &lt;br /&gt;
  generateKeysFromKeyblobAndKeyseeds (LT_400112f0)&lt;br /&gt;
  The function now takes in two keyseeds and sizes, previously it only took in one (keyseed, size) pair.&lt;br /&gt;
  Keyslot 15 (initially SSK) is now used where keyslot 10 was used previously, and keyslot 15 is no longer cleared when keyslot 14 (initially SBK) is cleared.&lt;br /&gt;
  The [[Flash_Filesystem|Keyblob]] keyseed was updated for keyblob 4.&lt;br /&gt;
  code block following the keyblob clear code was updated:&lt;br /&gt;
  After the decrypted keyblob is cleared, decryptDataIntoKeyslot(KEYSLOT_14, KEYSLOT_12, secondKeySeed, secondKeySeedSize) is now called before decryptDataIntoKeyslot(KEYSLOT_12, KEYSLOT_12, firstKeySeed, firstKeySeedSize).&lt;br /&gt;
  At the end of the function, &amp;quot;decryptDataIntoKeyslot(KEYSLOT_13, KEYSLOT_10, perConsoleKeyseed2, 0x10); clearKeyslot(KEYSLOT_10);&amp;quot; has been replaced with &amp;quot;decryptDataIntoKeyslot(KEYSLOT_13, KEYSLOT_15, perConsoleKeyseed3, 0x10); decryptDataIntoKeyslot(KEYSLOT_15, KEYSLOT_15, perConsoleKeyseed2, 0x10);&amp;quot;&lt;br /&gt;
&lt;br /&gt;
==Keys==&lt;br /&gt;
All of these updated titles now use the new [[NCA_Format|NCA]] crypto for [[NCA|non-ncatype0]](all content except .cnmt content), except for all of the FIRM-packages including the new one(required for FIRM installation).&lt;br /&gt;
&lt;br /&gt;
[[Flash_Filesystem|Keyblob]] 4 is now used, instead of 3.&lt;br /&gt;
&lt;br /&gt;
==OSS==&lt;br /&gt;
The updated [https://www.nintendo.co.jp/support/oss/index.html OSS] includes WebKit changes.&lt;br /&gt;
&lt;br /&gt;
==See Also==&lt;br /&gt;
System update report(s):&lt;br /&gt;
* [https://yls8.mtheall.com/ninupdates/reports.php?date=10-18-17_08-05-13&amp;amp;sys=hac]&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=2871</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=2871"/>
		<updated>2017-10-19T14:27:39Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: New keys&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== BootROM ==&lt;br /&gt;
The bootrom initializes two keyslots in the hardware engine:&lt;br /&gt;
&lt;br /&gt;
* the SBK (Secure Boot Key) in keyslot 14&lt;br /&gt;
* the SSK (Secure Storage Key) in keyslot 15.&lt;br /&gt;
&lt;br /&gt;
Reads from both of these keyslots are disabled by the bootROM.&lt;br /&gt;
The SBK is stored in [[Fuses#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY]], which are locked to read out only FFs after the bootrom finishes.&lt;br /&gt;
&lt;br /&gt;
SBK should be shared amongst all consoles, but we don&#039;t know this is the case.&lt;br /&gt;
&lt;br /&gt;
The SSK is derived on boot via the SBK, the 32-bit console-unique &amp;quot;Device Key&amp;quot;, and hardware information stored in fuses.&lt;br /&gt;
&lt;br /&gt;
Pseudocode for the derivation is as follows:&lt;br /&gt;
  void generateSSK() {&lt;br /&gt;
      char keyBuffer[0x10]; // Used to store keydata&lt;br /&gt;
      uint hwInfoBuffer[4]; // Used to store info about hardware from fuses&lt;br /&gt;
      uint deviceKey = getDeviceKey(); // Reads 32-bit device key from FUSE_PRIVATE_KEY4.&lt;br /&gt;
      for (int i = 0; i &amp;lt; 4; i++) { // Keybuffer = deviceKey || deviceKey || deviceKey || deviceKey&lt;br /&gt;
          ((uint *)keyBuffer)[i] = deviceKey;&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, deviceKey || {...})&lt;br /&gt;
      &lt;br /&gt;
      // Set up Hardware info buffer&lt;br /&gt;
      uint vendor_code = *((uint *)0x7000FA00) &amp;amp; 0x0000000F; // FUSE_VENDOR_CODE&lt;br /&gt;
      uint fab_code    = *((uint *)0x7000FA04) &amp;amp; 0x0000003F; // FUSE_FAB_CODE&lt;br /&gt;
      uint lot_code_0  = *((uint *)0x7000FA08) &amp;amp; 0xFFFFFFFF; // FUSE_LOT_CODE_0&lt;br /&gt;
      uint lot_code_1  = *((uint *)0x7000FA0C) &amp;amp; 0x0FFFFFFF; // FUSE_LOT_CODE_1&lt;br /&gt;
      uint wafer_id    = *((uint *)0x7000FA10) &amp;amp; 0x0000003F; // FUSE_WAFER_ID&lt;br /&gt;
      uint x_coord     = *((uint *)0x7000FA14) &amp;amp; 0x000001FF; // FUSE_X_COORDINATE&lt;br /&gt;
      uint y_coord     = *((uint *)0x7000FA18) &amp;amp; 0x000001FF; // FUSE_Y_COORDINATE&lt;br /&gt;
      uint unk_hw_fuse = *((uint *)0x7000FA20) &amp;amp; 0x0000003F; // Unknown cached fuse.&lt;br /&gt;
      &lt;br /&gt;
      // HARDWARE_INFO_BUFFER = unk_hw_fuse || Y_COORD || X_COORD || WAFER_ID || LOT_CODE || FAB_CODE || VENDOR_ID&lt;br /&gt;
      hwInfoBuffer[0] = (lot_code_1 &amp;lt;&amp;lt; 30) | (wafer_id &amp;lt;&amp;lt; 24) | (x_coord &amp;lt;&amp;lt; 15) | (y_coord &amp;lt;&amp;lt; 6) | unk_hw_fuse;&lt;br /&gt;
      hwInfoBuffer[1] = (lot_code_0 &amp;lt;&amp;lt; 26) | (lot_code_1 &amp;gt;&amp;gt; 2);&lt;br /&gt;
      hwInfoBuffer[2] = (fab_code &amp;lt;&amp;lt; 26) | (lot_code_0 &amp;gt;&amp;gt; 6);&lt;br /&gt;
      hwInfoBuffer[3] = vendor_code;&lt;br /&gt;
      &lt;br /&gt;
      for (int i = 0; i &amp;lt; 0x10; i++) { // keyBuffer = XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER)&lt;br /&gt;
          keyBuffer[i] ^= ((char *)hwInfoBuffer)[i];&lt;br /&gt;
      }&lt;br /&gt;
      &lt;br /&gt;
      encryptWithSBK(keyBuffer); // keyBuffer = AES-ECB(SBK, XOR(AES-ECB(SBK, deviceKey || {...}), HARDWARE_INFO_BUFFER))&lt;br /&gt;
      &lt;br /&gt;
      setKeyslot(KEYSLOT_SSK, keyBuffer); // SSK = keyBuffer.&lt;br /&gt;
  }&lt;br /&gt;
 &lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
The falcon processor (TSEC) stores a special console-unique key (that will be referred to as the &amp;quot;tsec key&amp;quot;).&lt;br /&gt;
&lt;br /&gt;
This is presumably stored in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
The tsec key is the source of all per-console entropy, because SSK is not used on retail.&lt;br /&gt;
&lt;br /&gt;
== Package1 ==&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Cleared by&lt;br /&gt;
! Per-console&lt;br /&gt;
! Per-firmware&lt;br /&gt;
! Introduced in&lt;br /&gt;
|-&lt;br /&gt;
| 11&lt;br /&gt;
| Package1Key&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| Yes&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
|-&lt;br /&gt;
| 12&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
|-&lt;br /&gt;
| 13&lt;br /&gt;
| PerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
| No&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
|-&lt;br /&gt;
| 14&lt;br /&gt;
| OtherMasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| ?&lt;br /&gt;
| No&lt;br /&gt;
| Yes, on security updates&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
| [[1.0.0]]&lt;br /&gt;
|-&lt;br /&gt;
| 15&lt;br /&gt;
| OtherPerConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| ?&lt;br /&gt;
| Yes&lt;br /&gt;
| No&lt;br /&gt;
| [[4.0.0]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Note: aes_unwrap(wrapped_key, wrap_key) is just another name for a single AES-128 block decryption.&lt;br /&gt;
&lt;br /&gt;
If bit0 of 0x7000FB94 is clear, it will initialize keys like this (probably used for internal development units only):&lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = aes_unwrap(f5baeadb.., sbk)&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(bct-&amp;gt;pubkey[0] == 0x11 ? aff11423.. : 5e177ee1.., aes_unwrap(5ff9c2d9.., sbk))&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e..., aes_unwrap(6e4a9592.., ssk))&lt;br /&gt;
&lt;br /&gt;
Normal key generation looks like this on 1.0.0/2.0.0:&lt;br /&gt;
  keyblob_key /* slot13 */ = aes_unwrap(aes_unwrap(df206f59.., tsec_key /* slot13 */, sbk /* slot14 */)&lt;br /&gt;
  cmac_key    /* slot11 */ = aes_unwrap(59c7fb6f.., keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  if aes_cmac(buf=keyblob+0x10, len=0xA0, cmac_key) != keyblob[0:0x10]:&lt;br /&gt;
    panic()&lt;br /&gt;
  &lt;br /&gt;
  aes_ctr_decrypt(buf=keyblob+0x20, len=0x90, iv=keyblob+0x10 key=keyblob_key)&lt;br /&gt;
  &lt;br /&gt;
  // Final keys:&lt;br /&gt;
  package1_key    /* slot11 */ = keyblob[0x80:0x90]&lt;br /&gt;
  master_key      /* slot12 */ = aes_unwrap(is_debug ? 0542a0fd.. : d8a2410a.., keyblob+0x20)&lt;br /&gt;
  per_console_key /* slot13 */ = aes_unwrap(4f025f0e.., keyblob_key)&lt;br /&gt;
&lt;br /&gt;
SBK and SSK keyslots are cleared after keys have been generated.&lt;br /&gt;
&lt;br /&gt;
See table above for which keys are console unique.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the hardcoded constants for the keyblob used in the current revision. Nintendo are withholding all the future hardcoded constants.&lt;br /&gt;
&lt;br /&gt;
This means that if you have an attack on the bootloader, you need to re-preform it every time they move to a new keyblob.&lt;br /&gt;
&lt;br /&gt;
Dumping the SBK and TSEC key of any single system should be enough to derive all key material on the system.&lt;br /&gt;
&lt;br /&gt;
The key-derivation is described in more detail [[Package1#Key_generation|here]].&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1-3.0.2&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 1 ==&lt;br /&gt;
It is currently unknown what key generation the stage 2 bootloader does.&lt;br /&gt;
&lt;br /&gt;
== Secure Monitor ==&lt;br /&gt;
The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Fuses&amp;diff=2864</id>
		<title>Fuses</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Fuses&amp;diff=2864"/>
		<updated>2017-10-19T14:16:01Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: /* Anti-downgrade */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Nintendo Switch makes use of Tegra&#039;s fuse driver for a number of operations. This driver is mapped to physical address 0x7000F800 with a total size of 0x400 bytes and exposes several registers for fuse programming.&lt;br /&gt;
&lt;br /&gt;
Registers from 0x7000F800 to 0x7000F800 + 0xFF can be used to directly program the hardware fuse array, while registers from 0x7000F800 + 0x100 (FUSE_CHIP_REG_START_OFFSET) to 0x7000F800 + 0x3FC (FUSE_CHIP_REG_END_OFFSET) represent cached values read from certain fuses.&lt;br /&gt;
&lt;br /&gt;
== Registers ==&lt;br /&gt;
Below is a list of fuse driver registers used by the Switch&#039;s bootloaders.&lt;br /&gt;
&lt;br /&gt;
=== Driver registers ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Name&lt;br /&gt;
!  Address&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_CTRL|FUSE_CTRL]]&lt;br /&gt;
| 0x7000F800&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_REG_ADDR|FUSE_REG_ADDR]]&lt;br /&gt;
| 0x7000F804&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_REG_READ|FUSE_REG_READ]]&lt;br /&gt;
| 0x7000F808&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_REG_WRITE|FUSE_REG_WRITE]]&lt;br /&gt;
| 0x7000F80C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TIME_RD1&lt;br /&gt;
| 0x7000F810&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TIME_RD2&lt;br /&gt;
| 0x7000F814&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TIME_PGM1&lt;br /&gt;
| 0x7000F818&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_TIME_PGM2|FUSE_TIME_PGM2]]&lt;br /&gt;
| 0x7000F81C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_PRIV2INTFC&lt;br /&gt;
| 0x7000F820&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_FUSEBYPASS&lt;br /&gt;
| 0x7000F824&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_PRIVATEKEYDISABLE&lt;br /&gt;
| 0x7000F828&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_DIS_PGM|FUSE_DIS_PGM]]&lt;br /&gt;
| 0x7000F82C&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_WRITE_ACCESS|FUSE_WRITE_ACCESS]]&lt;br /&gt;
| 0x7000F830&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_PWR_GOOD_SW&lt;br /&gt;
| 0x7000F834&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== FUSE_CTRL ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 0-1&lt;br /&gt;
| Fuse command (1 = FUSE_READ; 2 = FUSE_WRITE; 3 = FUSE_SENSE)&lt;br /&gt;
|-&lt;br /&gt;
| 26&lt;br /&gt;
| Fuse power down mode flag (FUSE_CTRL_PD)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Before fuse reading/writing the power down mode must be disabled.&lt;br /&gt;
FUSE_SENSE mode flushes programmed values into the [[Fuses#Cache_registers|cache registers]].&lt;br /&gt;
&lt;br /&gt;
==== FUSE_REG_ADDR ====&lt;br /&gt;
This register takes the address of the fuse to be read/written/sensed.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_REG_READ ====&lt;br /&gt;
This register receives the value read from the fuse.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_REG_WRITE ====&lt;br /&gt;
This register takes the value to be written to the fuse.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_TIME_PGM2 ====&lt;br /&gt;
This register takes the fuse programming pulse (0xC0 == 19200 kHz).&lt;br /&gt;
&lt;br /&gt;
==== FUSE_DIS_PGM ====&lt;br /&gt;
If set to 0x01, this register disables fuse programming.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_WRITE_ACCESS ====&lt;br /&gt;
If set to 0x01, this register disables software writes to the fuse driver registers.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
=== Cache registers ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Name&lt;br /&gt;
!  Address&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_SKU_INFO|FUSE_SKU_INFO]]&lt;br /&gt;
| 0x7000F910&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CPU_SPEEDO_0&lt;br /&gt;
| 0x7000F914&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CPU_IDDQ&lt;br /&gt;
| 0x7000F918&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_FT_REV&lt;br /&gt;
| 0x7000F928&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CPU_SPEEDO_1&lt;br /&gt;
| 0x7000F92C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CPU_SPEEDO_2&lt;br /&gt;
| 0x7000F930&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SOC_SPEEDO_0&lt;br /&gt;
| 0x7000F934&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_SOC_SPEEDO_1|FUSE_SOC_SPEEDO_1]]&lt;br /&gt;
| 0x7000F938&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SOC_SPEEDO_2&lt;br /&gt;
| 0x7000F93C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SOC_IDDQ&lt;br /&gt;
| 0x7000F940&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_FA|FUSE_FA]]&lt;br /&gt;
| 0x7000F948&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY0]]&lt;br /&gt;
| 0x7000F964&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY1]]&lt;br /&gt;
| 0x7000F968&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY2]]&lt;br /&gt;
| 0x7000F96C&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY3]]&lt;br /&gt;
| 0x7000F970&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY4]]&lt;br /&gt;
| 0x7000F974&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY5]]&lt;br /&gt;
| 0x7000F978&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY6]]&lt;br /&gt;
| 0x7000F97C&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PUBLIC_KEY|FUSE_PUBLIC_KEY7]]&lt;br /&gt;
| 0x7000F980&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_1&lt;br /&gt;
| 0x7000F984&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_2&lt;br /&gt;
| 0x7000F988&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_CP_REV&lt;br /&gt;
| 0x7000F990&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_0&lt;br /&gt;
| 0x7000F998&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_FIRST_BOOTROM_PATCH_SIZE_REG&lt;br /&gt;
| 0x7000F99C&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY0]]&lt;br /&gt;
| 0x7000F9A4&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY1]]&lt;br /&gt;
| 0x7000F9A8&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY2]]&lt;br /&gt;
| 0x7000F9AC&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY3]]&lt;br /&gt;
| 0x7000F9B0&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_PRIVATE_KEY|FUSE_PRIVATE_KEY4]]&lt;br /&gt;
| 0x7000F9B4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_VP8_ENABLE&lt;br /&gt;
| 0x7000F9C4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM0&lt;br /&gt;
| 0x7000F9C8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM1&lt;br /&gt;
| 0x7000F9CC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM2&lt;br /&gt;
| 0x7000F9D0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM3&lt;br /&gt;
| 0x7000F9D4&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_RESERVED_ODM4|FUSE_RESERVED_ODM4]]&lt;br /&gt;
| 0x7000F9D8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_ODM5&lt;br /&gt;
| 0x7000F9DC&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_RESERVED_ODM6|FUSE_RESERVED_ODM6]]&lt;br /&gt;
| 0x7000F9E0&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]]&lt;br /&gt;
| 0x7000F9E4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SKU_USB_CALIB&lt;br /&gt;
| 0x7000F9F0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SKU_DIRECT_CONFIG&lt;br /&gt;
| 0x7000F9F4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_VENDOR_CODE&lt;br /&gt;
| 0x7000FA00&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_FAB_CODE&lt;br /&gt;
| 0x7000FA04&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_LOT_CODE_0&lt;br /&gt;
| 0x7000FA08&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_LOT_CODE_1&lt;br /&gt;
| 0x7000FA0C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_WAFER_ID&lt;br /&gt;
| 0x7000FA10&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_X_COORDINATE&lt;br /&gt;
| 0x7000FA14&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_Y_COORDINATE&lt;br /&gt;
| 0x7000FA18&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_GPU_IDDQ&lt;br /&gt;
| 0x7000FA28&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_3&lt;br /&gt;
| 0x7000FA2C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_OPT_SUBREVISION&lt;br /&gt;
| 0x7000FA48&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_4&lt;br /&gt;
| 0x7000FA54&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_5&lt;br /&gt;
| 0x7000FA58&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_6&lt;br /&gt;
| 0x7000FA5C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_7&lt;br /&gt;
| 0x7000FA60&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_OPT_PRIV_SEC_DIS&lt;br /&gt;
| 0x7000FA64&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_COMMON&lt;br /&gt;
| 0x7000FA80&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_8&lt;br /&gt;
| 0x7000FAD4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_RESERVED_CALIB&lt;br /&gt;
| 0x7000FB04&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_TSENSOR_9&lt;br /&gt;
| 0x7000FB1C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_USB_CALIB_EXT&lt;br /&gt;
| 0x7000FB50&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_0&lt;br /&gt;
| 0x7000FB80&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_1&lt;br /&gt;
| 0x7000FB84&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_2&lt;br /&gt;
| 0x7000FB88&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_3&lt;br /&gt;
| 0x7000FB8C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_4&lt;br /&gt;
| 0x7000FB90&lt;br /&gt;
|-&lt;br /&gt;
| [[#FUSE_SPARE_BIT_5|FUSE_SPARE_BIT_5]]&lt;br /&gt;
| 0x7000FB94&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_6&lt;br /&gt;
| 0x7000FB98&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_7&lt;br /&gt;
| 0x7000FB9C&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_8&lt;br /&gt;
| 0x7000FBA0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_9&lt;br /&gt;
| 0x7000FBA4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_10&lt;br /&gt;
| 0x7000FBA8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_11&lt;br /&gt;
| 0x7000FBAC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_12&lt;br /&gt;
| 0x7000FBB0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_13&lt;br /&gt;
| 0x7000FBB4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_14&lt;br /&gt;
| 0x7000FBB8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_15&lt;br /&gt;
| 0x7000FBBC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_16&lt;br /&gt;
| 0x7000FBC0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_17&lt;br /&gt;
| 0x7000FBC4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_18&lt;br /&gt;
| 0x7000FBC8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_19&lt;br /&gt;
| 0x7000FBCC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_20&lt;br /&gt;
| 0x7000FBD0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_21&lt;br /&gt;
| 0x7000FBD4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_22&lt;br /&gt;
| 0x7000FBD8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_23&lt;br /&gt;
| 0x7000FBDC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_24&lt;br /&gt;
| 0x7000FBE0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_25&lt;br /&gt;
| 0x7000FBE4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_26&lt;br /&gt;
| 0x7000FBE8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_27&lt;br /&gt;
| 0x7000FBEC&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_28&lt;br /&gt;
| 0x7000FBF0&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_29&lt;br /&gt;
| 0x7000FBF4&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_30&lt;br /&gt;
| 0x7000FBF8&lt;br /&gt;
|-&lt;br /&gt;
| FUSE_SPARE_BIT_31&lt;br /&gt;
| 0x7000FBFC&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== FUSE_SKU_INFO ====&lt;br /&gt;
Stores the SKU ID (must be 0x83).&lt;br /&gt;
&lt;br /&gt;
==== FUSE_FA ====&lt;br /&gt;
Stores failure analysis mode.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_SOC_SPEEDO_1 ====&lt;br /&gt;
Stores the bootrom patch version.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_RESERVED_ODM4 ====&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 0-1&lt;br /&gt;
| Unit type (3 = debug; 0 = retail)&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| Unknown config (must be 1 on retail)&lt;br /&gt;
|-&lt;br /&gt;
| 8&lt;br /&gt;
| Unknown config mask (must be 0 on retail)&lt;br /&gt;
|-&lt;br /&gt;
| 9&lt;br /&gt;
| Unit type mask (0 = debug; 1 = retail)&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
This stores some device configuration parameters.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_RESERVED_ODM6 ====&lt;br /&gt;
This register returns the value programmed into index 0x3A of the fuse array. &lt;br /&gt;
&lt;br /&gt;
==== FUSE_RESERVED_ODM7 ====&lt;br /&gt;
This register returns the value programmed into index 0x3C of the fuse array.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_SPARE_BIT_5 ====&lt;br /&gt;
Must be non-zero on retail units, otherwise the first bootloader panics.&lt;br /&gt;
On debug units it can be zero, which tells the bootloader to choose from two debug master key seeds. If set to non-zero on a debug unit, it tells the bootloader to choose from two retail master key seeds (only the last one matches the retail master key seed).&lt;br /&gt;
&lt;br /&gt;
==== FUSE_PRIVATE_KEY ====&lt;br /&gt;
This stores the 160-bit private key (128 bit SBK + 32-bit device key).&lt;br /&gt;
Reads to these registers after the SBK is locked out produce all-FF output.&lt;br /&gt;
&lt;br /&gt;
==== FUSE_PUBLIC_KEY ====&lt;br /&gt;
This stores the SHA256 hash of the 2048-bit RSA key expected at BCT+0x210.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
== eFuses ==&lt;br /&gt;
The actual hardware fuses can be programmed through the fuse driver after enabling fuse programming.&lt;br /&gt;
&lt;br /&gt;
Below is a list of common fuse indexes used by Tegra devices (and applicable to the Switch).&lt;br /&gt;
Note that the indexes are relative to the start of the fuse array and each element is a 4 byte word. A single fuse write operation always writes the same word at both fuse_array + 0 (PRIMARY_ALIAS) and fuse_array + 1 (REDUNDANT_ALIAS).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Name&lt;br /&gt;
!  Index&lt;br /&gt;
!  Bits&lt;br /&gt;
|-&lt;br /&gt;
| jtag_disable&lt;br /&gt;
| 0x00&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| odm_production_mode&lt;br /&gt;
| 0x00&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| odm_lock&lt;br /&gt;
| 0x00&lt;br /&gt;
| 4&lt;br /&gt;
|-&lt;br /&gt;
| public_key&lt;br /&gt;
| 0x0C&lt;br /&gt;
| 256&lt;br /&gt;
|-&lt;br /&gt;
| secure_boot_key&lt;br /&gt;
| 0x22&lt;br /&gt;
| 128&lt;br /&gt;
|-&lt;br /&gt;
| device_key&lt;br /&gt;
| 0x2A&lt;br /&gt;
| 32&lt;br /&gt;
|-&lt;br /&gt;
| sec_boot_dev_cfg&lt;br /&gt;
| 0x2C&lt;br /&gt;
| 16&lt;br /&gt;
|-&lt;br /&gt;
| sec_boot_dev_sel&lt;br /&gt;
| 0x2C&lt;br /&gt;
| 3&lt;br /&gt;
|-&lt;br /&gt;
| sw_reserved&lt;br /&gt;
| 0x2E&lt;br /&gt;
| 12&lt;br /&gt;
|-&lt;br /&gt;
| ignore_dev_sel_straps&lt;br /&gt;
| 0x2E&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| [[#odm_reserved|odm_reserved]]&lt;br /&gt;
| 0x2E&lt;br /&gt;
| 256&lt;br /&gt;
|-&lt;br /&gt;
| pkc_disable&lt;br /&gt;
| 0x52&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| [[#bootrom_ipatch|bootrom_ipatch]]&lt;br /&gt;
| 0x72&lt;br /&gt;
| 624&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== odm_reserved ===&lt;br /&gt;
The first bootloader only burns fuses in this region.&lt;br /&gt;
Both fuse indexes 0x3A (odm_reserved + 0x0C) and 0x3C (odm_reserved + 0x0E) are used for anti-downgrade control. These fuses will have their values cached into [[#FUSE_RESERVED_ODM6|FUSE_RESERVED_ODM6]] and [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]].&lt;br /&gt;
&lt;br /&gt;
=== bootrom_ipatch ===&lt;br /&gt;
Tegra210 based hardware such as the Switch provides support for bootrom patches. The patch data is burned to the hardware fuse array using a specific format (see [https://gist.github.com/shuffle2/f8728159da100e9df2606d43925de0af shuffle2&#039;s ipatch decoder]) and is executed by the bootrom, replacing it&#039;s original code.&lt;br /&gt;
&lt;br /&gt;
The following represents the patch data dumped from a 2.0.0 Switch console:&lt;br /&gt;
 Patch address       Patch data &lt;br /&gt;
 0x001016AE          0xDF00    // svc #0x00 (offset 0x48)&lt;br /&gt;
 0x00103040          0xDF22    // svc #0x22 (offset 0x8c)&lt;br /&gt;
 0x00106F2E          0xDF26    // svc #0x26 (offset 0x94)&lt;br /&gt;
 0x0010FB3C          0x2000    // movs r0, #0x00&lt;br /&gt;
 0x00100856          0xDF2C    // svc #0x2c (offset 0xa0)&lt;br /&gt;
 0x00106F54          0xDF42    // svc #0x42 (offset 0xcc)&lt;br /&gt;
 0x001012E4          0xDF4B    // svc #0x4b (offset 0xde)&lt;br /&gt;
 0x00104526          0xDF54    // svc #0x54 (offset 0xf0)&lt;br /&gt;
 0x001043F4          0xDF5D    // svc #0x5d (offset 0x102)&lt;br /&gt;
 0x00117744          0xAC57    // data&lt;br /&gt;
 0x00117758          0x3D19    // data&lt;br /&gt;
 0x00103D2A          0x2001    // movs r0, #0x01&lt;br /&gt;
&lt;br /&gt;
The last 4 patches are exclusive to the Switch, while the remaining ones are often included in most Tegra210 based devices.&lt;br /&gt;
&lt;br /&gt;
== Anti-downgrade ==&lt;br /&gt;
The first bootloader verifies [[#FUSE_RESERVED_ODM7|FUSE_RESERVED_ODM7]] to prevent downgrading.&lt;br /&gt;
How many fuses are expected to be burnt depends the device&#039;s unit type as below.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Expected number of burnt fuses (retail)&lt;br /&gt;
! Expected number of burnt fuses (non-retail)&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0&lt;br /&gt;
| 1&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0-2.3.0&lt;br /&gt;
| 2&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1-3.0.2&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 4.0.0&lt;br /&gt;
| 5&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
If too many fuses are burnt the bootloader will panic immediately.&lt;br /&gt;
&lt;br /&gt;
If too few are burnt, the bootloader will enable fuse programming and write the expected value to fuse indexes 0x3A and 0x3C. Afterwards, fuse programming is disabled and a magic value (0x21 == TEGRA210) is written to PMC_SCRATCH200 register (0x7000EC40). Finally, the watchdog timer is initialized and programmed to force a reset.&lt;br /&gt;
&lt;br /&gt;
On a subsequent boot, after the anti-downgrade fuses are checked again, the PMC_RST_STATUS register (0x7000E5B4) is checked and if set to 0x01 (watchdog reset) the PMC_SCRATCH200 register (0x7000EC40) will be checked for the magic value (0x21 == TEGRA210).&lt;br /&gt;
PMC_RST_STATUS will only be set back to 0 (power on reset) if the fuse count matches the new expected value, otherwise the system will panic.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Flog&amp;diff=2510</id>
		<title>Flog</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Flog&amp;diff=2510"/>
		<updated>2017-09-23T16:18:35Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: /* Official Launch */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;This is the system &amp;quot;flog&amp;quot; 01008BB00013C000 [[Title_list|title]]. &amp;quot;flog&amp;quot; is a full-fledged NES emulator and is installed on retail systems since [[1.0.0]].&lt;br /&gt;
&lt;br /&gt;
The titleID for &amp;quot;flog&amp;quot; is used by 3 functions in [[qlaunch]]: 1 for checking whether to launch it, 1 for registering it as an [[AM_services#appletAE|applet]] and 1 to launch it.&lt;br /&gt;
&lt;br /&gt;
The ROM is not loaded via [[Filesystem_services|FS]] but is embedded in the main binary.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;flog&amp;quot; == &amp;quot;golf&amp;quot; backwards. This runs the NES &amp;quot;Golf&amp;quot; game. {1/2}-player via joy-con is supported. Controls are &amp;quot;d-pad&amp;quot; buttons + stick, however motion control while holding the Z{L/R} button is also supported instead of using buttons.&lt;br /&gt;
&lt;br /&gt;
==Official Launch==&lt;br /&gt;
[[qlaunch]] periodically checks if the user is in &amp;quot;/RootScene/SceneResidentMenu&amp;quot;, which represents the Home Menu (aka main-menu). If so, the following checks are then performed in order:&lt;br /&gt;
* The Joy-Cons&#039; state is read from [[HID_Shared_Memory|HID shared memory]] and both must be active and detached from the console.&lt;br /&gt;
* &amp;quot;StartSixAxisSensor&amp;quot; [[HID_services#hid|hid]] command is called for each Joy-Con so motion data can be captured.&lt;br /&gt;
* After capturing the motion data, the same motion checks for both Joy-Cons must pass at the same time. This motion data is analyzed in a small state machine consisting of a total of 7 steps and the motion itself is a reference to [https://www.youtube.com/watch?time_continue=17&amp;amp;v=BdQg43n2OaM Iwata&#039;s Direct gesture]. Hold the Joy-Cons pointing forwards/downwards, then move Joy-Cons to a vertical position, and hold it there for a bit. The Joy-Con grip can be used for this. &lt;br /&gt;
* The system&#039;s month and day must be July 11th, which is the date of Iwata&#039;s [https://en.wikipedia.org/wiki/Satoru_Iwata passing]. The loaded date originates from network-time-sync&#039;d time, regardless of whether the user has it enabled or not. When the system was never connected to the Internet and is on [[1.0.0]] it comes from the user-specified date instead. For newer systems, trying to load the network time if it was never set will result in an error: they won&#039;t ever be able to launch flog without a time-sync with Nintendo servers. This is loaded from the [[PCV_services|time]] service-cmds, with the actual time-sync being handled by [[NIM_services|NIM]].&lt;br /&gt;
* A wrapper for &amp;quot;GetLanguageCode&amp;quot; [[Settings_services#set|set]] command is called and the returned code must be 0 (JPja), 1 (USen) or 2 (EUen). Other combinations of region and language may have it&#039;s code translated internally to a valid one (0, 1 or 2), which seems to be the case for 12 (CNzh), 13 (KRko) and 14 (TWzh).&lt;br /&gt;
* Lastly, &amp;quot;IsSystemProgramInstalled&amp;quot; [[NS_Services#ns:am|ns:am]] command is called, which should return 1 if the &amp;quot;flog&amp;quot; title is installed.&lt;br /&gt;
&lt;br /&gt;
Once everything passes it continues to the code which launches &amp;quot;flog&amp;quot;. When &amp;quot;flog&amp;quot; is launched a small audio clip named &amp;quot;SeTestTone&amp;quot; is played which matches [https://www.youtube.com/watch?v=SeVTJu_Yn2Y&amp;amp;feature=youtu.be&amp;amp;t=17s this].&lt;br /&gt;
&lt;br /&gt;
==Screenshots==&lt;br /&gt;
These screenshots were originally taken by executing flog with an unofficial method.&lt;br /&gt;
&lt;br /&gt;
[[File:Flog0.jpg|200px|thumb|left|Flog main-screen]]&lt;br /&gt;
[[File:Flog1.jpg|200px|thumb|left|Flog 1-player]]&lt;br /&gt;
[[File:Flog2.jpg|200px|thumb|left|Flog 2-player mode as player-1.]]&lt;br /&gt;
[[File:Flog3.jpg|200px|thumb|left|Flog 2-player mode as player-2.]]&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Error_codes&amp;diff=2509</id>
		<title>Error codes</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Error_codes&amp;diff=2509"/>
		<updated>2017-09-23T16:18:16Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Structure =&lt;br /&gt;
These have been redesigned from the 3DS so that they fit within a Aarch64 MOV instruction immediate most of the time (without requiring the additional MOVK).&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Bits || Field&lt;br /&gt;
|-&lt;br /&gt;
| 8-0  || Module&lt;br /&gt;
|-&lt;br /&gt;
| 21-9  || Description&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
When a fatal-error is received the error code is outputted using the following formatter:&lt;br /&gt;
  %04d-%04x&lt;br /&gt;
&lt;br /&gt;
.. where the first code is &amp;lt;code&amp;gt;2000 + Module&amp;lt;/code&amp;gt;, and the other being &amp;lt;code&amp;gt;Description&amp;lt;/code&amp;gt;. Bits &amp;gt;=22 from the error-code are unused when displaying fatal-errors, since the Description ends with bit21.&lt;br /&gt;
&lt;br /&gt;
= Modules =&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Name&lt;br /&gt;
|-&lt;br /&gt;
| 1 || Kernel&lt;br /&gt;
|-&lt;br /&gt;
| 2 || FS&lt;br /&gt;
|-&lt;br /&gt;
| 3 || NVIDIA, TransferMemory&lt;br /&gt;
|-&lt;br /&gt;
| 5 || NCM&lt;br /&gt;
|-&lt;br /&gt;
| 6 || DD&lt;br /&gt;
|-&lt;br /&gt;
| 8 || LR&lt;br /&gt;
|-&lt;br /&gt;
| 9 || Loader&lt;br /&gt;
|-&lt;br /&gt;
| 10 || CMIF (IPC command interface)&lt;br /&gt;
|-&lt;br /&gt;
| 11 || HIPC (IPC)&lt;br /&gt;
|-&lt;br /&gt;
| 15 || PM&lt;br /&gt;
|-&lt;br /&gt;
| 16 || NS&lt;br /&gt;
|-&lt;br /&gt;
| 18 || HTC&lt;br /&gt;
|-&lt;br /&gt;
| 21 || SM&lt;br /&gt;
|-&lt;br /&gt;
| 22 || RO userland&lt;br /&gt;
|-&lt;br /&gt;
| 24 || SDMMC&lt;br /&gt;
|-&lt;br /&gt;
| 26 || SPL&lt;br /&gt;
|-&lt;br /&gt;
| 100 || ETHC&lt;br /&gt;
|-&lt;br /&gt;
| 101 || I2C&lt;br /&gt;
|-&lt;br /&gt;
| 105 || Settings&lt;br /&gt;
|-&lt;br /&gt;
| 110 || NIFM&lt;br /&gt;
|-&lt;br /&gt;
| 114 || Display&lt;br /&gt;
|-&lt;br /&gt;
| 116 || NTC&lt;br /&gt;
|-&lt;br /&gt;
| 117 || FGM&lt;br /&gt;
|-&lt;br /&gt;
| 120 || PCIE&lt;br /&gt;
|-&lt;br /&gt;
| 121 || Friends&lt;br /&gt;
|-&lt;br /&gt;
| 123 || SSL&lt;br /&gt;
|-&lt;br /&gt;
| 124 || Account&lt;br /&gt;
|-&lt;br /&gt;
| 126 || Mii&lt;br /&gt;
|-&lt;br /&gt;
| 128 || AM&lt;br /&gt;
|-&lt;br /&gt;
| 129 || Play Report&lt;br /&gt;
|-&lt;br /&gt;
| 133 || PCV&lt;br /&gt;
|-&lt;br /&gt;
| 134 || OMM&lt;br /&gt;
|-&lt;br /&gt;
| 137 || NIM&lt;br /&gt;
|-&lt;br /&gt;
| 138 || PSC&lt;br /&gt;
|-&lt;br /&gt;
| 140 || USB&lt;br /&gt;
|-&lt;br /&gt;
| 143 || BTM&lt;br /&gt;
|-&lt;br /&gt;
| 147 || ERPT&lt;br /&gt;
|-&lt;br /&gt;
| 148 || APM&lt;br /&gt;
|-&lt;br /&gt;
| 154 || NPNS&lt;br /&gt;
|-&lt;br /&gt;
| 157 || ARP&lt;br /&gt;
|-&lt;br /&gt;
| 158 || BOOT&lt;br /&gt;
|-&lt;br /&gt;
| 161 || NFC&lt;br /&gt;
|-&lt;br /&gt;
| 162 || Userland assert&lt;br /&gt;
|-&lt;br /&gt;
| 168 || Userland crash&lt;br /&gt;
|-&lt;br /&gt;
| 203 || HID&lt;br /&gt;
|-&lt;br /&gt;
| 206 || Capture&lt;br /&gt;
|-&lt;br /&gt;
| 651 || TC&lt;br /&gt;
|-&lt;br /&gt;
| 800 || [[Internet_Browser|General web-applet]]&lt;br /&gt;
|-&lt;br /&gt;
| 809 || [[Internet_Browser|WifiWebAuthApplet]]&lt;br /&gt;
|-&lt;br /&gt;
| 810 || [[Internet_Browser|Whitelisted-applet]]&lt;br /&gt;
|-&lt;br /&gt;
| 811 || [[Internet_Browser|ShopN]]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
8XX is for/includes system applets.&lt;br /&gt;
&lt;br /&gt;
= Error codes =&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Description || Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C01 || 14 || Invalid kernel capability descriptor&lt;br /&gt;
|-&lt;br /&gt;
| 0x4201 || 33 || [[SPL_services#GetConfig|IsDebugMode]] isn&#039;t set.&lt;br /&gt;
|-&lt;br /&gt;
| 0xCA01 || 101 || Invalid size&lt;br /&gt;
|-&lt;br /&gt;
| 0xCC01 || 102 || Invalid address&lt;br /&gt;
|-&lt;br /&gt;
| 0xCE01 || 103 || Address is NULL / buffer size is too small.&lt;br /&gt;
|-&lt;br /&gt;
| 0xD001 || 104 || Memory full&lt;br /&gt;
|-&lt;br /&gt;
| 0xD201 || 105 || Handle-table full.&lt;br /&gt;
|-&lt;br /&gt;
| 0xD401 || 106 || Invalid memory state / invalid memory permissions.&lt;br /&gt;
|-&lt;br /&gt;
| 0xD801 || 108 || When trying to set executable permission on memory.&lt;br /&gt;
|-&lt;br /&gt;
| 0xDC01 || 110 || Stack address outside allowed range&lt;br /&gt;
|-&lt;br /&gt;
| 0xE001 || 112 || Invalid thread priority.&lt;br /&gt;
|-&lt;br /&gt;
| 0xE201 || 113 || Invalid processor id.&lt;br /&gt;
|-&lt;br /&gt;
| 0xE401 || 114 || Invalid handle.&lt;br /&gt;
|-&lt;br /&gt;
| 0xE601 || 115 || Syscall copy from user failed.&lt;br /&gt;
|-&lt;br /&gt;
| 0xE801 || 116 || Invalid combination&lt;br /&gt;
|-&lt;br /&gt;
| 0xEA01 || 117 || Time out? When you give 0 handles to svcWaitSynchronizationN.&lt;br /&gt;
|-&lt;br /&gt;
| 0xEC01 || 118 || Canceled/interrupted [?]&lt;br /&gt;
|-&lt;br /&gt;
| 0xEE01 || 119 || Exceeding maximum&lt;br /&gt;
|-&lt;br /&gt;
| 0xF001 || 120 || Invalid enum&lt;br /&gt;
|-&lt;br /&gt;
| 0xF201 || 121 || No such entry&lt;br /&gt;
|-&lt;br /&gt;
| 0xF401 || 122 || Irq/DeviceAddressSpace/{...} already registered&lt;br /&gt;
|-&lt;br /&gt;
| 0xF601 || 123 || Port remote dead&lt;br /&gt;
|-&lt;br /&gt;
| 0xF801 || 124 || [Usermode] Unhandled interrupt&lt;br /&gt;
|-&lt;br /&gt;
| 0xFA01 || 125 || Wrong memory permission?&lt;br /&gt;
|-&lt;br /&gt;
| 0xFC01 || 126 || Reserved value&lt;br /&gt;
|-&lt;br /&gt;
| 0xFE01 || 127 || Invalid hardware breakpoint&lt;br /&gt;
|-&lt;br /&gt;
| 0x10001 || 128 || [Usermode] Fatal exception&lt;br /&gt;
|-&lt;br /&gt;
| 0x10601 || 131 || Port max sessions exceeded&lt;br /&gt;
|-&lt;br /&gt;
| 0x10801 || 132 || Resource limit exceeded&lt;br /&gt;
|-&lt;br /&gt;
| 0x41001 || 520 || Process not being debugged&lt;br /&gt;
|-&lt;br /&gt;
| 0xE02 || 7 || High byte in input u64 is zero.&lt;br /&gt;
|-&lt;br /&gt;
| 0x7802 || 60 || The specified [[NCA]]-type doesn&#039;t exist for this title.&lt;br /&gt;
|-&lt;br /&gt;
| 0x7D202 || 1001 || Process does not have RomFs &lt;br /&gt;
|-&lt;br /&gt;
| 0x7D402 || 1002 || Title-id not found / savedata not found.&lt;br /&gt;
|-&lt;br /&gt;
| 0x13B002 || 2520 || Gamecard not inserted&lt;br /&gt;
|-&lt;br /&gt;
| 0x13DA02 || 2541 || Version check failed when mounting gamecard sysupdate partition?&lt;br /&gt;
|-&lt;br /&gt;
| 0x171402 || 2954 || Invalid gamecard handle.&lt;br /&gt;
|-&lt;br /&gt;
| 0x196002 || 3248 || Out of memory&lt;br /&gt;
|-&lt;br /&gt;
| 0x196202 || 3249 || Out of memory&lt;br /&gt;
|-&lt;br /&gt;
| 0x1A4A02 || 3365 || Out of memory&lt;br /&gt;
|-&lt;br /&gt;
| 0x235E02 || 4527 || NCA-path used with the wrong titleID.&lt;br /&gt;
|-&lt;br /&gt;
| 0x250E02 || 4743 || [[NAX0|Corrupted]] NAX0 header.&lt;br /&gt;
|-&lt;br /&gt;
| 0x251002 || 4744 || Invalid [[NAX0]] magicnum.&lt;br /&gt;
|-&lt;br /&gt;
| 0x2EE202 || 6001 || Invalid input&lt;br /&gt;
|-&lt;br /&gt;
| 0x2EE602 || 6003 || Path too long&lt;br /&gt;
|-&lt;br /&gt;
| 0x2F5A02 || 6061 || Offset outside storage&lt;br /&gt;
|-&lt;br /&gt;
| 0x313802 || 6300 || Operation not supported&lt;br /&gt;
|-&lt;br /&gt;
| 0x320002 || 6400 || Permission denied&lt;br /&gt;
|-&lt;br /&gt;
| 0x326602 || 6451 || Missing titlekey(?) required to mount content&lt;br /&gt;
|-&lt;br /&gt;
| 0x3EA03 || 501 || Invalid handle&lt;br /&gt;
|-&lt;br /&gt;
| 0x3EE03 || 503 || Invalid memory mirror&lt;br /&gt;
|-&lt;br /&gt;
| 0xA05 || 5 || [[Content_Manager_services|NcaID]] not found. Returned when attempting to mount titles which exist that aren&#039;t *8XX titles, the same way *8XX titles are mounted.&lt;br /&gt;
|-&lt;br /&gt;
| 0xE05 || 7 || TitleId not found&lt;br /&gt;
|-&lt;br /&gt;
| 0x1805 || 12 || Invalid StorageId&lt;br /&gt;
|-&lt;br /&gt;
| 0xDC05 || 110 || Gamecard not inserted&lt;br /&gt;
|-&lt;br /&gt;
| 0x17C05 || 190 || Gamecard not initialized&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F405 || 250 || Sdcard not inserted&lt;br /&gt;
|-&lt;br /&gt;
| 0x20805 || 260 || Storage not mounted&lt;br /&gt;
|-&lt;br /&gt;
| 0x408 || 2 || Not initialized.&lt;br /&gt;
|-&lt;br /&gt;
| 0x608 || 3 || Invalid control StorageID.&lt;br /&gt;
|-&lt;br /&gt;
| 0x808 || 4 || Storage not found.&lt;br /&gt;
|-&lt;br /&gt;
| 0xA08 || 5 || Access denied.&lt;br /&gt;
|-&lt;br /&gt;
| 0xE08 || 7 || Title is not registered.&lt;br /&gt;
|-&lt;br /&gt;
| 0x409 || 2 || Maximum processes loaded.&lt;br /&gt;
|-&lt;br /&gt;
| 0x6609 || 51 || Invalid memory state/permission&lt;br /&gt;
|-&lt;br /&gt;
| 0x6A09 || 53 || Invalid NRR&lt;br /&gt;
|-&lt;br /&gt;
| 0xA209 || 81 || Unaligned NRR address&lt;br /&gt;
|-&lt;br /&gt;
| 0xA409 || 82 || Bad NRR size&lt;br /&gt;
|-&lt;br /&gt;
| 0xAA09 || 85 || Bad NRR address&lt;br /&gt;
|-&lt;br /&gt;
| 0x1A80A || 212 || Bad magic (expected &#039;SFCO&#039;)&lt;br /&gt;
|-&lt;br /&gt;
| 0x20B || 1 || Size too big to fit to marshal.&lt;br /&gt;
|-&lt;br /&gt;
| 0x11A0B || 141 || Went past maximum during marshalling.&lt;br /&gt;
|-&lt;br /&gt;
| 0x1900B || 200 || Session doesn&#039;t support domains.&lt;br /&gt;
|-&lt;br /&gt;
| 0x25A0B || 301 || Remote process is dead.&lt;br /&gt;
|-&lt;br /&gt;
| 0x3D60B || 491 || IPC Query 1 failed.&lt;br /&gt;
|-&lt;br /&gt;
| 0x20F || 1 || Pid not found&lt;br /&gt;
|-&lt;br /&gt;
| 0x60F || 3 || Process has no pending events&lt;br /&gt;
|-&lt;br /&gt;
| 0x410 || 2 || Title-id not found&lt;br /&gt;
|-&lt;br /&gt;
| 0xF010 || 120 || Gamecard sysupdate not required&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F610 || 251 || Unexpected StorageId&lt;br /&gt;
|-&lt;br /&gt;
| 0x415 || 2 || Not initialized.&lt;br /&gt;
|-&lt;br /&gt;
| 0x615 || 3 || Max sessions&lt;br /&gt;
|-&lt;br /&gt;
| 0xC15 || 6 || Invalid name (all zeroes)&lt;br /&gt;
|-&lt;br /&gt;
| 0x1015 || 8 || Permission denied&lt;br /&gt;
|-&lt;br /&gt;
| 0x416 || 2 || Address space is full&lt;br /&gt;
|-&lt;br /&gt;
| 0x616 || 3 || NRO already loaded&lt;br /&gt;
|-&lt;br /&gt;
| 0x816 || 4 || Invalid NRO header values&lt;br /&gt;
|-&lt;br /&gt;
| 0xC16 || 6 || Bad NRR magic&lt;br /&gt;
|-&lt;br /&gt;
| 0x1016 || 8 || Reached max NRR count&lt;br /&gt;
|-&lt;br /&gt;
| 0x1216 || 9 || Unable to verify NRO hash or NRR signature&lt;br /&gt;
|-&lt;br /&gt;
| 0x80216 || 1025 || Address not page-aligned&lt;br /&gt;
|-&lt;br /&gt;
| 0x80416 || 1026 || Incorrect NRO size&lt;br /&gt;
|-&lt;br /&gt;
| 0x80816 || 1028 || NRO not loaded&lt;br /&gt;
|-&lt;br /&gt;
| 0x80A16 || 1029 || NRR not loaded&lt;br /&gt;
|-&lt;br /&gt;
| 0x80C16 || 1030 || Already initialized&lt;br /&gt;
|-&lt;br /&gt;
| 0x80E16 || 1031 || Not initialized&lt;br /&gt;
|-&lt;br /&gt;
| 0x41A || 2 || Argument is invalid&lt;br /&gt;
|-&lt;br /&gt;
| 0xD01A || 104 || All AES engines busy&lt;br /&gt;
|-&lt;br /&gt;
| 0xD21A || 105 || Invalid AES engine-id&lt;br /&gt;
|-&lt;br /&gt;
| 0xCC74 || 102 || Time not set&lt;br /&gt;
|-&lt;br /&gt;
| 0x287C || 20 || Argument is NULL&lt;br /&gt;
|-&lt;br /&gt;
| 0x2C7C || 22 || Argument is invalid&lt;br /&gt;
|-&lt;br /&gt;
| 0x3C7C || 30 || Bad input buffer size&lt;br /&gt;
|-&lt;br /&gt;
| 0x407C || 32 || Invalid input buffer&lt;br /&gt;
|-&lt;br /&gt;
| 0x3C9D || 30 || Address is NULL&lt;br /&gt;
|-&lt;br /&gt;
| 0x3E9D || 31 || PID is NULL&lt;br /&gt;
|-&lt;br /&gt;
| 0x549D || 42 || Already bound&lt;br /&gt;
|-&lt;br /&gt;
| 0xCC9D || 102 || Invalid PID&lt;br /&gt;
|-&lt;br /&gt;
| 0x3CF089 || 7800 || Unknown/invalid libcurl error.&lt;br /&gt;
|-&lt;br /&gt;
| 0x3E8289-0x3F4089 || 8001-8096 || libcurl error 1-96. Some of the libcurl errors in the error-table map to the above unknown-libcurl-error however.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== FS Error Codes ==&lt;br /&gt;
&lt;br /&gt;
The following are the error codes recognized by nn::fs::detail::LogErrorMessage found in some [[Factory Setup|factory]] titles:&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Error Code || Description || Message&lt;br /&gt;
|-&lt;br /&gt;
| 0x7802 || 60 || Error: Specified mount name already exists.&lt;br /&gt;
|-&lt;br /&gt;
| 0xD401 || 106 || Error: Passed buffer is not usable for fs library.&lt;br /&gt;
|-&lt;br /&gt;
| 0x7D202 || 1001 || Error: Specified partition is not found.&lt;br /&gt;
|-&lt;br /&gt;
| 0x7D402 || 1002 || Error: Specified target is not found.&lt;br /&gt;
|-&lt;br /&gt;
| 0xFA002 - 0x138602 || 2000 - 2499 || Error: Failed to access SD card.&lt;br /&gt;
|-&lt;br /&gt;
| 0x136802 - 0x176E02 || 2500 - 2999 || Error: Failed to access game card.&lt;br /&gt;
|-&lt;br /&gt;
| 0x177202 || 3001 || Error: Specified operation is not implemented.&lt;br /&gt;
|-&lt;br /&gt;
| 0x177A02 || 3005 || Error: Specified value is out of range.&lt;br /&gt;
|-&lt;br /&gt;
| 0x1B5802 - 0x1F3E02 || 3500 - 3999 || Error: Failed to access MMC.&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F4202 - 0x219602 || 4001 - 4299 || Error: ROM is corrupted.&lt;br /&gt;
|-&lt;br /&gt;
| 0x219A02 - 0x232602 || 4301 - 4499 || Error: Save data is corrupted.&lt;br /&gt;
|-&lt;br /&gt;
| 0x232A02 - 0x23EE02 || 4501 - 4599 || Error: NCA is corrupted.&lt;br /&gt;
|-&lt;br /&gt;
| 0x23F202 - 0x243E02 || 4601 - 4639 || Error: Integrity verification failed.&lt;br /&gt;
|-&lt;br /&gt;
| 0x244202 - 0x246602 || 4641 - 4659 || Error: Partition FS is corrupted.&lt;br /&gt;
|-&lt;br /&gt;
| 0x246A02 - 0x248E02 || 4661 - 4679 || Error: Built-in-storage is corrupted.&lt;br /&gt;
|-&lt;br /&gt;
| 0x249202 - 0x24B602 || 4681 - 4699 || Error: FAT FS is corrupted.&lt;br /&gt;
|-&lt;br /&gt;
| 0x24BA02 - 0x24DE02 || 4701 - 4719 || Error: HOST FS is corrupted.&lt;br /&gt;
|-&lt;br /&gt;
| 0x1F4002 - 0x270E02 || 4000, 4300, 4500, 4600, 4640, 4660, 4680, 4700, 4720-4999 || Error: Data is corrupted.&lt;br /&gt;
|-&lt;br /&gt;
| 0x271002 - 0x2EDE02 || 5000-5999 || Error: Unexpected failure occurred.&lt;br /&gt;
|-&lt;br /&gt;
| 0x2EE402 - 0x2F1A02 || 6002-6029 || Error: Invalid path was specified.&lt;br /&gt;
|-&lt;br /&gt;
| 0x2F5A02 || 6061 || Error: Invalid offset was specified.&lt;br /&gt;
|-&lt;br /&gt;
| 0x2F5C02 || 6062 || Error: Invalid size was specified.&lt;br /&gt;
|-&lt;br /&gt;
| 0x2F5E02 || 6063 || Error: Null pointer argument was specified.&lt;br /&gt;
|-&lt;br /&gt;
| 0x2EE002 || 6000 || Error: Precondition violation.&lt;br /&gt;
|-&lt;br /&gt;
| 0x2EE202 - 0x306E02 || 6001-6199 || Error: Invalid argument was specified.&lt;br /&gt;
|-&lt;br /&gt;
| 0x307202 || 6201 || Error: OpenMode_AllowAppend is required for implicit extension of file size by WriteFile().&lt;br /&gt;
|-&lt;br /&gt;
| 0x307002 - 0x313602 || 6200, 6202 - 6299 || Error: Invalid operation for the open mode.&lt;br /&gt;
|-&lt;br /&gt;
| 0x313802 - 0x31FE02 || 6300-6399 || Error: Unsupported operation.&lt;br /&gt;
|-&lt;br /&gt;
| 0x320002 - 0x32C602 || 6400-6499 || Error: Permission denied.&lt;br /&gt;
|-&lt;br /&gt;
| 0x346402 || 6706 || Error: Enough journal space is not left.&lt;br /&gt;
|-&lt;br /&gt;
| 0x346A02 || 6709 || Error: The open count of files and directories reached the limitation.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Fatal Errors =&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Error || Description&lt;br /&gt;
|-&lt;br /&gt;
| 2162-0002&lt;br /&gt;
| Can be triggered by running [[SVC|svcBreak]]. The svcBreak params have no affect on the value of the thrown error-code.&lt;br /&gt;
|-&lt;br /&gt;
| 2168-0000&lt;br /&gt;
| Userland ARM undefined instruction exception&lt;br /&gt;
|-&lt;br /&gt;
| 2168-0001&lt;br /&gt;
| Userland ARM prefetch-abort due to PC set to non-executable region&lt;br /&gt;
|-&lt;br /&gt;
| 2168-0002&lt;br /&gt;
| Userland ARM data abort. Also caused by abnormal process termination via [[SVC|svcExitProcess]]. Note: directly jumping to nnMain()-retaddr from non-main-thread has the same result.&lt;br /&gt;
|-&lt;br /&gt;
| 2168-0003&lt;br /&gt;
| Userland PC address not aligned to 4 bytes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
= Support Errors =&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Error !! Module || Description || Notes&lt;br /&gt;
|-&lt;br /&gt;
| &lt;br /&gt;
| {web-applets listed above}&lt;br /&gt;
| 2750&lt;br /&gt;
| MP4 parsing failed.&lt;br /&gt;
|}&lt;br /&gt;
Normal error-codes displayed by the system also use the same format as fatal-errors.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=TSEC&amp;diff=2062</id>
		<title>TSEC</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=TSEC&amp;diff=2062"/>
		<updated>2017-08-12T14:26:02Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: The bootloader does not use the RTC but the timer&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;TSEC (Tegra Security Engine Controller) is a NVIDIA Falcon microprocessor with crypto extensions. Therefore, all information in this page related to Falcon is identical for TSEC and vice versa.&lt;br /&gt;
&lt;br /&gt;
= Driver =&lt;br /&gt;
A host driver for communicating with the TSEC/Falcon is mapped to physical address 0x54500000 with a total size of 0x40000 bytes and exposes several registers.&lt;br /&gt;
&lt;br /&gt;
== Registers ==&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Name&lt;br /&gt;
!  Address&lt;br /&gt;
!  Width&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_IRQMSET|FALCON_IRQMSET]]&lt;br /&gt;
| 0x54501010&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_IRQDEST|FALCON_IRQDEST]]&lt;br /&gt;
| 0x5450101C&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_SCRATCH0|FALCON_SCRATCH0]]&lt;br /&gt;
| 0x54501040&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_SCRATCH1|FALCON_SCRATCH1]]&lt;br /&gt;
| 0x54501044&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_ITFEN|FALCON_ITFEN]]&lt;br /&gt;
| 0x54501048&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_CPUCTL|FALCON_CPUCTL]]&lt;br /&gt;
| 0x54501100&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_BOOTVEC|FALCON_BOOTVEC]]&lt;br /&gt;
| 0x54501104&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_DMACTL|FALCON_DMACTL]]&lt;br /&gt;
| 0x5450110C&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_DMATRFBASE|FALCON_DMATRFBASE]]&lt;br /&gt;
| 0x54501110&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_DMATRFMOFFS|FALCON_DMATRFMOFFS]]&lt;br /&gt;
| 0x54501114&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_DMATRFCMD|FALCON_DMATRFCMD]]&lt;br /&gt;
| 0x54501118&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
| [[#FALCON_DMATRFFBOFFS|FALCON_DMATRFFBOFFS]]&lt;br /&gt;
| 0x5450111C&lt;br /&gt;
| 0x04&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== FALCON_IRQMSET ===&lt;br /&gt;
Used for configuring Falcon&#039;s IRQs.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_IRQDEST ===&lt;br /&gt;
Used for configuring Falcon&#039;s IRQs.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_SCRATCH0 ===&lt;br /&gt;
MMIO register for reading/writing data to Falcon.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_SCRATCH1 ===&lt;br /&gt;
MMIO register for reading/writing data to Falcon.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_ITFEN ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| FALCON_ITFEN_CTXEN&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| FALCON_ITFEN_MTHDEN&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Used for enabling/disabling Falcon interfaces.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_CPUCTL ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 0&lt;br /&gt;
| FALCON_CPUCTL_STARTCPU&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Used for signaling Falcon&#039;s CPU.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_BOOTVEC ===&lt;br /&gt;
Takes the Falcon&#039;s boot vector address.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_DMACTL ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| FALCON_DMACTL_DMEM_SCRUBBING&lt;br /&gt;
|-&lt;br /&gt;
| 2&lt;br /&gt;
| FALCON_DMACTL_IMEM_SCRUBBING&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Used for configuring the Falcon&#039;s DMA engine.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_DMATRFBASE ===&lt;br /&gt;
Takes the host&#039;s base address for transferring data to/from the Falcon (DMA).&lt;br /&gt;
&lt;br /&gt;
=== FALCON_DMATRFMOFFS ===&lt;br /&gt;
Takes the offset for the host&#039;s source memory being transferred.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_DMATRFCMD ===&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Bits&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 1&lt;br /&gt;
| FALCON_DMATRFCMD_IDLE (this is set if the engine is idle)&lt;br /&gt;
|-&lt;br /&gt;
| 4&lt;br /&gt;
| FALCON_DMATRFCMD_IMEM&lt;br /&gt;
|-&lt;br /&gt;
| 9-10&lt;br /&gt;
| FALCON_DMATRFCMD_SIZE_256B&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Used for configuring DMA transfers.&lt;br /&gt;
&lt;br /&gt;
=== FALCON_DMATRFFBOFFS ===&lt;br /&gt;
Takes the offset for Falcon&#039;s target memory being transferred.&lt;br /&gt;
&lt;br /&gt;
= Boot Process =&lt;br /&gt;
TSEC is configured and initialized by the first bootloader during key generation (sub_400114FC).&lt;br /&gt;
&lt;br /&gt;
== Initialization ==&lt;br /&gt;
During this stage several clocks are programmed.&lt;br /&gt;
 // Program the HOST1X clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_L, CLK_OUT_ENB_L, CLK_SOURCE_HOST1X and CLK_L_HOST1X&lt;br /&gt;
 enable_host1x_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Program the TSEC clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_U, CLK_OUT_ENB_U, CLK_SOURCE_TSEC and CLK_U_TSEC&lt;br /&gt;
 enable_tsec_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Program the SOR_SAFE clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_Y, CLK_OUT_ENB_Y and CLK_Y_SOR_SAFE&lt;br /&gt;
 enable_sor_safe_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Program the SOR0 clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_X, CLK_OUT_ENB_X and CLK_X_SOR0&lt;br /&gt;
 enable_sor0_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Program the SOR1 clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_X, CLK_OUT_ENB_X, CLK_SOURCE_SOR1 and CLK_X_SOR1&lt;br /&gt;
 enable_sor1_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Program the KFUSE clock resets&lt;br /&gt;
 // Uses RST_DEVICES_H, CLK_OUT_ENB_H and CLK_H_KFUSE&lt;br /&gt;
 enable_kfuse_clkrst();&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
In this stage the Falcon IRQs, interfaces and DMA engine are configured.&lt;br /&gt;
 // Clear the Falcon DMA control register&lt;br /&gt;
 *(u32 *)FALCON_DMACTL = 0;&lt;br /&gt;
 &lt;br /&gt;
 // Enable Falcon IRQs&lt;br /&gt;
 *(u32 *)FALCON_IRQMSET = 0xFFF2;&lt;br /&gt;
 &lt;br /&gt;
 // Enable Falcon IRQs&lt;br /&gt;
 *(u32 *)FALCON_IRQDEST = 0xFFF0;&lt;br /&gt;
 &lt;br /&gt;
 // Enable Falcon interfaces&lt;br /&gt;
 *(u32 *)FALCON_ITFEN = 0x03;&lt;br /&gt;
 &lt;br /&gt;
 // Wait for Falcon&#039;s DMA engine to be idle&lt;br /&gt;
 wait_flcn_dma_idle();&lt;br /&gt;
&lt;br /&gt;
== Firmware loading ==&lt;br /&gt;
The Falcon firmware code is stored in the first bootloader&#039;s data segment in IMEM.&lt;br /&gt;
 // Set DMA transfer base address to 0x40011900 &amp;gt;&amp;gt; 0x08&lt;br /&gt;
 *(u32 *)FALCON_DMATRFBASE = 0x400119;&lt;br /&gt;
 &lt;br /&gt;
 u32 trf_mode = 0;     // A value of 0 sets FALCON_DMATRFCMD_IMEM&lt;br /&gt;
 u32 dst_offset = 0;&lt;br /&gt;
 u32 src_offset = 0;&lt;br /&gt;
 &lt;br /&gt;
 // Load code into Falcon (0x100 bytes at a time)&lt;br /&gt;
 while (src_offset &amp;lt; 0xF00)&lt;br /&gt;
 {&lt;br /&gt;
    flcn_load_firm(trf_mode, src_offset, dst_offset);&lt;br /&gt;
    src_offset += 0x100;&lt;br /&gt;
    dst_offset += 0x100;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Firmware booting ==&lt;br /&gt;
Falcon is booted up and the first bootloader waits for it to finish.&lt;br /&gt;
 // Set host1x sync config&lt;br /&gt;
 *(u32 *)0x50003300 = 0x34C2E1DA;&lt;br /&gt;
 &lt;br /&gt;
 // Clear Falcon scratch1 MMIO&lt;br /&gt;
 *(u32 *)FALCON_SCRATCH1 = 0;&lt;br /&gt;
 &lt;br /&gt;
 // Set Falcon boot key version in scratch0 MMIO&lt;br /&gt;
 *(u32 *)FALCON_SCRATCH0 = 0x01;&lt;br /&gt;
 &lt;br /&gt;
 // Set Falcon&#039;s boot vector address&lt;br /&gt;
 *(u32 *)FALCON_BOOTVEC = 0;&lt;br /&gt;
 &lt;br /&gt;
 // Signal Falcon&#039;s CPU&lt;br /&gt;
 *(u32 *)FALCON_CPUCTL = 0x02;&lt;br /&gt;
 &lt;br /&gt;
 // Wait for Falcon&#039;s DMA engine to be idle&lt;br /&gt;
 wait_flcn_dma_idle();&lt;br /&gt;
 &lt;br /&gt;
 u32 boot_res = 0;&lt;br /&gt;
&lt;br /&gt;
 // The bootloader allows the TSEC two seconds from this point to do its job&lt;br /&gt;
 u32 maximum_time = read_timer() + 2000000; &lt;br /&gt;
 &lt;br /&gt;
 while (!boot_res)&lt;br /&gt;
 {&lt;br /&gt;
    // Read boot result from scratch1 MMIO&lt;br /&gt;
    boot_res = *(u32 *)FALCON_SCRATCH1;&lt;br /&gt;
    &lt;br /&gt;
    // Read from TIMERUS_CNTR_1US (microseconds from boot)&lt;br /&gt;
    u32 current_time = read_timer();&lt;br /&gt;
    &lt;br /&gt;
    // Booting is taking too long&lt;br /&gt;
    if (current_time &amp;gt; maximum_time)&lt;br /&gt;
       panic();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // Invalid boot result was returned&lt;br /&gt;
 if (boot_res != 0xB0B0B0B0)&lt;br /&gt;
    panic();&lt;br /&gt;
&lt;br /&gt;
== Keygen ==&lt;br /&gt;
The Falcon device key is generated by reading SOR registers modified by Falcon.&lt;br /&gt;
 // Clear host1x sync config&lt;br /&gt;
 *(u32 *)0x50003300 = 0;&lt;br /&gt;
 &lt;br /&gt;
 // Generate Falcon device key&lt;br /&gt;
 u32 falcon_device_key[4]; &lt;br /&gt;
 falcon_device_key[0] = *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB;&lt;br /&gt;
 falcon_device_key[1] = *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB;&lt;br /&gt;
 falcon_device_key[2] = *(u32 *)NV_SOR_TMDS_HDCP_CN_MSB;&lt;br /&gt;
 falcon_device_key[3] = *(u32 *)NV_SOR_TMDS_HDCP_CN_LSB;&lt;br /&gt;
 &lt;br /&gt;
 // Clear SOR registers&lt;br /&gt;
 *(u32 *)NV_SOR_DP_HDCP_BKSV_LSB = 0;&lt;br /&gt;
 *(u32 *)NV_SOR_TMDS_HDCP_BKSV_LSB = 0;&lt;br /&gt;
 *(u32 *)NV_SOR_TMDS_HDCP_CN_MSB = 0;&lt;br /&gt;
 *(u32 *)NV_SOR_TMDS_HDCP_CN_LSB = 0;&lt;br /&gt;
 &lt;br /&gt;
 if (out_size &amp;lt; 0x10)&lt;br /&gt;
    out_size = 0x10;&lt;br /&gt;
 &lt;br /&gt;
 // Copy back the Falcon key&lt;br /&gt;
 memcpy(out_buf, falcon_device_key, out_size);&lt;br /&gt;
&lt;br /&gt;
== Cleanup ==&lt;br /&gt;
Clocks and resets are disabled before returning.&lt;br /&gt;
 // Deprogram KFUSE clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_H, CLK_OUT_ENB_H and CLK_H_KFUSE&lt;br /&gt;
 disable_kfuse_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Deprogram SOR1 clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_X, CLK_OUT_ENB_X, CLK_SOURCE_SOR1 and CLK_X_SOR1&lt;br /&gt;
 disable_sor1_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Deprogram SOR0 clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_X, CLK_OUT_ENB_X and CLK_X_SOR0&lt;br /&gt;
 disable_sor0_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Deprogram SOR_SAFE clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_Y, CLK_OUT_ENB_Y and CLK_Y_SOR_SAFE&lt;br /&gt;
 disable_sor_safe_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Deprogram TSEC clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_U, CLK_OUT_ENB_U, CLK_SOURCE_TSEC and CLK_U_TSEC&lt;br /&gt;
 disable_tsec_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 // Deprogram HOST1X clock and resets&lt;br /&gt;
 // Uses RST_DEVICES_L, CLK_OUT_ENB_L, CLK_SOURCE_HOST1X and CLK_L_HOST1X&lt;br /&gt;
 disable_host1x_clkrst();&lt;br /&gt;
 &lt;br /&gt;
 return;&lt;br /&gt;
&lt;br /&gt;
= TSEC Firmware =&lt;br /&gt;
The actual code loaded into TSEC is assembled in NVIDIA&#039;s proprietary fuc5 ISA using crypto extensions.&lt;br /&gt;
Stored inside the first bootloader, this firmware binary is split into 4 blobs: Stage0, Stage1, Stage2 and key data.&lt;br /&gt;
&lt;br /&gt;
Firmware can be disassembled with [http://envytools.readthedocs.io/en/latest/ envytools&#039;] [https://github.com/envytools/envytools/tree/master/envydis envydis]:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;code&amp;gt;envydis -i tsec_fw.bin -m falcon -V fuc5 -F crypt&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Note that the instruction set has variable length instructions, and the disassembler is not very good at detecting locations it should start disassembling from. One needs to disassemble multiple sub-regions and join them together.&lt;br /&gt;
&lt;br /&gt;
== Stage 0 ==&lt;br /&gt;
During this stage key data is loaded and Stage 1 is authenticated, loaded and executed.&lt;br /&gt;
Before returning, this stage writes back to the host (using MMIO registers) and sets the device key used by the first bootloader.&lt;br /&gt;
&lt;br /&gt;
=== Initialization ===&lt;br /&gt;
Falcon sets up it&#039;s own stack pointer.&lt;br /&gt;
 // Read data segment size from IO space&lt;br /&gt;
 u32 data_seg_size = *(u32 *)UC_CAPS;&lt;br /&gt;
 data_seg_size &amp;gt;&amp;gt;= 0x09;&lt;br /&gt;
 data_seg_size &amp;amp;= 0x1FF;&lt;br /&gt;
 data_seg_size &amp;lt;&amp;lt;= 0x08;&lt;br /&gt;
 &lt;br /&gt;
 // Set the stack pointer&lt;br /&gt;
 *(u32 *)sp = data_seg_size;&lt;br /&gt;
&lt;br /&gt;
=== Stage 1 loading === &lt;br /&gt;
 u32 boot_base_addr = 0;&lt;br /&gt;
 u32 key_data_buf[0x7C];&lt;br /&gt;
 &lt;br /&gt;
 // Read the key data from memory&lt;br /&gt;
 u32 key_data_addr = 0x300;&lt;br /&gt;
 u32 key_data_size = 0x7C;&lt;br /&gt;
 read_code(key_data_buf, key_data_addr, key_data_size);&lt;br /&gt;
 &lt;br /&gt;
 // Read the next code segment into boot base&lt;br /&gt;
 u32 blob1_addr = 0x400;&lt;br /&gt;
 u32 blob1_size = *(u32 *)(key_data_buf + 0x74);&lt;br /&gt;
 read_code(boot_base_addr, blob1_addr, blob1_size);&lt;br /&gt;
 &lt;br /&gt;
 // Upload the next code segment into Falcon&#039;s CODE region&lt;br /&gt;
 u32 blob1_virt_addr = 0x300;&lt;br /&gt;
 bool use_secret = true;&lt;br /&gt;
 upload_code(blob1_virt_addr, boot_base_addr, blob1_size, blob1_virt_addr, use_secret);&lt;br /&gt;
 &lt;br /&gt;
 u32 boot_res = 0;&lt;br /&gt;
 bool is_done = false;&lt;br /&gt;
 u32 time = 0;&lt;br /&gt;
 bool is_blob_dec = false;&lt;br /&gt;
 &lt;br /&gt;
 while (!is_done)&lt;br /&gt;
 {&lt;br /&gt;
    if (time &amp;gt; 4000000)&lt;br /&gt;
    {&lt;br /&gt;
       // Write boot failed (timeout) magic to FALCON_SCRATCH1&lt;br /&gt;
       boot_res = 0xC0C0C0C0;&lt;br /&gt;
       *(u32 *)FALCON_SCRATCH1 = boot_res;&lt;br /&gt;
       &lt;br /&gt;
       break;&lt;br /&gt;
    }&lt;br /&gt;
    &lt;br /&gt;
    // Load key version from FALCON_SCRATCH0 (bootloader sends 0x01)&lt;br /&gt;
    u32 key_version = *(u32 *)FALCON_SCRATCH0;&lt;br /&gt;
 &lt;br /&gt;
    if (key_version == 0x64)&lt;br /&gt;
    {&lt;br /&gt;
       // Skip all next stages&lt;br /&gt;
       boot_res = 0xB0B0B0B0;&lt;br /&gt;
       *(u32 *)FALCON_SCRATCH1 = boot_res;&lt;br /&gt;
       &lt;br /&gt;
       break;&lt;br /&gt;
    }&lt;br /&gt;
    else&lt;br /&gt;
    {&lt;br /&gt;
       if (key_version &amp;gt; 0x03)&lt;br /&gt;
          boot_res = 0xD0D0D0D0;    // Invalid key version&lt;br /&gt;
       else if (key_version == 0)&lt;br /&gt;
          boot_res = 0xB0B0B0B0;    // No keys used&lt;br /&gt;
       else&lt;br /&gt;
       {&lt;br /&gt;
          u32 key_buf[0x7C];&lt;br /&gt;
          &lt;br /&gt;
          // Copy key data&lt;br /&gt;
          memcpy(key_buf, key_data_buf, 0x7C);&lt;br /&gt;
 &lt;br /&gt;
          u32 crypt_reg_flag = 0x00060000;&lt;br /&gt;
          u32 blob1_hash_addr = key_buf + 0x20; &lt;br /&gt;
 &lt;br /&gt;
          // fuc5 crypt cauth instruction&lt;br /&gt;
          // Set auth_addr to 0x300 and auth_size to blob1_size&lt;br /&gt;
          cauth((blob1_size &amp;lt;&amp;lt; 0x10) | (0x300 &amp;gt;&amp;gt; 0x08));&lt;br /&gt;
 &lt;br /&gt;
          // fuc5 crypt cxset instruction&lt;br /&gt;
          // The next 2 xfer instructions will be overridden&lt;br /&gt;
          // and target changes from DMA to crypto&lt;br /&gt;
          cxset(0x02);&lt;br /&gt;
          &lt;br /&gt;
          // Transfer data to crypto register c6&lt;br /&gt;
 	 xdst(0, (blob1_hash_addr | crypt_reg_flag));&lt;br /&gt;
 	  			&lt;br /&gt;
 	 // Wait for all data loads/stores to finish&lt;br /&gt;
 	 xdwait();&lt;br /&gt;
          &lt;br /&gt;
          // Jump to Stage1&lt;br /&gt;
          u32 stage1_res = exec_stage1(key_buf, key_version, is_blob_dec);&lt;br /&gt;
          is_blob_dec = true;  // Set this to prevent decrypting again&lt;br /&gt;
 &lt;br /&gt;
          // Set boot finish magic on success&lt;br /&gt;
 	  if (stage1_res == 0)&lt;br /&gt;
             boot_res = 0xB0B0B0B0&lt;br /&gt;
       }&lt;br /&gt;
       &lt;br /&gt;
       // Write result to FALCON_SCRATCH1&lt;br /&gt;
       *(u32 *)FALCON_SCRATCH1 = boot_res;&lt;br /&gt;
 &lt;br /&gt;
       if (boot_res == 0xB0B0B0B0)&lt;br /&gt;
          is_done = true;&lt;br /&gt;
    }&lt;br /&gt;
 &lt;br /&gt;
    time++;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // Write Falcon device key to registers&lt;br /&gt;
 set_device_key(key_data_buf);&lt;br /&gt;
 &lt;br /&gt;
 return boot_res;&lt;br /&gt;
&lt;br /&gt;
== Stage 1 ==&lt;br /&gt;
This stage is responsible for reconfiguring the Falcon&#039;s crypto co-processor and loading, decrypting, authenticating and executing Stage 2.&lt;br /&gt;
&lt;br /&gt;
=== Crypto setup ===&lt;br /&gt;
 // Clear interrupt flags&lt;br /&gt;
 *(u8 *)flags_ie0 = 0;&lt;br /&gt;
 *(u8 *)flags_ie1 = 0;&lt;br /&gt;
 *(u8 *)flags_ie2 = 0;&lt;br /&gt;
 &lt;br /&gt;
 // fuc5 crypt cxset instruction&lt;br /&gt;
 // Clear overrides?&lt;br /&gt;
 cxset(0x80);&lt;br /&gt;
 &lt;br /&gt;
 // fuc5 crypt cauth instruction&lt;br /&gt;
 // Clear auth_addr&lt;br /&gt;
 cauth(cauth_old &amp;amp; 0x7FFFF);&lt;br /&gt;
 &lt;br /&gt;
 // Set the target port for memory transfers&lt;br /&gt;
 // Target will now be 0 (crypto?)&lt;br /&gt;
 xtargets(0);&lt;br /&gt;
 &lt;br /&gt;
 // Wait for all data loads/stores to finish&lt;br /&gt;
 xdwait();&lt;br /&gt;
 &lt;br /&gt;
 // Wait for all code loads to finish&lt;br /&gt;
 xcwait();&lt;br /&gt;
 &lt;br /&gt;
 // fuc5 crypt cxset instruction&lt;br /&gt;
 // The next 2 xfer instructions will be overridden&lt;br /&gt;
 // and target changes from DMA to crypto&lt;br /&gt;
 cxset(0x02);&lt;br /&gt;
 &lt;br /&gt;
 // Transfer data to crypto register c0&lt;br /&gt;
 // This should clear any leftover data&lt;br /&gt;
 xdst(0, 0);&lt;br /&gt;
 &lt;br /&gt;
 // Wait for all data loads/stores to finish&lt;br /&gt;
 xdwait();&lt;br /&gt;
 &lt;br /&gt;
 // Clear all crypto registers, except c6 which is used for auth&lt;br /&gt;
 *(u32 *)c0 ^= *(u32 *)c0;&lt;br /&gt;
 *(u32 *)c1 = *(u32 *)c0;&lt;br /&gt;
 *(u32 *)c2 = *(u32 *)c0;&lt;br /&gt;
 *(u32 *)c3 = *(u32 *)c0;&lt;br /&gt;
 *(u32 *)c4 = *(u32 *)c0;&lt;br /&gt;
 *(u32 *)c5 = *(u32 *)c0;&lt;br /&gt;
 *(u32 *)c7 = *(u32 *)c0;&lt;br /&gt;
 &lt;br /&gt;
 // Update engine specific IO (crypto?)&lt;br /&gt;
 *(u32 *)0x00020E00 &amp;amp;= 0xEFFFF;&lt;br /&gt;
 &lt;br /&gt;
 // Update engine specific IO (crypto?)&lt;br /&gt;
 *(u32 *)0x00010600 |= 0x01;&lt;br /&gt;
 &lt;br /&gt;
 u32 wait_10600 = 0;&lt;br /&gt;
 &lt;br /&gt;
 // Wait for some device&lt;br /&gt;
 while (wait_10600 == 0)&lt;br /&gt;
    wait_10600 = (*(u32 *)0x00010600 &amp;amp; 0x02);&lt;br /&gt;
 &lt;br /&gt;
 // Read data segment size from IO space&lt;br /&gt;
 u32 data_seg_size = *(u32 *)UC_CAPS;&lt;br /&gt;
 data_seg_size &amp;gt;&amp;gt;= 0x09;&lt;br /&gt;
 data_seg_size &amp;amp;= 0x1FF;&lt;br /&gt;
 data_seg_size &amp;lt;&amp;lt;= 0x08;&lt;br /&gt;
 &lt;br /&gt;
 // Check stack bounds&lt;br /&gt;
 if ((*(u32 *)sp &amp;gt;= data_seg_size) || (*(u32 *)sp &amp;lt; 0x800))&lt;br /&gt;
   return;&lt;br /&gt;
 &lt;br /&gt;
 // Decrypt and load Stage2&lt;br /&gt;
 load_stage2(key_buf, key_version, is_blob_dec);&lt;br /&gt;
 &lt;br /&gt;
 // Partially unknown fuc5 instruction&lt;br /&gt;
 // Likely forces propagation of permissions, hiding all cX registers &lt;br /&gt;
 acl_chmod(c0, c0);&lt;br /&gt;
 &lt;br /&gt;
 // Clear all crypto registers and propagate permissions&lt;br /&gt;
 *(u32 *)c0 ^= *(u32 *)c0;&lt;br /&gt;
 *(u32 *)c1 ^= *(u32 *)c1;&lt;br /&gt;
 *(u32 *)c2 ^= *(u32 *)c2;&lt;br /&gt;
 *(u32 *)c3 ^= *(u32 *)c3;&lt;br /&gt;
 *(u32 *)c4 ^= *(u32 *)c4;&lt;br /&gt;
 *(u32 *)c5 ^= *(u32 *)c5;&lt;br /&gt;
 *(u32 *)c6 ^= *(u32 *)c6;&lt;br /&gt;
 *(u32 *)c7 ^= *(u32 *)c7;&lt;br /&gt;
 &lt;br /&gt;
 // Exit Authenticated Mode&lt;br /&gt;
 *(u32 *)0x00010300 = 0;&lt;br /&gt;
 &lt;br /&gt;
 return;&lt;br /&gt;
&lt;br /&gt;
=== Stage 2 loading ===&lt;br /&gt;
 u32 res = 0;&lt;br /&gt;
 &lt;br /&gt;
 u32 boot_base_addr = 0;&lt;br /&gt;
 u32 blob0_addr = 0;&lt;br /&gt;
 u32 blob0_size = *(u32 *)(key_buf + 0x70); &lt;br /&gt;
 &lt;br /&gt;
 // Load blob0 code again&lt;br /&gt;
 read_code(boot_base_addr, blob0_addr, blob0_size);&lt;br /&gt;
 &lt;br /&gt;
 // Generate &amp;quot;CODE_SIG_01&amp;quot; key into c4 crypto register&lt;br /&gt;
 keygen(0, 0);&lt;br /&gt;
 &lt;br /&gt;
 // Encrypt buffer with c4&lt;br /&gt;
 u32 sig_key[0x10];&lt;br /&gt;
 enc_buf(sig_key, blob0_size);&lt;br /&gt;
 &lt;br /&gt;
 u32 src_addr = boot_base_addr;&lt;br /&gt;
 u32 src_size = blob0_size;&lt;br /&gt;
 u32 iv_addr = sig_key;&lt;br /&gt;
 u32 dst_addr = sig_key;&lt;br /&gt;
 u32 mode = 0x02;   // AES-CMAC&lt;br /&gt;
 u32 version = 0;&lt;br /&gt;
 &lt;br /&gt;
 // Do AES-CMAC over blob0 code&lt;br /&gt;
 do_crypto(src_addr, src_size, iv_addr, dst_addr, mode, version);&lt;br /&gt;
 &lt;br /&gt;
 // Compare the hashes&lt;br /&gt;
 if (memcmp(sig_key, key_buf + 0x10, 0x10))&lt;br /&gt;
 {&lt;br /&gt;
   res = 0xDEADBEEF;&lt;br /&gt;
   return res;&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 u32 blob1_size = *(u32 *)(key_buf + 0x74);&lt;br /&gt;
 &lt;br /&gt;
 // Decrypt Stage2 blob if needed&lt;br /&gt;
 if (!is_blob_dec)&lt;br /&gt;
 {&lt;br /&gt;
    // Read Stage2&#039;s size from key buffer&lt;br /&gt;
    u32 blob2_size = *(u32 *)(key_buf + 0x78);&lt;br /&gt;
 &lt;br /&gt;
    // Check stack bounds&lt;br /&gt;
    if (*(u32 *)sp &amp;gt; blob2_size)&lt;br /&gt;
    {&lt;br /&gt;
       u32 boot_base_addr = 0;&lt;br /&gt;
       u32 blob2_virt_addr = blob0_size + blob1_size;&lt;br /&gt;
       u32 blob2_addr = blob2_virt_addr + 0x100;&lt;br /&gt;
       &lt;br /&gt;
       // Read Stage2&#039;s encrypted blob&lt;br /&gt;
       read_code(boot_base_addr, blob2_addr, blob2_size);&lt;br /&gt;
 &lt;br /&gt;
       // Generate &amp;quot;CODE_ENC_01&amp;quot; key into c4 crypt register&lt;br /&gt;
       keygen(0x01, 0x01);&lt;br /&gt;
       &lt;br /&gt;
       u32 src_addr = boot_base_addr;&lt;br /&gt;
       u32 src_size = blob2_size;&lt;br /&gt;
       u32 iv_addr = key_buf + 0x40;&lt;br /&gt;
       u32 dst_addr = boot_base_addr;&lt;br /&gt;
       u32 mode = 0;   // AES-128-ECB&lt;br /&gt;
       u32 version = 0;&lt;br /&gt;
       &lt;br /&gt;
       // Decrypt Stage2&lt;br /&gt;
       do_crypto(src_addr, src_size, iv_addr, dst_addr, mode, version);&lt;br /&gt;
       &lt;br /&gt;
       // Upload the next code segment into Falcon&#039;s CODE region&lt;br /&gt;
       bool use_secret = true;&lt;br /&gt;
       upload_code(blob2_virt_addr, boot_base_addr, blob2_size, blob2_virt_addr, use_secret);&lt;br /&gt;
 &lt;br /&gt;
       // Clear out the decrypted blob&lt;br /&gt;
       memset(boot_base_addr, 0, blob2_size);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 // fuc5 crypt cxset instruction&lt;br /&gt;
 // The next 2 xfer instructions will be overridden&lt;br /&gt;
 // and target changes from DMA to crypto&lt;br /&gt;
 cxset(0x02);&lt;br /&gt;
 &lt;br /&gt;
 u32 crypt_reg_flag = 0x00060000;&lt;br /&gt;
 u32 blob2_hash_addr = key_buf + 0x30;&lt;br /&gt;
 &lt;br /&gt;
 // Transfer data to crypto register c6&lt;br /&gt;
 xdst(0, (blob2_hash_addr | crypt_reg_flag));&lt;br /&gt;
 				&lt;br /&gt;
 // Wait for all data loads/stores to finish&lt;br /&gt;
 xdwait();&lt;br /&gt;
 &lt;br /&gt;
 // Save previous cauth value&lt;br /&gt;
 u32 c_old = cauth_old;&lt;br /&gt;
 &lt;br /&gt;
 // fuc5 crypt cauth instruction&lt;br /&gt;
 // Set auth_addr to blob2_virt_addr and auth_size to blob2_size&lt;br /&gt;
 cauth((blob2_virt_addr &amp;gt;&amp;gt; 0x08) | (blob2_size &amp;lt;&amp;lt; 0x10));&lt;br /&gt;
 &lt;br /&gt;
 u32 hovi_key_addr = 0;&lt;br /&gt;
 &lt;br /&gt;
 // Select next stage key&lt;br /&gt;
 if (key_version == 0x01)		// Use HOVI_EKS_01&lt;br /&gt;
   hovi_key_addr = key_buf + 0x50;&lt;br /&gt;
 else if (key_version == 0x02)	        // Use HOVI_COMMON_01&lt;br /&gt;
   hovi_key_addr = key_buf + 0x60;&lt;br /&gt;
 else if (key_version == 0x03)	        // Use device key&lt;br /&gt;
   hovi_key_addr = key_buf + 0x00;&lt;br /&gt;
 else&lt;br /&gt;
   res = 0xD0D0D0D0&lt;br /&gt;
 	&lt;br /&gt;
 // Jump to Stage2&lt;br /&gt;
 if (hovi_key_addr)&lt;br /&gt;
   res = exec_stage2(hovi_key_addr, key_version);&lt;br /&gt;
          &lt;br /&gt;
 // Clear out key data&lt;br /&gt;
 memset(key_buf, 0, 0x7C);&lt;br /&gt;
 &lt;br /&gt;
 // fuc5 crypt cauth instruction&lt;br /&gt;
 // Restore previous cauth value&lt;br /&gt;
 cauth(c_old);&lt;br /&gt;
 &lt;br /&gt;
 return res;&lt;br /&gt;
&lt;br /&gt;
== Stage 2 ==&lt;br /&gt;
This stage is decrypted by Stage 1 using an hardware secret (HOVI == Horizon VI?).&lt;br /&gt;
&lt;br /&gt;
== Key data ==&lt;br /&gt;
Small buffer stored after Stage 0&#039;s code and used across all stages.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
!  Offset&lt;br /&gt;
!  Size&lt;br /&gt;
!  Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x00&lt;br /&gt;
| 0x10&lt;br /&gt;
| Device key&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 0x10&lt;br /&gt;
| blob0 auth hash&lt;br /&gt;
|-&lt;br /&gt;
| 0x20&lt;br /&gt;
| 0x10&lt;br /&gt;
| blob1 auth hash&lt;br /&gt;
|-&lt;br /&gt;
| 0x30&lt;br /&gt;
| 0x10&lt;br /&gt;
| blob2 auth hash&lt;br /&gt;
|-&lt;br /&gt;
| 0x40&lt;br /&gt;
| 0x10&lt;br /&gt;
| blob2 AES IV&lt;br /&gt;
|-&lt;br /&gt;
| 0x50&lt;br /&gt;
| 0x10&lt;br /&gt;
| HOVI eks seed&lt;br /&gt;
|-&lt;br /&gt;
| 0x60&lt;br /&gt;
| 0x10&lt;br /&gt;
| HOVI common seed&lt;br /&gt;
|-&lt;br /&gt;
| 0x70&lt;br /&gt;
| 0x04&lt;br /&gt;
| blob0 size&lt;br /&gt;
|-&lt;br /&gt;
| 0x74&lt;br /&gt;
| 0x04&lt;br /&gt;
| blob1 size&lt;br /&gt;
|-&lt;br /&gt;
| 0x78&lt;br /&gt;
| 0x04&lt;br /&gt;
| blob2 size&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
[https://wiki.0x04.net/wiki/Marcin_Ko%C5%9Bcielnicki mwk] shared additional info learned from RE of falcon processors over the years, which hasn&#039;t made it into envytools documentation yet:&lt;br /&gt;
&lt;br /&gt;
=== cxset ===&lt;br /&gt;
&lt;br /&gt;
cxset instruction provides a way to change behavior of a variable amount of successively executed DMA-related instructions.&lt;br /&gt;
&lt;br /&gt;
for example: &amp;lt;code&amp;gt;000000de: f4 3c 02              cxset 0x2&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
can be read as: &amp;lt;code&amp;gt;dma_override(type=crypto_reg, count=2)&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The argument to cxset specifies the type of behavior change in the top 3 bits, and the number of DMA-related instructions the effect lasts for in the lower 5 bits.&lt;br /&gt;
&lt;br /&gt;
==== Override Types ====&lt;br /&gt;
&lt;br /&gt;
Unlisted values are unknown, but probably do something.&lt;br /&gt;
&lt;br /&gt;
{| class=wikitable&lt;br /&gt;
! Value || Effect&lt;br /&gt;
|-&lt;br /&gt;
|  0b000 || falcon data mem &amp;lt;-&amp;gt; falcon $cX register&lt;br /&gt;
|-&lt;br /&gt;
|  0b001 || external mem &amp;lt;-&amp;gt; crypto input/output stream&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== DMA-Related Instructions ====&lt;br /&gt;
&lt;br /&gt;
At least the following instructions may have changed behavior, and count against the cxset &amp;quot;count&amp;quot; argument: &amp;lt;code&amp;gt;xdwait&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;xdst&amp;lt;/code&amp;gt;, &amp;lt;code&amp;gt;xdld&amp;lt;/code&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
For example, if override type=0b000, then the &amp;quot;length&amp;quot; argument to &amp;lt;code&amp;gt;xdst&amp;lt;/code&amp;gt; is instead treated as the index of the target $cX register.&lt;br /&gt;
&lt;br /&gt;
=== Register ACLs ===&lt;br /&gt;
&lt;br /&gt;
Falcon tracks permission metadata about each crypto reg. Permissions include read/write ability per execution mode, as well as ability to use the reg for encrypt/decrypt, among other permissions. Permissions are propagated when registers are referenced by instructions (e.g. moving a value from read-protected $cX to $cY will result in $cY also being read-protected).&lt;br /&gt;
&lt;br /&gt;
=== Authenticated Mode Entry/Exit ===&lt;br /&gt;
&lt;br /&gt;
Entry to Authenticated Mode always sets $pc to the address supplied in $cauth (ie the base of the signature-checked region). This takes effect when trying to branch to any address within the range covered by $cauth. Entry to Authenticated Mode (also called &amp;quot;Secure Mode&amp;quot;) computes a MAC over the $cauth region and compares it to $c6 in order to perform the signature check.&lt;br /&gt;
&lt;br /&gt;
Exit from Authenticated Mode must poke a special register (this seems to be I[0x10300] = 0) before leaving authenticated code pages. Failure to do this would result in the Falcon core halting.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=XCI&amp;diff=1893</id>
		<title>XCI</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=XCI&amp;diff=1893"/>
		<updated>2017-08-03T11:16:11Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: According to the dumps on the cartridge page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;=Header=&lt;br /&gt;
The header is 0x200-bytes, at Gamecard+0.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x100&lt;br /&gt;
| RSA-2048 signature, presumably.&lt;br /&gt;
|-&lt;br /&gt;
| 0x100&lt;br /&gt;
| 0x4&lt;br /&gt;
| Magicnum &amp;quot;HEAD&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x104&lt;br /&gt;
| 0x4&lt;br /&gt;
| Offset of Secure partition (Size of non-secure data?), in Media Units (0x200 bytes for switch gamecarts)&lt;br /&gt;
|-&lt;br /&gt;
| 0x108&lt;br /&gt;
| 0x4&lt;br /&gt;
| 0xFFFFFFFF&lt;br /&gt;
|-&lt;br /&gt;
| 0x10C&lt;br /&gt;
| 0x1&lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| 0x10D&lt;br /&gt;
| 0x1&lt;br /&gt;
| Cartridge Size. 0xF8 = 2 GB, 0xF0 = 4 GB, 0xE0 = 8 GB, 0xE1 = 16 GB&lt;br /&gt;
|-&lt;br /&gt;
| 0x10E&lt;br /&gt;
| 0x1&lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| 0x10F&lt;br /&gt;
| 0x1&lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| 0x110&lt;br /&gt;
| 0x8&lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| 0x118&lt;br /&gt;
| 0x8&lt;br /&gt;
| Size of the Gamecart, in Media Units&lt;br /&gt;
|-&lt;br /&gt;
| 0x120&lt;br /&gt;
| 0x10&lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| 0x130&lt;br /&gt;
| 0x8&lt;br /&gt;
| Offset of HFS0 FS partition&lt;br /&gt;
|-&lt;br /&gt;
| 0x138&lt;br /&gt;
| 8&lt;br /&gt;
| HFS0 Header size&lt;br /&gt;
|-&lt;br /&gt;
| 0x140&lt;br /&gt;
| 0x20&lt;br /&gt;
| SHA256 hash of the HFS0 Header&lt;br /&gt;
|-&lt;br /&gt;
| 0x160&lt;br /&gt;
| 0x20&lt;br /&gt;
| SHA256 hash of the crypto header&lt;br /&gt;
|-&lt;br /&gt;
| 0x180&lt;br /&gt;
| 0x4&lt;br /&gt;
| 1?&lt;br /&gt;
|-&lt;br /&gt;
| 0x184&lt;br /&gt;
| 0x4&lt;br /&gt;
| 2?&lt;br /&gt;
|-&lt;br /&gt;
| 0x188&lt;br /&gt;
| 0x4&lt;br /&gt;
| 0?&lt;br /&gt;
|-&lt;br /&gt;
| 0x18C&lt;br /&gt;
| 0x4&lt;br /&gt;
| Offset of Secure partition (Size of non-secure data?), in Media Units, again.&lt;br /&gt;
|-&lt;br /&gt;
| 0x190&lt;br /&gt;
| 0x70&lt;br /&gt;
| Encrypted data/hashes of some kind&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
= Cert =&lt;br /&gt;
&lt;br /&gt;
This is for the CERT, located at Gamecard + 0x7000 (always?). This matches exactly the output from fsp-srv IDeviceOperator cmd 206 &amp;quot;GetGameCardDeviceCertificate&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x100&lt;br /&gt;
| RSA-2048 signature, presumably.&lt;br /&gt;
|-&lt;br /&gt;
| 0x100&lt;br /&gt;
| 0x4&lt;br /&gt;
| Magicnum &amp;quot;CERT&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x110&lt;br /&gt;
| 0x10&lt;br /&gt;
| ?&lt;br /&gt;
|-&lt;br /&gt;
| 0x12A&lt;br /&gt;
| 0xD6&lt;br /&gt;
| Encrypted data. Some kind of key?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The data between the CERT and the start of the HFS0 is all 0xFF.&lt;br /&gt;
&lt;br /&gt;
= HFS0 =&lt;br /&gt;
This is the FS which has magicnum &amp;quot;HFS0&amp;quot; at header+0.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x4&lt;br /&gt;
| HFS0 Magic&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 0x4&lt;br /&gt;
| Number of files&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 0x4&lt;br /&gt;
| Size of the string table&lt;br /&gt;
|-&lt;br /&gt;
| 0xC&lt;br /&gt;
| 0x4&lt;br /&gt;
| Zero/Reserved&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| X&lt;br /&gt;
| File Entry Table&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 + X&lt;br /&gt;
| Y&lt;br /&gt;
| String Table&lt;br /&gt;
|-&lt;br /&gt;
| 0x10 + X + Y&lt;br /&gt;
| Z&lt;br /&gt;
| Raw File Data&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Where File Entry Table consists of Number of Files FileEntries:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x8&lt;br /&gt;
| Offset of file in Data&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 0x8&lt;br /&gt;
| Size of file in Data&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 0x4&lt;br /&gt;
| Offset of filename in String Table&lt;br /&gt;
|-&lt;br /&gt;
| 0x14&lt;br /&gt;
| 0x4&lt;br /&gt;
| Size of Hashed region of file (for HFS0s, this is the size of the pre-filedata portion, for NCAs this is usually 0x200).&lt;br /&gt;
|-&lt;br /&gt;
| 0x18&lt;br /&gt;
| 8&lt;br /&gt;
| Zero/Reserved&lt;br /&gt;
|-&lt;br /&gt;
| 0x20&lt;br /&gt;
| 0x20&lt;br /&gt;
| SHA256 hash of the first (size of hashed region) bytes of filedata.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
The string table is 00-padded to align the start of raw filedata with a sector/media unit boundary (usually?).&lt;br /&gt;
&lt;br /&gt;
=Typical Cartridge Layout=&lt;br /&gt;
Observed gamecarts contain three partitions: &amp;quot;update&amp;quot;, &amp;quot;normal&amp;quot;, and &amp;quot;secure&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The update partition (Gamecard partition 0 for fsp-srv cmd 31) contains .cnmt.nca + .nca files for the entire system update required to play the game. Launch day carts contain a full copy of 1.0 ncas, newer carts contain newer sysupdate NCAs etc.&lt;br /&gt;
&lt;br /&gt;
The normal partition contains the .cnmt.nca and the game icondata nca. This is presumably for future compatibility so that if a future update changes the cryptographic protocol for the secure partition, Game icon data can still be shown in the home menu on old firmwares.&lt;br /&gt;
&lt;br /&gt;
The secure partition contains an identical copy of the .cnmt.nca and game icondata nca, as well as all other ncas required for the game.&lt;br /&gt;
&lt;br /&gt;
The entire rest of the gamecard after the secure partition ends is all FF padding.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=1848</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=1848"/>
		<updated>2017-07-31T23:08:47Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Updated with 3.0.1 information&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Like the 3DS, the Switch relies on a number of cryptographic keys to prevent unauthorized persons from dumping and analyzing its software and assets. This page will focus on the &amp;quot;symmetric&amp;quot; cryptography involved in the Switch&#039;s cryptosystem.&lt;br /&gt;
&lt;br /&gt;
== BootROM ==&lt;br /&gt;
&lt;br /&gt;
The Switch&#039;s BootROM does no symmetric cryptographic operations. However, it sets up two keys in the hardware security engine&#039;s keyslots: the SBK (Secure Boot Key) in keyslot 0xE and the SSK (Secure Storage Key) in keyslot 0xF. Reads from both of these keyslots are disabled by the bootROM. The material used to generate these keys is stored in special fuses that have their access disabled by the bootROM.&lt;br /&gt;
&lt;br /&gt;
The SBK is common to all consoles while the SSK is console unique. The SSK is not used on retail devices.&lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
&lt;br /&gt;
The falcon processor (TSEC) stores a special console-unique key (that will be referred to as the &amp;quot;device keyblob seed generation key&amp;quot;) in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 0 ==&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Cleared by&lt;br /&gt;
! Per-console&lt;br /&gt;
|-&lt;br /&gt;
| 0xB&lt;br /&gt;
| Pk11DecryptionKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 0xC&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 0xD&lt;br /&gt;
| ConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| Yes&lt;br /&gt;
|-&lt;br /&gt;
| 0xE&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 0xF&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Bootloader stage 0 generates three keys. Keyslot 0xB is cleared after it is used to decrypt the stage 2 bootloader; only keyslots 0xC and 0xD will be transferred to stage 2. Additionally, keyslots 0xC and 0xD are set read-only after they are generated. The SBK and the SSK are also cleared after use (although the SSK isn&#039;t used at all, except on dev units).&lt;br /&gt;
&lt;br /&gt;
The master static key is generated by decrypting the master static seed (a constant stored in bootloader .data) with the master static key encryption key. The master static seed used varies depending on whether the console is a retail unit or a dev unit.&lt;br /&gt;
Both the master static key encryption key and the stage 2 key are stored in a keyblob. The keyblob format is described [[Flash_Filesystem#Keyblob|here]].&lt;br /&gt;
&lt;br /&gt;
The 32 blobs are stored in the eMMC. Only one at a time is loaded, it is controlled by the bootloader version field in the BCT (at +0x2330).&lt;br /&gt;
&lt;br /&gt;
Although the keydata is presumably common to all consoles, each keyblob is console-unique, because the key used to encrypt it is at the factory is console unique. Each keyblob has its own encryption key, with keyblob key N generated by decrypting keyblob key seed N with the SBK, and keyblob key seed N generated by decrypting keyblob N&#039;s seed constant with the device keyblob seed generation key obtained from the Falcon. Keyblob key 1 is special: In addition to being used to decrypt keyblob 1, it is also used to generate the master device key by decrypting a constant block.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the seed constants for the keyblob loaded by the current revision and for keyblob 1 (So that the master device key can be generated). &lt;br /&gt;
&lt;br /&gt;
This mechanism provides several advantages. If the stage 2 bootloader is compromised, stage 1 can just use another master static key in the keyblob. If stage 1 itself is glitched or exploited in such a way the keyblob is dumped, Nintendo just has to change the loaded keyblob: the vulnerable bootloader won&#039;t be able to decrypt the new keyblob, as the keyblob key it knows is different from the one needed. Even if somehow an exploit or glitch allowed one to be able to use the SBK to generate keyblob keys, the seed constants for future keyblobs are unknown (and will be until Nintendo releases new bootloaders that use them), and so the exploit or glitch would have to be re-done on each new bootloader revision (if it&#039;s not patched).&lt;br /&gt;
&lt;br /&gt;
Dumping the fuses and TSEC key of any single system would effectively bypass all of the above security mechanisms.&lt;br /&gt;
&lt;br /&gt;
The key-derivation is described [[Package1#Key_generation|here]].&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 1 ==&lt;br /&gt;
&lt;br /&gt;
It is currently unknown what key generation the stage 2 bootloader does.&lt;br /&gt;
&lt;br /&gt;
== Secure Monitor ==&lt;br /&gt;
&lt;br /&gt;
The secure monitor performs some runtime cryptographic operations. See [[SMC]] for what operations it provides.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Package1&amp;diff=1847</id>
		<title>Package1</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Package1&amp;diff=1847"/>
		<updated>2017-07-31T23:08:25Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Updated with 3.0.1 information&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Nintendo Switch&#039;s bootloader (called &amp;quot;package1&amp;quot;) is the first custom piece of code running on the Switch. It is loaded in the IRAM and launched by the Tegra X1 bootROM according to the BCT. It runs on the boot processor, an ARM7TDMI called &amp;quot;BPMP&amp;quot; by NVidia (Boot and Power Management Processor).&lt;br /&gt;
It is split into two parts, one that is in plaintext, one that is encrypted. The bootROM does not perform any symmetric cryptographic operations on the bootloader it loads.&lt;br /&gt;
&lt;br /&gt;
== Stage 1 ==&lt;br /&gt;
&lt;br /&gt;
The first stage of the bootloader is the plaintext part of the bootloader. It has four goals: to power on devices, to look for incoherencies, to generate keys, and to decrypt and launch the second stage.&lt;br /&gt;
The stage 1 bootloader&#039;s authors knew that the code was in plaintext, and thus took extra care to try to protect the bootloader from side-channel attacks.&lt;br /&gt;
&lt;br /&gt;
=== Execution flow ===&lt;br /&gt;
&lt;br /&gt;
==== Startup ====&lt;br /&gt;
&lt;br /&gt;
After setting up the stack and branching to main, stage 1 poisons all the exception vectors to point at the panic function.&lt;br /&gt;
It then clears the (empty) bss and calls the functions in the (empty) init array.&lt;br /&gt;
&lt;br /&gt;
==== Main ====&lt;br /&gt;
&lt;br /&gt;
* Registers are setup&lt;br /&gt;
* A device (?) is powered on&lt;br /&gt;
* Flags are set on the clock-reset registers&lt;br /&gt;
* [3.0.0+] The security engine address is setup&lt;br /&gt;
* [3.0.0+] Bit30 of offset 0x800 of the security engine is checked: if set, panic.&lt;br /&gt;
* The SKU info is checked. If it doesn&#039;t match 0x83, panic.&lt;br /&gt;
* Fuse coherency is checked, potentially panicking.&lt;br /&gt;
* The copy of the BCT left by the bootROM is checked. If the version field doesn&#039;t match the expected version field, panic.&lt;br /&gt;
* Anti-downgrade fuses are checked, potentially panicking.&lt;br /&gt;
* [1.0.0-2.3.0] Fuse programming is disabled until next reboot.&lt;br /&gt;
* The memory controller is powered on and setup to allow GPU DMA to the IRAM. This will be needed to interact with the Falcon and with the security engine.&lt;br /&gt;
* [1.0.0-2.3.0] The security engine address is setup&lt;br /&gt;
* [1.0.0-2.3.0] Bit30 of offset 0x800 of the security engine is checked: if set, panic.&lt;br /&gt;
* Key generation is performed. If the unit type is equal to 0 (non-retail) AND if some fuse is clear, the secondary method will be used. Else, the main method will be used.&lt;br /&gt;
* Stage 2 is decrypted with keyslot 0xB. Keyslot 0xB is cleared, and the second stage&#039;s header validity is checked. If any of this fails, panic.&lt;br /&gt;
* The entrypoint of stage 2 is computed.&lt;br /&gt;
* The stack is pivoted to a secondary stack, the main stack and the key area are cleared, and stage 1 jumps to stage 2&#039;s entrypoint.&lt;br /&gt;
&lt;br /&gt;
==== Fuse coherency ====&lt;br /&gt;
&lt;br /&gt;
Unit type is computed from data from a fuse. It must be either 0 (non-retail) or 1 (retail). If it&#039;s neither, 2 will be returned by the function, and the check will call panic.&lt;br /&gt;
&lt;br /&gt;
==== Downgrade check ====&lt;br /&gt;
&lt;br /&gt;
The bootloader verifies a lockdown fuse counter to prevent downgrading. A 32-bit lockdown value at fuse offset 0x1E4 is checked. If too many fuses are burned the bootloader will panic. If too few are burned, the bootloader will program the expected number of bits and force a reset. The expected lockdown value differs between unit type 0 (non-retail) and unit type 1 (retail).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Expected number of burnt fuses (retail)&lt;br /&gt;
! Expected number of burnt fuses (non-retail)&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0&lt;br /&gt;
| 1&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0-2.3.0&lt;br /&gt;
| 2&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.1&lt;br /&gt;
| 4&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Panic ====&lt;br /&gt;
&lt;br /&gt;
The panic function does the following things:&lt;br /&gt;
* It clears the stack&lt;br /&gt;
* It disables(?) and clears the security engine&lt;br /&gt;
* It disables fuse programming&lt;br /&gt;
* It clears the key area&lt;br /&gt;
* It clears the data for stage 2&lt;br /&gt;
* It signals over the debug interface that a panic occurred until the Switch is reset.&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
For more detail on the Switch&#039;s Cryptosystem, please see [[Cryptosystem|this page]].&lt;br /&gt;
&lt;br /&gt;
In all cases, at the end of the key generation function three keys are generated: the stage 2 key (stored in keyslot 0xB), the master static key (stored in keyslot 0xC), and the master device key (stored in keyslot 0xD).&lt;br /&gt;
The two keys initialized by the bootROM (the SBK, stored in keyslot 0xE, and the SSK, stored in keyslot 0xF) are cleared immediately after the bootloader is finished using them.&lt;br /&gt;
Keyslots 0xC and 0xD are marked unreadable. Keyslot 0xB is not, but is is cleared by stage 1 after stage 2&#039;s decryption anyway.&lt;br /&gt;
&lt;br /&gt;
==== Main method ====&lt;br /&gt;
&lt;br /&gt;
This method is called when the unit type is equal to 1 (retail) OR when unit type is equal to 0 and some fuse is set. &lt;br /&gt;
&lt;br /&gt;
The master static seed selected depends on whether the unit type is zero and whether the last byte of the bootloader&#039;s RSA modulus is 0x4F.&lt;br /&gt;
&lt;br /&gt;
* Falcon microcode is loaded, the device keyblob seed generation key is obtained from the Falcon.&lt;br /&gt;
* The device keyblob seed generation key is stored in keyslot 0xD.&lt;br /&gt;
* [3.0.0+] keyblob key seed 1 is generated by decrypting the keyblob seed constant 1 with the device keyblob seed generation key&lt;br /&gt;
* [3.0.0+] keyblob key 1 is generated by decrypting keyblob key seed 1 with the SBK. The result is directly stored in keyslot 0xA without leaving the crypto engine.&lt;br /&gt;
* keyblob key seed N is generated by decrypting the keyblob seed constant N with the device keyblob seed generation key&lt;br /&gt;
* keyblob key N is generated by decrypting keyblob key seed N with the SBK. The result is directly stored in keyslot 0xD without leaving the crypto engine.&lt;br /&gt;
* The SBK and the SSK are cleared.&lt;br /&gt;
* The constant MAC key generator block is decrypted with keyblob key N to generate keyblob MAC key N. The result is directly stored in keyslot 0xB without leaving the crypto engine.&lt;br /&gt;
* With keyblob MAC key N, AES CMAC is performed over the keyblob.&lt;br /&gt;
* With a comparison function which is safe against timing attacks, the CMAC is compared with the stored CMAC. If they differ, panic is called.&lt;br /&gt;
* The keyblob data is decrypted with AES-CTR, using the keyblob key N and the stored CTR.&lt;br /&gt;
* The stage 2 decryption key (the ninth key in the blob) is loaded in keyslot 0xB.&lt;br /&gt;
* The master static key encryption key. is loaded in keyslot 0xC.&lt;br /&gt;
* The decrypted keyblob data is erased.&lt;br /&gt;
* The master static key is generated by decrypting the master static seed with the master static key encryption key. The result is directly stored in keyslot 0xC without leaving the crypto engine.&lt;br /&gt;
* [1.0.0-2.3.0] The master device key is generated by decrypting a constant block with keyslot 0xD (which contains keyblob N&#039;s key 1). The result is directly stored in keyslot 0xD without leaving the crypto engine.&lt;br /&gt;
* [3.0.0+] The master device key is generated by decrypting a constant block with keyslot 0xA (which contains keyblob 1&#039;s key 1). The result is directly stored in keyslot 0xD without leaving the crypto engine.&lt;br /&gt;
* [3.0.0+] Keyslot 0xA is cleared.&lt;br /&gt;
&lt;br /&gt;
==== Secondary method ====&lt;br /&gt;
&lt;br /&gt;
The secondary method (which is never launched on retail units) is very simple.&lt;br /&gt;
First a master static seed is selected (depending on whether the bootloader&#039;s RSA modulus ends with 0x11).&lt;br /&gt;
Then, a constant block is decrypted by the SBK. The result is the stage 2 key and will be stored in keyslot 0xB. &lt;br /&gt;
A constant block will be decrypted by the SBK and temporarily stored in keyslot 0xC. Another constant block will be decrypted by the SSK and temporarily stored in keyslot 0xD.&lt;br /&gt;
Both the SBK and the SSK are cleared.&lt;br /&gt;
The master static seed is decrypted with keyslot 0xC and stored in keyslot 0xC.&lt;br /&gt;
A constant block is decrypted with keyslot 0xD and stored in keyslot 0xD. &lt;br /&gt;
&lt;br /&gt;
== Stage 2 (package1.1) ==&lt;br /&gt;
&lt;br /&gt;
The second stage of the bootloader is the encrypted part of the bootloader. It is much bigger than stage 1, but what it does is currently unknown due to its being encrypted.&lt;br /&gt;
&lt;br /&gt;
=== Header format ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| Magic &amp;quot;PK11&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 8&lt;br /&gt;
| Unknown&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 2&lt;br /&gt;
|-&lt;br /&gt;
| 0x14&lt;br /&gt;
| 4&lt;br /&gt;
| Entrypoint of section 2&lt;br /&gt;
|-&lt;br /&gt;
| 0x18&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 1&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C&lt;br /&gt;
| 4&lt;br /&gt;
| Entrypoint of section 1?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Entrypoints are relative to the section.&lt;br /&gt;
Stage 1 jumps to the entrypoint of section 2.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=1801</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=1801"/>
		<updated>2017-07-26T15:55:31Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Like the 3DS, the Switch relies on a number of cryptographic keys to prevent unauthorized persons from dumping and analyzing its software and assets. This page will focus on the &amp;quot;symmetric&amp;quot; cryptography involved in the Switch&#039;s cryptosystem.&lt;br /&gt;
&lt;br /&gt;
== BootROM ==&lt;br /&gt;
&lt;br /&gt;
The Switch&#039;s BootROM does no symmetric cryptographic operations. However, it sets up two keys in the hardware security engine&#039;s keyslots: the SBK (Secure Boot Key) in keyslot 0xE and the SSK (Secure Storage Key) in keyslot 0xF. Reads from both of these keyslots are disabled by the bootROM. The material used to generate these keys is stored in special fuses that have their access disabled by the bootROM.&lt;br /&gt;
&lt;br /&gt;
The SBK is common to all consoles while the SSK is console unique. The SSK is not used on retail devices.&lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
&lt;br /&gt;
The falcon processor (TSEC) stores a special console-unique key (that will be referred to as the &amp;quot;device keyblob seed generation key&amp;quot;) in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 0 ==&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Keyslot&lt;br /&gt;
! Name&lt;br /&gt;
! Set by&lt;br /&gt;
! Cleared by&lt;br /&gt;
! Per-console&lt;br /&gt;
|-&lt;br /&gt;
| 0xB&lt;br /&gt;
| Pk11DecryptionKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 0xC&lt;br /&gt;
| MasterKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 0xD&lt;br /&gt;
| ConsoleKey&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Forever&lt;br /&gt;
| Yes&lt;br /&gt;
|-&lt;br /&gt;
| 0xE&lt;br /&gt;
| SecureBootKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| No&lt;br /&gt;
|-&lt;br /&gt;
| 0xF&lt;br /&gt;
| SecureStorageKey&lt;br /&gt;
| Bootrom&lt;br /&gt;
| [[Package1]]&lt;br /&gt;
| Yes&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Bootloader stage 0 generates three keys. Keyslot 0xB is cleared after it is used to decrypt the stage 2 bootloader; only keyslots 0xC and 0xD will be transferred to stage 2. Additionally, keyslots 0xC and 0xD are set read-only after they are generated. The SBK and the SSK are also cleared after use (although the SSK isn&#039;t used at all, except on dev units).&lt;br /&gt;
&lt;br /&gt;
The master static key is generated by decrypting the master static seed (a constant stored in bootloader .data) with the master static key encryption key. The master static seed used varies depending on whether the console is a retail unit or a dev unit.&lt;br /&gt;
Both the master static key encryption key and the stage 2 key are stored in a keyblob. The keyblob format is described [[Flash_Filesystem#Keyblob|here]].&lt;br /&gt;
&lt;br /&gt;
The 32 blobs are stored in the eMMC. Only one at a time is loaded, it is controlled by the bootloader version field in the BCT (at +0x2330).&lt;br /&gt;
&lt;br /&gt;
Although the keydata is presumably common to all consoles, each keyblob is console-unique, because the key used to encrypt it is at the factory is console unique. Each keyblob has its own encryption key, with keyblob key N generated by decrypting keyblob key seed N with the SBK, and keyblob key seed N generated by decrypting keyblob N&#039;s seed constant with the device keyblob seed generation key obtained from the Falcon. Keyblob key 1 is special: In addition to being used to decrypt keyblob 1, it is also used to generate the master device key by decrypting a constant block.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the seed constants for the keyblob loaded by the current revision and for keyblob 1 (So that the master device key can be generated). &lt;br /&gt;
&lt;br /&gt;
This mechanism provides several advantages. If the stage 2 bootloader is compromised, stage 1 can just use another master static key in the keyblob. If stage 1 itself is glitched or exploited in such a way the keyblob is dumped, Nintendo just has to change the loaded keyblob: the vulnerable bootloader won&#039;t be able to decrypt the new keyblob, as the keyblob key it knows is different from the one needed. Even if somehow an exploit or glitch allowed one to be able to use the SBK to generate keyblob keys, the seed constants for future keyblobs are unknown (and will be until Nintendo releases new bootloaders that use them), and so the exploit or glitch would have to be re-done on each new bootloader revision (if it&#039;s not patched).&lt;br /&gt;
&lt;br /&gt;
The key-derivation is described [[Package1#Key_generation|here]].&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 1 ==&lt;br /&gt;
&lt;br /&gt;
It is currently unknown what key generation the stage 2 bootloader does.&lt;br /&gt;
&lt;br /&gt;
== Secure world (TrustZone) software ==&lt;br /&gt;
&lt;br /&gt;
The Secure world software performs all runtime cryptographic operations.&lt;br /&gt;
&lt;br /&gt;
It is currently unknown what operations the Secure world software performs.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=1797</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=1797"/>
		<updated>2017-07-26T15:41:48Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: This info was moved in package1&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Like the 3DS, the Switch relies on a number of cryptographic keys to prevent unauthorized persons from dumping and analyzing its software and assets. This page will focus on the &amp;quot;symmetric&amp;quot; cryptography involved in the Switch&#039;s cryptosystem.&lt;br /&gt;
&lt;br /&gt;
== BootROM ==&lt;br /&gt;
&lt;br /&gt;
The Switch&#039;s BootROM does no symmetric cryptographic operations. However, it sets up two keys in the hardware security engine&#039;s keyslots: the SBK (Secure Boot Key) in keyslot 0xE and the SSK (Secure Storage Key) in keyslot 0xF. Reads from both of these keyslots are disabled by the bootROM. The material used to generate these keys is stored in special fuses that have their access disabled by the bootROM.&lt;br /&gt;
&lt;br /&gt;
The SBK is common to all consoles while the SSK is console unique. The SSK is not used on retail devices.&lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
&lt;br /&gt;
The falcon processor (TSEC) stores a special console-unique key (that will be referred to as the &amp;quot;device keyblob seed generation key&amp;quot;) in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 1 ==&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
&lt;br /&gt;
Bootloader stage 1 generates three keys: the stage 2 decryption key, stored in keyslot 0xB; the master static key, which will be used by stage 2 to generate all the static keys, stored in keyslot 0xC; and the master device key, which will be used by stage 2 to generate all the device-specific keys, stored in keyslot 0xD.&lt;br /&gt;
Keyslot 0xB is cleared after it is used to decrypt the stage 2 bootloader; only keyslots 0xC and 0xD will be transferred to stage 2. Additionally, keyslots 0xC and 0xD are set read-only after they are generated. The SBK and the SSK are also cleared after use (although the SSK isn&#039;t used at all, except on dev units).&lt;br /&gt;
&lt;br /&gt;
The master static key is generated by decrypting the master static seed (a constant stored in bootloader .data) with the master static key encryption key. The master static seed used varies depending on whether the console is a retail unit or a dev unit.&lt;br /&gt;
Both the master static key encryption key and the stage 2 key are stored in a keyblob. The keyblob format is described [[Flash_Filesystem#Keyblob|here]].&lt;br /&gt;
&lt;br /&gt;
32 of these blobs are stored in the eMMC. Only one at a time is loaded, it is controlled by the bootloader version field in the BCT (at +0x2330).&lt;br /&gt;
&lt;br /&gt;
Although the keydata is presumably common to all consoles, each keyblob is console-unique, because the key used to encrypt it is at the factory is console unique. Each keyblob has its own encryption key, with keyblob key N generated by decrypting keyblob key seed N with the SBK, and keyblob key seed N generated by decrypting keyblob N&#039;s seed constant with the device keyblob seed generation key obtained from the Falcon. Keyblob key 1 is special: In addition to being used to decrypt keyblob 1, it is also used to generate the master device key by decrypting a constant block.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the seed constants for the keyblob loaded by the current revision and for keyblob 1 (So that the master device key can be generated). &lt;br /&gt;
&lt;br /&gt;
This mechanism provides several advantages. If the stage 2 bootloader is compromised, stage 1 can just use another master static key in the keyblob. If stage 1 itself is glitched or exploited in such a way the keyblob is dumped, Nintendo just has to change the loaded keyblob: the vulnerable bootloader won&#039;t be able to decrypt the new keyblob, as the keyblob key it knows is different from the one needed. Even if somehow an exploit or glitch allowed one to be able to use the SBK to generate keyblob keys, the seed constants for future keyblobs are unknown (and will be until Nintendo releases new bootloaders that use them), and so the exploit or glitch would have to be re-done on each new bootloader revision (if it&#039;s not patched).&lt;br /&gt;
&lt;br /&gt;
==== Summary of key derivations ====&lt;br /&gt;
&lt;br /&gt;
The device keyblob seed generation key is unique to each device and obtained from the Falcon. It is used to generate one or several of the keyblob key seeds by decrypting keybloob&#039;s seed constants. The keyblob key seeds are decrypted by the SBK to create the keyblob keys.&lt;br /&gt;
Each keyblob key is used to decrypt its associated keyblob&#039;s keydata, and the keyblob key for the first keyblob is additionally used to generate the master device key.&lt;br /&gt;
Each keyblob stores 8 master static key encryption keys, and the stage 2 bootloader decryption key. The master static key is generated by decrypting the master static key seed (one of two constants depending on retail or dev unit) with the master static key encryption key.&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 2 ==&lt;br /&gt;
&lt;br /&gt;
It is currently unknown what key generation the stage 2 bootloader does.&lt;br /&gt;
&lt;br /&gt;
== Secure world (TrustZone) software ==&lt;br /&gt;
&lt;br /&gt;
The Secure world software performs all runtime cryptographic operations.&lt;br /&gt;
&lt;br /&gt;
It is currently unknown what operations the Secure world software performs.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Package1&amp;diff=1793</id>
		<title>Package1</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Package1&amp;diff=1793"/>
		<updated>2017-07-26T15:03:00Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Nintendo Switch&#039;s bootloader (called &amp;quot;package1&amp;quot;) is the first custom piece of code running on the Switch. It is loaded in the IRAM and launched by the Tegra X1 bootROM according to the BCT. It runs on the boot processor, an ARM7TDMI called &amp;quot;BPMP&amp;quot; by NVidia (Boot and Power Management Processor).&lt;br /&gt;
It is split into two parts, one that is in plaintext, one that is encrypted. The bootROM does not perform any symmetric cryptographic operations on the bootloader it loads.&lt;br /&gt;
&lt;br /&gt;
== Stage 1 ==&lt;br /&gt;
&lt;br /&gt;
The first stage of the bootloader is the plaintext part of the bootloader. It has four goals: to power on devices, to look for incoherencies, to generate keys, and to decrypt and launch the second stage.&lt;br /&gt;
The stage 1 bootloader&#039;s authors knew that the code was in plaintext, and thus took extra care to try to protect the bootloader from side-channel attacks.&lt;br /&gt;
&lt;br /&gt;
=== Execution flow ===&lt;br /&gt;
&lt;br /&gt;
==== Startup ====&lt;br /&gt;
&lt;br /&gt;
After setting up the stack and branching to main, stage 1 poisons all the exception vectors to point at the panic function.&lt;br /&gt;
It then clears the (empty) bss and calls the functions in the (empty) init array.&lt;br /&gt;
&lt;br /&gt;
==== Main ====&lt;br /&gt;
&lt;br /&gt;
* Registers are setup&lt;br /&gt;
* A device (?) is powered on&lt;br /&gt;
* Flags are set on the clock-reset registers&lt;br /&gt;
* [3.0.0+] The security engine address is setup&lt;br /&gt;
* [3.0.0+] Bit30 of offset 0x800 of the security engine is checked: if set, panic.&lt;br /&gt;
* The SKU info is checked. If it doesn&#039;t match 0x83, panic.&lt;br /&gt;
* Fuse coherency is checked, potentially panicking.&lt;br /&gt;
* The copy of the BCT left by the bootROM is checked. If the version field doesn&#039;t match the expected version field, panic.&lt;br /&gt;
* Anti-downgrade fuses are checked, potentially panicking.&lt;br /&gt;
* [1.0.0-2.3.0] Fuse programming is disabled until next reboot.&lt;br /&gt;
* The memory controller is powered on and setup to allow GPU DMA to the IRAM. This will be needed to interact with the Falcon and with the security engine.&lt;br /&gt;
* [1.0.0-2.3.0] The security engine address is setup&lt;br /&gt;
* [1.0.0-2.3.0] Bit30 of offset 0x800 of the security engine is checked: if set, panic.&lt;br /&gt;
* Key generation is performed. If the unit type is equal to 0 (non-retail) AND if some fuse is clear, the secondary method will be used. Else, the main method will be used.&lt;br /&gt;
* Stage 2 is decrypted with keyslot 0xB. Keyslot 0xB is cleared, and the second stage&#039;s header validity is checked. If any of this fails, panic.&lt;br /&gt;
* The entrypoint of stage 2 is computed.&lt;br /&gt;
* The stack is pivoted to a secondary stack, the main stack and the key area are cleared, and stage 1 jumps to stage 2&#039;s entrypoint.&lt;br /&gt;
&lt;br /&gt;
==== Fuse coherency ====&lt;br /&gt;
&lt;br /&gt;
Unit type is computed from data from a fuse. It must be either 0 (non-retail) or 1 (retail). If it&#039;s neither, 2 will be returned by the function, and the check will call panic.&lt;br /&gt;
&lt;br /&gt;
==== Downgrade check ====&lt;br /&gt;
&lt;br /&gt;
The bootloader will check if someone attempted to downgrade it. A fuse array will be checked, if too many fuses are burnt the bootloader will detect a downgrade attempt. The fuse array and the expected number of burnt fuses is different on unit type 0 (non-retail) and unit type 1 (retail).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Expected number of burnt fuses (retail)&lt;br /&gt;
! Expected number of burnt fuses (non-retail)&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0&lt;br /&gt;
| 1&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0-2.3.0&lt;br /&gt;
| 2&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Panic ====&lt;br /&gt;
&lt;br /&gt;
The panic function does the following things:&lt;br /&gt;
* It clears the stack&lt;br /&gt;
* It disables(?) and clears the security engine&lt;br /&gt;
* It sets a fuse (so that Nintendo knows that you attempted to mess with the bootloader)&lt;br /&gt;
* It clears the key area&lt;br /&gt;
* It clears the data for stage 2&lt;br /&gt;
* It signals over the debug interface that a panic occurred until the Switch is reset.&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
For more detail on the Switch&#039;s Cryptosystem, please see [[Cryptosystem|this page]].&lt;br /&gt;
&lt;br /&gt;
In all cases, at the end of the key generation function three keys are generated: the stage 2 key (stored in keyslot 0xB), the master static key (stored in keyslot 0xC), and the master device key (stored in keyslot 0xD).&lt;br /&gt;
The two keys initialized by the bootROM (the SBK, stored in keyslot 0xE, and the SSK, stored in keyslot 0xF) are cleared immediately after the bootloader is finished using them.&lt;br /&gt;
Keyslots 0xC and 0xD are marked unreadable. Keyslot 0xB is not, but is is cleared by stage 1 after stage 2&#039;s decryption anyway.&lt;br /&gt;
&lt;br /&gt;
==== Main method ====&lt;br /&gt;
&lt;br /&gt;
This method is called when the unit type is equal to 1 (retail) OR when unit type is equal to 0 and some fuse is set. &lt;br /&gt;
&lt;br /&gt;
The master static seed selected depends on whether the unit type is zero and whether the last byte of the bootloader&#039;s RSA modulus is 0x4F.&lt;br /&gt;
&lt;br /&gt;
This method is described on the [[Cryptosystem|cryptosystem]] page.&lt;br /&gt;
&lt;br /&gt;
==== Secondary method ====&lt;br /&gt;
&lt;br /&gt;
The secondary method (which is never launched on retail units) is very simple.&lt;br /&gt;
First a master static seed is selected (depending on whether the bootloader&#039;s RSA modulus ends with 0x11).&lt;br /&gt;
Then, a constant block is decrypted by the SBK. The result is the stage 2 key and will be stored in keyslot 0xB. &lt;br /&gt;
A constant block will be decrypted by the SBK and temporarily stored in keyslot 0xC. Another constant block will be decrypted by the SSK and temporarily stored in keyslot 0xD.&lt;br /&gt;
Both the SBK and the SSK are cleared.&lt;br /&gt;
The master static seed is decrypted with keyslot 0xC and stored in keyslot 0xC.&lt;br /&gt;
A constant block is decrypted with keyslot 0xD and stored in keyslot 0xD. &lt;br /&gt;
&lt;br /&gt;
== Stage 2 ==&lt;br /&gt;
&lt;br /&gt;
The second stage of the bootloader is the encrypted part of the bootloader. It is much bigger than stage 1, but what it does is currently unknown due to its being encryptd.&lt;br /&gt;
&lt;br /&gt;
=== Header format ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| Magic &amp;quot;PK11&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 8&lt;br /&gt;
| Unknown&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 2&lt;br /&gt;
|-&lt;br /&gt;
| 0x14&lt;br /&gt;
| 4&lt;br /&gt;
| Entrypoint of section 2&lt;br /&gt;
|-&lt;br /&gt;
| 0x18&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 1&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C&lt;br /&gt;
| 4&lt;br /&gt;
| Entrypoint of section 1?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Entrypoints are relative to the section.&lt;br /&gt;
Stage 1 jumps to the entrypoint of section 2.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Package1&amp;diff=1792</id>
		<title>Package1</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Package1&amp;diff=1792"/>
		<updated>2017-07-26T14:53:57Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Thanks hexkyz&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Nintendo Switch&#039;s bootloader (called &amp;quot;package1&amp;quot;) is the first custom piece of code running on the Switch. It is loaded in the IRAM and launched by the Tegra X1 bootROM according to the BCT. It runs on the boot processor, an ARM7TDMI called &amp;quot;BPMP&amp;quot; by NVidia (Boot and Power Management Processor).&lt;br /&gt;
It is split into two parts, one that is in plaintext, one that is encrypted. The bootROM does not perform any symmetric cryptographic operations on the bootloader it loads.&lt;br /&gt;
&lt;br /&gt;
== Stage 1 ==&lt;br /&gt;
&lt;br /&gt;
The first stage of the bootloader is the plaintext part of the bootloader. It has four goals: to power on devices, to look for incoherencies, to generate keys, and to decrypt and launch the second stage.&lt;br /&gt;
The stage 1 bootloader&#039;s authors knew that the code was in plaintext, and thus took extra care to try to protect the bootloader from side-channel attacks.&lt;br /&gt;
&lt;br /&gt;
=== Execution flow ===&lt;br /&gt;
&lt;br /&gt;
==== Startup ====&lt;br /&gt;
&lt;br /&gt;
After setting up the stack and branching to main, stage 1 poisons all the exception vectors to point at the panic function.&lt;br /&gt;
It then clears the (empty) bss and calls the functions in the (empty) init array.&lt;br /&gt;
&lt;br /&gt;
==== Main ====&lt;br /&gt;
&lt;br /&gt;
* Registers are setup&lt;br /&gt;
* A device (?) is powered on&lt;br /&gt;
* Flags are set on the clock-reset registers&lt;br /&gt;
* [3.0.0+] The security engine address is setup&lt;br /&gt;
* [3.0.0+] Bit30 of offset 0x800 of the security engine is checked: if set, panic.&lt;br /&gt;
* The SKU info is checked. If it doesn&#039;t match 0x83, panic.&lt;br /&gt;
* Fuse coherency is checked, potentially panicking.&lt;br /&gt;
* The copy of the BCT left by the bootROM is checked. If the version field doesn&#039;t match the expected version field, panic.&lt;br /&gt;
* Anti-downgrade fuses are checked, potentially panicking.&lt;br /&gt;
* [1.0.0-2.3.0] Fuse programming is disabled until next reboot.&lt;br /&gt;
* The memory controller is powered on and setup to allow GPU DMA to the IRAM. This will be needed to interact with the Falcon.&lt;br /&gt;
* [1.0.0-2.3.0] The security engine address is setup&lt;br /&gt;
* [1.0.0-2.3.0] Bit30 of offset 0x800 of the security engine is checked: if set, panic.&lt;br /&gt;
* Key generation is performed. If the unit type is equal to 0 (non-retail) AND if some fuse is clear, the secondary method will be used. Else, the main method will be used.&lt;br /&gt;
* Stage 2 is decrypted with keyslot 0xB. Keyslot 0xB is cleared, and the second stage&#039;s header validity is checked. If any of this fails, panic.&lt;br /&gt;
* The entrypoint of stage 2 is computed.&lt;br /&gt;
* The stack is pivoted to a secondary stack, the main stack and the key area are cleared, and stage 1 jumps to stage 2&#039;s entrypoint.&lt;br /&gt;
&lt;br /&gt;
==== Fuse coherency ====&lt;br /&gt;
&lt;br /&gt;
Unit type is computed from data from a fuse. It must be either 0 (non-retail) or 1 (retail). If it&#039;s neither, 2 will be returned by the function, and the check will call panic.&lt;br /&gt;
&lt;br /&gt;
==== Downgrade check ====&lt;br /&gt;
&lt;br /&gt;
The bootloader will check if someone attempted to downgrade it. A fuse array will be checked, if too many fuses are burnt the bootloader will detect a downgrade attempt. The fuse array and the expected number of burnt fuses is different on unit type 0 (non-retail) and unit type 1 (retail).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Expected number of burnt fuses (retail)&lt;br /&gt;
! Expected number of burnt fuses (non-retail)&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0&lt;br /&gt;
| 1&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0-2.3.0&lt;br /&gt;
| 2&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Panic ====&lt;br /&gt;
&lt;br /&gt;
The panic function does the following things:&lt;br /&gt;
* It clears the stack&lt;br /&gt;
* It disables(?) and clears the security engine&lt;br /&gt;
* It sets a fuse (so that Nintendo knows that you attempted to mess with the bootloader)&lt;br /&gt;
* It clears the key area&lt;br /&gt;
* It clears the data for stage 2&lt;br /&gt;
* It signals over the debug interface that a panic occurred until the Switch is reset.&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
For more detail on the Switch&#039;s Cryptosystem, please see [[Cryptosystem|this page]].&lt;br /&gt;
&lt;br /&gt;
In all cases, at the end of the key generation function three keys are generated: the stage 2 key (stored in keyslot 0xB), the master static key (stored in keyslot 0xC), and the master device key (stored in keyslot 0xD).&lt;br /&gt;
The two keys initialized by the bootROM (the SBK, stored in keyslot 0xE, and the SSK, stored in keyslot 0xF) are cleared immediately after the bootloader is finished using them.&lt;br /&gt;
Keyslots 0xC and 0xD are marked unreadable. Keyslot 0xB is not, but is is cleared by stage 1 after stage 2&#039;s decryption anyway.&lt;br /&gt;
&lt;br /&gt;
==== Main method ====&lt;br /&gt;
&lt;br /&gt;
This method is called when the unit type is equal to 1 (retail) OR when unit type is equal to 0 and some fuse is set. &lt;br /&gt;
&lt;br /&gt;
The master static seed selected depends on whether the unit type is zero and whether the last byte of the bootloader&#039;s RSA modulus is 0x4F.&lt;br /&gt;
&lt;br /&gt;
This method is described on the [[Cryptosystem|cryptosystem]] page.&lt;br /&gt;
&lt;br /&gt;
==== Secondary method ====&lt;br /&gt;
&lt;br /&gt;
The secondary method (which is never launched on retail units) is very simple.&lt;br /&gt;
First a master static seed is selected (depending on whether the bootloader&#039;s RSA modulus ends with 0x11).&lt;br /&gt;
Then, a constant block is decrypted by the SBK. The result is the stage 2 key and will be stored in keyslot 0xB. &lt;br /&gt;
A constant block will be decrypted by the SBK and temporarily stored in keyslot 0xC. Another constant block will be decrypted by the SSK and temporarily stored in keyslot 0xD.&lt;br /&gt;
Both the SBK and the SSK are cleared.&lt;br /&gt;
The master static seed is decrypted with keyslot 0xC and stored in keyslot 0xC.&lt;br /&gt;
A constant block is decrypted with keyslot 0xD and stored in keyslot 0xD. &lt;br /&gt;
&lt;br /&gt;
== Stage 2 ==&lt;br /&gt;
&lt;br /&gt;
The second stage of the bootloader is the encrypted part of the bootloader. It is much bigger than stage 1, but what it does is currently unknown due to its being encryptd.&lt;br /&gt;
&lt;br /&gt;
=== Header format ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| Magic &amp;quot;PK11&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 8&lt;br /&gt;
| Unknown&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 2&lt;br /&gt;
|-&lt;br /&gt;
| 0x14&lt;br /&gt;
| 4&lt;br /&gt;
| Entrypoint of section 2&lt;br /&gt;
|-&lt;br /&gt;
| 0x18&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 1&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C&lt;br /&gt;
| 4&lt;br /&gt;
| Entrypoint of section 1?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Entrypoints are relative to the section.&lt;br /&gt;
Stage 1 jumps to the entrypoint of section 2.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Package1&amp;diff=1787</id>
		<title>Package1</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Package1&amp;diff=1787"/>
		<updated>2017-07-26T14:25:46Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Thanks to SciresM for help with writing this page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Nintendo Switch&#039;s bootloader (called &amp;quot;package1&amp;quot;) is the first custom piece of code running on the Switch. It is loaded in the IRAM and launched by the Tegra X1 bootROM according to the BCT. It runs on the boot processor, an ARM7TDMI called &amp;quot;BPMP&amp;quot; by NVidia (Boot and Power Management Processor).&lt;br /&gt;
It is split into two parts, one that is in plaintext, one that is encrypted. The bootROM does not perform any symmetric cryptographic operations on the bootloader it loads.&lt;br /&gt;
&lt;br /&gt;
== Stage 1 ==&lt;br /&gt;
&lt;br /&gt;
The first stage of the bootloader is the plaintext part of the bootloader. It has four goals: to power on devices, to look for incoherencies, to generate keys, and to decrypt and launch the second stage.&lt;br /&gt;
The stage 1 bootloader&#039;s authors knew that the code was in plaintext, and thus took extra care to try to protect the bootloader from side-channel attacks.&lt;br /&gt;
&lt;br /&gt;
=== Execution flow ===&lt;br /&gt;
&lt;br /&gt;
==== Startup ====&lt;br /&gt;
&lt;br /&gt;
After setting up the stack and branching to main, stage 1 poisons all the exception vectors to point at the panic function.&lt;br /&gt;
It then clears the (empty) bss and calls the functions in the (empty) init array.&lt;br /&gt;
&lt;br /&gt;
==== Main ====&lt;br /&gt;
&lt;br /&gt;
* Registers are setup&lt;br /&gt;
* A device (?) is powered on&lt;br /&gt;
* Flags are set on the clock-reset registers&lt;br /&gt;
* [3.0.0+] The security engine address is setup&lt;br /&gt;
* [3.0.0+] Bit30 of offset 0x800 of the security engine is checked: if set, panic.&lt;br /&gt;
* The SKU info is checked. If it doesn&#039;t match 0x83, panic.&lt;br /&gt;
* Fuse coherency is checked, potentially panicking.&lt;br /&gt;
* The copy of the BCT left by the bootROM is checked. If the version field doesn&#039;t match the expected version field, panic.&lt;br /&gt;
* Anti-downgrade fuses are checked, potentially panicking.&lt;br /&gt;
* [1.0.0-2.3.0] Some fuse is written to.&lt;br /&gt;
* The memory controller is powered on and setup to allow GPU DMA to the IRAM. This will be needed to interact with the Falcon.&lt;br /&gt;
* [1.0.0-2.3.0] The security engine address is setup&lt;br /&gt;
* [1.0.0-2.3.0] Bit30 of offset 0x800 of the security engine is checked: if set, panic.&lt;br /&gt;
* Key generation is performed. If the unit type is equal to 0 (non-retail) AND if some fuse is clear, the secondary method will be used. Else, the main method will be used.&lt;br /&gt;
* Stage 2 is decrypted with keyslot 0xB. Keyslot 0xB is cleared, and the second stage&#039;s header validity is checked. If any of this fails, panic.&lt;br /&gt;
* The entrypoint of stage 2 is computed.&lt;br /&gt;
* The stack is pivoted to a secondary stack, the main stack and the key area are cleared, and stage 1 jumps to stage 2&#039;s entrypoint.&lt;br /&gt;
&lt;br /&gt;
==== Fuse coherency ====&lt;br /&gt;
&lt;br /&gt;
Unit type is computed from data from a fuse. It must be either 0 (non-retail) or 1 (retail). If it&#039;s neither, 2 will be returned by the function, and the check will call panic.&lt;br /&gt;
&lt;br /&gt;
==== Downgrade check ====&lt;br /&gt;
&lt;br /&gt;
The bootloader will check if someone attempted to downgrade it. A fuse array will be checked, if too many fuses are burnt the bootloader will detect a downgrade attempt. The fuse array and the expected number of burnt fuses is different on unit type 0 (non-retail) and unit type 1 (retail).&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Expected number of burnt fuses (retail)&lt;br /&gt;
! Expected number of burnt fuses (non-retail)&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0&lt;br /&gt;
| 1&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 2.0.0-2.3.0&lt;br /&gt;
| 2&lt;br /&gt;
| 0&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 3&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
==== Panic ====&lt;br /&gt;
&lt;br /&gt;
The panic function does the following things:&lt;br /&gt;
* It clears the stack&lt;br /&gt;
* It disables(?) and clears the security engine&lt;br /&gt;
* It sets a fuse (so that Nintendo knows that you attempted to mess with the bootloader)&lt;br /&gt;
* It clears the key area&lt;br /&gt;
* It clears the data for stage 2&lt;br /&gt;
* It signals over the debug interface that a panic occurred until the Switch is reset.&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
For more detail on the Switch&#039;s Cryptosystem, please see [[Cryptosystem|this page]].&lt;br /&gt;
&lt;br /&gt;
In all cases, at the end of the key generation function three keys are generated: the stage 2 key (stored in keyslot 0xB), the master static key (stored in keyslot 0xC), and the master device key (stored in keyslot 0xD).&lt;br /&gt;
The two keys initialized by the bootROM (the SBK, stored in keyslot 0xE, and the SSK, stored in keyslot 0xF) are cleared immediately after the bootloader is finished using them.&lt;br /&gt;
Keyslots 0xC and 0xD are marked unreadable. Keyslot 0xB is not, but is is cleared by stage 1 after stage 2&#039;s decryption anyway.&lt;br /&gt;
&lt;br /&gt;
==== Main method ====&lt;br /&gt;
&lt;br /&gt;
This method is called when the unit type is equal to 1 (retail) OR when unit type is equal to 0 and some fuse is set. &lt;br /&gt;
&lt;br /&gt;
The master static seed selected depends on whether the unit type is zero and whether the last byte of the bootloader&#039;s RSA modulus is 0x4F.&lt;br /&gt;
&lt;br /&gt;
This method is described on the [[Cryptosystem|cryptosystem]] page.&lt;br /&gt;
&lt;br /&gt;
==== Secondary method ====&lt;br /&gt;
&lt;br /&gt;
The secondary method (which is never launched on retail units) is very simple.&lt;br /&gt;
First a master static seed is selected (depending on whether the bootloader&#039;s RSA modulus ends with 0x11).&lt;br /&gt;
Then, a constant block is decrypted by the SBK. The result is the stage 2 key and will be stored in keyslot 0xB. &lt;br /&gt;
A constant block will be decrypted by the SBK and temporarily stored in keyslot 0xC. Another constant block will be decrypted by the SSK and temporarily stored in keyslot 0xD.&lt;br /&gt;
Both the SBK and the SSK are cleared.&lt;br /&gt;
The master static seed is decrypted with keyslot 0xC and stored in keyslot 0xC.&lt;br /&gt;
A constant block is decrypted with keyslot 0xD and stored in keyslot 0xD. &lt;br /&gt;
&lt;br /&gt;
== Stage 2 ==&lt;br /&gt;
&lt;br /&gt;
The second stage of the bootloader is the encrypted part of the bootloader. It is much bigger than stage 1, but what it does is currently unknown due to its being encryptd.&lt;br /&gt;
&lt;br /&gt;
=== Header format ===&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 4&lt;br /&gt;
| Magic &amp;quot;PK11&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
| 0x4&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 3&lt;br /&gt;
|-&lt;br /&gt;
| 0x8&lt;br /&gt;
| 8&lt;br /&gt;
| Unknown&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 2&lt;br /&gt;
|-&lt;br /&gt;
| 0x14&lt;br /&gt;
| 4&lt;br /&gt;
| Entrypoint of section 2&lt;br /&gt;
|-&lt;br /&gt;
| 0x18&lt;br /&gt;
| 4&lt;br /&gt;
| Size of section 1&lt;br /&gt;
|-&lt;br /&gt;
| 0x1C&lt;br /&gt;
| 4&lt;br /&gt;
| Entrypoint of section 1?&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Entrypoints are relative to the section.&lt;br /&gt;
Stage 1 jumps to the entrypoint of section 2.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
	<entry>
		<id>https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=1784</id>
		<title>Cryptosystem</title>
		<link rel="alternate" type="text/html" href="https://switchbrew.org/w/index.php?title=Cryptosystem&amp;diff=1784"/>
		<updated>2017-07-26T14:19:41Z</updated>

		<summary type="html">&lt;p&gt;Motezazer: Thanks to SciresM for helping with writing this page&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Like the 3DS, the Switch relies on a number of cryptographic keys to prevent unauthorized persons from dumping and analyzing its software and assets. This page will focus on the &amp;quot;symmetric&amp;quot; cryptography involved in the Switch&#039;s cryptosystem.&lt;br /&gt;
&lt;br /&gt;
== BootROM ==&lt;br /&gt;
&lt;br /&gt;
The Switch&#039;s BootROM does no symmetric cryptographic operations. However, it sets up two keys in the hardware security engine&#039;s keyslots: the SBK (Secure Boot Key) in keyslot 0xE and the SSK (Secure Storage Key) in keyslot 0xF. Reads from both of these keyslots are disabled by the bootROM. The material used to generate these keys is stored in special fuses that have their access disabled by the bootROM.&lt;br /&gt;
&lt;br /&gt;
The SBK is common to all consoles while the SSK is console unique. The SSK is not used on retail devices.&lt;br /&gt;
== Falcon coprocessor ==&lt;br /&gt;
&lt;br /&gt;
The falcon processor (TSEC) stores a special console-unique key (that will be referred to as the &amp;quot;device keyblob seed generation key&amp;quot;) in fuses that only microcode authenticated by NVidia has access to.&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 1 ==&lt;br /&gt;
&lt;br /&gt;
=== Key generation ===&lt;br /&gt;
&lt;br /&gt;
Bootloader stage 1 generates three keys: the stage 2 decryption key, stored in keyslot 0xB; the master static key, which will be used by stage 2 to generate all the static keys, stored in keyslot 0xC; and the master device key, which will be used by stage 2 to generate all the device-specific keys, stored in keyslot 0xD.&lt;br /&gt;
Keyslot 0xB is cleared after it is used to decrypt the stage 2 bootloader; only keyslots 0xC and 0xD will be transferred to stage 2. Additionally, keyslots 0xC and 0xD are set read-only after they are generated. The SBK and the SSK are also cleared after use (although the SSK isn&#039;t used at all, except on dev units).&lt;br /&gt;
&lt;br /&gt;
The master static key is generated by decrypting the master static seed (a constant stored in bootloader .data) with the master static key encryption key. The master static seed used varies depending on whether the console is a retail unit or a dev unit.&lt;br /&gt;
Both the master static key encryption key and the stage 2 key are stored in a keyblob. The following table describes the keyblob format.&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x10&lt;br /&gt;
| AES-CMAC over the next 0xA0 bytes&lt;br /&gt;
|-&lt;br /&gt;
| 0x10&lt;br /&gt;
| 0x10&lt;br /&gt;
| CTR&lt;br /&gt;
|-&lt;br /&gt;
| 0x20&lt;br /&gt;
| 0x90&lt;br /&gt;
| Encrypted keydata&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Decrypted Keydata format:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! Offset&lt;br /&gt;
! Size&lt;br /&gt;
! Description&lt;br /&gt;
|-&lt;br /&gt;
| 0x0&lt;br /&gt;
| 0x80&lt;br /&gt;
| Array of master static key encryption keys&lt;br /&gt;
|-&lt;br /&gt;
| 0x80&lt;br /&gt;
| 0x10 &lt;br /&gt;
| Stage 2 key&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
32 of these blobs are stored in the eMMC. Only one at a time is loaded, it is controlled by the bootloader version field in the BCT (at +0x2330).&lt;br /&gt;
&lt;br /&gt;
Although the keydata is presumably common to all consoles, each keyblob is console-unique, because the key used to encrypt it is at the factory is console unique. Each keyblob has its own encryption key, with keyblob key N generated by decrypting keyblob key seed N with the SBK, and keyblob key seed N generated by decrypting keyblob N&#039;s seed constant with the device keyblob seed generation key obtained from the Falcon. Keyblob key 1 is special: In addition to being used to decrypt keyblob 1, it is also used to generate the master device key by decrypting a constant block.&lt;br /&gt;
&lt;br /&gt;
The key used to verify a keyblob&#039;s MAC is not the keyblob key but a key derived from it; this is likely part of an attempt to mitigate side-channel attacks as the MAC is an alterable part of the keyblob.&lt;br /&gt;
&lt;br /&gt;
The bootloader only stores the seed constants for the keyblob loaded by the current revision and for keyblob 1 (So that the master device key can be generated). &lt;br /&gt;
&lt;br /&gt;
This mechanism provides several advantages. If the stage 2 bootloader is compromised, stage 1 can just use another master static key in the keyblob. If stage 1 itself is glitched or exploited in such a way the keyblob is dumped, Nintendo just has to change the loaded keyblob: the vulnerable bootloader won&#039;t be able to decrypt the new keyblob, as the keyblob key it knows is different from the one needed. Even if somehow an exploit or glitch allowed one to be able to use the SBK to generate keyblob keys, the seed constants for future keyblobs are unknown (and will be until Nintendo releases new bootloaders that use them), and so the exploit or glitch would have to be re-done on each new bootloader revision (if it&#039;s not patched).&lt;br /&gt;
&lt;br /&gt;
==== Summary of key derivations ====&lt;br /&gt;
&lt;br /&gt;
The device keyblob seed generation key is unique to each device and obtained from the Falcon. It is used to generate one or several of the keyblob key seeds by decrypting keybloob&#039;s seed constants. The keyblob key seeds are decrypted by the SBK to create the keyblob keys.&lt;br /&gt;
Each keyblob key is used to decrypt its associated keyblob&#039;s keydata, and the keyblob key for the first keyblob is additionally used to generate the master device key.&lt;br /&gt;
Each keyblob stores 8 master static key encryption keys, and the stage 2 bootloader decryption key. The master static key is generated by decrypting the master static key seed (one of two constants depending on retail or dev unit) with the master static key encryption key.&lt;br /&gt;
&lt;br /&gt;
=== Step by step generation code ===&lt;br /&gt;
&lt;br /&gt;
* Falcon microcode is loaded, the device keyblob seed generation key is obtained from the Falcon.&lt;br /&gt;
* The device keyblob seed generation key is stored in keyslot 0xD.&lt;br /&gt;
* [3.0.0+] keyblob key seed 1 is generated by decrypting the keyblob seed constant 1 with the device keyblob seed generation key&lt;br /&gt;
* [3.0.0+] keyblob key 1 is generated by decrypting keyblob key seed 1 with the SBK. The result is directly stored in keyslot 0xA without leaving the crypto engine.&lt;br /&gt;
* keyblob key seed N is generated by decrypting the keyblob seed constant N with the device keyblob seed generation key&lt;br /&gt;
* keyblob key N is generated by decrypting keyblob key seed N with the SBK. The result is directly stored in keyslot 0xD without leaving the crypto engine.&lt;br /&gt;
* The SBK and the SSK are cleared.&lt;br /&gt;
* The constant MAC key generator block is decrypted with keyblob key N to generate keyblob MAC key N. The result is directly stored in keyslot 0xB without leaving the crypto engine.&lt;br /&gt;
* With keyblob MAC key N, AES CMAC is performed over the keyblob.&lt;br /&gt;
* With a comparison function which is safe against timing attacks, the CMAC is compared with the stored CMAC. If they differ, panic is called.&lt;br /&gt;
* The keyblob data is decrypted with AES-CTR, using the keyblob key N and the stored CTR.&lt;br /&gt;
* The stage 2 decryption key (the ninth key in the blob) is loaded in keyslot 0xB.&lt;br /&gt;
* The master static key encryption key. is loaded in keyslot 0xC.&lt;br /&gt;
* The decrypted keyblob data is erased.&lt;br /&gt;
* The master static key is generated by decrypting the master static seed with the master static key encryption key. The result is directly stored in keyslot 0xC without leaving the crypto engine.&lt;br /&gt;
* [1.0.0-2.3.0] The master device key is generated by decrypting a constant block with keyslot 0xD (which contains keyblob N&#039;s key 1). The result is directly stored in keyslot 0xD without leaving the crypto engine.&lt;br /&gt;
* [3.0.0+] The master device key is generated by decrypting a constant block with keyslot 0xA (which contains keyblob 1&#039;s key 1). The result is directly stored in keyslot 0xD without leaving the crypto engine.&lt;br /&gt;
* [3.0.0+] Keyslot 0xA is cleared.&lt;br /&gt;
&lt;br /&gt;
==== Table of used keyblobs ====&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot; border=&amp;quot;1&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
! System version&lt;br /&gt;
! Used keyblob&lt;br /&gt;
! Used master static key encryption key in keyblob&lt;br /&gt;
|-&lt;br /&gt;
| 1.0.0-2.3.0&lt;br /&gt;
| 1&lt;br /&gt;
| 1&lt;br /&gt;
|-&lt;br /&gt;
| 3.0.0&lt;br /&gt;
| 2&lt;br /&gt;
| 1&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Bootloader stage 2 ==&lt;br /&gt;
&lt;br /&gt;
It is currently unknown what key generation the stage 2 bootloader does.&lt;br /&gt;
&lt;br /&gt;
== Secure world (TrustZone) software ==&lt;br /&gt;
&lt;br /&gt;
The Secure world software performs all runtime cryptographic operations.&lt;br /&gt;
&lt;br /&gt;
It is currently unknown what operations the Secure world software performs.&lt;/div&gt;</summary>
		<author><name>Motezazer</name></author>
	</entry>
</feed>