Difference between revisions of "IPC Marshalling"

From Nintendo Switch Brew
Jump to: navigation, search
(Marshall Portion)
(Raw data portion)
 
(46 intermediate revisions by 5 users not shown)
Line 1: Line 1:
== Marshall Portion ==
+
== IPC Command Structure ==
 
This is an array of u32's.
 
This is an array of u32's.
  
Line 5: Line 5:
 
! Word || Bits || Description
 
! Word || Bits || Description
 
|-
 
|-
| 0 || 19-16 || Number of marshalls type X (each: 2 words).
+
| 0 || 15-0 || Type. 4=Request, 5=Control
 
|-
 
|-
| 0 || 23-20 || Number of inbufs (each: 3 words). Type mask: 5
+
| 0 || 19-16 || Number of buf X descriptors (each: 2 words).
 
|-
 
|-
| 0 || 27-24 || Number of outbufs (each: 3 words). Type mask: 6
+
| 0 || 23-20 || Number of buf A descriptors (each: 3 words).
 
|-
 
|-
| 0 || 31-28 || Number of marshalls type W (each: 3 words)
+
| 0 || 27-24 || Number of buf B descriptors (each: 3 words).
 
|-
 
|-
| 1 || 9-0 || Size of data portion in u32's.
+
| 0 || 31-28 || Number of buf W desciptors (each: 3 words), never observed.
 
|-
 
|-
| 1 || 13-10 || Marshal type T something.  
+
| 1 || 9-0 || Raw data size (in u32's).
 
|-
 
|-
| 1 || 17-14 || Marshal type T something.  
+
| 1 || 13-10 || Flags for buf C descriptor.
 
|-
 
|-
| 1 || 31 || Enable special descriptor.
+
| 1 || 31 || Enable handle descriptor.
 
|-
 
|-
| ... || || Special descriptor, if enabled.
+
| ... || || Handle descriptor, if enabled.
 
|-
 
|-
| ... || || Type X descriptors, each one 2 words.
+
| ... || || Buf X descriptors, each one 2 words.
 
|-
 
|-
| ... || || Inbuf descriptors, each one 3 words.
+
| ... || || Buf A descriptors, each one 3 words.
 
|-
 
|-
| ... || || Outbuf descriptors, each one 3 words.
+
| ... || || Buf B descriptors, each one 3 words.
 
|-
 
|-
 
| ... || || Type W descriptors, each one 3 words.
 
| ... || || Type W descriptors, each one 3 words.
 +
|-
 +
| ... || || Raw data (including any padding).
 +
|-
 +
| ... || || Buf C descriptors, each one 2 words.
 
|}
 
|}
  
=== Special descriptor ===
+
=== Handle descriptor ===
 
There can only be one of this descriptor type. It is enabled by bit31 of the second word.
 
There can only be one of this descriptor type. It is enabled by bit31 of the second word.
  
Line 38: Line 42:
 
! Word || Bits || Description
 
! Word || Bits || Description
 
|-
 
|-
| 0 || 0 || ?
+
| 0 || 0 || Send current PID.
 +
|-
 +
| 0 || 4-1 || Number of handles to copy
 +
|-
 +
| 0 || 8-5 || Number of handles to move
 +
|-
 +
| ... || || 8-byte PID if enabled
 +
|-
 +
| ... || || Handles to copy
 +
|-
 +
| ... || || Handles to move
 +
|}
 +
 
 +
=== Buffer descriptor X "Pointer" ===
 +
This one is packed even worse than A, they inserted the bit38-36 of the address ''on top'' of the counter field.
 +
 
 +
