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
+
|}