Difference between revisions of "NCCH/Extended Header"
(23 intermediate revisions by 10 users not shown) | |||
Line 1: | Line 1: | ||
− | This page documents the format of the '''NCCH Extended Header''' | + | This page documents the format of the '''NCCH Extended Header''', or '''exheader''' for short. |
− | The exheader | + | The exheader has two sections: |
− | * The actual exheader data, containing System Control Info and Access Control Info | + | |
− | * | + | * The actual exheader data, containing System Control Info (SCI) and Access Control Info (ACI); |
+ | * A signed copy of NCCH HDR public key, and exheader ACI. This version of the ACI is used as limitation to the actual ACI. | ||
== Main Structure == | == Main Structure == | ||
All values are little endian unless otherwise specified. | All values are little endian unless otherwise specified. | ||
− | See also: [https://github.com/ | + | See also: [https://github.com/3DSGuy/Project_CTR/blob/20f708450b9c6e7f64eafa6c2a8eeb25a630c69a/ctrtool/exheader.h] |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>0x200</code> |
− | | | + | | SCI |
|- | |- | ||
− | | | + | | <code>0x200</code> |
− | | | + | | <code>0x200</code> |
− | | | + | | ACI |
|- | |- | ||
− | | | + | | <code>0x400</code> |
− | | | + | | <code>0x100</code> |
− | | | + | | <code>AccessDesc</code> signature (RSA-2048-SHA256) |
|- | |- | ||
− | | | + | | <code>0x500</code> |
− | | | + | | <code>0x100</code> |
− | | | + | | NCCH HDR RSA-2048 public key |
|- | |- | ||
− | | | + | | <code>0x600</code> |
− | | | + | | <code>0x200</code> |
− | | | + | | ACI (for limitation of first ACI) |
|} | |} | ||
− | The AccessDesc | + | The <code>AccessDesc</code> signature covers the NCCH HDR public key and second ACI. The <code>AccessDesc</code> public key is initialised by the boot ROM. |
− | When loading the exheader, [[FIRM|Process9]] compares the exheader data with the data in the | + | When loading the exheader, [[FIRM|Process9]] compares the exheader data with the data in the <code>AccessDesc</code> (note that not everything is compared here). When these don't match, an error is returned. The Process9 code handling this validation was updated with [[6.0.0-11|v6.0]]; the only change in this function seems to be the check for the "Ideal processor" field. |
== System Control Info == | == System Control Info == | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>0x8</code> |
− | | | + | | Application title (default is "CtrApp") |
|- | |- | ||
− | | | + | | <code>0x8</code> |
− | | | + | | <code>0x5</code> |
− | | | + | | Reserved |
|- | |- | ||
− | | | + | | <code>0xD</code> |
− | | | + | | <code>0x1</code> |
− | | | + | | Flag (bit 0: <code>CompressExefsCode</code>, bit 1: <code>SDApplication</code>) |
|- | |- | ||
− | | | + | | <code>0xE</code> |
− | | | + | | <code>0x2</code> |
− | | | + | | Remaster version |
|- | |- | ||
− | | | + | | <code>0x10</code> |
− | | | + | | <code>0xC</code> |
− | | | + | | Text code set info |
|- | |- | ||
− | | | + | | <code>0x1C</code> |
− | | | + | | <code>0x4</code> |
− | | | + | | Stack size |
|- | |- | ||
− | | | + | | <code>0x20</code> |
− | | | + | | <code>0xC</code> |
− | | | + | | Read-only code set info |
|- | |- | ||
− | | | + | | <code>0x2C</code> |
− | | | + | | <code>0x4</code> |
− | | | + | | Reserved |
|- | |- | ||
− | | | + | | <code>0x30</code> |
− | | | + | | <code>0xC</code> |
− | | | + | | Data code set info |
|- | |- | ||
− | | | + | | <code>0x3C</code> |
− | | | + | | <code>0x4</code> |
− | | | + | | BSS size |
|- | |- | ||
− | | | + | | <code>0x40</code> |
− | | | + | | <code>0x180</code> (<code>48*8</code>) |
− | | | + | | Dependency [[Title list#00040130 - System Modules|module]] (program ID) list |
|- | |- | ||
− | | | + | | <code>0x1C0</code> |
− | | | + | | <code>0x40</code> |
− | | | + | | <code>SystemInfo</code> |
|} | |} | ||
Line 102: | Line 103: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>4</code> |
− | | | + | | Address |
|- | |- | ||
− | | | + | | <code>0x4</code> |
− | | | + | | <code>4</code> |
− | | | + | | Physical region size (in page-multiples) |
|- | |- | ||
− | | | + | | <code>0x8</code> |
− | | | + | | <code>4</code> |
− | | | + | | Size (in bytes) |
|} | |} | ||
Line 122: | Line 123: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>0x8</code> |
− | | | + | | <code>SaveData</code> Size |
|- | |- | ||
− | | | + | | <code>0x8</code> |
− | | | + | | <code>0x8</code> |
− | | | + | | Jump ID |
|- | |- | ||
− | | | + | | <code>0x10</code> |
− | | | + | | <code>0x30</code> |
− | | | + | | Reserved |
|} | |} | ||
Line 142: | Line 143: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>0x170</code> |
− | | | + | | [[#ARM11 Local System Capabilities|ARM11 local system capabilities]] |
|- | |- | ||
− | | | + | | <code>0x170</code> |
− | | | + | | <code>0x80</code> |
− | | | + | | [[#ARM11 Kernel Capabilities|ARM11 kernel capabilities]] |
|- | |- | ||
− | | | + | | <code>0x1F0</code> |
− | | | + | | <code>0x10</code> |
− | | | + | | [[#ARM9 Access Control|ARM9 access control]] |
|} | |} | ||
Line 162: | Line 163: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>0x8</code> |
− | | | + | | Program ID |
|- | |- | ||
− | | | + | | <code>0x8</code> |
− | | | + | | <code>0x4</code> |
− | | | + | | Core version (The Title ID low of the required [[FIRM]]) |
|- | |- | ||
− | | | + | | <code>0xC</code> |
− | | | + | | <code>0x2</code> |
− | | | + | | [[#Flag1|Flag1]] and [[#Flag2|Flag2]] (both implemented starting from [[8.0.0-18]]). |
|- | |- | ||
− | | | + | | <code>0xE</code> |
− | | | + | | <code>0x1</code> |
− | | | + | | [[#Flag0|Flag0]] |
|- | |- | ||
− | | | + | | <code>0xF</code> |
− | | | + | | <code>0x1</code> |
− | | | + | | Priority |
|- | |- | ||
− | | | + | | <code>0x10</code> |
− | | | + | | <code>0x20</code> (<code>16*2</code>) |
− | | | + | | Resource limit descriptors. The first byte here controls the maximum allowed [[PMApp:SetAppResourceLimit|<code>CpuTime</code>]]. |
|- | |- | ||
− | | | + | | <code>0x30</code> |
− | | | + | | <code>0x20</code> |
− | | | + | | [[#Storage Info|Storage info]] |
|- | |- | ||
− | | | + | | <code>0x50</code> |
− | | | + | | <code>0x100</code> (<code>32*8</code>) |
− | | | + | | [[#Service Access Control|Service access control]] |
|- | |- | ||
− | | | + | | <code>0x150</code> |
− | | | + | | <code>0x10</code> (<code>2*8</code>) |
− | | | + | | Extended service access control, support for this was implemented with [[9.3.0-21|9.3.0-X]]. |
|- | |- | ||
− | | | + | | <code>0x160</code> |
− | | | + | | <code>0xF</code> |
− | | | + | | Reserved |
|- | |- | ||
− | | | + | | <code>0x16F</code> |
− | | | + | | <code>0x1</code> |
− | | | + | | Resource limit category. (0 = <code>APPLICATION</code>, 1 = <code>SYS_APPLET</code>, 2 = <code>LIB_APPLET</code>, 3 = <code>OTHER</code> (sysmodules running under the BASE memregion)) |
|} | |} | ||
− | === | + | ==== Flag0 ==== |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Bits |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0-1</code> |
− | | | + | | Ideal processor |
|- | |- | ||
− | | | + | | <code>2-3</code> |
− | | | + | | Affinity mask |
|- | |- | ||
− | | | + | | <code>4-7</code> |
− | | | + | | Old3DS system mode |
+ | |} | ||
+ | |||
+ | ===== Old3DS System Mode ===== | ||
+ | {| class="wikitable" border="1" | ||
|- | |- | ||
− | + | ! Value | |
− | + | ! Description | |
|- | |- | ||
− | | | + | | <code>0</code> |
− | | | + | | <code>Prod</code> (64MB of usable application memory) |
|- | |- | ||
− | | | + | | <code>1</code> |
− | | | + | | <code>Undefined</code> (unusable) |
|- | |- | ||
− | | | + | | <code>2</code> |
− | | | + | | <code>Dev1</code> (96MB of usable application memory) |
|- | |- | ||
− | | | + | | <code>3</code> |
− | | | + | | <code>Dev2</code> (80MB of usable application memory) |
|- | |- | ||
− | | | + | | <code>4</code> |
− | | | + | | <code>Dev3</code> (72MB of usable application memory) |
|- | |- | ||
− | | | + | | <code>5</code> |
− | | | + | | <code>Dev4</code> (32MB of usable application memory) |
|- | |- | ||
− | | | + | | <code>6-7</code> |
− | | | + | | <code>Undefined</code> Same as <code>Prod</code>? |
|} | |} | ||
− | + | In the exheader data, the ideal processor field is a bit-index, while in the <code>AccessDesc</code> the ideal processor field is a bitmask. When the bit specified by the exheader field is not set in the <code>AccessDesc</code> field, an error is returned. | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | In the exheader data, the | ||
− | + | <pre>if((1 << exheaderval) & accessdescval == 0) return error</pre> | |
− | + | During a FIRM-launch when a <code>TitleInfo</code> structure was specified, the field at offset [[FIRM#FIRM_Launch_Parameters|0x400]] in the FIRM-launch parameters is set to the SystemMode of the specified title, however in some cases other values are written there. With [[8.0.0-18]] NS will now check the output of [[PTM|PTMSYSM]] command <code>0x040A0000</code>, when the output is non-zero and a certain NS state field is value-zero, the following is executed otherwise this is skipped. With that check passed on [[8.0.0-18]], NS will then check (<code>Flag2 & 0xF</code>). When that is <code>value2</code>, the output value (used for the FIRM-launcher parameter field mentioned above) is set to <code>value7</code>. Otherwise, when that value is non-zero, the output value is set to 6. | |
− | |||
− | + | ==== Flag1 ==== | |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Bits |
− | ! | + | ! Description |
|- | |- | ||
− | | 0 | + | | <code>0</code> |
− | | | + | | <code>EnableL2Cache</code> (Unknown what this actually does, New3DS-only presumably) |
|- | |- | ||
− | | 1 | + | | <code>1</code> |
− | | | + | | <code>cpuspeed_804MHz</code> (Default "cpuspeed" when not set) |
|- | |- | ||
− | | 2-7 | + | | <code>2-7</code> |
| Unused | | Unused | ||
|} | |} | ||
− | In order for the exheader to have any of the above new bits set, the | + | In order for the exheader to have any of the above new bits set, the <code>AccessDesc</code> must have the corresponding bit set, otherwise the invalid-exheader error is returned. |
− | Homebrew which runs under a title which has the above cpuspeed flag set, runs much faster on New3DS. It's unknown how exactly the system handles these flags. | + | Homebrew which runs under a title which has the above <code>cpuspeed</code> flag set, runs much faster on New3DS. It's unknown how exactly the system handles these flags. |
− | When launching titles / perhaps other things with APT, [[NS]] uses [[PTMSYSM:ConfigureNew3DSCPU]] with data which originally came from these flags | + | When launching titles / perhaps other things with [[APT]], [[NS]] uses [[PTMSYSM:ConfigureNew3DSCPU]] with data which originally came from these flags; NS does this regardless of what the running 3DS system is. However, due to a bug(?) in NS the value sent to that command is always either 0x0 or 0x3. When calculating that value, the code only ever uses the cpuspeed field, not the cache field: code to actually load and check the value of the cache field appears to be missing. |
− | + | ==== Flag2 ==== | |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Bit |
− | ! | + | ! Description |
|- | |- | ||
− | | 0-3 | + | | <code>0-3</code> |
− | | | + | | New3DS system mode |
|- | |- | ||
− | | 4-7 | + | | <code>4-7</code> |
| Unused | | Unused | ||
|} | |} | ||
− | The exheader value for the | + | ===== New3DS System Mode ===== |
+ | {| class="wikitable" border="1" | ||
+ | |- | ||
+ | ! Value | ||
+ | ! Description | ||
+ | |- | ||
+ | | <code>0</code> | ||
+ | | <code>Legacy</code> (use Old3DS system mode) | ||
+ | |- | ||
+ | | <code>1</code> | ||
+ | | <code>Prod</code> (124MB of usable application memory) | ||
+ | |- | ||
+ | | <code>2</code> | ||
+ | | <code>Dev1</code> (178MB of usable application memory) | ||
+ | |- | ||
+ | | <code>3</code> | ||
+ | | <code>Dev2</code> (124MB of usable application memory) | ||
+ | |- | ||
+ | | <code>4-7</code> | ||
+ | | <code>Undefined</code> Same as <code>Prod</code>? | ||
+ | |} | ||
+ | |||
+ | When in <code>Legacy</code> mode, the actual memory layout is the same as in <code>New3DS Prod</code>, except the available application memory as reported to the application is reduced to the Old3DS size. | ||
+ | |||
+ | The exheader value for the New3DS system mode value must be ≤ to the <code>AccessDesc</code> value, otherwise the invalid-exheader error is returned. | ||
==== Storage Info ==== | ==== Storage Info ==== | ||
+ | Used in [[FSReg:Register]]. | ||
+ | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>8</code> |
− | | | + | | Extdata ID |
|- | |- | ||
− | | | + | | <code>0x8</code> |
− | | | + | | <code>8</code> |
− | | | + | | System savedata IDs |
|- | |- | ||
− | | | + | | <code>0x10</code> |
− | | | + | | <code>8</code> |
− | | | + | | Storage accessible unique IDs |
|- | |- | ||
− | | | + | | <code>0x18</code> |
− | | | + | | <code>7</code> |
− | | | + | | Filesystem access info |
|- | |- | ||
− | | | + | | <code>0x1F</code> |
− | | | + | | <code>1</code> |
− | | | + | | Other attributes |
|} | |} | ||
Line 334: | Line 356: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Bit and bitmask |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0</code>, <code>0x1</code> |
− | | | + | | Category system application |
|- | |- | ||
− | | | + | | <code>1</code>, <code>0x2</code> |
− | | | + | | Category hardware check |
|- | |- | ||
− | | | + | | <code>2</code>, <code>0x4</code> |
− | | | + | | Category filesystem tool |
|- | |- | ||
− | | | + | | <code>3</code>, <code>0x8</code> |
− | | | + | | Debug |
|- | |- | ||
− | | | + | | <code>4</code>, <code>0x10</code> |
− | | | + | | TWL card backup |
|- | |- | ||
− | | | + | | <code>5</code>, <code>0x20</code> |
− | | | + | | TWL NAND data |
|- | |- | ||
− | | | + | | <code>6</code>, <code>0x40</code> |
− | | | + | | BOSS |
|- | |- | ||
− | | | + | | <code>7</code>, <code>0x80</code> |
− | | | + | | [[FS:OpenArchive|<code>sdmc:/</code>]] |
|- | |- | ||
− | | | + | | <code>8</code>, <code>0x100</code> |
− | | | + | | Core |
|- | |- | ||
− | | | + | | <code>9</code>, <code>0x200</code> |
− | | | + | | [[Flash Filesystem|<code>nand:/ro/</code>]] (Read Only) |
|- | |- | ||
− | | | + | | <code>10</code>, <code>0x400</code> |
− | | | + | | [[Flash Filesystem|<code>nand:/rw/</code>]] |
|- | |- | ||
− | | | + | | <code>11</code>, <code>0x800</code> |
− | | | + | | [[Flash Filesystem|<code>nand:/ro/</code>]] (Write Access) |
|- | |- | ||
− | | | + | | <code>12</code>, <code>0x1000</code> |
− | | | + | | Category system settings |
|- | |- | ||
− | | | + | | <code>13</code>, <code>0x2000</code> |
− | | | + | | Cardboard |
|- | |- | ||
− | | | + | | <code>14</code>, <code>0x4000</code> |
− | | | + | | Export/Import IVS |
|- | |- | ||
− | | | + | | <code>15</code>, <code>0x8000</code> |
− | | | + | | [[FS:OpenArchive|<code>sdmc:/</code>]] (Write-only) |
|- | |- | ||
− | | | + | | <code>16</code>, <code>0x10000</code> |
− | | | + | | Switch cleanup (Introduced in [[3.0.0-5|3.0.0]]?) |
|- | |- | ||
− | | | + | | <code>17</code>, <code>0x20000</code> |
− | | | + | | Savedata move (Introduced in [[5.0.0-11|5.0.0]]) |
|- | |- | ||
− | | | + | | <code>18</code>, <code>0x40000</code> |
− | | | + | | Shop (Introduced in [[5.0.0-11|5.0.0]]) |
|- | |- | ||
− | | | + | | <code>19</code>, <code>0x80000</code> |
− | | | + | | Shell (Introduced in [[5.0.0-11|5.0.0]]) |
|- | |- | ||
− | | | + | | <code>20</code>, <code>0x100000</code> |
− | | | + | | Category home menu (Introduced in [[6.0.0-11|6.0.0]]) |
|- | |- | ||
− | | | + | | <code>21</code>, <code>0x200000</code> |
− | | | + | | Seed DB. Introduced in [[9.6.0-24|9.6.0-X]] [[FIRM]]. [[Home Menu]] has this bit set starting with [[9.6.0-24|9.6.0-X]]. |
|} | |} | ||
− | Other Attributes | + | ====Other Attributes==== |
+ | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Bit |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0</code> |
− | | | + | | Not use ROMFS |
|- | |- | ||
− | | | + | | <code>1</code> |
− | | | + | | Use Extended savedata access. |
|} | |} | ||
+ | |||
+ | When Bit1 is set, the "Extdata ID" and "Storage Accessable Unique IDs" regions are used to store a total of 6 "Accessible Save IDs". Introduced in [[6.0.0-11|6.0.0]]. | ||
==== Service Access Control ==== | ==== Service Access Control ==== | ||
− | This is the list of [[Services_API|services]] which the process is allowed to access, this is registered with the [[Services|services]] manager. Each service listed in the exheader must be listed in the | + | This is the list of [[Services_API|services]] which the process is allowed to access, this is registered with the [[Services|services]] manager. Each service listed in the exheader must be listed in the <code>AccessDesc</code>, otherwise the invalid exheader error is returned. The order of the services for exheader/<code>AccessDesc</code> doesn't matter. The <code>AccessDesc</code> can list services which are not in the exheader, but normally the service-access-control data for exheader/<code>AccessDesc</code> are exactly the same. |
+ | |||
+ | This list is submitted to [[SRVPM:RegisterProcess]]. | ||
=== ARM11 Kernel Capabilities === | === ARM11 Kernel Capabilities === | ||
+ | The kernel capability descriptors are passed to [[SVC|svcCreateProcess]]. | ||
+ | |||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>0x70</code> (<code>28*4</code>) |
− | | | + | | Descriptors |
|- | |- | ||
− | | | + | | <code>0x70</code> |
− | | | + | | <code>0x10</code> |
− | | | + | | Reserved |
|} | |} | ||
− | There are different descriptor types, determined by the number of leading | + | There are different descriptor types, determined by the number of leading ones in the binary value representation of bits 20-31. The different types are laid out as follows: |
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Pattern of bits 20-31 |
− | ! | + | ! Type |
− | ! | + | ! Fields |
|- | |- | ||
− | | | + | | <code>0b1110xxxxxxxx</code> |
− | | | + | | Interrupt info |
| | | | ||
|- | |- | ||
− | | | + | | <code>0b11110xxxxxxx</code> |
− | | | + | | System call mask |
− | | | + | | Bits 24-26: System call mask table index; Bits 0-23: mask |
+ | |- | ||
+ | | <code>0b1111110xxxxx</code> | ||
+ | | Kernel release version | ||
+ | | Bits 8-15: Major version; Bits 0-7: Minor version | ||
+ | |- | ||
+ | | <code>0b11111110xxxx</code> | ||
+ | | Handle table size | ||
+ | | Bits 0-18: size | ||
|- | |- | ||
− | | | + | | <code>0b111111110xxx</code> |
− | | | + | | [[#ARM11_Kernel_Flags|Kernel flags]] |
− | | | + | | See below |
|- | |- | ||
− | | | + | | <code>0b11111111100x</code> |
− | | | + | | Map IO/static address range |
− | | | + | | Describes a memory mapping like the 0b111111111110 descriptor, but an entire range rather than a single page is mapped. Another 0b11111111100x descriptor must follow this one to denote the (exclusive) end of the address range to map. Bit20 on the first descriptor: map read-only (otherwise RW), bit20 on the second descriptor: map static (cacheable, otherwise IO if the bit is not set) |
|- | |- | ||
− | | | + | | <code>0b111111111110</code> |
− | | | + | | Map IO memory page |
− | | | + | | Bits 0-19: page index to map (virtual address >> 12; the physical address is determined per-page according to [[Memory layout]]); Bit 20: Map read-only (otherwise read-write) |
+ | |} | ||
+ | |||
+ | ==== ARM11 Kernel Flags ==== | ||
+ | {| class="wikitable" border="1" | ||
|- | |- | ||
− | | | + | ! Bit |
− | | | + | ! Description |
− | | | + | |- |
+ | | <code>0</code> | ||
+ | | Allow debug | ||
+ | |- | ||
+ | | <code>1</code> | ||
+ | | Force debug | ||
+ | |- | ||
+ | | <code>2</code> | ||
+ | | Allow non-alphanum | ||
+ | |- | ||
+ | | <code>3</code> | ||
+ | | Shared page writing | ||
+ | |- | ||
+ | | <code>4</code> | ||
+ | | Privilege priority | ||
+ | |- | ||
+ | | <code>5</code> | ||
+ | | Allow <code>main()</code> args | ||
+ | |- | ||
+ | | <code>6</code> | ||
+ | | Shared device memory | ||
+ | |- | ||
+ | | <code>7</code> | ||
+ | | Runnable on sleep | ||
+ | |- | ||
+ | | <code>8-11</code> | ||
+ | | Memory type (1: application, 2: system, 3: base) | ||
+ | |- | ||
+ | | <code>12</code> | ||
+ | | [[Memory_layout#NATIVE_FIRM.2FSAFE_MODE_FIRM_Userland_Memory|Special memory]] | ||
|- | |- | ||
− | | | + | | <code>13</code> |
− | | | + | | Process has access to CPU core 2 (New3DS only) |
− | |||
|} | |} | ||
Line 476: | Line 545: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Offset |
− | ! | + | ! Size |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0x0</code> |
− | | | + | | <code>15</code> |
− | | | + | | Descriptors |
|- | |- | ||
− | | | + | | <code>0xF</code> |
− | | | + | | <code>1</code> |
− | | | + | | ARM9 Descriptor Version. Originally this value had to be ≥ 2. Starting with [[9.3.0-21|9.3.0-X]] this value has to be either value 2 or value 3. |
|} | |} | ||
Line 492: | Line 561: | ||
{| class="wikitable" border="1" | {| class="wikitable" border="1" | ||
|- | |- | ||
− | ! | + | ! Bit |
− | ! | + | ! Description |
|- | |- | ||
− | | | + | | <code>0</code> |
− | | | + | | Mount [[Flash Filesystem|<code>nand:/</code>]] |
|- | |- | ||
− | | | + | | <code>1</code> |
− | | | + | | Mount [[Flash Filesystem|<code>nand:/ro/</code>]] (Write Access) |
|- | |- | ||
− | | | + | | <code>2</code> |
− | | | + | | Mount [[Flash Filesystem|<code>twln:/</code>]] |
|- | |- | ||
− | | | + | | <code>3</code> |
− | | | + | | Mount [[Flash Filesystem|<code>wnand:/</code>]] |
|- | |- | ||
− | | | + | | <code>4</code> |
− | | | + | | Mount card SPI |
|- | |- | ||
− | | | + | | <code>5</code> |
− | | | + | | Use SDIF3 |
|- | |- | ||
− | | | + | | <code>6</code> |
− | | | + | | Create seed |
|- | |- | ||
− | | | + | | <code>7</code> |
− | | | + | | Use card SPI |
|- | |- | ||
− | | | + | | <code>8</code> |
− | | | + | | SD application (Not checked) |
|- | |- | ||
− | | | + | | <code>9</code> |
− | | | + | | Mount [[SD Filesystem|sdmc:/]] (Write Access) |
|} | |} |
Latest revision as of 19:09, 9 August 2023
This page documents the format of the NCCH Extended Header, or exheader for short.
The exheader has two sections:
- The actual exheader data, containing System Control Info (SCI) and Access Control Info (ACI);
- A signed copy of NCCH HDR public key, and exheader ACI. This version of the ACI is used as limitation to the actual ACI.
Main Structure[edit]
All values are little endian unless otherwise specified.
See also: [1]
Offset | Size | Description |
---|---|---|
0x0
|
0x200
|
SCI |
0x200
|
0x200
|
ACI |
0x400
|
0x100
|
AccessDesc signature (RSA-2048-SHA256)
|
0x500
|
0x100
|
NCCH HDR RSA-2048 public key |
0x600
|
0x200
|
ACI (for limitation of first ACI) |
The AccessDesc
signature covers the NCCH HDR public key and second ACI. The AccessDesc
public key is initialised by the boot ROM.
When loading the exheader, Process9 compares the exheader data with the data in the AccessDesc
(note that not everything is compared here). When these don't match, an error is returned. The Process9 code handling this validation was updated with v6.0; the only change in this function seems to be the check for the "Ideal processor" field.
System Control Info[edit]
Offset | Size | Description |
---|---|---|
0x0
|
0x8
|
Application title (default is "CtrApp") |
0x8
|
0x5
|
Reserved |
0xD
|
0x1
|
Flag (bit 0: CompressExefsCode , bit 1: SDApplication )
|
0xE
|
0x2
|
Remaster version |
0x10
|
0xC
|
Text code set info |
0x1C
|
0x4
|
Stack size |
0x20
|
0xC
|
Read-only code set info |
0x2C
|
0x4
|
Reserved |
0x30
|
0xC
|
Data code set info |
0x3C
|
0x4
|
BSS size |
0x40
|
0x180 (48*8 )
|
Dependency module (program ID) list |
0x1C0
|
0x40
|
SystemInfo
|
Most of these fields are used in LOADER:LoadProcess.
Code Set Info[edit]
Offset | Size | Description |
---|---|---|
0x0
|
4
|
Address |
0x4
|
4
|
Physical region size (in page-multiples) |
0x8
|
4
|
Size (in bytes) |
System Info[edit]
Offset | Size | Description |
---|---|---|
0x0
|
0x8
|
SaveData Size
|
0x8
|
0x8
|
Jump ID |
0x10
|
0x30
|
Reserved |
Access Control Info[edit]
Offset | Size | Description |
---|---|---|
0x0
|
0x170
|
ARM11 local system capabilities |
0x170
|
0x80
|
ARM11 kernel capabilities |
0x1F0
|
0x10
|
ARM9 access control |
ARM11 Local System Capabilities[edit]
Offset | Size | Description |
---|---|---|
0x0
|
0x8
|
Program ID |
0x8
|
0x4
|
Core version (The Title ID low of the required FIRM) |
0xC
|
0x2
|
Flag1 and Flag2 (both implemented starting from 8.0.0-18). |
0xE
|
0x1
|
Flag0 |
0xF
|
0x1
|
Priority |
0x10
|
0x20 (16*2 )
|
Resource limit descriptors. The first byte here controls the maximum allowed CpuTime .
|
0x30
|
0x20
|
Storage info |
0x50
|
0x100 (32*8 )
|
Service access control |
0x150
|
0x10 (2*8 )
|
Extended service access control, support for this was implemented with 9.3.0-X. |
0x160
|
0xF
|
Reserved |
0x16F
|
0x1
|
Resource limit category. (0 = APPLICATION , 1 = SYS_APPLET , 2 = LIB_APPLET , 3 = OTHER (sysmodules running under the BASE memregion))
|
Flag0[edit]
Bits | Description |
---|---|
0-1
|
Ideal processor |
2-3
|
Affinity mask |
4-7
|
Old3DS system mode |
Old3DS System Mode[edit]
Value | Description |
---|---|
0
|
Prod (64MB of usable application memory)
|
1
|
Undefined (unusable)
|
2
|
Dev1 (96MB of usable application memory)
|
3
|
Dev2 (80MB of usable application memory)
|
4
|
Dev3 (72MB of usable application memory)
|
5
|
Dev4 (32MB of usable application memory)
|
6-7
|
Undefined Same as Prod ?
|
In the exheader data, the ideal processor field is a bit-index, while in the AccessDesc
the ideal processor field is a bitmask. When the bit specified by the exheader field is not set in the AccessDesc
field, an error is returned.
if((1 << exheaderval) & accessdescval == 0) return error
During a FIRM-launch when a TitleInfo
structure was specified, the field at offset 0x400 in the FIRM-launch parameters is set to the SystemMode of the specified title, however in some cases other values are written there. With 8.0.0-18 NS will now check the output of PTMSYSM command 0x040A0000
, when the output is non-zero and a certain NS state field is value-zero, the following is executed otherwise this is skipped. With that check passed on 8.0.0-18, NS will then check (Flag2 & 0xF
). When that is value2
, the output value (used for the FIRM-launcher parameter field mentioned above) is set to value7
. Otherwise, when that value is non-zero, the output value is set to 6.
Flag1[edit]
Bits | Description |
---|---|
0
|
EnableL2Cache (Unknown what this actually does, New3DS-only presumably)
|
1
|
cpuspeed_804MHz (Default "cpuspeed" when not set)
|
2-7
|
Unused |
In order for the exheader to have any of the above new bits set, the AccessDesc
must have the corresponding bit set, otherwise the invalid-exheader error is returned.
Homebrew which runs under a title which has the above cpuspeed
flag set, runs much faster on New3DS. It's unknown how exactly the system handles these flags.
When launching titles / perhaps other things with APT, NS uses PTMSYSM:ConfigureNew3DSCPU with data which originally came from these flags; NS does this regardless of what the running 3DS system is. However, due to a bug(?) in NS the value sent to that command is always either 0x0 or 0x3. When calculating that value, the code only ever uses the cpuspeed field, not the cache field: code to actually load and check the value of the cache field appears to be missing.
Flag2[edit]
Bit | Description |
---|---|
0-3
|
New3DS system mode |
4-7
|
Unused |
New3DS System Mode[edit]
Value | Description |
---|---|
0
|
Legacy (use Old3DS system mode)
|
1
|
Prod (124MB of usable application memory)
|
2
|
Dev1 (178MB of usable application memory)
|
3
|
Dev2 (124MB of usable application memory)
|
4-7
|
Undefined Same as Prod ?
|
When in Legacy
mode, the actual memory layout is the same as in New3DS Prod
, except the available application memory as reported to the application is reduced to the Old3DS size.
The exheader value for the New3DS system mode value must be ≤ to the AccessDesc
value, otherwise the invalid-exheader error is returned.
Storage Info[edit]
Used in FSReg:Register.
Offset | Size | Description |
---|---|---|
0x0
|
8
|
Extdata ID |
0x8
|
8
|
System savedata IDs |
0x10
|
8
|
Storage accessible unique IDs |
0x18
|
7
|
Filesystem access info |
0x1F
|
1
|
Other attributes |
File System Access Info:
Bit and bitmask | Description |
---|---|
0 , 0x1
|
Category system application |
1 , 0x2
|
Category hardware check |
2 , 0x4
|
Category filesystem tool |
3 , 0x8
|
Debug |
4 , 0x10
|
TWL card backup |
5 , 0x20
|
TWL NAND data |
6 , 0x40
|
BOSS |
7 , 0x80
|
sdmc:/
|
8 , 0x100
|
Core |
9 , 0x200
|
nand:/ro/ (Read Only)
|
10 , 0x400
|
nand:/rw/
|
11 , 0x800
|
nand:/ro/ (Write Access)
|
12 , 0x1000
|
Category system settings |
13 , 0x2000
|
Cardboard |
14 , 0x4000
|
Export/Import IVS |
15 , 0x8000
|
sdmc:/ (Write-only)
|
16 , 0x10000
|
Switch cleanup (Introduced in 3.0.0?) |
17 , 0x20000
|
Savedata move (Introduced in 5.0.0) |
18 , 0x40000
|
Shop (Introduced in 5.0.0) |
19 , 0x80000
|
Shell (Introduced in 5.0.0) |
20 , 0x100000
|
Category home menu (Introduced in 6.0.0) |
21 , 0x200000
|
Seed DB. Introduced in 9.6.0-X FIRM. Home Menu has this bit set starting with 9.6.0-X. |
Other Attributes[edit]
Bit | Description |
---|---|
0
|
Not use ROMFS |
1
|
Use Extended savedata access. |
When Bit1 is set, the "Extdata ID" and "Storage Accessable Unique IDs" regions are used to store a total of 6 "Accessible Save IDs". Introduced in 6.0.0.
Service Access Control[edit]
This is the list of services which the process is allowed to access, this is registered with the services manager. Each service listed in the exheader must be listed in the AccessDesc
, otherwise the invalid exheader error is returned. The order of the services for exheader/AccessDesc
doesn't matter. The AccessDesc
can list services which are not in the exheader, but normally the service-access-control data for exheader/AccessDesc
are exactly the same.
This list is submitted to SRVPM:RegisterProcess.
ARM11 Kernel Capabilities[edit]
The kernel capability descriptors are passed to svcCreateProcess.
Offset | Size | Description |
---|---|---|
0x0
|
0x70 (28*4 )
|
Descriptors |
0x70
|
0x10
|
Reserved |
There are different descriptor types, determined by the number of leading ones in the binary value representation of bits 20-31. The different types are laid out as follows:
Pattern of bits 20-31 | Type | Fields |
---|---|---|
0b1110xxxxxxxx
|
Interrupt info | |
0b11110xxxxxxx
|
System call mask | Bits 24-26: System call mask table index; Bits 0-23: mask |
0b1111110xxxxx
|
Kernel release version | Bits 8-15: Major version; Bits 0-7: Minor version |
0b11111110xxxx
|
Handle table size | Bits 0-18: size |
0b111111110xxx
|
Kernel flags | See below |
0b11111111100x
|
Map IO/static address range | Describes a memory mapping like the 0b111111111110 descriptor, but an entire range rather than a single page is mapped. Another 0b11111111100x descriptor must follow this one to denote the (exclusive) end of the address range to map. Bit20 on the first descriptor: map read-only (otherwise RW), bit20 on the second descriptor: map static (cacheable, otherwise IO if the bit is not set) |
0b111111111110
|
Map IO memory page | Bits 0-19: page index to map (virtual address >> 12; the physical address is determined per-page according to Memory layout); Bit 20: Map read-only (otherwise read-write) |
ARM11 Kernel Flags[edit]
Bit | Description |
---|---|
0
|
Allow debug |
1
|
Force debug |
2
|
Allow non-alphanum |
3
|
Shared page writing |
4
|
Privilege priority |
5
|
Allow main() args
|
6
|
Shared device memory |
7
|
Runnable on sleep |
8-11
|
Memory type (1: application, 2: system, 3: base) |
12
|
Special memory |
13
|
Process has access to CPU core 2 (New3DS only) |
ARM9 Access Control[edit]
Offset | Size | Description |
---|---|---|
0x0
|
15
|
Descriptors |
0xF
|
1
|
ARM9 Descriptor Version. Originally this value had to be ≥ 2. Starting with 9.3.0-X this value has to be either value 2 or value 3. |
Descriptors:
Bit | Description |
---|---|
0
|
Mount nand:/
|
1
|
Mount nand:/ro/ (Write Access)
|
2
|
Mount twln:/
|
3
|
Mount wnand:/
|
4
|
Mount card SPI |
5
|
Use SDIF3 |
6
|
Create seed |
7
|
Use card SPI |
8
|
SD application (Not checked) |
9
|
Mount sdmc:/ (Write Access) |