NPDM
This is the Switch equivalent of 3DS exheader. This is the file with extension ".npdm" in {Switch ExeFS}. The size of this file varies.
Offset | Size | Description |
---|---|---|
0x0 | 0x80 | META |
0x80 | <Varies> | ACID |
<See META> | <See META> | ACI0 |
META
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | Magic "META". |
0x4 | 0x8 | Reserved (Padding / Unused) |
0xC | 0x1 | MmuFlags, bit0: 64-bit instructions, bits1-3: address space width (1=64-bit, 2=32-bit). Needs to be <= 0xF |
0xE | 0x1 | Main thread priority (0-63) |
0xF | 0x1 | DefaultCpuId |
0x10 | 0x4 | Reserved |
0x14 | 0x4 | System resource size (max size as of 5.x: 534773760). Unknown usage. |
0x18 | 0x4 | ProcessCategory (0: regular title, 1: kernel built-in). Should be 0 here. |
0x1C | 0x4 | Main entrypoint stack size (Should(?) be page-aligned. In non-nspwn scenarios, values of 0 can also rarely break in Horizon. This might be something auto-adapting or a security feature of some sort?) |
0x20 | 0x10 | Title name |
0x30 | 0x10 | Product code |
0x70 | 0x4 | #ACI0 offset |
0x74 | 0x4 | #ACI0 size |
0x78 | 0x4 | #ACID offset |
0x7C | 0x4 | #ACID size |
ACID
Offset | Size | Description |
---|---|---|
0x0 | 0x100 | RSA-2048 signature, seems to verify the data starting at 0x100 with the size field from 0x204. |
0x100 | 0x100 | RSA-2048 public key, seems to be used for the second NCA signature. |
0x200 | 0x4 | Magic "ACID". |
0x204 | 0x4 | s32 Size field used with the above signature(?). |
0x208 | 0x4 | Zeroes |
0x20C | 0x4 | Flags. Bit0 must be 1 on retail, on devunit 0 is also allowed. Bit1 is unknown, set to 1 for ARMS? [5.0.0+] Bit3-2: PoolPartition? For applets set to 0b01, for sysmodules set to 0b10. Exceptions: "starter" is set to 0, "nvservices" is set to 3. |
0x210 | 0x8 | TitleIdRange_Min |
0x218 | 0x8 | TitleIdRange_Max |
0x220 | 0x4 | #FS Access Control offset |
0x224 | 0x4 | #FS Access Control size |
0x228 | 0x4 | #Service Access Control offset |
0x22C | 0x4 | #Service Access Control size |
0x230 | 0x4 | #Kernel Access Control offset |
0x234 | 0x4 | #Kernel Access Control size |
0x238 | 0x8 | Padding |
ACI0
Offset | Size | Description |
---|---|---|
0x0 | 0x4 | Magic "ACI0". |
0x4 | 0xC | Zeroes |
0x10 | 0x8 | Title id |
0x18 | 0x8 | Reserved (Not currently used, potentially to be used for lowest title ID in future.) |
0x20 | 0x4 | #FS Access Header offset |
0x24 | 0x4 | #FS Access Header size |
0x28 | 0x4 | #Service Access Control offset |
0x2C | 0x4 | #Service Access Control size |
0x30 | 0x4 | #Kernel Access Control offset |
0x34 | 0x4 | #Kernel Access Control size |
0x38 | 0x8 | Padding |
FS Access Header
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | Version? Always 1. Must be non-zero. |
0x1 | 0x3 | Padding |
0x4 | 0x8 | Permissions bitmask |
0xC | 0x4 | Data Size (Always 0x1C) |
0x10 | 0x4 | Size of Content Owner ID section. |
0x14 | 0x4 | Data size (0x1C) plus Content Owner size |
0x18 | 0x4 | Size of Save Data owners section (for applications that wish to share save data?) |
0x1C | 0x4 | (OPTIONAL) Amount of content owner id's |
0x1C | 0x8 * Content Owner ID's | Content owner ID's as uint64's. |
VARIABLE | 0x4 | Amount of save owner id's |
VARIABLE | 0x1 * Save data owner accessibilities (?) | Sets flags for what save data owners can do with other applications save data (?) |
VARIABLE (Pad to nearest 4 bytes) | 0x8 * Amount of save owner ID's | Save data owner ID's |
FS Access Control
Offset | Size | Description |
---|---|---|
0x0 | 0x1 | Version? Always 1. Must be non-zero. |
0x1 | 0x3 | Padding |
0x4 | 0x8 | Permissions bitmask |
0xC | 0x20 | Usually all zeroes for applications |
Permissions bitmask:
Bit | Description |
---|---|
0 | MountContent* is accessible when set. |
34 | Enables access to Bis partitionID 27 and 28? |
63 | Enables access to everything: all permission-types which check a bitmask have this bit set. |
For bit62 in permissions, see here.
Web-applets permissions:
- "LibAppletWeb" and "LibAppletOff" have same access control: bit0 and bit3 set, and bit62 set.
- Rest of the web-applets: Same as above except bit0 isn't set.
Service Access Control
This is a list of service-name strings which the title has access to, with the following structure:
+0: control_byte +1: {service-name without nul-terminator}
Bitmask 0x07 in control_byte is the {length of the service-name without nul-terminator} - 1.
Bitmask 0x80 in control_byte means service is allowed to be registered.
The service string can contain a wildcard *
character.
Kernel Access Control
On Switch, descriptors are identified by pattern 01..11 in low bits.
Pattern of lower bits | Lowest clear bitmask/bit | Type | Fields |
---|---|---|---|
0bxxxxxxxxxxxx0111
|
Bit3 | KernelFlags | Bit31-24: Highest allowed cpu id, bit23-16: Lowest allowed cpu id, bit15-10: Highest allowed thread prio, bit9-4: Lowest allowed thread prio |
0bxxxxxxxxxxx01111
|
Bit4 | SyscallMask | Bits 29-31: Syscall mask table index; Bits 5-28: Mask |
0bxxxxxxxxx0111111
|
Bit6 | MapIoOrNormalRange | Bits 7-30: Alternating start page and number of pages, bit31: Alternating read-only flag then MemoryAttribute 0x2001/0x42002 selector flag |
0bxxxxxxxx01111111
|
Bit7 | MapNormalPage (RW) | Bits 8-31: Page |
0bxxxx011111111111
|
Bit11 | InterruptPair | Bits 12-21: Irq0, bits 20-31: Irq1, 0x3FF means empty. |
0bxx01111111111111
|
Bit13 | ApplicationType | Bit16-14: ApplicationType (0=sysmodule, 1=application, 2=applet), bit16 ignored. Parsed by Process Manager services. Defaults to 0 if descriptor doesn't exist. Can only run 1 application at a time. |
0bx011111111111111
|
Bit14 | KernelReleaseVersion | Bits 15-X: Version. The raw descriptor is compared with 0x80000, when less than an error is returned. This is equivalent to comparing the bits starting at bit15 with 0x10. This enforces a minimum required version, not a maximum. |
0b0111111111111111
|
Bit15 | HandleTableSize | Bit25-16: Number of handles the table shall fit. |
0b1111111111111111
|
Bit16 | DebugFlags | Bit17: can be debugged, bit18: can debug others |
All ones | Ignored |
Mapping restrictions
The physaddr range 0x80060000-0x2000000000 is not allowed to be mapped as IO. The physaddr range 0x80000000-0x2000000000 is not allowed to be mapped as Normal.
[2.0.0-4.1.0] The range for IO was changed into 0x80060000-0x81D3FFFF.
[2.0.0-4.1.0] A blacklist was added for IO and Normal mappings:
- 0x50040000-0x50060000 (ARM, Interrupt Controller)
- 0x6000F000 (Exception Vectors)
- 0x6001DC00-0x6001E000 (IPATCH)
- 0x7000E000 (RTC/PMC)
- 0x70019000 (MC)
- 0x7001C000 (MC0)
- 0x7001D000 (MC1)
[5.0.0+] For IO, this blacklist was abandoned and instead two range checks were added. For Normal mappings it is still applied
Kernel versions
Firmware | Kernel Version | Minimum Allowed |
---|---|---|
1.0.0 | 5.0.0 | 3.0.0 |
2.0.0 | 6.1.0 | 3.0.0 |
3.0.0 | 7.4.0 | 3.0.0 |
3.0.2 | 7.4.0 | 3.0.0 |
Bit31-19: Major version Bit18-15: Minor version Bit14-0: Zeroes