2020-03-27 20:36:02 +01:00
// SPDX-License-Identifier: LGPL-3.0-or-later
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
2019-09-24 22:54:27 +02:00
# pragma once
# include <array>
2019-10-13 10:04:47 +02:00
# include <common.h>
2019-09-24 22:54:27 +02:00
namespace skyline : : kernel : : ipc {
/**
* @ brief This reflects the value in CommandStruct : : type
*/
enum class CommandType : u16 {
Invalid = 0 , LegacyRequest = 1 , Close = 2 , LegacyControl = 3 , Request = 4 , Control = 5 , RequestWithContext = 6 , ControlWithContext = 7
} ;
/**
* @ brief This reflects the value in CommandStruct : : c_flags
*/
enum class BufferCFlag : u8 {
None = 0 , InlineDescriptor = 1 , SingleDescriptor = 2
} ;
2019-11-14 20:06:38 +01:00
/**
* @ brief This bit - field structure holds the header of an IPC command . ( https : //switchbrew.org/wiki/IPC_Marshalling#IPC_Command_Structure)
*/
struct CommandHeader {
CommandType type : 16 ;
2020-01-21 08:16:57 +01:00
u8 xNo : 4 ;
u8 aNo : 4 ;
u8 bNo : 4 ;
u8 wNo : 4 ;
2019-11-14 20:06:38 +01:00
u32 rawSize : 10 ;
BufferCFlag cFlag : 4 ;
u32 : 17 ;
bool handleDesc : 1 ;
} ;
static_assert ( sizeof ( CommandHeader ) = = 8 ) ;
2019-09-24 22:54:27 +02:00
/**
* @ brief This bit - field structure holds the handle descriptor of a received IPC command . ( https : //switchbrew.org/wiki/IPC_Marshalling#Handle_descriptor)
*/
struct HandleDescriptor {
2019-11-14 20:06:38 +01:00
bool sendPid : 1 ;
u32 copyCount : 4 ;
u32 moveCount : 4 ;
u32 : 23 ;
2019-09-24 22:54:27 +02:00
} ;
static_assert ( sizeof ( HandleDescriptor ) = = 4 ) ;
/**
* @ brief This bit - field structure holds the domain ' s header of an IPC request command . ( https : //switchbrew.org/wiki/IPC_Marshalling#Domains)
*/
struct DomainHeaderRequest {
u8 command ;
2019-11-14 20:06:38 +01:00
u8 inputCount ;
u16 payloadSz ;
u32 objectId ;
2019-09-24 22:54:27 +02:00
u32 : 32 ;
u32 token ;
} ;
static_assert ( sizeof ( DomainHeaderRequest ) = = 16 ) ;
/**
* @ brief This reflects the value of DomainHeaderRequest : : command
*/
enum class DomainCommand : u8 {
SendMessage = 1 , CloseVHandle = 2
} ;
/**
* @ brief This bit - field structure holds the domain ' s header of an IPC response command . ( https : //switchbrew.org/wiki/IPC_Marshalling#Domains)
*/
struct DomainHeaderResponse {
2019-11-14 20:06:38 +01:00
u32 outputCount ;
2019-09-24 22:54:27 +02:00
u32 : 32 ;
u64 : 64 ;
} ;
static_assert ( sizeof ( DomainHeaderResponse ) = = 16 ) ;
/**
* @ brief This bit - field structure holds the data payload of an IPC command . ( https : //switchbrew.org/wiki/IPC_Marshalling#Data_payload)
*/
struct PayloadHeader {
u32 magic ;
u32 version ;
u32 value ;
u32 token ;
} ;
static_assert ( sizeof ( PayloadHeader ) = = 16 ) ;
/**
* @ brief This reflects which function PayloadHeader : : value refers to when a control request is sent ( https : //switchbrew.org/wiki/IPC_Marshalling#Control)
*/
enum class ControlCommand : u32 {
ConvertCurrentObjectToDomain = 0 , CopyFromCurrentDomain = 1 , CloneCurrentObject = 2 , QueryPointerBufferSize = 3 , CloneCurrentObjectEx = 4
} ;
/**
* @ brief This is a buffer descriptor for X buffers : https : //switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_X_.22Pointer.22
*/
struct BufferDescriptorX {
2020-02-15 10:38:17 +01:00
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
2019-09-24 22:54:27 +02:00
BufferDescriptorX ( u64 address , u16 counter , u16 size ) : size ( size ) {
2019-11-14 20:06:38 +01:00
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 ) ;
2019-09-24 22:54:27 +02:00
}
2020-02-15 10:38:17 +01:00
/**
* @ return The address of the buffer
*/
2019-09-24 22:54:27 +02:00
inline u64 Address ( ) const {
2019-11-14 20:06:38 +01:00
return static_cast < u64 > ( address0_31 ) | static_cast < u64 > ( address32_35 ) < < 32 | static_cast < u64 > ( address36_38 ) < < 36 ;
2019-09-24 22:54:27 +02:00
}
2020-02-15 10:38:17 +01:00
/**
* @ return The buffer counter
*/
2019-09-24 22:54:27 +02:00
inline u16 Counter ( ) const {
2019-11-14 20:06:38 +01:00
return static_cast < u16 > ( counter0_5 ) | static_cast < u16 > ( counter9_11 ) < < 9 ;
2019-09-24 22:54:27 +02:00
}
} ;
static_assert ( sizeof ( BufferDescriptorX ) = = 8 ) ;
/**
* @ brief This is a buffer descriptor for A / B / W buffers : https : //switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_A.2FB.2FW_.22Send.22.2F.22Receive.22.2F.22Exchange.22
*/
struct BufferDescriptorABW {
2020-02-15 10:38:17 +01:00
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
2019-11-14 20:06:38 +01:00
u32 : 19 ;
2020-02-15 10:38:17 +01:00
u8 size32_35 : 4 ; //!< Bit 32-35 of the size
u8 address32_35 : 4 ; //!< Bit 32-35 of the address
2019-09-24 22:54:27 +02:00
BufferDescriptorABW ( u64 address , u64 size ) {
2019-11-14 20:06:38 +01:00
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 ) ;
2019-09-24 22:54:27 +02:00
}
2020-02-15 10:38:17 +01:00
/**
* @ return The address of the buffer
*/
2019-09-24 22:54:27 +02:00
inline u64 Address ( ) const {
2019-11-14 20:06:38 +01:00
return static_cast < u64 > ( address0_31 ) | static_cast < u64 > ( address32_35 ) < < 32 | static_cast < u64 > ( address36_38 ) < < 36 ;
2019-09-24 22:54:27 +02:00
}
2020-02-15 10:38:17 +01:00
/**
* @ return The size of the buffer
*/
2019-09-24 22:54:27 +02:00
inline u64 Size ( ) const {
2019-11-14 20:06:38 +01:00
return static_cast < u64 > ( size0_31 ) | static_cast < u64 > ( size32_35 ) < < 32 ;
2019-09-24 22:54:27 +02:00
}
} ;
static_assert ( sizeof ( BufferDescriptorABW ) = = 12 ) ;
/**
* @ brief This is a buffer descriptor for C buffers : https : //switchbrew.org/wiki/IPC_Marshalling#Buffer_descriptor_C_.22ReceiveList.22
*/
struct BufferDescriptorC {
2020-02-15 10:38:17 +01:00
u64 address : 48 ; //!< The 48-bit address of the buffer
u32 size : 16 ; //!< The 16-bit size of the buffer
2019-09-24 22:54:27 +02:00
BufferDescriptorC ( u64 address , u16 size ) : address ( address ) , size ( size ) { }
} ;
static_assert ( sizeof ( BufferDescriptorC ) = = 8 ) ;
2019-11-23 19:48:22 +01:00
/**
* @ brief This enumerates the types of IPC buffers
*/
enum class IpcBufferType {
X , //!< This is a type-X buffer
A , //!< This is a type-A buffer
B , //!< This is a type-B buffer
W , //!< This is a type-W buffer
C //!< This is a type-C buffer
} ;
/**
* @ brief Describes a buffer by holding the address and size
*/
struct IpcBuffer {
u64 address ; //!< The address of the buffer
size_t size ; //!< The size of the buffer
IpcBufferType type ; //!< The type of the buffer
/**
* @ param address The address of the buffer
* @ param size The size of the buffer
* @ param type The type of the buffer
*/
IpcBuffer ( u64 address , size_t size , IpcBufferType type ) ;
} ;
/**
* @ brief This holds an input IPC buffer
*/
struct InputBuffer : public IpcBuffer {
/**
* @ param aBuf The X Buffer Descriptor that has contains the input data
*/
InputBuffer ( kernel : : ipc : : BufferDescriptorX * xBuf ) ;
/**
* @ param aBuf The A or W Buffer Descriptor that has contains the input data
*/
InputBuffer ( kernel : : ipc : : BufferDescriptorABW * aBuf , IpcBufferType type = IpcBufferType : : A ) ;
} ;
/**
* @ brief This holds an output IPC buffer
*/
struct OutputBuffer : public IpcBuffer {
/**
* @ param bBuf The B or W Buffer Descriptor that has to be outputted to
*/
OutputBuffer ( kernel : : ipc : : BufferDescriptorABW * bBuf , IpcBufferType type = IpcBufferType : : B ) ;
/**
* @ param cBuf The C Buffer Descriptor that has to be outputted to
*/
OutputBuffer ( kernel : : ipc : : BufferDescriptorC * cBuf ) ;
} ;
2019-09-24 22:54:27 +02:00
/**
* @ brief This class encapsulates an IPC Request ( https : //switchbrew.org/wiki/IPC_Marshalling)
*/
class IpcRequest {
private :
const DeviceState & state ; //!< The state of the device
2019-11-23 19:48:22 +01:00
u8 * payloadOffset ; //!< This is the offset of the data read from the payload
2019-09-24 22:54:27 +02:00
public :
CommandHeader * header { } ; //!< The header of the request
HandleDescriptor * handleDesc { } ; //!< The handle descriptor in case CommandHeader::handle_desc is true in the header
bool isDomain { } ; //!< If this is a domain request
DomainHeaderRequest * domain { } ; //!< In case this is a domain request, this holds data regarding it
PayloadHeader * payload { } ; //!< This is the header of the payload
u8 * cmdArg { } ; //!< This is a pointer to the data payload (End of PayloadHeader)
u64 cmdArgSz { } ; //!< This is the size of the data payload
2020-03-25 18:59:37 +01:00
std : : vector < KHandle > copyHandles ; //!< A vector of 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 ; //!< A vector of handles that should be moved from the server to the client process rather than copied
std : : vector < KHandle > domainObjects ; //!< A vector of all input domain objects
2019-11-23 19:48:22 +01:00
std : : vector < InputBuffer > inputBuf ; //!< This is a vector of input buffers
std : : vector < OutputBuffer > outputBuf ; //!< This is a vector of output buffers
2019-09-24 22:54:27 +02:00
/**
* @ param isDomain If the following request is a domain request
* @ param state The state of the device
*/
IpcRequest ( bool isDomain , const DeviceState & state ) ;
2019-11-23 19:48:22 +01:00
/**
* @ brief This returns a reference to an item from the top of the payload
* @ tparam ValueType The type of the object to read
*/
template < typename ValueType >
2020-01-11 05:52:25 +01:00
inline ValueType & Pop ( ) {
ValueType & value = * reinterpret_cast < ValueType * > ( payloadOffset ) ;
2019-11-23 19:48:22 +01:00
payloadOffset + = sizeof ( ValueType ) ;
return value ;
}
/**
* @ brief This skips an object to pop off the top
* @ tparam ValueType The type of the object to skip
*/
template < typename ValueType >
inline void Skip ( ) {
payloadOffset + = sizeof ( ValueType ) ;
}
2019-09-24 22:54:27 +02:00
} ;
/**
* @ brief This class encapsulates an IPC Response ( https : //switchbrew.org/wiki/IPC_Marshalling)
*/
class IpcResponse {
private :
std : : vector < u8 > argVec ; //!< This holds all of the contents to be pushed to the payload
const DeviceState & state ; //!< The state of the device
public :
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
bool nWrite { } ; //!< This is to signal the IPC handler to not write this, as it will be manually written
2019-09-24 22:54:27 +02:00
bool isDomain { } ; //!< If this is a domain request
u32 errorCode { } ; //!< The error code to respond with, it is 0 (Success) by default
2020-03-25 18:59:37 +01:00
std : : vector < KHandle > copyHandles ; //!< A vector of handles to copy
std : : vector < KHandle > moveHandles ; //!< A vector of handles to move
std : : vector < KHandle > domainObjects ; //!< A vector of domain objects to write
2019-09-24 22:54:27 +02:00
/**
* @ param isDomain If the following request is a domain request
* @ param state The state of the device
*/
IpcResponse ( bool isDomain , const DeviceState & state ) ;
/**
* @ brief Writes an object to the payload
* @ tparam ValueType The type of the object to write
2019-11-23 19:48:22 +01:00
* @ param value A reference to the object to be written
2019-09-24 22:54:27 +02:00
*/
template < typename ValueType >
2019-11-23 19:48:22 +01:00
inline void Push ( const ValueType & value ) {
2019-09-24 22:54:27 +02:00
argVec . reserve ( argVec . size ( ) + sizeof ( ValueType ) ) ;
auto item = reinterpret_cast < const u8 * > ( & value ) ;
for ( uint index = 0 ; sizeof ( ValueType ) > index ; index + + ) {
argVec . push_back ( * item ) ;
item + + ;
}
}
/**
* @ brief Writes this IpcResponse object ' s contents into TLS
*/
2019-11-23 19:48:22 +01:00
void WriteResponse ( ) ;
2019-09-24 22:54:27 +02:00
} ;
}