Changes

Jump to navigation Jump to search
6,146 bytes added ,  23:12, 9 November 2018
no edit summary
Line 5: Line 5:  
! Word || Bits || Description
 
! Word || Bits || Description
 
|-
 
|-
| 0 || 15-0 || Type. 4=Request, 5=Control
+
| 0 || 15-0 || [[#Type|Type]].
 
|-
 
|-
 
| 0 || 19-16 || Number of buf X descriptors (each: 2 words).
 
| 0 || 19-16 || Number of buf X descriptors (each: 2 words).
Line 13: Line 13:  
| 0 || 27-24 || Number of buf B descriptors (each: 3 words).
 
| 0 || 27-24 || Number of buf B descriptors (each: 3 words).
 
|-
 
|-
| 0 || 31-28 || Number of buf W desciptors (each: 3 words), never observed.
+
| 0 || 31-28 || Number of buf W desciptors (each: 3 words), not observed
 
|-
 
|-
| 1 || 9-0 || Size of raw data section in u32s.
+
| 1 || 9-0 || Size of [[#Raw data section|raw data]] in u32s.
 
|-
 
|-
 
| 1 || 13-10 || Flags for buf C descriptor.
 
| 1 || 13-10 || Flags for buf C descriptor.
Line 39: Line 39:     
First two header u32's and handle descriptor (if enabled) are copied as-is from one process to the other.
 
First two header u32's and handle descriptor (if enabled) are copied as-is from one process to the other.
 +
 +
=== Type ===
 +
IPC commands can have different types which influence how the IPC server processes requests in "nn::sf::hipc::server::HipcServerSessionManagerBase::ProcessRequest".
 +
 +
{| class="wikitable" border="1"
 +
|-
 +
! Value || Name
 +
|-
 +
| 0 || Invalid
 +
|-
 +
| 1 || [[#LegacyRequest, LegacyControl|LegacyRequest]]
 +
|-
 +
| 2 || [[#Close|Close]]
 +
|-
 +
| 3 || [[#LegacyRequest, LegacyControl|LegacyControl]]
 +
|-
 +
| 4 || [[#Request, Control|Request]]
 +
|-
 +
| 5 || [[#Request, Control|Control]]
 +
|-
 +
| 6 || [5.0.0+] [[#RequestWithContext, ControlWithContext|RequestWithContext]]
 +
|-
 +
| 7 || [5.0.0+] [[#RequestWithContext, ControlWithContext|ControlWithContext]]
 +
|}
 +
 +
==== Close ====
 +
When processing a request of this type, the IPC server calls:
 +
* "nn::sf::hipc::server::HipcServerSessionManager::DestroyServerSession"
 +
* "nn::sf::hipc::CloseServerSessionHandle"
 +
 +
This ensures that the server session is destroyed internally and properly closed.
 +
 +
==== LegacyRequest, LegacyControl ====
 +
These types are handled by calling:
 +
* "nn::sf::hipc::detail::HipcMessageBufferAccessor::ParseHeader"
 +
* "nn::sf::hipc::server::HipcServerSessionManager::ProcessMessage"
 +
* "nn::sf::hipc::Reply"
 +
* "nn::sf::hipc::server::HipcServerSessionManager::RegisterServerSessionToWaitBase"
 +
 +
It is speculated that these are part of an older message processing system where headers were further partitioned.
 +
 +
==== Request, Control ====
 +
These types are handled by calling:
 +
* "nn::sf::hipc::server::HipcServerSessionManager::ProcessMessage2"
 +
* "nn::sf::hipc::server::HipcServerSessionManager::RegisterServerSessionToWaitBase"
 +
 +
This represents a more modern message handling system where contents follow the general marshalling structure.
 +
 +
==== RequestWithContext, ControlWithContext ====
 +
These are identical to normal Request and Control types, but with the additional requirement of suppling a token in their [[#Data payload|data payload]].
 +
 +
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.
    
=== Handle descriptor ===
 
=== Handle descriptor ===
Line 155: Line 207:     
No user-process->sysmodule memcpy is done for outbufs, only sysmodule->user-process.
 
No user-process->sysmodule memcpy is done for outbufs, only sysmodule->user-process.
 +
 +
Buffer descriptors C/X are somewhat different. Rather than mapping new memory into the server process, C/X descriptors copy data between existing buffers in different processes. Each X descriptor in a message has its data copied into a C descriptor on the other side. Each C descriptor in a message is used to reserve space for the other side's X descriptors to copy into.
 +
 +
When the kernel processes X descriptors, it must determine where to copy the data to. If the destination used C descriptors with flags >= 3, each X descriptor from the source is matched to a C descriptor in the destination by the X descriptor's index field. If the destination used a "single" C descriptor, the data from all the X descriptors is copied into the same buffer specified by the destination's C descriptor (causing error 0xce01 if there is not enough space) and the X descriptor index is ignored. The kernel then modifies the addresses in the X descriptors to indicate where the data was copied to in the destination.
 +
 +
Before receiving a request, if the IPC server is expecting X descriptors, it prepares a message with a "single" C descriptor (flags=2) in its message buffer before calling svcReplyAndReceive so that X descriptors from the client have a place to copy their data to.  The usage of the flag-2 C descriptor allows the server to receive an arbitrary number of X descriptors, since they're all packed into the same buffer. If the server had used flag-3+ C descriptors, it would be limited in how many X descriptors it could receive since the X descriptors would have to be matched to distinct C descriptors. The buffer that the server's C descriptor points to is called the '''pointer buffer'''.
 +
 +
When the client sends X descriptors, data is copied into the server's pointer buffer. When the client sends C descriptors, no data is copied automatically. The server needs to use X descriptors to copy the data back to the client's C descriptors (using the index field to match X descriptors in the response back to the correct C descriptors).
    
== Raw data section ==
 
== Raw data section ==
   
[[File:Ipc msg buffer type a example.png|thumb|An example of an IPC message with a type 0xA buffer in it. Red is headers/descriptors, yellow is padding, and blue is data/buffer lengths. Note that the size of the u16 array for type A lengths is padded to fill up a whole word.]]
 
[[File:Ipc msg buffer type a example.png|thumb|An example of an IPC message with a type 0xA buffer in it. Red is headers/descriptors, yellow is padding, and blue is data/buffer lengths. Note that the size of the u16 array for type A lengths is padded to fill up a whole word.]]
   Line 174: Line 233:  
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 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 lengths).
   −
=== Domain message ===
+
=== Domains ===
This header is used to wrap up requests sent to domains instead of sessions.
+
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.
    +
Format for the extra request header for domain message:
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
! Word || Bits || Description
 
! Word || Bits || Description
 
|-
 
|-
 
| 0 || 7-0 || Command. 1=send message, 2=close virtual handle
 
| 0 || 7-0 || Command. 1=send message, 2=close virtual handle
 +
|-
 +
| 0 || 8-15 || Input object count
 
|-
 
|-
 
| 0 || 31-16 || Length of [[IPC_Marshalling#Data_payload|data payload]] in bytes.
 
| 0 || 31-16 || Length of [[IPC_Marshalling#Data_payload|data payload]] in bytes.
Line 186: Line 248:  
| 1 || || Object ID (from cmd 0 in [[IPC_Marshalling#Control|Control]]).
 
| 1 || || Object ID (from cmd 0 in [[IPC_Marshalling#Control|Control]]).
 
|-
 
|-
  | 2
+
| 2 || || Padding
  |rowspan="2"|
  −
  |rowspan="2"| Padding to align to u64
   
|-
 
|-
  | 3
+
| 3 || || [1.0.0-4.1.0] Padding [5.0.0+] Token for (NewRequest only)
 
|-
 
|-
 
| 4... || || [[#Data payload|Data payload]]
 
| 4... || || [[#Data payload|Data payload]]
 +
|-
 +
| ... || || Input object IDs (u32s, not aligned)
 +
|}
 +
 +
Format for the extra response header for domain message:
 +
{| class="wikitable" border="1"
 +
! Word || Bits || Description
 +
|-
 +
| 0 || 31-0 || Output object count
 +
|-
 +
| 1-3 || || Padding
 +
|-
 
|}
 
|}
    
=== Data payload ===
 
=== Data payload ===
   
This is an array of u32's, but individual parameters are generally stored as u64's.
 
This is an array of u32's, but individual parameters are generally stored as u64's.
   Line 202: Line 273:  
! Word || Description
 
! Word || Description
 
|-
 
|-
| 0 || Magic ("SFCI" for requests, "SFCO" for responses) as u64.
+
| 0 || Magic ("SFCI" for requests, "SFCO" for responses) as u32.
 +
|-
 +
| 1 || Version as u32. 1 for NewRequest, 0 for Request.
 
|-
 
|-
 
| 2 || Command id as u64 for requests, [[Error_codes|error code]] as u64 for responses.
 
| 2 || Command id as u64 for requests, [[Error_codes|error code]] as u64 for responses.
 +
|-
 +
| 3 || [1.0.0-4.1.0] Padding [5.0.0+] Token (for NewRequest only, non-domain messages).
 
|-
 
|-
 
| 4... || Input parameters or return values
 
| 4... || Input parameters or return values
 
|}
 
|}
 +
 +
[5.0.0+] Version was incremented from 0 to 1, and a token value was introduced into raw_data+12 (regardless of domain or not, in either case it overlaps with padding).
 +
 +
The input rawdata struct 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.
    
== Official marshalling code ==
 
== Official marshalling code ==
 
The official marshalling function takes an array of (buf_ptr, size) pairs and a type-field for each such pair.
 
The official marshalling function takes an array of (buf_ptr, size) pairs and a type-field for each such pair.
   −
Bitmask 0x10 seems to indicate null-terminated strings, but that flag is ignored by the marshalling code.
+
Bitmask 0x10 seems to indicate null-terminated strings.
    
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 238: Line 317:  
|-
 
|-
 
| 0x20 + 2 || Creates both an B and C descriptor || Out
 
| 0x20 + 2 || Creates both an B and C descriptor || Out
 +
|-
 +
| 0x20 + 2 + 0x40 || Same as 0x20 + 2, except a certain value is set to hard-coded 0x1 instead. || Out
 
|}
 
|}
   Line 278: Line 359:  
! Cmd || Name || Arguments || Output
 
! Cmd || Name || Arguments || Output
 
|-
 
|-
| 0 || ConvertSessionToDomain || None ||  
+
| 0 || ConvertCurrentObjectToDomain || None || u32 CmifDomainObjectId
 
|-
 
|-
| 1 || ConvertDomainToSession || u32 domain ||  
+
| 1 || CopyFromCurrentDomain || u32 CmifDomainObjectId || u32 NativeHandle
 
|-
 
|-
| 2 || DuplicateSession || None ||  
+
| 2 || CloneCurrentObject || None || u32 NativeHandle
 
|-
 
|-
| 3 || QueryPointerBufferSize || None || u32 as u16-size
+
| 3 || QueryPointerBufferSize || None || u16 size
 
|-
 
|-
| 4 || DuplicateSessionEx || u32 unknown ||  
+
| 4 || CloneCurrentObjectEx || u32 unknown || u32 NativeHandle
 
|}
 
|}

Navigation menu