2014-12-14 03:30:11 -02:00
// Copyright 2014 Citra Emulator Project
2014-12-16 21:38:14 -08:00
// Licensed under GPLv2 or any later version
2014-12-14 03:30:11 -02:00
// Refer to the license.txt file included.
# pragma once
2015-06-21 13:40:28 +01:00
# include <string>
# include "common/assert.h"
# include "common/common_types.h"
2014-12-14 03:30:11 -02:00
# include "core/hle/kernel/kernel.h"
2015-05-10 18:35:37 -05:00
# include "core/hle/kernel/thread.h"
2015-06-21 13:40:28 +01:00
# include "core/hle/result.h"
2015-05-12 22:38:29 -03:00
# include "core/memory.h"
2014-12-14 03:30:11 -02:00
2015-06-21 22:47:55 -03:00
namespace IPC {
2016-07-30 18:19:00 +02:00
enum DescriptorType : u32 {
// Buffer related desciptors types (mask : 0x0F)
StaticBuffer = 0x02 ,
PXIBuffer = 0x04 ,
MappedBuffer = 0x08 ,
// Handle related descriptors types (mask : 0x30, but need to check for buffer related descriptors first )
CopyHandle = 0x00 ,
MoveHandle = 0x10 ,
CallingPid = 0x20 ,
} ;
/**
* @brief Creates a command header to be used for IPC
* @param command_id ID of the command to create a header for.
* @param normal_params Size of the normal parameters in words. Up to 63.
* @param translate_params_size Size of the translate parameters in words. Up to 63.
* @return The created IPC header.
*
* Normal parameters are sent directly to the process while the translate parameters might go through modifications and checks by the kernel.
* The translate parameters are described by headers generated with the IPC::*Desc functions.
*
* @note While #normal_params is equivalent to the number of normal parameters, #translate_params_size includes the size occupied by the translate parameters headers.
*/
constexpr u32 MakeHeader ( u16 command_id , unsigned int normal_params , unsigned int translate_params_size ) {
return ( u32 ( command_id ) < < 16 ) | ( ( u32 ( normal_params ) & 0x3F ) < < 6 ) | ( u32 ( translate_params_size ) & 0x3F ) ;
2015-06-21 22:47:55 -03:00
}
2016-07-30 18:19:00 +02:00
union Header {
u32 raw ;
BitField < 0 , 6 , u32 > translate_params_size ;
BitField < 6 , 6 , u32 > normal_params ;
BitField < 16 , 16 , u32 > command_id ;
} ;
inline Header ParseHeader ( u32 header ) {
return { header } ;
2015-06-21 22:47:55 -03:00
}
2016-07-30 18:19:00 +02:00
constexpr u32 MoveHandleDesc ( u32 num_handles = 1 ) {
return MoveHandle | ( ( num_handles - 1 ) < < 26 ) ;
}
constexpr u32 CopyHandleDesc ( u32 num_handles = 1 ) {
return CopyHandle | ( ( num_handles - 1 ) < < 26 ) ;
2015-06-21 22:47:55 -03:00
}
2016-03-21 04:07:03 -04:00
constexpr u32 CallingPidDesc ( ) {
2016-07-30 18:19:00 +02:00
return CallingPid ;
}
constexpr bool isHandleDescriptor ( u32 descriptor ) {
return ( descriptor & 0xF ) = = 0x0 ;
}
constexpr u32 HandleNumberFromDesc ( u32 handle_descriptor ) {
return ( handle_descriptor > > 26 ) + 1 ;
}
constexpr u32 StaticBufferDesc ( u32 size , u8 buffer_id ) {
return StaticBuffer | ( size < < 14 ) | ( ( buffer_id & 0xF ) < < 10 ) ;
2015-06-21 22:47:55 -03:00
}
2016-07-30 18:19:00 +02:00
union StaticBufferDescInfo {
u32 raw ;
BitField < 10 , 4 , u32 > buffer_id ;
BitField < 14 , 18 , u32 > size ;
} ;
inline StaticBufferDescInfo ParseStaticBufferDesc ( const u32 desc ) {
return { desc } ;
2016-05-31 10:05:31 +03:00
}
2016-07-30 18:19:00 +02:00
/**
* @brief Creates a header describing a buffer to be sent over PXI.
* @param size Size of the buffer. Max 0x00FFFFFF.
* @param buffer_id The Id of the buffer. Max 0xF.
* @param is_read_only true if the buffer is read-only. If false, the buffer is considered to have read-write access.
* @return The created PXI buffer header.
*
* The next value is a phys-address of a table located in the BASE memregion.
*/
inline u32 PXIBufferDesc ( u32 size , unsigned buffer_id , bool is_read_only ) {
u32 type = PXIBuffer ;
if ( is_read_only ) type | = 0x2 ;
return type | ( size < < 8 ) | ( ( buffer_id & 0xF ) < < 4 ) ;
2015-06-21 22:47:55 -03:00
}
enum MappedBufferPermissions {
2016-07-30 18:19:00 +02:00
R = 1 ,
W = 2 ,
2015-06-21 22:47:55 -03:00
RW = R | W ,
} ;
2016-03-21 04:07:03 -04:00
constexpr u32 MappedBufferDesc ( u32 size , MappedBufferPermissions perms ) {
2016-07-30 18:19:00 +02:00
return MappedBuffer | ( size < < 4 ) | ( u32 ( perms ) < < 1 ) ;
2015-06-21 22:47:55 -03:00
}
2016-07-30 18:19:00 +02:00
union MappedBufferDescInfo {
u32 raw ;
BitField < 4 , 28 , u32 > size ;
BitField < 1 , 2 , MappedBufferPermissions > perms ;
} ;
inline MappedBufferDescInfo ParseMappedBufferDesc ( const u32 desc ) {
return { desc } ;
2015-06-21 22:47:55 -03:00
}
2016-07-30 18:19:00 +02:00
inline DescriptorType GetDescriptorType ( u32 descriptor ) {
// Note: Those checks must be done in this order
if ( isHandleDescriptor ( descriptor ) )
return ( DescriptorType ) ( descriptor & 0x30 ) ;
// handle the fact that the following descriptors can have rights
if ( descriptor & MappedBuffer )
return MappedBuffer ;
if ( descriptor & PXIBuffer )
return PXIBuffer ;
return StaticBuffer ;
}
} // namespace IPC
2014-12-14 03:30:11 -02:00
namespace Kernel {
static const int kCommandHeaderOffset = 0x80 ; ///< Offset into command buffer of header
/**
2015-05-10 18:35:37 -05:00
* Returns a pointer to the command buffer in the current thread's TLS
* TODO(Subv): This is not entirely correct, the command buffer should be copied from
* the thread's TLS to an intermediate buffer in kernel memory, and then copied again to
* the service handler process' memory.
2014-12-14 03:30:11 -02:00
* @param offset Optional offset into command buffer
* @return Pointer to command buffer
*/
2016-07-30 18:19:00 +02:00
inline u32 * GetCommandBuffer ( const int offset = 0 ) {
2015-05-10 18:35:37 -05:00
return ( u32 * ) Memory : : GetPointer ( GetCurrentThread ( ) - > GetTLSAddress ( ) + kCommandHeaderOffset + offset ) ;
2014-12-14 03:30:11 -02:00
}
/**
* Kernel object representing the client endpoint of an IPC session. Sessions are the basic CTR-OS
* primitive for communication between different processes, and are used to implement service calls
* to the various system services.
*
* To make a service call, the client must write the command header and parameters to the buffer
* located at offset 0x80 of the TLS (Thread-Local Storage) area, then execute a SendSyncRequest
* SVC call with its Session handle. The kernel will read the command header, using it to marshall
* the parameters to the process at the server endpoint of the session. After the server replies to
* the request, the response is marshalled back to the caller's TLS buffer and control is
* transferred back to it.
*
* In Citra, only the client endpoint is currently implemented and only HLE calls, where the IPC
* request is answered by C++ code in the emulator, are supported. When SendSyncRequest is called
* with the session handle, this class's SyncRequest method is called, which should read the TLS
* buffer and emulate the call accordingly. Since the code can directly read the emulated memory,
* no parameter marshalling is done.
*
* In the long term, this should be turned into the full-fledged IPC mechanism implemented by
* CTR-OS so that IPC calls can be optionally handled by the real implementations of processes, as
* opposed to HLE simulations.
*/
2015-01-18 20:40:53 -05:00
class Session : public WaitObject {
2014-12-14 03:30:11 -02:00
public :
2015-01-31 22:56:59 -02:00
Session ( ) ;
~ Session ( ) override ;
2014-12-14 03:30:11 -02:00
std : : string GetTypeName ( ) const override { return " Session " ; }
2014-12-21 08:40:29 -02:00
static const HandleType HANDLE_TYPE = HandleType : : Session ;
HandleType GetHandleType ( ) const override { return HANDLE_TYPE ; }
2014-12-14 03:30:11 -02:00
/**
* Handles a synchronous call to this session using HLE emulation. Emulated <-> emulated calls
* aren't supported yet.
*/
virtual ResultVal < bool > SyncRequest ( ) = 0 ;
2015-01-18 20:40:53 -05:00
2015-01-20 17:41:12 -05:00
// TODO(bunnei): These functions exist to satisfy a hardware test with a Session object
// passed into WaitSynchronization. Figure out the meaning of them.
2015-01-20 18:16:45 -05:00
bool ShouldWait ( ) override {
return true ;
2015-01-18 20:40:53 -05:00
}
2015-01-20 17:41:12 -05:00
2015-01-20 18:16:45 -05:00
void Acquire ( ) override {
2015-01-20 17:16:47 -08:00
ASSERT_MSG ( ! ShouldWait ( ) , " object unavailable! " ) ;
2015-01-20 17:41:12 -05:00
}
2014-12-14 03:30:11 -02:00
} ;
}