2020-04-19 23:04:05 +02:00
// SPDX-License-Identifier: MPL-2.0
2020-03-27 20:36:02 +01:00
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
2019-09-24 22:54:27 +02:00
# pragma once
2019-10-13 10:04:47 +02:00
# include <common.h>
2019-09-24 22:54:27 +02:00
2020-04-17 23:19:19 +02:00
namespace skyline {
namespace constant {
2020-09-26 07:17:57 +02:00
constexpr u8 IpcPaddingSum { 0x10 } ; // The sum of the padding surrounding the data payload
constexpr u16 TlsIpcSize { 0x100 } ; // The size of the IPC command buffer in a TLS slot
2020-04-17 23:19:19 +02:00
}
2019-09-24 22:54:27 +02:00
2020-04-17 23:19:19 +02:00
namespace kernel : : ipc {
2020-02-15 10:38:17 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Type
2020-02-15 10:38:17 +01:00
*/
2020-04-17 23:19:19 +02:00
enum class CommandType : u16 {
2020-09-28 12:05:17 +02:00
Invalid = 0 ,
LegacyRequest = 1 ,
Close = 2 , //!< Closes the IPC Session
LegacyControl = 3 ,
Request = 4 , //!< A normal IPC transaction between the server and client process
Control = 5 , //!< A transaction between the client and IPC Manager
RequestWithContext = 6 , //!< Request with Token
ControlWithContext = 7 , //!< Control with Token
2020-04-17 23:19:19 +02:00
} ;
2019-09-24 22:54:27 +02:00
2020-02-15 10:38:17 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_C_.22ReceiveList.22
* @ note Any values beyond this are the amount of C - Buffers present ( Which is calculated as value - 2 )
2020-02-15 10:38:17 +01:00
*/
2020-04-17 23:19:19 +02:00
enum class BufferCFlag : u8 {
2020-09-28 12:05:17 +02:00
None = 0 , //!< No C-Buffers present
InlineDescriptor = 1 , //!< An inlined C-Buffer which is written after the raw data section
SingleDescriptor = 2 , //!< A single C-Buffer
2020-04-17 23:19:19 +02:00
} ;
2019-09-24 22:54:27 +02:00
2020-02-15 10:38:17 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#IPC_Command_Structure
2020-02-15 10:38:17 +01:00
*/
2020-04-17 23:19:19 +02:00
struct CommandHeader {
CommandType type : 16 ;
u8 xNo : 4 ;
u8 aNo : 4 ;
u8 bNo : 4 ;
u8 wNo : 4 ;
u32 rawSize : 10 ;
BufferCFlag cFlag : 4 ;
u32 : 17 ;
bool handleDesc : 1 ;
} ;
static_assert ( sizeof ( CommandHeader ) = = 8 ) ;
2019-09-24 22:54:27 +02:00
2020-02-15 10:38:17 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Handle_descriptor
2020-02-15 10:38:17 +01:00
*/
2020-04-17 23:19:19 +02:00
struct HandleDescriptor {
bool sendPid : 1 ;
u32 copyCount : 4 ;
u32 moveCount : 4 ;
u32 : 23 ;
} ;
static_assert ( sizeof ( HandleDescriptor ) = = 4 ) ;
2019-11-23 19:48:22 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ brief Commands which can be issued via a domain request
*/
enum class DomainCommand : u8 {
SendMessage = 1 ,
CloseVHandle = 2 ,
} ;
/**
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Domains
2019-11-23 19:48:22 +01:00
*/
2020-04-17 23:19:19 +02:00
struct DomainHeaderRequest {
2020-09-28 12:05:17 +02:00
DomainCommand command ;
2020-04-17 23:19:19 +02:00
u8 inputCount ;
u16 payloadSz ;
u32 objectId ;
u32 : 32 ;
u32 token ;
} ;
static_assert ( sizeof ( DomainHeaderRequest ) = = 16 ) ;
2019-11-23 19:48:22 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Domains
2019-11-23 19:48:22 +01:00
*/
2020-04-17 23:19:19 +02:00
struct DomainHeaderResponse {
u32 outputCount ;
u32 : 32 ;
u64 : 64 ;
} ;
static_assert ( sizeof ( DomainHeaderResponse ) = = 16 ) ;
2019-11-23 19:48:22 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Data_payload
2019-11-23 19:48:22 +01:00
*/
2020-04-17 23:19:19 +02:00
struct PayloadHeader {
u32 magic ;
u32 version ;
u32 value ;
u32 token ;
} ;
static_assert ( sizeof ( PayloadHeader ) = = 16 ) ;
2019-11-23 19:48:22 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ brief The IPC Control commands as encoded into the payload value
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Control
2019-11-23 19:48:22 +01:00
*/
2020-04-17 23:19:19 +02:00
enum class ControlCommand : u32 {
2020-09-28 12:05:17 +02:00
ConvertCurrentObjectToDomain = 0 , //!< Converts a regular IPC session into a domain session
CopyFromCurrentDomain = 1 ,
CloneCurrentObject = 2 , //!< Creates a duplicate of the current session
QueryPointerBufferSize = 3 , //!< The size of the X buffers written by the servers (and by extension C-buffers supplied by the client)
CloneCurrentObjectEx = 4 , //!< Same as CloneCurrentObject
2020-04-17 23:19:19 +02:00
} ;
2019-09-24 22:54:27 +02:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_X_.22Pointer.22
2019-09-24 22:54:27 +02:00
*/
2020-04-17 23:19:19 +02:00
struct BufferDescriptorX {
u16 counter0_5 : 6 ; //!< The first 5 bits of the counter
u16 address36_38 : 3 ; //!< Bit 36-38 of the address
u16 counter9_11 : 3 ; //!< Bit 9-11 of the counter
u16 address32_35 : 4 ; //!< Bit 32-35 of the address
u16 size : 16 ; //!< The 16 bit size of the buffer
u32 address0_31 : 32 ; //!< The first 32-bits of the address
BufferDescriptorX ( u64 address , u16 counter , u16 size ) : size ( size ) {
address0_31 = static_cast < u32 > ( address & 0x7FFFFFFF80000000 ) ;
address32_35 = static_cast < u16 > ( address & 0x78000000 ) ;
address36_38 = static_cast < u16 > ( address & 0x7000000 ) ;
counter0_5 = static_cast < u16 > ( address & 0x7E00 ) ;
counter9_11 = static_cast < u16 > ( address & 0x38 ) ;
}
2020-04-22 19:02:27 +02:00
inline u64 Address ( ) {
2020-04-17 23:19:19 +02:00
return static_cast < u64 > ( address0_31 ) | static_cast < u64 > ( address32_35 ) < < 32 | static_cast < u64 > ( address36_38 ) < < 36 ;
}
2020-04-22 19:02:27 +02:00
inline u16 Counter ( ) {
2020-04-17 23:19:19 +02:00
return static_cast < u16 > ( counter0_5 ) | static_cast < u16 > ( counter9_11 ) < < 9 ;
}
} ;
static_assert ( sizeof ( BufferDescriptorX ) = = 8 ) ;
2019-11-23 19:48:22 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_A.2FB.2FW_.22Send.22.2F.22Receive.22.2F.22Exchange.22
2019-11-23 19:48:22 +01:00
*/
2020-04-17 23:19:19 +02:00
struct BufferDescriptorABW {
u32 size0_31 : 32 ; //!< The first 32 bits of the size
u32 address0_31 : 32 ; //!< The first 32 bits of the address
u8 flags : 2 ; //!< The buffer flags
u8 address36_38 : 3 ; //!< Bit 36-38 of the address
u32 : 19 ;
u8 size32_35 : 4 ; //!< Bit 32-35 of the size
u8 address32_35 : 4 ; //!< Bit 32-35 of the address
BufferDescriptorABW ( u64 address , u64 size ) {
address0_31 = static_cast < u32 > ( address & 0x7FFFFFFF80000000 ) ;
address32_35 = static_cast < u8 > ( address & 0x78000000 ) ;
address36_38 = static_cast < u8 > ( address & 0x7000000 ) ;
size0_31 = static_cast < u32 > ( size & 0x7FFFFFFF80000000 ) ;
size32_35 = static_cast < u8 > ( size & 0x78000000 ) ;
}
2020-04-22 19:02:27 +02:00
inline u64 Address ( ) {
2020-04-17 23:19:19 +02:00
return static_cast < u64 > ( address0_31 ) | static_cast < u64 > ( address32_35 ) < < 32 | static_cast < u64 > ( address36_38 ) < < 36 ;
}
2020-04-22 19:02:27 +02:00
inline u64 Size ( ) {
2020-04-17 23:19:19 +02:00
return static_cast < u64 > ( size0_31 ) | static_cast < u64 > ( size32_35 ) < < 32 ;
}
} ;
static_assert ( sizeof ( BufferDescriptorABW ) = = 12 ) ;
2019-11-23 19:48:22 +01:00
/**
2020-09-28 12:05:17 +02:00
* @ url https : //switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_C_.22ReceiveList.22
2019-11-23 19:48:22 +01:00
*/
2020-04-17 23:19:19 +02:00
struct BufferDescriptorC {
u64 address : 48 ; //!< The 48-bit address of the buffer
u32 size : 16 ; //!< The 16-bit size of the buffer
BufferDescriptorC ( u64 address , u16 size ) : address ( address ) , size ( size ) { }
} ;
static_assert ( sizeof ( BufferDescriptorC ) = = 8 ) ;
2019-09-24 22:54:27 +02:00
2020-04-17 23:19:19 +02:00
enum class IpcBufferType {
2020-09-28 12:05:17 +02:00
X , //!< Type-X buffer (BufferDescriptorX)
A , //!< Type-A buffer (BufferDescriptorABW)
B , //!< Type-B buffer (BufferDescriptorABW)
W , //!< Type-W buffer (BufferDescriptorABW)
C , //!< Type-C buffer (BufferDescriptorC)
2020-04-17 23:19:19 +02:00
} ;
2019-09-24 22:54:27 +02:00
2020-04-17 23:19:19 +02:00
/**
2020-09-28 12:05:17 +02:00
* @ brief A wrapper over an IPC Request which allows it to be parsed and used effectively
* @ url https : //switchbrew.org/wiki/IPC_Marshalling
2020-04-17 23:19:19 +02:00
*/
class IpcRequest {
private :
2020-09-28 12:05:17 +02:00
u8 * payloadOffset ; //!< The offset of the data read from the payload
2020-04-17 23:19:19 +02:00
public :
2020-09-28 12:05:17 +02:00
CommandHeader * header { } ;
HandleDescriptor * handleDesc { } ;
2020-04-17 23:19:19 +02:00
bool isDomain { } ; //!< If this is a domain request
2020-09-28 12:05:17 +02:00
DomainHeaderRequest * domain { } ;
PayloadHeader * payload { } ;
u8 * cmdArg { } ; //!< A pointer to the data payload
u64 cmdArgSz { } ; //!< The size of the data payload
std : : vector < KHandle > copyHandles ; //!< The handles that should be copied from the server to the client process (The difference is just to match application expectations, there is no real difference b/w copying and moving handles)
std : : vector < KHandle > moveHandles ; //!< The handles that should be moved from the server to the client process rather than copied
std : : vector < KHandle > domainObjects ;
std : : vector < span < u8 > > inputBuf ;
std : : vector < span < u8 > > outputBuf ;
2020-04-17 23:19:19 +02:00
IpcRequest ( bool isDomain , const DeviceState & state ) ;
/**
2020-09-28 12:05:17 +02:00
* @ brief Returns a reference to an item from the top of the payload
2020-04-17 23:19:19 +02:00
*/
template < typename ValueType >
inline ValueType & Pop ( ) {
2020-09-26 07:17:57 +02:00
ValueType & value { * reinterpret_cast < ValueType * > ( payloadOffset ) } ;
2020-04-17 23:19:19 +02:00
payloadOffset + = sizeof ( ValueType ) ;
return value ;
}
2020-04-23 18:39:40 +02:00
/**
2020-09-28 12:05:17 +02:00
* @ brief Returns a std : : string_view from the payload
2020-04-23 18:39:40 +02:00
* @ param size The length of the string ( 0 means the string is null terminated )
*/
inline std : : string_view PopString ( size_t size = 0 ) {
2020-09-26 07:17:57 +02:00
auto view { size ? std : : string_view ( reinterpret_cast < const char * > ( payloadOffset ) , size ) : std : : string_view ( reinterpret_cast < const char * > ( payloadOffset ) ) } ;
2020-04-23 18:39:40 +02:00
payloadOffset + = view . length ( ) ;
return view ;
}
2020-04-17 23:19:19 +02:00
/**
2020-09-28 12:05:17 +02:00
* @ brief Skips an object to pop off the top
2020-04-17 23:19:19 +02:00
*/
template < typename ValueType >
inline void Skip ( ) {
payloadOffset + = sizeof ( ValueType ) ;
2019-09-24 22:54:27 +02:00
}
2020-04-17 23:19:19 +02:00
} ;
2019-09-24 22:54:27 +02:00
/**
2020-09-28 12:05:17 +02:00
* @ brief A wrapper over an IPC Response which allows it to be defined and serialized efficiently
* @ url https : //switchbrew.org/wiki/IPC_Marshalling
2019-09-24 22:54:27 +02:00
*/
2020-04-17 23:19:19 +02:00
class IpcResponse {
private :
2020-09-28 12:05:17 +02:00
const DeviceState & state ;
std : : vector < u8 > payload ; //!< The contents to be pushed to the data payload
2020-04-17 23:19:19 +02:00
public :
2020-09-03 20:43:52 +02:00
Result errorCode { } ; //!< The error code to respond with, it is 0 (Success) by default
2020-09-28 12:05:17 +02:00
std : : vector < KHandle > copyHandles ;
std : : vector < KHandle > moveHandles ;
std : : vector < KHandle > domainObjects ;
2020-04-17 23:19:19 +02:00
2020-06-23 20:49:06 +02:00
IpcResponse ( const DeviceState & state ) ;
2020-04-17 23:19:19 +02:00
/**
* @ brief Writes an object to the payload
* @ tparam ValueType The type of the object to write
* @ param value A reference to the object to be written
*/
template < typename ValueType >
inline void Push ( const ValueType & value ) {
2020-09-26 07:17:57 +02:00
auto size { payload . size ( ) } ;
2020-04-23 18:39:40 +02:00
payload . resize ( size + sizeof ( ValueType ) ) ;
std : : memcpy ( payload . data ( ) + size , reinterpret_cast < const u8 * > ( & value ) , sizeof ( ValueType ) ) ;
}
/**
* @ brief Writes a string to the payload
* @ param string The string to write to the payload
*/
2020-09-28 12:05:17 +02:00
inline void Push ( std : : string_view string ) {
2020-09-26 07:17:57 +02:00
auto size { payload . size ( ) } ;
2020-04-23 18:39:40 +02:00
payload . resize ( size + string . size ( ) ) ;
std : : memcpy ( payload . data ( ) + size , string . data ( ) , string . size ( ) ) ;
2020-04-17 23:19:19 +02:00
}
/**
* @ brief Writes this IpcResponse object ' s contents into TLS
2020-06-23 20:49:06 +02:00
* @ param isDomain Indicates if this is a domain response
2020-04-17 23:19:19 +02:00
*/
2020-06-23 20:49:06 +02:00
void WriteResponse ( bool isDomain ) ;
2020-04-17 23:19:19 +02:00
} ;
}
2019-09-24 22:54:27 +02:00
}