Officially, the counter is known as "receive index". This one writes to the buffer described in the ReceiveList.
 +
 
 +
{| class="wikitable" border="1"
 +
! Word || Bits || Description
 +
|-
 +
| 0 || 5-0 || Bits 5-0 of counter.
 +
|-
 +
| 0 || 8-6 || Bit 38-36 of address.
 
|-
 
|-
| 0 || 4-1 || Number of A-words for this special descriptor (=x).
+
| 0 || 11-9 || Bits 11-9 of counter.
 
|-
 
|-
| 0 || 8-5 || Number of B-words for this special descriptor (=y).
+
| 0 || 15-12 || Bit 35-32 of address.
 
|-
 
|-
| 1 || || A-words, purpose unknown.
+
| 0 || 31-16 || Size
 
|-
 
|-
| 1+x || || B-words, purpose unknown.
+
| 1 || || Lower 32-bits of address.
 
|}
 
|}
  
=== Inbuf/outbuf Descriptor ===
+
=== Buffer descriptor A/B/W "Send"/"Receive"/"Exchange" ===
They fucked up this one, big time.
+
This packing is so unnecessarily complex.
  
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
Line 59: Line 86:
 
| 1 || || Lower 32-bits of address.
 
| 1 || || Lower 32-bits of address.
 
|-
 
|-
| 2 || 1-0 || Unknown flag.
+
| 2 || 1-0 || Flags. Always set to 1 or 3.
 
|-
 
|-
 
| 2 || 4-2 || Bit 38-36 of address.
 
| 2 || 4-2 || Bit 38-36 of address.
Line 68: Line 95:
 
|}
 
|}
  
=== Descriptor type B ===
+
=== Buffer descriptor C "ReceiveList" ===
 +
There's a 4-bit flag in the main header controlling the behavior of C descriptors.
 +
 
 +
If it has value 0, the C descriptor functionality is disabled. If it has value 1, there is no C descriptor. If it has value 2, there is a single C descriptor.
 +
 
 +
Otherwise it has (flag-2) C descriptors.
 +
 
 +
{| class="wikitable" border="1"
 +
! Word || Bits || Description
 +
|-
 +
| 0 || || Lower 32-bits of address.
 +
|-
 +
| 1 || 15-0 || Rest of address.
 +
|-
 +
| 1 || 31-16 || Size
 +
|}
 +
 
 +
== Raw data portion ==
 +
This is an array of u32's, but individual parameters are generally stored as u64's.
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
 
! Word || Description
 
! Word || Description
 
|-
 
|-
| 0 || Lower 32-bits of addr?
+
| ... || Padding to align to 16
 +
|-
 +
| ... || [[IPC_Marshalling#Domain_header|Domain header]] padded to 16 if required
 +
|-
 +
| +0 || Magic ("SFCI" for requests, "SFCO" for responses) as u64
 
|-
 
|-
| 1 || Upper 16bits: Size, Lower 16bits: Rest of addr?
+
| +2 || Cmd id as u64
 +
|-
 +
| ... || Input parameters
 +
|-
 +
| ... || Any u16 buffer sizes packed and aligned to 2 bytes
 
|}
 
|}
  
=== Descriptor type C ===
+
=== Domain header ===
 +
This is an optional header used to wrap up requests sent to domains instead of sessions.
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
! Word || Description
+
! Word || Bits || Description
 +
|-
 +
| 0 || 15-0 || Always 1.
 
|-
 
|-
| 0 || Upper 16bits: Size, Lower 16: ?
+
| 0 || 31-16 || Request size (0x10 bytes for SFCI magic and cmd ID, plus size of input parameters).
 
|-
 
