NPDM: Difference between revisions

No edit summary
No edit summary
Line 9: Line 9:
| 0x0
| 0x0
| 0x80
| 0x80
| META
| [[#META|META]]
|-
|-
| 0x80
| 0x80
| <Varies>
| <Varies>
| ACID
| [[#ACID|ACID]]
|-
|-
| <See META>
| <See META>
| <See META>
| <See META>
| ACI0
| [[#ACI0|ACI0]]
|}
|}


Line 37: Line 37:
| 0xC
| 0xC
| 0x1
| 0x1
| Flags (bit0 = Is64BitInstruction, bit1 = AddressSpace64BitOld, bit2 = AddressSpace32Bit, bit3 = AddressSpace32BitNoReserved, bit4 = AddressSpace64Bit)
| [[#Flags]]
|-
|-
| 0xD
| 0xD
Line 45: Line 45:
| 0xE
| 0xE
| 0x1
| 0x1
| MainThreadPriority (0-63)
| [[#MainThreadPriority]]
|-
|-
| 0xF
| 0xF
Line 57: Line 57:
| 0x14
| 0x14
| 0x4
| 0x4
| [3.0.0+] System resource (PersonalMmHeap) size (max size as of 5.x: 534773760)
| [3.0.0+] [[#SystemResourceSize]]
|-
|-
| 0x18
| 0x18
| 0x4
| 0x4
| Version (0 for all titles prior to [[8.1.0]], 1 for certain titles since).
| [[#Version]]
|-
|-
| 0x1C
| 0x1C
| 0x4
| 0x4
| MainThreadStackSize (Must be aligned to 0x1000. 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?)
| [[#MainThreadStackSize]]
|-
|-
| 0x20
| 0x20
| 0x10
| 0x10
| Title name (usually/always "Application")
| Name (usually/always "Application")
|-
|-
| 0x30
| 0x30
| 0x10
| 0x10
| Product code (usually/always all zeroes)
| ProductCode (usually/always all zeroes)
|-
|-
| 0x40
| 0x40
Line 81: Line 81:
| 0x70
| 0x70
| 0x4
| 0x4
| [[#ACI0]] offset
| [[#ACI0|AciOffset]]
|-
|-
| 0x74
| 0x74
| 0x4
| 0x4
| [[#ACI0]] size
| [[#ACI0|AciSize]]
|-
|-
| 0x78
| 0x78
| 0x4
| 0x4
| [[#ACID]] offset
| [[#ACID|AcidOffset]]
|-
|-
| 0x7C
| 0x7C
| 0x4
| 0x4
| [[#ACID]] size
| [[#ACID|AcidSize]]
|}
|}
== Flags ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 0
| Is64BitInstruction
|-
| 1-3
| ProcessAddressSpace (0x00 = AddressSpace32Bit, 0x01 = AddressSpace64BitOld, 0x02 = AddressSpace32BitNoReserved, 0x03 = AddressSpace64Bit)
|-
| 4
| OptimizeMemoryAllocation
|}
== MainThreadPriority ==
Ranges from 0 to 0x3F.
== SystemResourceSize ==
This is the size of PersonalMmHeap. Maximum size as of 5.0.0 is 0x1FE00000.
== Version ==
0 for all titles.
[8.1.0+] Now set to 1 for certain titles.
== MainThreadStackSize ==
Must be aligned to 0x1000.
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?


= ACID =
= ACID =
Line 117: Line 149:
| 0x204
| 0x204
| 0x4
| 0x4
| Data size
| Size
|-
|-
| 0x208
| 0x208
Line 125: Line 157:
| 0x20C
| 0x20C
| 0x4
| 0x4
| Flags (bit0 = ProductionFlag, bit1 = UnqualifiedApproval, [5.0.0+] bit2-3: MemoryRegion (0 = Application, 1 = Applet, 2 = SecureSystem, 3 = NonSecureSystem) "starter" is set to Application and "nvservices" is set to NonSecureSystem)
| [[#Flags]]
|-
|-
| 0x210
| 0x210
Line 137: Line 169:
| 0x220
| 0x220
| 0x4
| 0x4
| [[#FS Access Control]] offset
| [[#FsAccessControl|FsAccessControlOffset]]
|-
|-
| 0x224
| 0x224
| 0x4
| 0x4
| [[#FS Access Control]] size
| [[#FsAccessControl|FsAccessControlSize]]
|-
|-
| 0x228
| 0x228
| 0x4
| 0x4
| [[#Service Access Control]] offset
| [[#SrvAccessControl|SrvAccessControlOffset]]
|-
|-
| 0x22C
| 0x22C
| 0x4
| 0x4
| [[#Service Access Control]] size
| [[#SrvAccessControl|SrvAccessControlSize]]
|-
|-
| 0x230
| 0x230
| 0x4
| 0x4
| [[#Kernel Access Control]] offset
| [[#KernelCapability|KernelCapabilityOffset]]
|-
|-
| 0x234
| 0x234
| 0x4
| 0x4
| [[#Kernel Access Control]] size
| [[#KernelCapability|KernelCapabilitySize]]
|-
|-
| 0x238
| 0x238
Line 163: Line 195:
| Reserved
| Reserved
|}
|}
== Flags ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 0
| ProductionFlag
|-
| 1
| UnqualifiedApproval
|-
| 2-3
| [5.0.0+ ] MemoryRegion (0 = Application, 1 = Applet, 2 = SecureSystem, 3 = NonSecureSystem)
|}
MemoryRegion is set to Application for "starter" and NonSecureSystem for "nvservices".


= ACI0 =
= ACI0 =
Line 189: Line 239:
| 0x20
| 0x20
| 0x4
| 0x4
| [[#FS Access Header]] offset
| [[#FsAccessControl|FsAccessControlOffset]]
|-
|-
| 0x24
| 0x24
| 0x4
| 0x4
| [[#FS Access Header]] size
| [[#FsAccessControl|FsAccessControlSize]]
|-
|-
| 0x28
| 0x28
| 0x4
| 0x4
| [[#Service Access Control]] offset
| [[#SrvAccessControl|SrvAccessControlOffset]]
|-
|-
| 0x2C
| 0x2C
| 0x4
| 0x4
| [[#Service Access Control]] size
| [[#SrvAccessControl|SrvAccessControlSize]]
|-
|-
| 0x30
| 0x30
| 0x4
| 0x4
| [[#Kernel Access Control]] offset
| [[#KernelCapability|KernelCapabilityOffset]]
|-
|-
| 0x34
| 0x34
| 0x4
| 0x4
| [[#Kernel Access Control]] size
| [[#KernelCapability|KernelCapabilitySize]]
|-
|-
| 0x38
| 0x38
Line 216: Line 266:
|}
|}


= FS Access Header =
= FsAccessControl =
For [[#ACID]] this is a simple descriptor as follows:
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 224: Line 275:
|-
|-
| 0x0
| 0x0
| 0x1
| Version (always 1, must be non-zero)
|-
| 0x1
| 0x3
| Padding
|-
| 0x4
| 0x4
| 0x8
| [[#FsAccessFlag]]
|-
| 0xC
| 0x20
| Reserved
|}
For [[#ACI0]] this embeds data as follows:
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x1
| Version (always 1, must be non-zero)
| Version (always 1, must be non-zero)
|-
| 0x1
| 0x3
| Padding
|-
|-
| 0x4
| 0x4
| 0x8
| 0x8
| Permissions bitmask
| [[#FsAccessFlag]]
|-
|-
| 0xC
| 0xC
Line 268: Line 347:
|}
|}


= FS Access Control =
== FsAccessFlag ==
{| class="wikitable" border="1"
|-
! Offset
! Size
! Description
|-
| 0x0
| 0x1
| Version (always 1, must be non-zero)
|-
| 0x1
| 0x3
| Padding
|-
| 0x4
| 0x8
| Permissions bitmask
|-
| 0xC
| 0x20
| Reserved
|}
 
[[Filesystem_services#Permissions|Permissions]] bitmask:
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
! Bit
! Bits
! Name
! Name
! Description
! Description
Line 435: Line 490:
|  
|  
|-
|-
| 34-61
| 34
| RegisterProgramIndexMapInfo
|
|-
| 35
| CreateOwnSaveData
|
|-
| 36-61
| Reserved
| Reserved
|  
|  
Line 447: Line 510:
| Enables access to everything: all [[Filesystem_services#Permissions|permission types]] which check a bitmask have this bit set.
| Enables access to everything: all [[Filesystem_services#Permissions|permission types]] which check a bitmask have this bit set.
|}
|}
Controls the [[Filesystem_services#Permissions|filesystem permissions]].


Web-applets permissions:
Web-applets permissions:
Line 453: Line 518:


= Service Access Control =
= Service Access Control =
This is a list of [[Services_API|service]]-name strings which the title has access to, with the following structure:
{| class="wikitable" border="1"
  +0: control_byte
|-
  +1: {service-name without nul-terminator}
! Bits
! Description
|-
| 0-2
| Size (length of the service-name without null-terminator minus 1)
|-
| 7
| IsServer (service is allowed to be registered)
|-
| Variable
| Name
|}


Bitmask 0x07 in control_byte is the {length of the service-name without nul-terminator} - 1.
This is a list of [[Services_API|service]]-name strings which the title has access to.


Bitmask 0x80 in control_byte means IsServer (service is allowed to be registered).
The service name string starts after the first byte and supports the wildcard <code>*</code> character.


The service string can contain a wildcard <code>*</code> character.
= KernelCapability =
 
These descriptors are identified by pattern 01..11 in low bits.
= Kernel Access Control =
On Switch, descriptors are identified by pattern 01..11 in low bits.


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Line 470: Line 544:
! Pattern of lower bits
! Pattern of lower bits
! Lowest clear bitmask/bit
! Lowest clear bitmask/bit
! Type
! Description
! Fields
|-
|-
| <code>0bxxxxxxxxxxxx0111</code>
| <code>0bxxxxxxxxxxxx0111</code>
| Bit3
| Bit3
| ThreadInfo
| [[#ThreadInfo]]
| Bit31-24: MaxCoreNumber, bit23-16: MinCoreNumber, bit15-10: HighestPriority, bit9-4: LowestPriority.
|-
|-
| <code>0bxxxxxxxxxxx01111</code>
| <code>0bxxxxxxxxxxx01111</code>
| Bit4
| Bit4
| EnableSystemCalls
| [[#EnableSystemCalls]]
| Bits29-31: SystemCallId; Bits5-28: Mask.
|-
|-
| <code>0bxxxxxxxxx0111111</code>
| <code>0bxxxxxxxxx0111111</code>
| Bit6
| Bit6
| MemoryMap
| [[#MemoryMap]]
| Bits7-30: Alternates between BeginAddress and Size, bit31: Alternates between Permission (MemoryPermission_RO or MemoryPermission_RW) and Type (MemoryType_Io or MemoryType_Static).
|-
|-
| <code>0bxxxxxxxx01111111</code>
| <code>0bxxxxxxxx01111111</code>
| Bit7
| Bit7
| MemoryMap (RW)
| [[#IoMemoryMap]]
| Bits8-31: BeginAddress.
|-
|-
| <code>0bxxxxx01111111111</code>
| <code>0bxxxxx01111111111</code>
| Bit10
| Bit10
| [8.0.0+] MemoryRegionMap
| [8.0.0+] [[#MemoryRegionMap]]
| Bits 11-17: Region0, Bits 18-24: Region1, bits 25-31: Region2. Region is bit 0-6: MemoryRegionType, bit 7 = IsReadOnly.
|-
|-
| <code>0bxxxx011111111111</code>
| <code>0bxxxx011111111111</code>
| Bit11
| Bit11
| EnableInterrupts
| [[#EnableInterrupts]]
| Bits12-21: Irq0, bits22-31: Irq1, 0x3FF means empty.
|-
|-
| <code>0bxx01111111111111</code>
| <code>0bxx01111111111111</code>
| Bit13
| Bit13
| MiscParams
| [[#MiscParams]]
| Bit16-14: ProgramType (0 = System, 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.
|-
|-
| <code>0bx011111111111111</code>
| <code>0bx011111111111111</code>
| Bit14
| Bit14
| KernelVersion
| [[#KernelVersion]]
| Bits15-18: MinorVersion, bits19-31: MajorVersion. 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.
|-
|-
| <code>0b0111111111111111</code>
| <code>0b0111111111111111</code>
| Bit15
| Bit15
| HandleTableSize
| [[#HandleTableSize]]
| Bit16-25: Number of handles the table shall fit.
|-
|-
| <code>0b1111111111111111</code>
| <code>0b1111111111111111</code>
| Bit16
| Bit16
| MiscFlags
| [[#MiscFlags]]
| Bit17: EnableDebug, bit18: ForceDebug.
|-
|-
| All ones
| All ones
|  
|  
| Ignored
| Ignored
|
|}
|}


Note: the 8.0.0+ MemoryRegionMap descriptor is supported by the kernel but not by [[Loader_services|Loader]]. Thus, only initial processes may possess this capability.
== ThreadInfo ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 4-9
| LowestPriority
|-
| 10-15
| HighestPriority
|-
| 16-23
| MinCoreNumber
|-
| 24-31
| MaxCoreNumber
|}
 
== EnableSystemCalls ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 5-28
| Mask
|-
| 29-31
| SystemCallId
|}
 
== MemoryMap ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 7-30
| BeginAddress or Size
|-
| 31
| IsRw or IsIo
|}
 
MemoryMap entries are stored alternating between BeginAddress + IsRw and Size + IsIo.


== Mapping restrictions ==
=== Restrictions ===
The physaddr range 0x80060000-0x2000000000 is not allowed to be mapped as IO.
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.
The physaddr range 0x80000000-0x2000000000 is not allowed to be mapped as Normal.
Line 548: Line 655:
[5.0.0+] For IO, this blacklist was abandoned and instead two range checks were added. For Normal mappings it is still applied
[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 ==
== IoMemoryMap ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 8-31
| BeginAddress
|}
 
== MemoryRegionMap ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 11-16
| RegionType0
|-
| 17
| RegionIsReadOnly0
|-
| 18-23
| RegionType1
|-
| 24
| RegionIsReadOnly1
|-
| 25-30
| RegionType2
|-
| 31
| RegionIsReadOnly2
|}
 
MemoryRegionMap is supported by the kernel but not by [[Loader_services|Loader]]. Thus, only initial processes may possess this capability.
 
== EnableInterrupts ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 12-21
| InterruptNumber0
|-
| 22-31
| InterruptNumber1
|}
 
0x3FF means empty.
 
== MiscParams ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 14-16
| ProgramType (0 = System, 1 = Application, 2 = Applet)
|}
 
ProgramType is parsed by [[Process Manager services]]. Defaults to 0 if descriptor doesn't exist. Can only run 1 application at a time.
 
== KernelVersion ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 15-18
| MinorVersion
|-
| 19-31
| MajorVersion
|}
 
This 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.
 
=== Versions ===
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 564: Line 750:
|}
|}


Bit31-19: Major version</br>
== HandleTableSize ==
Bit18-15: Minor version</br>
{| class="wikitable" border="1"
Bit14-0: Zeroes
|-
! Bits
! Description
|-
| 16-25
| HandleTableSize
|}
 
== MiscFlags ==
{| class="wikitable" border="1"
|-
! Bits
! Description
|-
| 17
| EnableDebug
|-
| 18
| ForceDebug
|}