HIPC: Difference between revisions

m Header1Tag: Fix bits
No edit summary
Line 10: Line 10:
| 0x0 || 0x8 || [[#HeaderData|HeaderData]]
| 0x0 || 0x8 || [[#HeaderData|HeaderData]]
|-
|-
| 0x8 || Variable || [[#SpecialData|SpecialData]] (if HasSpecial is set)
| 0x8 || 0x4 || [[#SpecialTag|SpecialHeaderData]] (if [[#Header1Tag|SpecialCount]] is set)
|-
|-
| Variable || Variable || Array of [[#PointerData|PointerData]]
| 0xC || 0x8 || ProcessId (if [[#SpecialTag|Pid]] is set)
|-
|-
| Variable || Variable || Array of [[#MapData|SendData]]
| 0x14 || Variable || Array of CopyHandle (if [[#SpecialTag|CopyHandleCount]] > 0)
|-
|-
| Variable || Variable || Array of [[#MapData|ReceiveData]]
| Variable || Variable || Array of MoveHandle (if [[#SpecialTag|MoveHandleCount]] > 0)
|-
|-
| Variable || Variable || Array of [[#MapData|ExchangeData]]
| Variable || Variable || Array of [[#PointerData|PointerData]] (if [[#Header0Tag|PointerCount]] > 0)
|-
|-
| Variable || Variable || [[#RawData|RawData]]
| Variable || Variable || Array of [[#MapData|SendData]] (if [[#Header0Tag|SendCount]] > 0)
|-
|-
| Variable || Variable || Array of [[#ReceiveListData|ReceiveListData]]
| Variable || Variable || Array of [[#MapData|ReceiveData]] (if [[#Header0Tag|ReceiveCount]] > 0)
|-
| Variable || Variable || Array of [[#MapData|ExchangeData]] (if [[#Header0Tag|ExchangeCount]] > 0)
|-
| Variable || Variable || [[#RawData|RawData]] (if [[#Header1Tag|RawCount]] > 0)
|-
| Variable || Variable || Array of [[#ReceiveListData|ReceiveListData]] (if [[#Header1Tag|ReceiveListCount]] > 0)
|}
|}


[[#HeaderData|HeaderData]] and [[#SpecialTag|SpecialHeaderData]] (if available) are copied as-is from one process to another.
[[#HeaderData|HeaderData]] and [[#SpecialTag|SpecialHeaderData]] (if available) are copied as-is from one process to another.


Sysmodules load the last u64 of rawdata when handling the [[#SpecialData|SpecialData]] ProcessId. This is not written by kernel. For sysmodule handling:
Sysmodules load the last u64 of rawdata when handling the ProcessId. This is not written by kernel. For sysmodule handling:
* In some cases: these commands require a placeholder u64 value passed in the input parameters, as mentioned above. In these cases the OverwriteClientProcessId method is called to replace the value before it is used.
* In some cases: these commands require a placeholder u64 value passed in the input parameters, as mentioned above. In these cases the OverwriteClientProcessId method is called to replace the value before it is used.
* In other cases: The rawdata_u64 is compared with the ProcessId from [[#SpecialData|SpecialData]]. On mismatch and when rawdata_u64!=0, error 0x60A is returned. The ProcessId value passed to the cmdhandler vtable funcptr is the rawdata_u64.
* In other cases: The rawdata_u64 is compared with the ProcessId. On mismatch and when rawdata_u64!=0, error 0x60A is returned. The ProcessId value passed to the cmdhandler vtable funcptr is the rawdata_u64.


Handle 0 is allowed, and just means no handle was sent.
Handle 0 is allowed, and just means no handle was sent.
Line 50: Line 56:
| Variable || Variable || Reserved (padding to align to 16 bytes)
| Variable || Variable || Reserved (padding to align to 16 bytes)
|-
|-
| Variable || Variable || [[#Payload|Payload]] or [[#Domain|Domain]]  
| Variable || Variable || [[#CmifMessage|CmifMessage]] or [[#CmifDomain|CmifDomain]]  
|-
|-
| Variable || Variable || Reserved (padding to align to 16 bytes)
| Variable || Variable || Reserved (padding to align to 16 bytes)
Line 59: Line 65:
The total amount of padding within the raw data section is always 0x10 bytes. This means that if no padding is required before the message, there will be 0x10 bytes of padding after the message (before the buffer type 0xA (OutPointer) - lengths).
The total amount of padding within the raw data section is always 0x10 bytes. This means that if no padding is required before the message, there will be 0x10 bytes of padding after the message (before the buffer type 0xA (OutPointer) - lengths).


=== Payload ===
=== CmifMessage ===
This is an array of u32s, but individual parameters are generally stored as u64s.
This is an array of u32s, but individual parameters are generally stored as u64s.


Line 73: Line 79:
The rawdata struct for input parameters/return values is generated by stable-sorting function parameters by alignment, from low to high. It is likely this is a mistake, as it generates structs with suboptimal possible padding -- Nintendo probably meant to sort from high to low (which would give minimized padding), but couldn't/can't change this without breaking backwards compatibility.
The rawdata struct for input parameters/return values is generated by stable-sorting function parameters by alignment, from low to high. It is likely this is a mistake, as it generates structs with suboptimal possible padding -- Nintendo probably meant to sort from high to low (which would give minimized padding), but couldn't/can't change this without breaking backwards compatibility.


=== Domain ===
=== CmifDomain ===
Because the switch has relatively low limits on the total number of sessions available to the system (Kernel slabheap limits, sysmodule handle table size limits), HIPC supports a "Domains" feature that allows multiplexing multiple service sessions through a single handle. Domains store (effectively) a mapping from u32 object id to a SharedPointer<IServiceObject> -- When messages are sent to a domain, an extra header is sent in the raw data section (before anything else) with information about what object in the domain is being acted on; responses similarly contain an additional header. Official session code implements this by just using the dispatch table for the object in the map with the appropriate ID, instead of the dispatch table the session was initialized with.
Because the switch has relatively low limits on the total number of sessions available to the system (Kernel slabheap limits, sysmodule handle table size limits), HIPC supports a "Domains" feature that allows multiplexing multiple service sessions through a single handle. Domains store (effectively) a mapping from u32 object id to a SharedPointer<IServiceObject> -- When messages are sent to a domain, an extra header is sent in the raw data section (before anything else) with information about what object in the domain is being acted on; responses similarly contain an additional header. Official session code implements this by just using the dispatch table for the object in the map with the appropriate ID, instead of the dispatch table the session was initialized with.


Line 82: Line 88:
| 0x0 || 0x10 || [[#CmifDomainMessageInHeader|CmifDomainMessageInHeader]] or [[#CmifDomainMessageOutHeader|CmifDomainMessageOutHeader]]
| 0x0 || 0x10 || [[#CmifDomainMessageInHeader|CmifDomainMessageInHeader]] or [[#CmifDomainMessageOutHeader|CmifDomainMessageOutHeader]]
|-
|-
| 0x10 || Variable || [[#Payload|Payload]] (size must be InRawSize, only for input domain messages)
| 0x10 || Variable || [[#CmifMessage|CmifMessage]] (size must be InRawSize, only for input domain messages)
|-
|-
| Variable || Variable || Array of [[#CmifDomainObjectId|CmifDomainObjectId]] (count must be InObjectCount, only for input domain messages)
| Variable || Variable || Array of [[#CmifDomainObjectId|CmifDomainObjectId]] (count must be InObjectCount, only for input domain messages)
Line 103: Line 109:
! Cmd || Name
! Cmd || Name
|-
|-
| 0 || [[#ConvertCurrentObjectToDomain]]
| 0 || [[#ConvertCurrentObjectToDomain|ConvertCurrentObjectToDomain]]
|-
|-
| 1 || [[#CopyFromCurrentDomain]]
| 1 || [[#CopyFromCurrentDomain|CopyFromCurrentDomain]]
|-
|-
| 2 || [[#CloneCurrentObject]]
| 2 || [[#CloneCurrentObject|CloneCurrentObject]]
|-
|-
| 3 || [[#QueryPointerBufferSize]]
| 3 || [[#QueryPointerBufferSize|QueryPointerBufferSize]]
|-
|-
| 4 || [[#CloneCurrentObjectEx]]  
| 4 || [[#CloneCurrentObjectEx|CloneCurrentObjectEx]]  
|}
|}


Line 129: Line 135:
Takes an input u32 '''Tag'''. Returns an output handle.
Takes an input u32 '''Tag'''. Returns an output handle.


== Invoke2Method ==
== Invoke2MethodOld ==
Same as [[#InvokeMethod|InvokeMethod]] but using a more streamlined logic that no longer requires additional internal copying and parsing.
Same as [[#InvokeMethod|InvokeMethod]] but using a more streamlined logic that no longer requires additional internal copying and parsing.


== Invoke2ManagerMethod ==
== Invoke2ManagerMethodOld ==
Same as [[#InvokeManagerMethod|InvokeManagerMethod]] but using a more streamlined logic that no longer requires additional internal copying and parsing.
Same as [[#InvokeManagerMethod|InvokeManagerMethod]] but using a more streamlined logic that no longer requires additional internal copying and parsing.


== Invoke2MethodWithContext ==
== Invoke2Method ==
Same as [[#Invoke2Method|Invoke2Method]] but with the additional requirement of suppling a token in the [[#Data payload|data payload]].
Same as [[#Invoke2MethodOld|Invoke2MethodOld]] but with the additional requirement of suppling a token in the [[#CmifInHeader|CmifInHeader]].


This token is used by "nn::sf::cmif::SetInlineContext" which has the sole purpose of saving it into the TLS in order for it to be distributed to any IPC commands that are made while processing the current command. It's unknown if this token serves any purpose or if it's just a debug-tool to figure out what IPC command caused a particular chain of commands.
This token is used by "nn::sf::cmif::SetInlineContext" which has the sole purpose of saving it into the TLS in order for it to be distributed to any IPC commands that are made while processing the current command. It's unknown if this token serves any purpose or if it's just a debug-tool to figure out what IPC command caused a particular chain of commands.


== Invoke2ManagerMethodWithContext ==
== Invoke2ManagerMethod ==
Same as [[#Invoke2ManagerMethod|Invoke2ManagerMethod]] but with the additional requirement of suppling a token in the [[#Data payload|data payload]].
Same as [[#Invoke2ManagerMethodOld|Invoke2ManagerMethodOld]] but with the additional requirement of suppling a token in the [[#CmifInHeader|CmifInHeader]].


This token is used by "nn::sf::cmif::SetInlineContext" which has the sole purpose of saving it into the TLS in order for it to be distributed to any IPC commands that are made while processing the current command. It's unknown if this token serves any purpose or if it's just a debug-tool to figure out what IPC command caused a particular chain of commands.
This token is used by "nn::sf::cmif::SetInlineContext" which has the sole purpose of saving it into the TLS in order for it to be distributed to any IPC commands that are made while processing the current command. It's unknown if this token serves any purpose or if it's just a debug-tool to figure out what IPC command caused a particular chain of commands.
Line 232: Line 238:


= ReceiveListData =
= ReceiveListData =
This is "nn::sf::hipc::detail::HipcFormat::ReceiveListData". This is a 0x8-byte struct.
{| class="wikitable" border="1"
{| class="wikitable" border="1"
|-
|-
Line 239: Line 247:
|-
|-
| 0x4 || 0x4 || [[#ReceiveList1Tag|Data1]]
| 0x4 || 0x4 || [[#ReceiveList1Tag|Data1]]
|}
= SpecialData =
{| class="wikitable" border="1"
|-
! Offset || Size || Description
|-
| 0x0 || 0x4 || [[#SpecialTag|SpecialHeaderData]]
|-
| 0x4 || 0x8 || ProcessId
|-
| 0xC || Variable || Array of CopyHandle
|-
| Variable || Variable || Array of MoveHandle
|}
|}


Line 263: Line 257:
|-
|-
| 0-15
| 0-15
| [[#MessageType|MessageType]]
| Tag
|-
|-
| 16-19
| 16-19
Line 286: Line 280:
|-
|-
| 0-9
| 0-9
| RawDataByteSize
| RawCount
|-
|-
| 10-13
| 10-13
Line 295: Line 289:
|-
|-
| 31
| 31
| HasSpecial
| SpecialCount
|}
|}


Line 306: Line 300:
|-
|-
| 0
| 0
| HasPid
| Pid
|-
|-
| 1-4
| 1-4
Line 326: Line 320:
|-
|-
| 0-31
| 0-31
| Size (bits 0 to 31)
| MapSizeLow (bits 0 to 31)
|}
|}


Line 337: Line 331:
|-
|-
| 0-31
| 0-31
| AddressValue (bits 0 to 31)
| MapAddress0 (bits 0 to 31)
|}
|}


Line 351: Line 345:
|-
|-
| 2-4
| 2-4
| AddressValue (bits 36 to 38)
| MapAddress36 (bits 36 to 38)
|-
|-
| 5-23
| 5-23
Line 357: Line 351:
|-
|-
| 24-27
| 24-27
| Size (bits 32 to 35)
| MapSizeHi (bits 32 to 35)
|-
|-
| 28-31
| 28-31
| AddressValue (bits 32 to 35)
| MapAddress32 (bits 32 to 35)
|}
|}


Line 371: Line 365:
|-
|-
| 0-3
| 0-3
| ReceiveIndex
| PointerIndex
|-
|-
| 4-5
| 4-5
Line 377: Line 371:
|-
|-
| 6-8
| 6-8
| AddressValue (bits 36 to 38)
| PointerAddress36 (bits 36 to 38)
|-
|-
| 9-11
| 9-11
Line 383: Line 377:
|-
|-
| 12-15
| 12-15
| AddressValue (bits 32 to 35)
| PointerAddress32 (bits 32 to 35)
|-
|-
| 16-31
| 16-31
| Size
| PointerSize
|}
|}


Line 397: Line 391:
|-
|-
| 0-31
| 0-31
| AddressValue (bits 0 to 31)
| PointerAddress0 (bits 0 to 31)
|}
|}


Line 408: Line 402:
|-
|-
| 0-31
| 0-31
| AddressValue (bits 0 to 31)
| ReceiveListAddressLow (bits 0 to 31)
|}
|}


Line 419: Line 413:
|-
|-
| 0-6
| 0-6
| AddressValue (bits 32 to 38)
| ReceiveListAddressHi (bits 32 to 38)
|-
|-
| 7-15
| 7-15
Line 425: Line 419:
|-
|-
| 16-31
| 16-31
| Size
| ReceiveListSize
|}
|}


Line 450: Line 444:
| 0 || Invalid
| 0 || Invalid
|-
|-
| 1 || InvokeMethod
| 1 || [[#InvokeMethod|InvokeMethod]]
|-
|-
| 2 || Release
| 2 || [[#Release|Release]]
|-
|-
| 3 || InvokeManagerMethod
| 3 || [[#InvokeManagerMethod|InvokeManagerMethod]]
|-
|-
| 4 || Invoke2Method
| 4 || [[#Invoke2MethodOld|Invoke2MethodOld]]
|-
|-
| 5 || Invoke2ManagerMethod
| 5 || [[#Invoke2ManagerMethodOld|Invoke2ManagerMethodOld]]
|-
|-
| 6 || [5.0.0+] Invoke2MethodWithContext
| 6 || [5.0.0+] [[#Invoke2Method|Invoke2Method]]
|-
|-
| 7 || [5.0.0+] Invoke2ManagerMethodWithContext
| 7 || [5.0.0+] [[#Invoke2ManagerMethod|Invoke2ManagerMethod]]
|}
|}


Line 540: Line 534:
! Offset || Size || Description
! Offset || Size || Description
|-
|-
| 0x0 || 0x1 || [[#RequestKind|RequestKind]]
| 0x0 || 0x1 || [[#CmifDomainRequestKind|RequestKind]]
|-
|-
| 0x1 || 0x1 || InObjectCount
| 0x1 || 0x1 || InObjectCount
Line 567: Line 561:
= CmifDomainObjectId =
= CmifDomainObjectId =
This is "nn::sf::cmif::CmifDomainObjectId". This is a 4 byte value.
This is "nn::sf::cmif::CmifDomainObjectId". This is a 4 byte value.
= CmifDomainRequestKind =
This is "nn::sf::cmif::detail::CmifDomainRequestKind".
{| class="wikitable" border="1"
!  Value
!  Description
|-
| 0 || Invalid
|-
| 1 || InvokeMethod
|-
| 2 || Release
|}


= BufferAttribute =
= BufferAttribute =
Line 572: Line 580:


{| class="wikitable" border="1"
{| class="wikitable" border="1"
Value
Bits
!  Description
!  Description
|-
|-
| 0x0 || None
| 0
| In
|-
|-
| 0x1 || In
| 1
| Out
|-
|-
| 0x2 || Out
| 2
| HipcMapAlias
|-
|-
| 0x4 || HipcMapAlias
| 3
| HipcPointer
|-
|-
| 0x8 || HipcPointer
| 4
| FixedSize
|-
|-
| 0x10 || FixedSize
| 5
| HipcAutoSelect
|-
|-
| 0x20 || HipcAutoSelect
| 6
| HipcMapTransferAllowsNonSecure
|-
|-
| 0x40 || HipcMapTransferAllowsNonSecure
| 7
|-
| HipcMapTransferAllowsNonDevice
| 0x80 || HipcMapTransferAllowsNonDevice
|}
|}


= RequestKind =
= NativeHandleAttribute =
This is "nn::sf::cmif::NativeHandleAttribute".
 
{| class="wikitable" border="1"
{| class="wikitable" border="1"
Value
Bits
!  Description
!  Description
|-
|-
| 0 || Invalid
| 0
| HipcCopy
|-
|-
| 1 || Send
| 1
|-
| HipcMove
| 2 || Close
|}
|}