|-
| 1 || ?
+
| 1 || || Domain ID (from cmd 0 in [[IPC_Marshalling#Control|Control]]).
 
|}
 
|}
  
== Data Portion ==
+
== Official marshalling code ==
This is an array of u64's placed after the marshall header. But it's always aligned to 16 so sometimes there is padding words inserted inbetween.
+
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.
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
! Word || Description
+
! Type Mask || Description || Direction
 +
|-
 +
| 4 + 1 || Creates a A descriptor with flags=0. || In
 +
|-
 +
| 0x40 + 4 + 1 || Creates a A descriptor with flags=1. || In
 +
|-
 +
| 0x80 + 4 + 1 || Creates a A descriptor with flags=3. || In
 +
|-
 +
| 4 + 2 || Creates a B descriptor with flags=0. || Out
 +
|-
 +
| 0x40 + 4 + 2 || Creates a B descriptor with flags=1. || Out
 +
|-
 +
| 0x80 + 4 + 2 || Creates a B descriptor with flags=3. || Out
 +
|-
 +
| 8 + 1 || Creates an X descriptor || In
 +
|-
 +
| 8 + 2 || Creates a C descriptor, and writes the u16 size to an offset into raw data. || Out
 
|-
 
|-
| 0 || Magic ("SFCI")
+
| 0x10 + 8 + 2 || Creates a C descriptor || Out
 
|-
 
|-
| 1 || Cmd id
+
| 0x20 + 1 || Creates both an A and X descriptor || In
 
|-
 
|-
| ... || Non-marshalled data is placed here
+
| 0x20 + 2 || Creates both an B and C descriptor || Out
 
|}
 
|}
  
== Cmd header ==
+
For types 0x21, 0x22 if size doesn't fit in u16, it's added to a list. Some magic shit happens to that list.
 +
 
 +
== Official IPC Cmd Structure ==
 +
Official struct that is stored for each IPC command. It contains precalculated offsets for different portions of the command structure.
 +
 
 +
All offsets are given is in number of u32 words.
 +
 
 +
struct IpcCmdStruct {
 +
  u8  unk0;
 +
  u8  has_handle_descriptor;
 +
  u8  pad0[2];
 +
  u32 cmd0;
 +
  u32 cmd1;
 +
  u32 offset_handle_descriptor;
 +
  u32 pad1;
 +
  u32 offset_handles;         
 +
  u32 pad2;
 +
  u32 offset_x_descriptors;
 +
  u32 offset_a_descriptors;
 +
  u32 offset_b_descriptors;
 +
  u32 offset_w_descriptors; /* this is a guess */
 +
  u32 offset_raw_data;
 +
  u32 offset_c_descriptors;
 +
  u32 unk2;
 +
  u32 unk3;
 +
}
 +
 
 +
== Control ==
 +
When type == 5 you are talking to the IPC manager.
 +
 
 
{| class="wikitable" border="1"
 
{| class="wikitable" border="1"
! Cmd header 1 || Cmd header 2 || Description
 
 
|-
 
|-
| 4 || 9 || Data portion size 20.
+
! Cmd || Name
 
|-
 
|-
| 4 || 10 || Data portion size 24.
+
| 0 || ConvertSessionToDomain
 
|-
 
|-
| 4 || 12 || Data portion size 32.
+
| 2 || DuplicateSession
 
|-
 
|-
| 4 || 14 || Data portion size 40.
+
| 3 || QueryPointerBufferSize
 
|-
 
|-
| 4 || 0x8000000C || Marshall words: (u32) 1. Data portion size 32.
+
| 4 || DuplicateSessionEx
 
|}
 
|}

Latest revision as of 07:52, 6 July 2017

IPC Command Structure

This is an array of u32's.

Word Bits Description
0 15-0 Type. 4=Request, 5=Control
0 19-16 Number of buf X descriptors (each: 2 words).
0 23-20 Number of buf A 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.
1 9-0 Raw data size (in u32's).
1 13-10 Flags for buf C descriptor.
1 31 Enable handle descriptor.
... Handle descriptor, if enabled.
... Buf X descriptors, each one 2 words.
... Buf A descriptors, each one 3 words.
... Buf B descriptors, each one 3 words.
... Type W descriptors, each one 3 words.
... Raw data (including any padding).
... Buf C descriptors, each one 2 words.

Handle descriptor

There can only be one of this descriptor type. It is enabled by bit31 of the second word.

Word Bits Description
0 0 Send current PID.
0 4-1 Number of handles to copy
0 8-5 Number of handles to move
... 8-byte PID if enabled
... Handles to copy
... Handles to move

Buffer descriptor X "Pointer"

This one is packed even worse than A, they inserted the bit38-36 of the address on top of the counter field.

Officially, the counter is known as "receive index". This one writes to the buffer described in the ReceiveList.

Word Bits Description
0 5-0 Bits 5-0 of counter.
0 8-6 Bit 38-36 of address.
0 11-9 Bits 11-9 of counter.
0 15-12 Bit 35-32 of address.
0 31-16 Size
1 Lower 32-bits of address.

Buffer descriptor A/B/W "Send"/"Receive"/"Exchange"

This packing is so unnecessarily complex.

Word Bits Description
0 Lower 32-bits of size.
1 Lower 32-bits of address.
2 1-0 Flags. Always set to 1 or 3.
2 4-2 Bit 38-36 of address.
2 27-24 Bit 35-32 of size.
2 31-28 Bit 35-32 of address.

Buffer descriptor C "ReceiveList"

There's a 4-bit flag in the main header controlling the behavior of C descriptors.

If it has value 0, the C descriptor functionality is disabled. If it has value 1, there is no C descriptor. If it has value 2, there is a single C descriptor.

Otherwise it has (flag-2) C descriptors.

Word Bits Description
0 Lower 32-bits of address.
1 15-0 Rest of address.
1 31-16 Size

Raw data portion

This is an array of u32's, but individual parameters are generally stored as u64's.

Word Description
... Padding to align to 16
... Domain header padded to 16 if required
+0 Magic ("SFCI" for requests, "SFCO" for responses) as u64
+2 Cmd id as u64
... Input parameters
... Any u16 buffer sizes packed and aligned to 2 bytes

Domain header

This is an optional header used to wrap up requests sent to domains instead of sessions.

Word Bits Description
0 15-0 Always 1.
0 31-16 Request size (0x10 bytes for SFCI magic and cmd ID, plus size of input parameters).
1 Domain ID (from cmd 0 in Control).

Official marshalling code

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.

Type Mask Description Direction
4 + 1 Creates a A descriptor with flags=0. In
0x40 + 4 + 1 Creates a A descriptor with flags=1. In
0x80 + 4 + 1 Creates a A descriptor with flags=3. In
4 + 2 Creates a B descriptor with flags=0. Out
0x40 + 4 + 2 Creates a B descriptor with flags=1. Out
0x80 + 4 + 2 Creates a B descriptor with flags=3. Out
8 + 1 Creates an X descriptor In
8 + 2 Creates a C descriptor, and writes the u16 size to an offset into raw data. Out
0x10 + 8 + 2 Creates a C descriptor Out
0x20 + 1 Creates both an A and X descriptor In
0x20 + 2 Creates both an B and C descriptor Out

For types 0x21, 0x22 if size doesn't fit in u16, it's added to a list. Some magic shit happens to that list.

Official IPC Cmd Structure

Official struct that is stored for each IPC command. It contains precalculated offsets for different portions of the command structure.

All offsets are given is in number of u32 words.

struct IpcCmdStruct {
  u8  unk0;
  u8  has_handle_descriptor;
  u8  pad0[2];
  u32 cmd0;
  u32 cmd1;
  u32 offset_handle_descriptor;
  u32 pad1;
  u32 offset_handles;          
  u32 pad2;
  u32 offset_x_descriptors;
  u32 offset_a_descriptors;
  u32 offset_b_descriptors;
  u32 offset_w_descriptors; /* this is a guess */
  u32 offset_raw_data;
  u32 offset_c_descriptors;
  u32 unk2;
  u32 unk3;
}

Control

When type == 5 you are talking to the IPC manager.

Cmd Name
0 ConvertSessionToDomain
2 DuplicateSession
3 QueryPointerBufferSize
4 DuplicateSessionEx