mirror of
https://github.com/switchbrew/libnx.git
synced 2025-06-21 20:42:44 +02:00
Introduce new IPC interface wrapper code, see details:
- Service object moved away from sm.h and into its own file (sf/service.h) - Service object completely redesigned, but a (mostly) backwards compatible API was kept - New low level HIPC request/response code - New CMIF client-oriented code - New service IPC dispatch functions - Pointer buffer size automatically retrieved for all sessions - Removed previous manual pointer buffer size query code - SM rewritten with new IPC code - All other services are still pending IPC rewrite
This commit is contained in:
parent
0a3592d4dd
commit
6ad0042147
@ -36,9 +36,13 @@ extern "C" {
|
|||||||
#include "switch/kernel/detect.h"
|
#include "switch/kernel/detect.h"
|
||||||
#include "switch/kernel/random.h"
|
#include "switch/kernel/random.h"
|
||||||
#include "switch/kernel/jit.h"
|
#include "switch/kernel/jit.h"
|
||||||
#include "switch/kernel/ipc.h"
|
#include "switch/kernel/ipc.h" // Deprecated
|
||||||
#include "switch/kernel/barrier.h"
|
#include "switch/kernel/barrier.h"
|
||||||
|
|
||||||
|
#include "switch/sf/hipc.h"
|
||||||
|
#include "switch/sf/cmif.h"
|
||||||
|
#include "switch/sf/service.h"
|
||||||
|
|
||||||
#include "switch/services/sm.h"
|
#include "switch/services/sm.h"
|
||||||
#include "switch/services/smm.h"
|
#include "switch/services/smm.h"
|
||||||
#include "switch/services/fs.h"
|
#include "switch/services/fs.h"
|
||||||
|
@ -10,7 +10,7 @@ typedef struct {
|
|||||||
bool initialized : 1;
|
bool initialized : 1;
|
||||||
bool has_transact_auto : 1;
|
bool has_transact_auto : 1;
|
||||||
s32 id;
|
s32 id;
|
||||||
size_t ipc_buffer_size;
|
size_t dummy;
|
||||||
Service* relay;
|
Service* relay;
|
||||||
} Binder;
|
} Binder;
|
||||||
|
|
||||||
|
@ -9,71 +9,11 @@
|
|||||||
#include "../types.h"
|
#include "../types.h"
|
||||||
#include "../kernel/svc.h"
|
#include "../kernel/svc.h"
|
||||||
#include "../kernel/ipc.h"
|
#include "../kernel/ipc.h"
|
||||||
|
#include "../sf/service.h"
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||||
|
|
||||||
/// Service type.
|
|
||||||
typedef enum {
|
|
||||||
ServiceType_Uninitialized, ///< Uninitialized service.
|
|
||||||
ServiceType_Normal, ///< Normal service.
|
|
||||||
ServiceType_Domain, ///< Domain.
|
|
||||||
ServiceType_DomainSubservice, ///< Domain subservice;
|
|
||||||
ServiceType_Override, ///< Service overriden in the homebrew environment.
|
|
||||||
} ServiceType;
|
|
||||||
|
|
||||||
/// Service object structure.
|
|
||||||
typedef struct {
|
|
||||||
Handle handle;
|
|
||||||
u32 object_id;
|
|
||||||
ServiceType type;
|
|
||||||
} Service;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns whether a service is overriden in the homebrew environment.
|
|
||||||
* @param[in] s Service object.
|
|
||||||
* @return true if overriden.
|
|
||||||
*/
|
|
||||||
static inline bool serviceIsOverride(Service* s) {
|
|
||||||
return s->type == ServiceType_Override;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns whether a service has been initialized.
|
|
||||||
* @param[in] s Service object.
|
|
||||||
* @return true if initialized.
|
|
||||||
*/
|
|
||||||
static inline bool serviceIsActive(Service* s) {
|
|
||||||
return s->type != ServiceType_Uninitialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns whether a service is a domain.
|
|
||||||
* @param[in] s Service object.
|
|
||||||
* @return true if a domain.
|
|
||||||
*/
|
|
||||||
static inline bool serviceIsDomain(Service* s) {
|
|
||||||
return s->type == ServiceType_Domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns whether a service is a domain subservice.
|
|
||||||
* @param[in] s Service object.
|
|
||||||
* @return true if a domain subservice.
|
|
||||||
*/
|
|
||||||
static inline bool serviceIsDomainSubservice(Service* s) {
|
|
||||||
return s->type == ServiceType_DomainSubservice;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief For a domain/domain subservice, return the associated object ID.
|
|
||||||
* @param[in] s Service object, necessarily a domain or domain subservice.
|
|
||||||
* @return The object ID.
|
|
||||||
*/
|
|
||||||
static inline u32 serviceGetObjectId(Service* s) {
|
|
||||||
return s->object_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Closes a domain object by ID.
|
* @brief Closes a domain object by ID.
|
||||||
* @param[in] s Service object, necessarily a domain or domain subservice.
|
* @param[in] s Service object, necessarily a domain or domain subservice.
|
||||||
@ -82,7 +22,7 @@ static inline u32 serviceGetObjectId(Service* s) {
|
|||||||
*/
|
*/
|
||||||
DEPRECATED
|
DEPRECATED
|
||||||
static inline Result serviceCloseObjectById(Service* s, u32 object_id) {
|
static inline Result serviceCloseObjectById(Service* s, u32 object_id) {
|
||||||
return ipcCloseObjectById(s->handle, object_id);
|
return ipcCloseObjectById(s->session, object_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -92,30 +32,7 @@ static inline Result serviceCloseObjectById(Service* s, u32 object_id) {
|
|||||||
*/
|
*/
|
||||||
DEPRECATED
|
DEPRECATED
|
||||||
static inline Result serviceIpcDispatch(Service* s) {
|
static inline Result serviceIpcDispatch(Service* s) {
|
||||||
return ipcDispatch(s->handle);
|
return ipcDispatch(s->session);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a service object from an IPC session handle.
|
|
||||||
* @param[out] s Service object.
|
|
||||||
* @param[in] h IPC session handle.
|
|
||||||
*/
|
|
||||||
static inline void serviceCreate(Service* s, Handle h) {
|
|
||||||
s->handle = h;
|
|
||||||
s->type = ServiceType_Normal;
|
|
||||||
s->object_id = IPC_INVALID_OBJECT_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Creates a domain subservice object from a parent service.
|
|
||||||
* @param[out] s Service object.
|
|
||||||
* @param[in] parent Parent service, necessarily a domain or domain subservice.
|
|
||||||
* @param[in] object_id Object ID for this subservice.
|
|
||||||
*/
|
|
||||||
static inline void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id) {
|
|
||||||
s->handle = parent->handle;
|
|
||||||
s->type = ServiceType_DomainSubservice;
|
|
||||||
s->object_id = object_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -146,57 +63,6 @@ static inline void serviceSendObject(Service* s, IpcCommand* cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Converts a regular service to a domain.
|
|
||||||
* @param[in] s Service object.
|
|
||||||
* @return Result code.
|
|
||||||
*/
|
|
||||||
static inline Result serviceConvertToDomain(Service* s) {
|
|
||||||
Result rc = 0;
|
|
||||||
if (serviceIsOverride(s)) {
|
|
||||||
rc = ipcCloneSession(s->handle, 1, &s->handle);
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
s->type = ServiceType_Normal;
|
|
||||||
}
|
|
||||||
rc = ipcConvertSessionToDomain(s->handle, &s->object_id);
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
s->type = ServiceType_Domain;
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Closes a service.
|
|
||||||
* @param[in] s Service object.
|
|
||||||
*/
|
|
||||||
static inline void serviceClose(Service* s) {
|
|
||||||
switch (s->type) {
|
|
||||||
|
|
||||||
case ServiceType_Normal:
|
|
||||||
case ServiceType_Domain:
|
|
||||||
ipcCloseSession(s->handle);
|
|
||||||
svcCloseHandle(s->handle);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServiceType_DomainSubservice:
|
|
||||||
serviceCloseObjectById(s, s->object_id);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServiceType_Override:
|
|
||||||
// Don't close because we don't own the overridden handle.
|
|
||||||
break;
|
|
||||||
|
|
||||||
case ServiceType_Uninitialized:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
s->type = ServiceType_Uninitialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Prepares the header of an IPC command structure for a service.
|
* @brief Prepares the header of an IPC command structure for a service.
|
||||||
* @param s Service to prepare message header for
|
* @param s Service to prepare message header for
|
||||||
@ -229,6 +95,8 @@ static inline Result serviceIpcParse(Service* s, IpcParsedCommand* r, size_t siz
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes SM.
|
* @brief Initializes SM.
|
||||||
* @return Result code.
|
* @return Result code.
|
||||||
@ -308,5 +176,3 @@ u64 smEncodeName(const char* name);
|
|||||||
* @param[in] handle IPC session handle.
|
* @param[in] handle IPC session handle.
|
||||||
*/
|
*/
|
||||||
void smAddOverrideHandle(u64 name, Handle handle);
|
void smAddOverrideHandle(u64 name, Handle handle);
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
|
||||||
|
@ -96,7 +96,6 @@ typedef struct {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
Service s;
|
Service s;
|
||||||
Event eventXfer; ///< [2.0.0+] Signaled when PostBufferAsync finishes.
|
Event eventXfer; ///< [2.0.0+] Signaled when PostBufferAsync finishes.
|
||||||
size_t ptrbufsize; ///< [3.0.0+] IPC pointer buffer size.
|
|
||||||
|
|
||||||
struct usb_endpoint_descriptor desc;
|
struct usb_endpoint_descriptor desc;
|
||||||
} UsbHsClientEpSession;
|
} UsbHsClientEpSession;
|
||||||
|
362
nx/include/switch/sf/cmif.h
Normal file
362
nx/include/switch/sf/cmif.h
Normal file
@ -0,0 +1,362 @@
|
|||||||
|
/**
|
||||||
|
* @file cmif.h
|
||||||
|
* @brief Common Message Interface Framework protocol
|
||||||
|
* @author fincs
|
||||||
|
* @author SciresM
|
||||||
|
* @copyright libnx Authors
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "hipc.h"
|
||||||
|
|
||||||
|
#define CMIF_IN_HEADER_MAGIC 0x49434653 // "SFCI"
|
||||||
|
#define CMIF_OUT_HEADER_MAGIC 0x4F434653 // "SFCO"
|
||||||
|
|
||||||
|
typedef enum CmifCommandType {
|
||||||
|
CmifCommandType_Invalid = 0,
|
||||||
|
CmifCommandType_LegacyRequest = 1,
|
||||||
|
CmifCommandType_Close = 2,
|
||||||
|
CmifCommandType_LegacyControl = 3,
|
||||||
|
CmifCommandType_Request = 4,
|
||||||
|
CmifCommandType_Control = 5,
|
||||||
|
CmifCommandType_RequestWithContext = 6,
|
||||||
|
CmifCommandType_ControlWithContext = 7,
|
||||||
|
} CmifCommandType;
|
||||||
|
|
||||||
|
typedef enum CmifDomainRequestType {
|
||||||
|
CmifDomainRequestType_Invalid = 0,
|
||||||
|
CmifDomainRequestType_SendMessage = 1,
|
||||||
|
CmifDomainRequestType_Close = 2,
|
||||||
|
} CmifDomainRequestType;
|
||||||
|
|
||||||
|
typedef struct CmifInHeader {
|
||||||
|
u32 magic;
|
||||||
|
u32 version;
|
||||||
|
u32 command_id;
|
||||||
|
u32 token;
|
||||||
|
} CmifInHeader;
|
||||||
|
|
||||||
|
typedef struct CmifOutHeader {
|
||||||
|
u32 magic;
|
||||||
|
u32 version;
|
||||||
|
Result result;
|
||||||
|
u32 token;
|
||||||
|
} CmifOutHeader;
|
||||||
|
|
||||||
|
typedef struct CmifDomainInHeader {
|
||||||
|
u8 type;
|
||||||
|
u8 num_in_objects;
|
||||||
|
u16 data_size;
|
||||||
|
u32 object_id;
|
||||||
|
u32 padding;
|
||||||
|
u32 token;
|
||||||
|
} CmifDomainInHeader;
|
||||||
|
|
||||||
|
typedef struct CmifDomainOutHeader {
|
||||||
|
u32 num_out_objects;
|
||||||
|
u32 padding[3];
|
||||||
|
} CmifDomainOutHeader;
|
||||||
|
|
||||||
|
typedef struct CmifRequestFormat {
|
||||||
|
u32 object_id;
|
||||||
|
u32 request_id;
|
||||||
|
u32 context;
|
||||||
|
u32 data_size;
|
||||||
|
u32 server_pointer_size;
|
||||||
|
u32 num_in_auto_buffers;
|
||||||
|
u32 num_out_auto_buffers;
|
||||||
|
u32 num_in_buffers;
|
||||||
|
u32 num_out_buffers;
|
||||||
|
u32 num_inout_buffers;
|
||||||
|
u32 num_in_pointers;
|
||||||
|
u32 num_out_pointers;
|
||||||
|
u32 num_out_fixed_pointers;
|
||||||
|
u32 num_objects;
|
||||||
|
u32 num_handles;
|
||||||
|
u32 send_pid;
|
||||||
|
} CmifRequestFormat;
|
||||||
|
|
||||||
|
typedef struct CmifRequest {
|
||||||
|
HipcRequest hipc;
|
||||||
|
void* data;
|
||||||
|
u16* out_pointer_sizes;
|
||||||
|
u32* objects;
|
||||||
|
u32 server_pointer_size;
|
||||||
|
u32 cur_in_ptr_id;
|
||||||
|
} CmifRequest;
|
||||||
|
|
||||||
|
typedef struct CmifResponse {
|
||||||
|
void* data;
|
||||||
|
u32* objects;
|
||||||
|
Handle* copy_handles;
|
||||||
|
Handle* move_handles;
|
||||||
|
} CmifResponse;
|
||||||
|
|
||||||
|
NX_CONSTEXPR void* cmifGetAlignedDataStart(u32* data_words, void* base)
|
||||||
|
{
|
||||||
|
intptr_t data_start = ((u8*)data_words - (u8*)base + 15) &~ 15;
|
||||||
|
return (u8*)base + data_start;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR CmifRequest cmifMakeRequest(void* base, CmifRequestFormat fmt)
|
||||||
|
{
|
||||||
|
// First of all, we need to figure out what size we need.
|
||||||
|
u32 actual_size = 16;
|
||||||
|
if (fmt.object_id)
|
||||||
|
actual_size += sizeof(CmifDomainInHeader) + fmt.num_objects*sizeof(u32);
|
||||||
|
actual_size += sizeof(CmifInHeader) + fmt.data_size;
|
||||||
|
actual_size = (actual_size + 1) &~ 1; // hword-align
|
||||||
|
u32 out_pointer_size_table_offset = actual_size;
|
||||||
|
u32 out_pointer_size_table_size = fmt.num_out_auto_buffers + fmt.num_out_pointers;
|
||||||
|
actual_size += sizeof(u16)*out_pointer_size_table_size;
|
||||||
|
u32 num_data_words = (actual_size + 3) / 4;
|
||||||
|
|
||||||
|
CmifRequest req = {};
|
||||||
|
req.hipc = hipcMakeRequestInline(base,
|
||||||
|
.type = CmifCommandType_Request,
|
||||||
|
.num_send_statics = fmt.num_in_auto_buffers + fmt.num_in_pointers,
|
||||||
|
.num_send_buffers = fmt.num_in_auto_buffers + fmt.num_in_buffers,
|
||||||
|
.num_recv_buffers = fmt.num_out_auto_buffers + fmt.num_out_buffers,
|
||||||
|
.num_exch_buffers = fmt.num_inout_buffers,
|
||||||
|
.num_data_words = num_data_words,
|
||||||
|
.num_recv_statics = out_pointer_size_table_size + fmt.num_out_fixed_pointers,
|
||||||
|
.send_pid = fmt.send_pid,
|
||||||
|
.num_copy_handles = fmt.num_handles,
|
||||||
|
.num_move_handles = 0,
|
||||||
|
);
|
||||||
|
|
||||||
|
CmifInHeader* hdr = NULL;
|
||||||
|
void* start = cmifGetAlignedDataStart(req.hipc.data_words, base);
|
||||||
|
if (fmt.object_id) {
|
||||||
|
CmifDomainInHeader* domain_hdr = (CmifDomainInHeader*)start;
|
||||||
|
u32 payload_size = sizeof(CmifInHeader) + fmt.data_size;
|
||||||
|
*domain_hdr = (CmifDomainInHeader){
|
||||||
|
.type = CmifDomainRequestType_SendMessage,
|
||||||
|
.num_in_objects = fmt.num_objects,
|
||||||
|
.data_size = (u16)payload_size,
|
||||||
|
.object_id = fmt.object_id,
|
||||||
|
.padding = 0,
|
||||||
|
.token = 0,
|
||||||
|
};
|
||||||
|
hdr = (CmifInHeader*)(domain_hdr+1);
|
||||||
|
req.objects = (u32*)((u8*)hdr + payload_size);
|
||||||
|
} else
|
||||||
|
hdr = (CmifInHeader*)start;
|
||||||
|
|
||||||
|
*hdr = (CmifInHeader){
|
||||||
|
.magic = CMIF_IN_HEADER_MAGIC,
|
||||||
|
.version = 0,
|
||||||
|
.command_id = fmt.request_id,
|
||||||
|
.token = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
req.data = hdr+1;
|
||||||
|
req.out_pointer_sizes = (u16*)((u8*)req.hipc.data_words + out_pointer_size_table_offset);
|
||||||
|
req.server_pointer_size = fmt.server_pointer_size;
|
||||||
|
|
||||||
|
return req;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void* cmifMakeControlRequest(void* base, u32 request_id, u32 size)
|
||||||
|
{
|
||||||
|
u32 actual_size = 16 + sizeof(CmifInHeader) + size;
|
||||||
|
HipcRequest hipc = hipcMakeRequestInline(base,
|
||||||
|
.type = CmifCommandType_Control,
|
||||||
|
.num_data_words = (actual_size + 3) / 4,
|
||||||
|
);
|
||||||
|
CmifInHeader* hdr = (CmifInHeader*)cmifGetAlignedDataStart(hipc.data_words, base);
|
||||||
|
*hdr = (CmifInHeader){
|
||||||
|
.magic = CMIF_IN_HEADER_MAGIC,
|
||||||
|
.version = 0,
|
||||||
|
.command_id = request_id,
|
||||||
|
.token = 0,
|
||||||
|
};
|
||||||
|
return hdr+1;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifMakeCloseRequest(void* base, u32 object_id)
|
||||||
|
{
|
||||||
|
if (object_id) {
|
||||||
|
HipcRequest hipc = hipcMakeRequestInline(base,
|
||||||
|
.type = CmifCommandType_Request,
|
||||||
|
.num_data_words = (16 + sizeof(CmifDomainInHeader)) / 4,
|
||||||
|
);
|
||||||
|
CmifDomainInHeader* domain_hdr = (CmifDomainInHeader*)cmifGetAlignedDataStart(hipc.data_words, base);
|
||||||
|
*domain_hdr = (CmifDomainInHeader){
|
||||||
|
.type = CmifDomainRequestType_Close,
|
||||||
|
.object_id = object_id,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
hipcMakeRequestInline(base,
|
||||||
|
.type = CmifCommandType_Close,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestInBuffer(CmifRequest* req, const void* buffer, size_t size, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
*req->hipc.send_buffers++ = hipcMakeBuffer(buffer, size, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestOutBuffer(CmifRequest* req, void* buffer, size_t size, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
*req->hipc.recv_buffers++ = hipcMakeBuffer(buffer, size, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestInOutBuffer(CmifRequest* req, void* buffer, size_t size, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
*req->hipc.exch_buffers++ = hipcMakeBuffer(buffer, size, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestInPointer(CmifRequest* req, const void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
*req->hipc.send_statics++ = hipcMakeSendStatic(buffer, size, req->cur_in_ptr_id++);
|
||||||
|
req->server_pointer_size -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestOutFixedPointer(CmifRequest* req, void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
*req->hipc.recv_list++ = hipcMakeRecvStatic(buffer, size);
|
||||||
|
req->server_pointer_size -= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestOutPointer(CmifRequest* req, void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
cmifRequestOutFixedPointer(req, buffer, size);
|
||||||
|
*req->out_pointer_sizes++ = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestInAutoBuffer(CmifRequest* req, const void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (req->server_pointer_size && size <= req->server_pointer_size) {
|
||||||
|
cmifRequestInPointer(req, buffer, size);
|
||||||
|
cmifRequestInBuffer(req, NULL, 0, HipcBufferMode_Normal);
|
||||||
|
} else {
|
||||||
|
cmifRequestInPointer(req, NULL, 0);
|
||||||
|
cmifRequestInBuffer(req, buffer, size, HipcBufferMode_Normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestOutAutoBuffer(CmifRequest* req, void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
if (req->server_pointer_size && size <= req->server_pointer_size) {
|
||||||
|
cmifRequestOutPointer(req, buffer, size);
|
||||||
|
cmifRequestOutBuffer(req, NULL, 0, HipcBufferMode_Normal);
|
||||||
|
} else {
|
||||||
|
cmifRequestOutPointer(req, NULL, 0);
|
||||||
|
cmifRequestOutBuffer(req, buffer, size, HipcBufferMode_Normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestObject(CmifRequest* req, u32 object_id)
|
||||||
|
{
|
||||||
|
*req->objects++ = object_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void cmifRequestHandle(CmifRequest* req, Handle handle)
|
||||||
|
{
|
||||||
|
*req->hipc.copy_handles++ = handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR Result cmifParseResponse(CmifResponse* res, void* base, bool is_domain, u32 size)
|
||||||
|
{
|
||||||
|
HipcResponse hipc = hipcParseResponse(base);
|
||||||
|
void* start = cmifGetAlignedDataStart(hipc.data_words, base);
|
||||||
|
|
||||||
|
CmifOutHeader* hdr = NULL;
|
||||||
|
u32* objects = NULL;
|
||||||
|
if (is_domain)
|
||||||
|
{
|
||||||
|
CmifDomainOutHeader* domain_hdr = (CmifDomainOutHeader*)start;
|
||||||
|
hdr = (CmifOutHeader*)(domain_hdr+1);
|
||||||
|
objects = (u32*)((u8*)hdr + sizeof(CmifOutHeader) + size);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
hdr = (CmifOutHeader*)start;
|
||||||
|
|
||||||
|
if (hdr->magic != CMIF_OUT_HEADER_MAGIC)
|
||||||
|
return MAKERESULT(Module_Libnx, LibnxError_BadInput); // todo: proper result code
|
||||||
|
if (R_FAILED(hdr->result))
|
||||||
|
return hdr->result;
|
||||||
|
|
||||||
|
*res = (CmifResponse){
|
||||||
|
.data = hdr+1,
|
||||||
|
.objects = objects,
|
||||||
|
.copy_handles = hipc.copy_handles,
|
||||||
|
.move_handles = hipc.move_handles,
|
||||||
|
};
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR u32 cmifResponseGetObject(CmifResponse* res)
|
||||||
|
{
|
||||||
|
return *res->objects++;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR Handle cmifResponseGetCopyHandle(CmifResponse* res)
|
||||||
|
{
|
||||||
|
return *res->copy_handles++;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR Handle cmifResponseGetMoveHandle(CmifResponse* res)
|
||||||
|
{
|
||||||
|
return *res->move_handles++;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result cmifConvertCurrentObjectToDomain(Handle h, u32* out_object_id)
|
||||||
|
{
|
||||||
|
cmifMakeControlRequest(armGetTls(), 0, 0);
|
||||||
|
Result rc = svcSendSyncRequest(h);
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
CmifResponse resp = {};
|
||||||
|
rc = cmifParseResponse(&resp, armGetTls(), false, sizeof(u32));
|
||||||
|
if (R_SUCCEEDED(rc) && out_object_id)
|
||||||
|
*out_object_id = *(u32*)resp.data;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result cmifCopyFromCurrentDomain(Handle h, u32 object_id, Handle* out_h)
|
||||||
|
{
|
||||||
|
void* raw = cmifMakeControlRequest(armGetTls(), 1, sizeof(u32));
|
||||||
|
*(u32*)raw = object_id;
|
||||||
|
Result rc = svcSendSyncRequest(h);
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
CmifResponse resp = {};
|
||||||
|
rc = cmifParseResponse(&resp, armGetTls(), false, 0);
|
||||||
|
if (R_SUCCEEDED(rc) && out_h)
|
||||||
|
*out_h = resp.move_handles[0];
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result cmifQueryPointerBufferSize(Handle h, u16* out_size)
|
||||||
|
{
|
||||||
|
cmifMakeControlRequest(armGetTls(), 3, 0);
|
||||||
|
Result rc = svcSendSyncRequest(h);
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
CmifResponse resp = {};
|
||||||
|
rc = cmifParseResponse(&resp, armGetTls(), false, sizeof(u16));
|
||||||
|
if (R_SUCCEEDED(rc) && out_size)
|
||||||
|
*out_size = *(u16*)resp.data;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result cmifCloneCurrentObjectEx(Handle h, u32 unk, Handle* out_h)
|
||||||
|
{
|
||||||
|
void* raw = cmifMakeControlRequest(armGetTls(), 4, sizeof(u32));
|
||||||
|
*(u32*)raw = unk;
|
||||||
|
Result rc = svcSendSyncRequest(h);
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
CmifResponse resp = {};
|
||||||
|
rc = cmifParseResponse(&resp, armGetTls(), false, 0);
|
||||||
|
if (R_SUCCEEDED(rc) && out_h)
|
||||||
|
*out_h = resp.move_handles[0];
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
363
nx/include/switch/sf/hipc.h
Normal file
363
nx/include/switch/sf/hipc.h
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
/**
|
||||||
|
* @file hipc.h
|
||||||
|
* @brief Horizon Inter-Process Communication protocol
|
||||||
|
* @author fincs
|
||||||
|
* @author SciresM
|
||||||
|
* @copyright libnx Authors
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "../result.h"
|
||||||
|
#include "../arm/tls.h"
|
||||||
|
#include "../kernel/svc.h"
|
||||||
|
|
||||||
|
#define HIPC_AUTO_RECV_STATIC UINT8_MAX
|
||||||
|
#define HIPC_RESPONSE_NO_PID UINT32_MAX
|
||||||
|
|
||||||
|
typedef struct HipcMetadata {
|
||||||
|
u32 type;
|
||||||
|
u32 num_send_statics;
|
||||||
|
u32 num_send_buffers;
|
||||||
|
u32 num_recv_buffers;
|
||||||
|
u32 num_exch_buffers;
|
||||||
|
u32 num_data_words;
|
||||||
|
u32 num_recv_statics; // also accepts HIPC_AUTO_RECV_STATIC
|
||||||
|
u32 send_pid;
|
||||||
|
u32 num_copy_handles;
|
||||||
|
u32 num_move_handles;
|
||||||
|
} HipcMetadata;
|
||||||
|
|
||||||
|
typedef struct HipcHeader {
|
||||||
|
u32 type : 16;
|
||||||
|
u32 num_send_statics : 4;
|
||||||
|
u32 num_send_buffers : 4;
|
||||||
|
u32 num_recv_buffers : 4;
|
||||||
|
u32 num_exch_buffers : 4;
|
||||||
|
u32 num_data_words : 10;
|
||||||
|
u32 recv_static_mode : 4;
|
||||||
|
u32 padding : 6;
|
||||||
|
u32 recv_list_offset : 11; // Unused.
|
||||||
|
u32 has_special_header : 1;
|
||||||
|
} HipcHeader;
|
||||||
|
|
||||||
|
typedef struct HipcSpecialHeader {
|
||||||
|
u32 send_pid : 1;
|
||||||
|
u32 num_copy_handles : 4;
|
||||||
|
u32 num_move_handles : 4;
|
||||||
|
u32 padding : 23;
|
||||||
|
} HipcSpecialHeader;
|
||||||
|
|
||||||
|
typedef struct HipcStaticDescriptor {
|
||||||
|
u32 index : 6;
|
||||||
|
u32 address_high : 6;
|
||||||
|
u32 address_mid : 4;
|
||||||
|
u32 size : 16;
|
||||||
|
u32 address_low;
|
||||||
|
} HipcStaticDescriptor;
|
||||||
|
|
||||||
|
typedef struct HipcBufferDescriptor {
|
||||||
|
u32 size_low;
|
||||||
|
u32 address_low;
|
||||||
|
u32 mode : 2;
|
||||||
|
u32 address_high : 22;
|
||||||
|
u32 size_high : 4;
|
||||||
|
u32 address_mid : 4;
|
||||||
|
} HipcBufferDescriptor;
|
||||||
|
|
||||||
|
typedef struct HipcRecvListEntry {
|
||||||
|
u32 address_low;
|
||||||
|
u32 address_high : 16;
|
||||||
|
u32 size : 16;
|
||||||
|
} HipcRecvListEntry;
|
||||||
|
|
||||||
|
typedef struct HipcRequest {
|
||||||
|
HipcStaticDescriptor* send_statics;
|
||||||
|
HipcBufferDescriptor* send_buffers;
|
||||||
|
HipcBufferDescriptor* recv_buffers;
|
||||||
|
HipcBufferDescriptor* exch_buffers;
|
||||||
|
u32* data_words;
|
||||||
|
HipcRecvListEntry* recv_list;
|
||||||
|
Handle* copy_handles;
|
||||||
|
Handle* move_handles;
|
||||||
|
} HipcRequest;
|
||||||
|
|
||||||
|
typedef struct HipcParsedRequest {
|
||||||
|
HipcMetadata meta;
|
||||||
|
HipcRequest data;
|
||||||
|
u64 pid;
|
||||||
|
} HipcParsedRequest;
|
||||||
|
|
||||||
|
typedef struct HipcResponse {
|
||||||
|
u64 pid;
|
||||||
|
u32 num_statics;
|
||||||
|
u32 num_data_words;
|
||||||
|
u32 num_copy_handles;
|
||||||
|
u32 num_move_handles;
|
||||||
|
HipcStaticDescriptor* statics;
|
||||||
|
u32* data_words;
|
||||||
|
Handle* copy_handles;
|
||||||
|
Handle* move_handles;
|
||||||
|
} HipcResponse;
|
||||||
|
|
||||||
|
typedef enum HipcBufferMode {
|
||||||
|
HipcBufferMode_Normal = 0,
|
||||||
|
HipcBufferMode_NonSecure = 1,
|
||||||
|
HipcBufferMode_Invalid = 2,
|
||||||
|
HipcBufferMode_NonDevice = 3,
|
||||||
|
} HipcBufferMode;
|
||||||
|
|
||||||
|
NX_CONSTEXPR HipcStaticDescriptor hipcMakeSendStatic(const void* buffer, size_t size, u8 index)
|
||||||
|
{
|
||||||
|
return (HipcStaticDescriptor){
|
||||||
|
.index = index,
|
||||||
|
.address_high = (u32)((uintptr_t)buffer >> 36),
|
||||||
|
.address_mid = (u32)((uintptr_t)buffer >> 32),
|
||||||
|
.size = (u32)size,
|
||||||
|
.address_low = (u32)(uintptr_t)buffer,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR HipcBufferDescriptor hipcMakeBuffer(const void* buffer, size_t size, HipcBufferMode mode)
|
||||||
|
{
|
||||||
|
return (HipcBufferDescriptor){
|
||||||
|
.size_low = (u32)size,
|
||||||
|
.address_low = (u32)(uintptr_t)buffer,
|
||||||
|
.mode = mode,
|
||||||
|
.address_high = (u32)((uintptr_t)buffer >> 36),
|
||||||
|
.size_high = (u32)(size >> 32),
|
||||||
|
.address_mid = (u32)((uintptr_t)buffer >> 32),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR HipcRecvListEntry hipcMakeRecvStatic(void* buffer, size_t size)
|
||||||
|
{
|
||||||
|
return (HipcRecvListEntry){
|
||||||
|
.address_low = (u32)((uintptr_t)buffer),
|
||||||
|
.address_high = (u32)((uintptr_t)buffer >> 32),
|
||||||
|
.size = (u32)size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void* hipcGetStaticAddress(const HipcStaticDescriptor* desc)
|
||||||
|
{
|
||||||
|
return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR size_t hipcGetStaticSize(const HipcStaticDescriptor* desc)
|
||||||
|
{
|
||||||
|
return desc->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void* hipcGetBufferAddress(const HipcBufferDescriptor* desc)
|
||||||
|
{
|
||||||
|
return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36));
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR size_t hipcGetBufferSize(const HipcBufferDescriptor* desc)
|
||||||
|
{
|
||||||
|
return desc->size_low | ((size_t)desc->size_high << 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR HipcRequest hipcCalcRequestLayout(HipcMetadata meta, void* base)
|
||||||
|
{
|
||||||
|
// Copy handles
|
||||||
|
Handle* copy_handles = NULL;
|
||||||
|
if (meta.num_copy_handles) {
|
||||||
|
copy_handles = (Handle*)base;
|
||||||
|
base = copy_handles + meta.num_copy_handles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move handles
|
||||||
|
Handle* move_handles = NULL;
|
||||||
|
if (meta.num_move_handles) {
|
||||||
|
move_handles = (Handle*)base;
|
||||||
|
base = move_handles + meta.num_move_handles;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send statics
|
||||||
|
HipcStaticDescriptor* send_statics = NULL;
|
||||||
|
if (meta.num_send_statics) {
|
||||||
|
send_statics = (HipcStaticDescriptor*)base;
|
||||||
|
base = send_statics + meta.num_send_statics;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send buffers
|
||||||
|
HipcBufferDescriptor* send_buffers = NULL;
|
||||||
|
if (meta.num_send_buffers) {
|
||||||
|
send_buffers = (HipcBufferDescriptor*)base;
|
||||||
|
base = send_buffers + meta.num_send_buffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recv buffers
|
||||||
|
HipcBufferDescriptor* recv_buffers = NULL;
|
||||||
|
if (meta.num_recv_buffers) {
|
||||||
|
recv_buffers = (HipcBufferDescriptor*)base;
|
||||||
|
base = recv_buffers + meta.num_recv_buffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exch buffers
|
||||||
|
HipcBufferDescriptor* exch_buffers = NULL;
|
||||||
|
if (meta.num_exch_buffers) {
|
||||||
|
exch_buffers = (HipcBufferDescriptor*)base;
|
||||||
|
base = exch_buffers + meta.num_exch_buffers;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data words
|
||||||
|
u32* data_words = NULL;
|
||||||
|
if (meta.num_data_words) {
|
||||||
|
data_words = (u32*)base;
|
||||||
|
base = data_words + meta.num_data_words;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recv list
|
||||||
|
HipcRecvListEntry* recv_list = NULL;
|
||||||
|
if (meta.num_recv_statics)
|
||||||
|
recv_list = (HipcRecvListEntry*)base;
|
||||||
|
|
||||||
|
return (HipcRequest){
|
||||||
|
.send_statics = send_statics,
|
||||||
|
.send_buffers = send_buffers,
|
||||||
|
.recv_buffers = recv_buffers,
|
||||||
|
.exch_buffers = exch_buffers,
|
||||||
|
.data_words = data_words,
|
||||||
|
.recv_list = recv_list,
|
||||||
|
.copy_handles = copy_handles,
|
||||||
|
.move_handles = move_handles,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR HipcRequest hipcMakeRequest(void* base, HipcMetadata meta)
|
||||||
|
{
|
||||||
|
// Write message header
|
||||||
|
bool has_special_header = meta.send_pid || meta.num_copy_handles || meta.num_move_handles;
|
||||||
|
HipcHeader* hdr = (HipcHeader*)base;
|
||||||
|
base = hdr+1;
|
||||||
|
*hdr = (HipcHeader){
|
||||||
|
.type = meta.type,
|
||||||
|
.num_send_statics = meta.num_send_statics,
|
||||||
|
.num_send_buffers = meta.num_send_buffers,
|
||||||
|
.num_recv_buffers = meta.num_recv_buffers,
|
||||||
|
.num_exch_buffers = meta.num_exch_buffers,
|
||||||
|
.num_data_words = meta.num_data_words,
|
||||||
|
.recv_static_mode = meta.num_recv_statics ? (meta.num_recv_statics != HIPC_AUTO_RECV_STATIC ? 2u + meta.num_recv_statics : 2u) : 0u,
|
||||||
|
.padding = 0,
|
||||||
|
.recv_list_offset = 0,
|
||||||
|
.has_special_header = has_special_header,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Write special header
|
||||||
|
if (has_special_header) {
|
||||||
|
HipcSpecialHeader* sphdr = (HipcSpecialHeader*)base;
|
||||||
|
base = sphdr+1;
|
||||||
|
*sphdr = (HipcSpecialHeader){
|
||||||
|
.send_pid = meta.send_pid,
|
||||||
|
.num_copy_handles = meta.num_copy_handles,
|
||||||
|
.num_move_handles = meta.num_move_handles,
|
||||||
|
};
|
||||||
|
if (meta.send_pid)
|
||||||
|
base = (u8*)base + sizeof(u64);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate layout
|
||||||
|
return hipcCalcRequestLayout(meta, base);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define hipcMakeRequestInline(_base,...) hipcMakeRequest((_base),(HipcMetadata){ __VA_ARGS__ })
|
||||||
|
|
||||||
|
NX_CONSTEXPR HipcParsedRequest hipcParseRequest(void* base)
|
||||||
|
{
|
||||||
|
// Parse message header
|
||||||
|
HipcHeader hdr = {};
|
||||||
|
__builtin_memcpy(&hdr, base, sizeof(hdr));
|
||||||
|
base = (u8*)base + sizeof(hdr);
|
||||||
|
u32 num_recv_statics = 0;
|
||||||
|
u64 pid = 0;
|
||||||
|
|
||||||
|
// Parse recv static mode
|
||||||
|
if (hdr.recv_static_mode) {
|
||||||
|
if (hdr.recv_static_mode == 2u)
|
||||||
|
num_recv_statics = HIPC_AUTO_RECV_STATIC;
|
||||||
|
else if (hdr.recv_static_mode > 2u)
|
||||||
|
num_recv_statics = hdr.recv_static_mode - 2u;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse special header
|
||||||
|
HipcSpecialHeader sphdr = {};
|
||||||
|
if (hdr.has_special_header) {
|
||||||
|
__builtin_memcpy(&sphdr, base, sizeof(sphdr));
|
||||||
|
base = (u8*)base + sizeof(sphdr);
|
||||||
|
|
||||||
|
// Read PID descriptor
|
||||||
|
if (sphdr.send_pid) {
|
||||||
|
pid = *(u64*)base;
|
||||||
|
base = (u8*)base + sizeof(u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const HipcMetadata meta = {
|
||||||
|
.type = hdr.type,
|
||||||
|
.num_send_statics = hdr.num_send_statics,
|
||||||
|
.num_send_buffers = hdr.num_send_buffers,
|
||||||
|
.num_recv_buffers = hdr.num_recv_buffers,
|
||||||
|
.num_exch_buffers = hdr.num_exch_buffers,
|
||||||
|
.num_data_words = hdr.num_data_words,
|
||||||
|
.num_recv_statics = num_recv_statics,
|
||||||
|
.send_pid = sphdr.send_pid,
|
||||||
|
.num_copy_handles = sphdr.num_copy_handles,
|
||||||
|
.num_move_handles = sphdr.num_move_handles,
|
||||||
|
};
|
||||||
|
|
||||||
|
return (HipcParsedRequest){
|
||||||
|
.meta = meta,
|
||||||
|
.data = hipcCalcRequestLayout(meta, base),
|
||||||
|
.pid = pid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR HipcResponse hipcParseResponse(void* base)
|
||||||
|
{
|
||||||
|
// Parse header
|
||||||
|
HipcHeader hdr = {};
|
||||||
|
__builtin_memcpy(&hdr, base, sizeof(hdr));
|
||||||
|
base = (u8*)base + sizeof(hdr);
|
||||||
|
|
||||||
|
// Initialize response
|
||||||
|
HipcResponse response = {};
|
||||||
|
response.num_statics = hdr.num_send_statics;
|
||||||
|
response.num_data_words = hdr.num_data_words;
|
||||||
|
response.pid = HIPC_RESPONSE_NO_PID;
|
||||||
|
|
||||||
|
// Parse special header
|
||||||
|
if (hdr.has_special_header)
|
||||||
|
{
|
||||||
|
HipcSpecialHeader sphdr = {};
|
||||||
|
__builtin_memcpy(&sphdr, base, sizeof(sphdr));
|
||||||
|
base = (u8*)base + sizeof(sphdr);
|
||||||
|
|
||||||
|
// Update response
|
||||||
|
response.num_copy_handles = sphdr.num_copy_handles;
|
||||||
|
response.num_move_handles = sphdr.num_move_handles;
|
||||||
|
|
||||||
|
// Parse PID descriptor
|
||||||
|
if (sphdr.send_pid) {
|
||||||
|
response.pid = *(u64*)base;
|
||||||
|
base = (u8*)base + sizeof(u64);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy handles
|
||||||
|
response.copy_handles = (Handle*)base;
|
||||||
|
base = response.copy_handles + response.num_copy_handles;
|
||||||
|
|
||||||
|
// Move handles
|
||||||
|
response.move_handles = (Handle*)base;
|
||||||
|
base = response.move_handles + response.num_move_handles;
|
||||||
|
|
||||||
|
// Send statics
|
||||||
|
response.statics = (HipcStaticDescriptor*)base;
|
||||||
|
base = response.statics + response.num_statics;
|
||||||
|
|
||||||
|
// Data words
|
||||||
|
response.data_words = (u32*)base;
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
417
nx/include/switch/sf/service.h
Normal file
417
nx/include/switch/sf/service.h
Normal file
@ -0,0 +1,417 @@
|
|||||||
|
/**
|
||||||
|
* @file service.h
|
||||||
|
* @brief Service wrapper object
|
||||||
|
* @author fincs
|
||||||
|
* @author SciresM
|
||||||
|
* @copyright libnx Authors
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "hipc.h"
|
||||||
|
#include "cmif.h"
|
||||||
|
|
||||||
|
/// Service object structure
|
||||||
|
typedef struct Service
|
||||||
|
{
|
||||||
|
Handle session;
|
||||||
|
u32 own_handle;
|
||||||
|
u32 object_id;
|
||||||
|
u16 pointer_buffer_size;
|
||||||
|
} Service;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SfBufferAttr_In = BIT(0),
|
||||||
|
SfBufferAttr_Out = BIT(1),
|
||||||
|
SfBufferAttr_HipcMapAlias = BIT(2),
|
||||||
|
SfBufferAttr_HipcPointer = BIT(3),
|
||||||
|
SfBufferAttr_FixedSize = BIT(4),
|
||||||
|
SfBufferAttr_HipcAutoSelect = BIT(5),
|
||||||
|
SfBufferAttr_HipcMapTransferAllowsNonSecure = BIT(6),
|
||||||
|
SfBufferAttr_HipcMapTransferAllowsNonDevice = BIT(7),
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct SfBufferAttrs {
|
||||||
|
u32 attr0;
|
||||||
|
u32 attr1;
|
||||||
|
u32 attr2;
|
||||||
|
u32 attr3;
|
||||||
|
u32 attr4;
|
||||||
|
u32 attr5;
|
||||||
|
u32 attr6;
|
||||||
|
u32 attr7;
|
||||||
|
} SfBufferAttrs;
|
||||||
|
|
||||||
|
typedef struct SfBuffer
|
||||||
|
{
|
||||||
|
const void* ptr;
|
||||||
|
size_t size;
|
||||||
|
} SfBuffer;
|
||||||
|
|
||||||
|
typedef enum SfOutHandleAttr {
|
||||||
|
SfOutHandleAttr_None = 0,
|
||||||
|
SfOutHandleAttr_HipcCopy = 1,
|
||||||
|
SfOutHandleAttr_HipcMove = 2,
|
||||||
|
} SfOutHandleAttr;
|
||||||
|
|
||||||
|
typedef struct SfOutHandleAttrs
|
||||||
|
{
|
||||||
|
SfOutHandleAttr attr0;
|
||||||
|
SfOutHandleAttr attr1;
|
||||||
|
SfOutHandleAttr attr2;
|
||||||
|
SfOutHandleAttr attr3;
|
||||||
|
SfOutHandleAttr attr4;
|
||||||
|
SfOutHandleAttr attr5;
|
||||||
|
SfOutHandleAttr attr6;
|
||||||
|
SfOutHandleAttr attr7;
|
||||||
|
} SfOutHandleAttrs;
|
||||||
|
|
||||||
|
typedef struct SfDispatchParams
|
||||||
|
{
|
||||||
|
Handle target_session;
|
||||||
|
|
||||||
|
SfBufferAttrs buffer_attrs;
|
||||||
|
SfBuffer buffers[8];
|
||||||
|
|
||||||
|
bool in_send_pid;
|
||||||
|
|
||||||
|
u32 in_num_objects;
|
||||||
|
const Service* in_objects[8];
|
||||||
|
|
||||||
|
u32 in_num_handles;
|
||||||
|
Handle in_handles[8];
|
||||||
|
|
||||||
|
u32 out_num_objects;
|
||||||
|
Service* out_objects;
|
||||||
|
|
||||||
|
SfOutHandleAttrs out_handle_attrs;
|
||||||
|
Handle* out_handles;
|
||||||
|
} SfDispatchParams;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns whether a service has been initialized.
|
||||||
|
* @param[in] s Service object.
|
||||||
|
* @return true if initialized.
|
||||||
|
*/
|
||||||
|
NX_CONSTEXPR bool serviceIsActive(Service* s) {
|
||||||
|
return s->session != INVALID_HANDLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns whether a service is overriden in the homebrew environment.
|
||||||
|
* @param[in] s Service object.
|
||||||
|
* @return true if overriden.
|
||||||
|
*/
|
||||||
|
NX_CONSTEXPR bool serviceIsOverride(Service* s) {
|
||||||
|
return serviceIsActive(s) && !s->own_handle && !s->object_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns whether a service is a domain.
|
||||||
|
* @param[in] s Service object.
|
||||||
|
* @return true if a domain.
|
||||||
|
*/
|
||||||
|
NX_CONSTEXPR bool serviceIsDomain(Service* s) {
|
||||||
|
return serviceIsActive(s) && s->own_handle && s->object_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns whether a service is a domain subservice.
|
||||||
|
* @param[in] s Service object.
|
||||||
|
* @return true if a domain subservice.
|
||||||
|
*/
|
||||||
|
NX_CONSTEXPR bool serviceIsDomainSubservice(Service* s) {
|
||||||
|
return serviceIsActive(s) && !s->own_handle && s->object_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief For a domain/domain subservice, return the associated object ID.
|
||||||
|
* @param[in] s Service object, necessarily a domain or domain subservice.
|
||||||
|
* @return The object ID.
|
||||||
|
*/
|
||||||
|
NX_CONSTEXPR u32 serviceGetObjectId(Service* s) {
|
||||||
|
return s->object_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a service object from an IPC session handle.
|
||||||
|
* @param[out] s Service object.
|
||||||
|
* @param[in] h IPC session handle.
|
||||||
|
*/
|
||||||
|
NX_INLINE void serviceCreate(Service* s, Handle h)
|
||||||
|
{
|
||||||
|
s->session = h;
|
||||||
|
s->own_handle = 1;
|
||||||
|
s->object_id = 0;
|
||||||
|
s->pointer_buffer_size = 0;
|
||||||
|
cmifQueryPointerBufferSize(h, &s->pointer_buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a domain subservice object from a parent service.
|
||||||
|
* @param[out] s Service object.
|
||||||
|
* @param[in] parent Parent service, necessarily a domain or domain subservice.
|
||||||
|
* @param[in] object_id Object ID for this subservice.
|
||||||
|
*/
|
||||||
|
NX_CONSTEXPR void serviceCreateDomainSubservice(Service* s, Service* parent, u32 object_id)
|
||||||
|
{
|
||||||
|
s->session = parent->session;
|
||||||
|
s->own_handle = 0;
|
||||||
|
s->object_id = object_id;
|
||||||
|
s->pointer_buffer_size = parent->pointer_buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Closes a service.
|
||||||
|
* @param[in] s Service object.
|
||||||
|
*/
|
||||||
|
NX_INLINE void serviceClose(Service* s)
|
||||||
|
{
|
||||||
|
if (s->own_handle || s->object_id) {
|
||||||
|
cmifMakeCloseRequest(armGetTls(), s->own_handle ? 0 : s->object_id);
|
||||||
|
svcSendSyncRequest(s->session);
|
||||||
|
if (s->own_handle)
|
||||||
|
svcCloseHandle(s->session);
|
||||||
|
}
|
||||||
|
*s = (Service){};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Clones a service.
|
||||||
|
* @param[in] s Service object.
|
||||||
|
* @param[out] out_s Output service object.
|
||||||
|
*/
|
||||||
|
NX_INLINE Result serviceClone(Service* s, Service* out_s)
|
||||||
|
{
|
||||||
|
out_s->session = 0;
|
||||||
|
out_s->own_handle = 1;
|
||||||
|
out_s->object_id = s->object_id;
|
||||||
|
out_s->pointer_buffer_size = s->pointer_buffer_size;
|
||||||
|
return cmifCloneCurrentObjectEx(s->session, 0, &out_s->session);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Converts a regular service to a domain.
|
||||||
|
* @param[in] s Service object.
|
||||||
|
* @return Result code.
|
||||||
|
*/
|
||||||
|
NX_INLINE Result serviceConvertToDomain(Service* s)
|
||||||
|
{
|
||||||
|
if (s->object_id)
|
||||||
|
return 0; // Nothing to do
|
||||||
|
|
||||||
|
if (!s->own_handle)
|
||||||
|
{
|
||||||
|
// For overridden services, create a clone first.
|
||||||
|
Result rc = cmifCloneCurrentObjectEx(s->session, 0, &s->session);
|
||||||
|
if (R_FAILED(rc))
|
||||||
|
return rc;
|
||||||
|
s->own_handle = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmifConvertCurrentObjectToDomain(s->session, &s->object_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void _serviceRequestFormatProcessBuffer(CmifRequestFormat* fmt, u32 attr)
|
||||||
|
{
|
||||||
|
if (!attr) return;
|
||||||
|
const bool is_in = (attr & SfBufferAttr_In) != 0;
|
||||||
|
const bool is_out = (attr & SfBufferAttr_Out) != 0;
|
||||||
|
|
||||||
|
if (attr & SfBufferAttr_HipcAutoSelect) {
|
||||||
|
if (is_in)
|
||||||
|
fmt->num_in_auto_buffers ++;
|
||||||
|
if (is_out)
|
||||||
|
fmt->num_out_auto_buffers ++;
|
||||||
|
} else if (attr & SfBufferAttr_HipcPointer) {
|
||||||
|
if (is_in)
|
||||||
|
fmt->num_in_pointers ++;
|
||||||
|
if (is_out) {
|
||||||
|
if (attr & SfBufferAttr_FixedSize)
|
||||||
|
fmt->num_out_fixed_pointers ++;
|
||||||
|
else
|
||||||
|
fmt->num_out_pointers ++;
|
||||||
|
}
|
||||||
|
} else if (attr & SfBufferAttr_HipcMapAlias) {
|
||||||
|
if (is_in && is_out)
|
||||||
|
fmt->num_inout_buffers ++;
|
||||||
|
else if (is_in)
|
||||||
|
fmt->num_in_buffers ++;
|
||||||
|
else if (is_out)
|
||||||
|
fmt->num_out_buffers ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void _serviceRequestProcessBuffer(CmifRequest* req, const SfBuffer* buf, u32 attr)
|
||||||
|
{
|
||||||
|
if (!attr) return;
|
||||||
|
const bool is_in = (attr & SfBufferAttr_In);
|
||||||
|
const bool is_out = (attr & SfBufferAttr_Out);
|
||||||
|
|
||||||
|
if (attr & SfBufferAttr_HipcAutoSelect) {
|
||||||
|
if (is_in)
|
||||||
|
cmifRequestInAutoBuffer(req, buf->ptr, buf->size);
|
||||||
|
if (is_out)
|
||||||
|
cmifRequestOutAutoBuffer(req, (void*)buf->ptr, buf->size);
|
||||||
|
} else if (attr & SfBufferAttr_HipcPointer) {
|
||||||
|
if (is_in)
|
||||||
|
cmifRequestInPointer(req, buf->ptr, buf->size);
|
||||||
|
if (is_out) {
|
||||||
|
if (attr & SfBufferAttr_FixedSize)
|
||||||
|
cmifRequestOutFixedPointer(req, (void*)buf->ptr, buf->size);
|
||||||
|
else
|
||||||
|
cmifRequestOutPointer(req, (void*)buf->ptr, buf->size);
|
||||||
|
}
|
||||||
|
} else if (attr & SfBufferAttr_HipcMapAlias) {
|
||||||
|
HipcBufferMode mode = HipcBufferMode_Normal;
|
||||||
|
if (attr & SfBufferAttr_HipcMapTransferAllowsNonSecure)
|
||||||
|
mode = HipcBufferMode_NonSecure;
|
||||||
|
if (attr & SfBufferAttr_HipcMapTransferAllowsNonDevice)
|
||||||
|
mode = HipcBufferMode_NonDevice;
|
||||||
|
|
||||||
|
if (is_in && is_out)
|
||||||
|
cmifRequestInOutBuffer(req, (void*)buf->ptr, buf->size, mode);
|
||||||
|
else if (is_in)
|
||||||
|
cmifRequestInBuffer(req, buf->ptr, buf->size, mode);
|
||||||
|
else if (is_out)
|
||||||
|
cmifRequestOutBuffer(req, (void*)buf->ptr, buf->size, mode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE void* serviceMakeRequest(
|
||||||
|
Service* s, u32 request_id, u32 data_size, bool send_pid,
|
||||||
|
const SfBufferAttrs buffer_attrs, const SfBuffer* buffers,
|
||||||
|
u32 num_objects, const Service* const* objects,
|
||||||
|
u32 num_handles, const Handle* handles
|
||||||
|
) {
|
||||||
|
CmifRequestFormat fmt = {};
|
||||||
|
fmt.object_id = s->object_id;
|
||||||
|
fmt.request_id = request_id;
|
||||||
|
fmt.data_size = data_size;
|
||||||
|
fmt.server_pointer_size = s->pointer_buffer_size;
|
||||||
|
fmt.num_objects = num_objects;
|
||||||
|
fmt.num_handles = num_handles;
|
||||||
|
fmt.send_pid = send_pid;
|
||||||
|
|
||||||
|
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr0);
|
||||||
|
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr1);
|
||||||
|
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr2);
|
||||||
|
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr3);
|
||||||
|
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr4);
|
||||||
|
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr5);
|
||||||
|
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr6);
|
||||||
|
_serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr7);
|
||||||
|
|
||||||
|
CmifRequest req = cmifMakeRequest(armGetTls(), fmt);
|
||||||
|
|
||||||
|
if (s->object_id) // TODO: Check behavior of input objects in non-domain sessions
|
||||||
|
for (u32 i = 0; i < num_objects; i ++)
|
||||||
|
cmifRequestObject(&req, objects[i]->object_id);
|
||||||
|
|
||||||
|
for (u32 i = 0; i < num_handles; i ++)
|
||||||
|
cmifRequestHandle(&req, handles[i]);
|
||||||
|
|
||||||
|
_serviceRequestProcessBuffer(&req, &buffers[0], buffer_attrs.attr0);
|
||||||
|
_serviceRequestProcessBuffer(&req, &buffers[1], buffer_attrs.attr1);
|
||||||
|
_serviceRequestProcessBuffer(&req, &buffers[2], buffer_attrs.attr2);
|
||||||
|
_serviceRequestProcessBuffer(&req, &buffers[3], buffer_attrs.attr3);
|
||||||
|
_serviceRequestProcessBuffer(&req, &buffers[4], buffer_attrs.attr4);
|
||||||
|
_serviceRequestProcessBuffer(&req, &buffers[5], buffer_attrs.attr5);
|
||||||
|
_serviceRequestProcessBuffer(&req, &buffers[6], buffer_attrs.attr6);
|
||||||
|
_serviceRequestProcessBuffer(&req, &buffers[7], buffer_attrs.attr7);
|
||||||
|
|
||||||
|
return req.data;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_CONSTEXPR void _serviceResponseGetHandle(CmifResponse* res, SfOutHandleAttr type, Handle* out)
|
||||||
|
{
|
||||||
|
switch (type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
case SfOutHandleAttr_None:
|
||||||
|
break;
|
||||||
|
case SfOutHandleAttr_HipcCopy:
|
||||||
|
*out = cmifResponseGetCopyHandle(res);
|
||||||
|
break;
|
||||||
|
case SfOutHandleAttr_HipcMove:
|
||||||
|
*out = cmifResponseGetMoveHandle(res);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result serviceParseResponse(
|
||||||
|
Service* s, u32 out_size, void** out_data,
|
||||||
|
u32 num_out_objects, Service* out_objects,
|
||||||
|
const SfOutHandleAttrs out_handle_attrs, Handle* out_handles
|
||||||
|
) {
|
||||||
|
CmifResponse res = {};
|
||||||
|
bool is_domain = s->object_id != 0;
|
||||||
|
Result rc = cmifParseResponse(&res, armGetTls(), is_domain, out_size);
|
||||||
|
if (R_FAILED(rc))
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
if (out_size)
|
||||||
|
*out_data = res.data;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < num_out_objects; i ++)
|
||||||
|
{
|
||||||
|
if (is_domain)
|
||||||
|
serviceCreateDomainSubservice(&out_objects[i], s, cmifResponseGetObject(&res));
|
||||||
|
else // Output objects are marshalled as move handles at the beginning of the list.
|
||||||
|
serviceCreate(&out_objects[i], cmifResponseGetMoveHandle(&res));
|
||||||
|
}
|
||||||
|
|
||||||
|
_serviceResponseGetHandle(&res, out_handle_attrs.attr0, &out_handles[0]);
|
||||||
|
_serviceResponseGetHandle(&res, out_handle_attrs.attr1, &out_handles[1]);
|
||||||
|
_serviceResponseGetHandle(&res, out_handle_attrs.attr2, &out_handles[2]);
|
||||||
|
_serviceResponseGetHandle(&res, out_handle_attrs.attr3, &out_handles[3]);
|
||||||
|
_serviceResponseGetHandle(&res, out_handle_attrs.attr4, &out_handles[4]);
|
||||||
|
_serviceResponseGetHandle(&res, out_handle_attrs.attr5, &out_handles[5]);
|
||||||
|
_serviceResponseGetHandle(&res, out_handle_attrs.attr6, &out_handles[6]);
|
||||||
|
_serviceResponseGetHandle(&res, out_handle_attrs.attr7, &out_handles[7]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
NX_INLINE Result serviceDispatchImpl(
|
||||||
|
Service* s, u32 request_id,
|
||||||
|
const void* in_data, u32 in_data_size,
|
||||||
|
void* out_data, u32 out_data_size,
|
||||||
|
SfDispatchParams disp
|
||||||
|
)
|
||||||
|
{
|
||||||
|
void* in = serviceMakeRequest(s, request_id,
|
||||||
|
in_data_size, disp.in_send_pid,
|
||||||
|
disp.buffer_attrs, disp.buffers,
|
||||||
|
disp.in_num_objects, disp.in_objects,
|
||||||
|
disp.in_num_handles, disp.in_handles);
|
||||||
|
|
||||||
|
if (in_data_size)
|
||||||
|
__builtin_memcpy(in, in_data, in_data_size);
|
||||||
|
|
||||||
|
Result rc = svcSendSyncRequest(disp.target_session == INVALID_HANDLE ? s->session : disp.target_session);
|
||||||
|
if (R_SUCCEEDED(rc))
|
||||||
|
{
|
||||||
|
void* out = NULL;
|
||||||
|
rc = serviceParseResponse(s,
|
||||||
|
out_data_size, &out,
|
||||||
|
disp.out_num_objects, disp.out_objects,
|
||||||
|
disp.out_handle_attrs, disp.out_handles);
|
||||||
|
|
||||||
|
if (R_SUCCEEDED(rc) && out_data_size)
|
||||||
|
__builtin_memcpy(out_data, out, out_data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define serviceDispatch(_s,_rid,...) \
|
||||||
|
serviceDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfDispatchParams){ __VA_ARGS__ })
|
||||||
|
|
||||||
|
#define serviceDispatchIn(_s,_rid,_in,...) \
|
||||||
|
serviceDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfDispatchParams){ __VA_ARGS__ })
|
||||||
|
|
||||||
|
#define serviceDispatchOut(_s,_rid,_out,...) \
|
||||||
|
serviceDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ })
|
||||||
|
|
||||||
|
#define serviceDispatchInOut(_s,_rid,_in,_out,...) \
|
||||||
|
serviceDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ })
|
@ -51,12 +51,6 @@ Result binderInitSession(Binder* b, Service* relay)
|
|||||||
|
|
||||||
b->initialized = true;
|
b->initialized = true;
|
||||||
|
|
||||||
rc = ipcQueryPointerBufferSize(b->relay->handle, &b->ipc_buffer_size);
|
|
||||||
if (R_FAILED(rc)) {
|
|
||||||
binderClose(b);
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use TransactParcelAuto when available.
|
// Use TransactParcelAuto when available.
|
||||||
if (hosversionAtLeast(3,0,0))
|
if (hosversionAtLeast(3,0,0))
|
||||||
b->has_transact_auto = true;
|
b->has_transact_auto = true;
|
||||||
@ -148,8 +142,8 @@ static Result _binderTransactParcelAuto(
|
|||||||
u32 flags;
|
u32 flags;
|
||||||
} PACKED *raw;
|
} PACKED *raw;
|
||||||
|
|
||||||
ipcAddSendSmart(&c, b->ipc_buffer_size, parcel_data, parcel_data_size, 0);
|
ipcAddSendSmart(&c, b->relay->pointer_buffer_size, parcel_data, parcel_data_size, 0);
|
||||||
ipcAddRecvSmart(&c, b->ipc_buffer_size, parcel_reply, parcel_reply_size, 0);
|
ipcAddRecvSmart(&c, b->relay->pointer_buffer_size, parcel_reply, parcel_reply_size, 0);
|
||||||
|
|
||||||
raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
|
raw = _binderIpcPrepareHeader(b, &c, sizeof(*raw));
|
||||||
raw->magic = SFCI_MAGIC;
|
raw->magic = SFCI_MAGIC;
|
||||||
|
@ -50,9 +50,6 @@ static Service g_appletIAudioController;
|
|||||||
static Service g_appletIDisplayController;
|
static Service g_appletIDisplayController;
|
||||||
static Service g_appletIDebugFunctions;
|
static Service g_appletIDebugFunctions;
|
||||||
|
|
||||||
static size_t g_appletIAppletCommonFunctions_ptrbufsize;
|
|
||||||
static size_t g_appletISelfController_ptrbufsize;
|
|
||||||
|
|
||||||
static Event g_appletMessageEvent;
|
static Event g_appletMessageEvent;
|
||||||
|
|
||||||
static u64 g_appletResourceUserId = 0;
|
static u64 g_appletResourceUserId = 0;
|
||||||
@ -192,7 +189,6 @@ Result appletInitialize(void)
|
|||||||
if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) {
|
if (R_SUCCEEDED(rc) && hosversionAtLeast(7,0,0)) {
|
||||||
if (__nx_applet_type == AppletType_SystemApplet || __nx_applet_type == AppletType_LibraryApplet || __nx_applet_type == AppletType_OverlayApplet) {
|
if (__nx_applet_type == AppletType_SystemApplet || __nx_applet_type == AppletType_LibraryApplet || __nx_applet_type == AppletType_OverlayApplet) {
|
||||||
rc = _appletGetSession(&g_appletProxySession, &g_appletIAppletCommonFunctions, __nx_applet_type == AppletType_SystemApplet ? 23 : 21);
|
rc = _appletGetSession(&g_appletProxySession, &g_appletIAppletCommonFunctions, __nx_applet_type == AppletType_SystemApplet ? 23 : 21);
|
||||||
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_appletIAppletCommonFunctions.handle, &g_appletIAppletCommonFunctions_ptrbufsize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,9 +239,6 @@ Result appletInitialize(void)
|
|||||||
if (R_SUCCEEDED(rc))
|
if (R_SUCCEEDED(rc))
|
||||||
rc = _appletGetSession(&g_appletProxySession, &g_appletIDebugFunctions, 1000);
|
rc = _appletGetSession(&g_appletProxySession, &g_appletIDebugFunctions, 1000);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc))
|
|
||||||
rc = ipcQueryPointerBufferSize(g_appletISelfController.handle, &g_appletISelfController_ptrbufsize);
|
|
||||||
|
|
||||||
Result rc2 = _appletGetAccumulatedSuspendedTickChangedEvent(&g_appletSuspendedTickEvent);
|
Result rc2 = _appletGetAccumulatedSuspendedTickChangedEvent(&g_appletSuspendedTickEvent);
|
||||||
if (R_SUCCEEDED(rc2)) {
|
if (R_SUCCEEDED(rc2)) {
|
||||||
g_appletInitTickBase = armGetSystemTick();
|
g_appletInitTickBase = armGetSystemTick();
|
||||||
@ -2090,7 +2083,7 @@ Result appletSetApplicationAlbumUserData(const void* buffer, size_t size) {
|
|||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddSendSmart(&c, g_appletISelfController_ptrbufsize, buffer, size, 0);
|
ipcAddSendSmart(&c, g_appletISelfController.pointer_buffer_size, buffer, size, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -3240,7 +3233,6 @@ Result appletStorageGetSize(AppletStorage *s, s64 *size) {
|
|||||||
|
|
||||||
static Result _appletStorageRW(AppletStorage *s, s64 offset, void* buffer, size_t size, bool rw) {
|
static Result _appletStorageRW(AppletStorage *s, s64 offset, void* buffer, size_t size, bool rw) {
|
||||||
Result rc=0;
|
Result rc=0;
|
||||||
size_t ipcbufsize=0;
|
|
||||||
Service tmp_srv;//IStorageAccessor
|
Service tmp_srv;//IStorageAccessor
|
||||||
|
|
||||||
if (!serviceIsActive(&s->s))
|
if (!serviceIsActive(&s->s))
|
||||||
@ -3249,9 +3241,7 @@ static Result _appletStorageRW(AppletStorage *s, s64 offset, void* buffer, size_
|
|||||||
rc = _appletGetSession(&s->s, &tmp_srv, 0);//Open
|
rc = _appletGetSession(&s->s, &tmp_srv, 0);//Open
|
||||||
if (R_FAILED(rc)) return rc;
|
if (R_FAILED(rc)) return rc;
|
||||||
|
|
||||||
rc = ipcQueryPointerBufferSize(tmp_srv.handle, &ipcbufsize);
|
if (R_SUCCEEDED(rc)) rc = _appletStorageAccessorRW(&tmp_srv, tmp_srv.pointer_buffer_size, offset, buffer, size, rw);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) rc = _appletStorageAccessorRW(&tmp_srv, ipcbufsize, offset, buffer, size, rw);
|
|
||||||
serviceClose(&tmp_srv);
|
serviceClose(&tmp_srv);
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -5442,7 +5432,7 @@ Result appletReadThemeStorage(void* buffer, size_t size, u64 offset, size_t *tra
|
|||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddRecvSmart(&c, g_appletIAppletCommonFunctions_ptrbufsize, buffer, size, 0);
|
ipcAddRecvSmart(&c, g_appletIAppletCommonFunctions.pointer_buffer_size, buffer, size, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -5484,7 +5474,7 @@ Result appletWriteThemeStorage(const void* buffer, size_t size, u64 offset) {
|
|||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddSendSmart(&c, g_appletIAppletCommonFunctions_ptrbufsize, buffer, size, 0);
|
ipcAddSendSmart(&c, g_appletIAppletCommonFunctions.pointer_buffer_size, buffer, size, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
static Service g_auddevIAudioDevice;
|
static Service g_auddevIAudioDevice;
|
||||||
static u64 g_auddevRefCnt;
|
static u64 g_auddevRefCnt;
|
||||||
static size_t g_auddevIpcBufferSize;
|
|
||||||
|
|
||||||
static Result _auddevGetAudioDeviceService(Service* srv, Service* out_srv, u64 aruid);
|
static Result _auddevGetAudioDeviceService(Service* srv, Service* out_srv, u64 aruid);
|
||||||
|
|
||||||
@ -32,8 +31,6 @@ Result auddevInitialize(void) {
|
|||||||
rc = _auddevGetAudioDeviceService(&audrenMgrSrv, &g_auddevIAudioDevice, aruid);
|
rc = _auddevGetAudioDeviceService(&audrenMgrSrv, &g_auddevIAudioDevice, aruid);
|
||||||
|
|
||||||
serviceClose(&audrenMgrSrv);
|
serviceClose(&audrenMgrSrv);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_auddevIAudioDevice.handle, &g_auddevIpcBufferSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED(rc)) auddevExit();
|
if (R_FAILED(rc)) auddevExit();
|
||||||
@ -102,7 +99,7 @@ Result auddevListAudioDeviceName(AudioDeviceName *DeviceNames, s32 max_names, s3
|
|||||||
} *raw;
|
} *raw;
|
||||||
|
|
||||||
if (!new_cmd) ipcAddRecvBuffer(&c, DeviceNames, sizeof(AudioDeviceName) * max_names, BufferType_Normal);
|
if (!new_cmd) ipcAddRecvBuffer(&c, DeviceNames, sizeof(AudioDeviceName) * max_names, BufferType_Normal);
|
||||||
if (new_cmd) ipcAddRecvSmart(&c, g_auddevIpcBufferSize, DeviceNames, sizeof(AudioDeviceName) * max_names, 0);
|
if (new_cmd) ipcAddRecvSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceNames, sizeof(AudioDeviceName) * max_names, 0);
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
||||||
|
|
||||||
@ -144,7 +141,7 @@ Result auddevSetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float
|
|||||||
} *raw;
|
} *raw;
|
||||||
|
|
||||||
if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal);
|
if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal);
|
||||||
if (new_cmd) ipcAddSendSmart(&c, g_auddevIpcBufferSize, DeviceName, sizeof(AudioDeviceName), 0);
|
if (new_cmd) ipcAddSendSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceName, sizeof(AudioDeviceName), 0);
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
||||||
|
|
||||||
@ -183,7 +180,7 @@ Result auddevGetAudioDeviceOutputVolume(const AudioDeviceName *DeviceName, float
|
|||||||
} *raw;
|
} *raw;
|
||||||
|
|
||||||
if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal);
|
if (!new_cmd) ipcAddSendBuffer(&c, DeviceName, sizeof(AudioDeviceName), BufferType_Normal);
|
||||||
if (new_cmd) ipcAddSendSmart(&c, g_auddevIpcBufferSize, DeviceName, sizeof(AudioDeviceName), 0);
|
if (new_cmd) ipcAddSendSmart(&c, g_auddevIAudioDevice.pointer_buffer_size, DeviceName, sizeof(AudioDeviceName), 0);
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
raw = serviceIpcPrepareHeader(&g_auddevIAudioDevice, &c, sizeof(*raw));
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@ __thread Result g_bsdResult;
|
|||||||
__thread int g_bsdErrno;
|
__thread int g_bsdErrno;
|
||||||
|
|
||||||
static Service g_bsdSrv;
|
static Service g_bsdSrv;
|
||||||
static size_t g_bsdSrvIpcBufferSize;
|
|
||||||
static Service g_bsdMonitor;
|
static Service g_bsdMonitor;
|
||||||
static u64 g_bsdClientPid = -1;
|
static u64 g_bsdClientPid = -1;
|
||||||
|
|
||||||
@ -189,7 +188,7 @@ static int _bsdNameGetterCommand(u32 cmd_id, int sockfd, struct sockaddr *addr,
|
|||||||
|
|
||||||
socklen_t maxaddrlen = addrlen == NULL ? 0 : *addrlen;
|
socklen_t maxaddrlen = addrlen == NULL ? 0 : *addrlen;
|
||||||
|
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, addr, maxaddrlen, 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, addr, maxaddrlen, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -247,9 +246,6 @@ Result bsdInitialize(const BsdInitConfig *config) {
|
|||||||
}
|
}
|
||||||
if(R_FAILED(rc)) goto error;
|
if(R_FAILED(rc)) goto error;
|
||||||
|
|
||||||
rc = ipcQueryPointerBufferSize(g_bsdSrv.handle, &g_bsdSrvIpcBufferSize);
|
|
||||||
if(R_FAILED(rc)) goto error;
|
|
||||||
|
|
||||||
rc = smGetService(&g_bsdMonitor, bsd_srv);
|
rc = smGetService(&g_bsdMonitor, bsd_srv);
|
||||||
if(R_FAILED(rc)) goto error;
|
if(R_FAILED(rc)) goto error;
|
||||||
|
|
||||||
@ -270,7 +266,6 @@ error:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void bsdExit(void) {
|
void bsdExit(void) {
|
||||||
g_bsdSrvIpcBufferSize = 0;
|
|
||||||
g_bsdClientPid = 0;
|
g_bsdClientPid = 0;
|
||||||
serviceClose(&g_bsdMonitor);
|
serviceClose(&g_bsdMonitor);
|
||||||
serviceClose(&g_bsdSrv);
|
serviceClose(&g_bsdSrv);
|
||||||
@ -294,7 +289,7 @@ int bsdOpen(const char *pathname, int flags) {
|
|||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
size_t pathlen = strlen(pathname) + 1;
|
size_t pathlen = strlen(pathname) + 1;
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, pathname, pathlen, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, pathname, pathlen, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -315,15 +310,15 @@ int bsdSelect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, st
|
|||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
|
||||||
|
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, readfds, readfds == NULL ? 0 : sizeof(fd_set), 0);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, writefds, writefds == NULL ? 0 : sizeof(fd_set), 1);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 2);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, exceptfds, exceptfds == NULL ? 0 : sizeof(fd_set), 3);
|
||||||
|
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
@ -349,8 +344,8 @@ int bsdPoll(struct pollfd *fds, nfds_t nfds, int timeout) {
|
|||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, fds, nfds * sizeof(struct pollfd), 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, fds, nfds * sizeof(struct pollfd), 0);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, fds, nfds * sizeof(struct pollfd), 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, fds, nfds * sizeof(struct pollfd), 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -375,10 +370,10 @@ int bsdSysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp
|
|||||||
|
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, name, 4 * namelen, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, name, 4 * namelen, 0);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, newp, newlen, 1);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, newp, newlen, 1);
|
||||||
|
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, oldp, inlen, 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, oldp, inlen, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -405,7 +400,7 @@ int bsdSysctl(const int *name, unsigned int namelen, void *oldp, size_t *oldlenp
|
|||||||
ssize_t bsdRecv(int sockfd, void *buf, size_t len, int flags) {
|
ssize_t bsdRecv(int sockfd, void *buf, size_t len, int flags) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -430,8 +425,8 @@ ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockadd
|
|||||||
|
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, src_addr, inaddrlen, 1);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, src_addr, inaddrlen, 1);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -453,7 +448,7 @@ ssize_t bsdRecvFrom(int sockfd, void *buf, size_t len, int flags, struct sockadd
|
|||||||
ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags) {
|
ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -475,8 +470,8 @@ ssize_t bsdSend(int sockfd, const void* buf, size_t len, int flags) {
|
|||||||
ssize_t bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
|
ssize_t bsdSendTo(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, len, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, len, 0);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, dest_addr, addrlen, 1);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, dest_addr, addrlen, 1);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -502,7 +497,7 @@ int bsdAccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
|
|||||||
int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, addr, addrlen, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, addr, addrlen, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -522,7 +517,7 @@ int bsdBind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
|||||||
int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
int bsdConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, addr, addrlen, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, addr, addrlen, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -553,7 +548,7 @@ int bsdGetSockOpt(int sockfd, int level, int optname, void *optval, socklen_t *o
|
|||||||
|
|
||||||
socklen_t inoptlen = optlen == NULL ? 0 : *optlen;
|
socklen_t inoptlen = optlen == NULL ? 0 : *optlen;
|
||||||
|
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, optval, inoptlen, 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, optval, inoptlen, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -645,15 +640,15 @@ int bsdIoctl(int fd, int request, void *data) {
|
|||||||
|
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in1, in1sz, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in1, in1sz, 0);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in2, in2sz, 1);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in2, in2sz, 1);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in3, in3sz, 2);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in3, in3sz, 2);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, in4, in4sz, 3);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, in4, in4sz, 3);
|
||||||
|
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out1, out1sz, 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out1, out1sz, 0);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out2, out2sz, 1);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out2, out2sz, 1);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out3, out3sz, 2);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out3, out3sz, 2);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, out4, out4sz, 3);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, out4, out4sz, 3);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -711,7 +706,7 @@ int bsdSetSockOpt(int sockfd, int level, int optname, const void *optval, sockle
|
|||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, optval, optlen, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, optval, optlen, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -775,7 +770,7 @@ int bsdShutdownAllSockets(int how) {
|
|||||||
ssize_t bsdWrite(int fd, const void *buf, size_t count) {
|
ssize_t bsdWrite(int fd, const void *buf, size_t count) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddSendSmart(&c, g_bsdSrvIpcBufferSize, buf, count, 0);
|
ipcAddSendSmart(&c, g_bsdSrv.pointer_buffer_size, buf, count, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -795,7 +790,7 @@ ssize_t bsdWrite(int fd, const void *buf, size_t count) {
|
|||||||
ssize_t bsdRead(int fd, void *buf, size_t count) {
|
ssize_t bsdRead(int fd, void *buf, size_t count) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddRecvSmart(&c, g_bsdSrvIpcBufferSize, buf, count, 0);
|
ipcAddRecvSmart(&c, g_bsdSrv.pointer_buffer_size, buf, count, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
|
|
||||||
static Service g_hiddbgSrv;
|
static Service g_hiddbgSrv;
|
||||||
static u64 g_hiddbgRefCnt;
|
static u64 g_hiddbgRefCnt;
|
||||||
static size_t g_hiddbgPtrbufsize;
|
|
||||||
|
|
||||||
static bool g_hiddbgHdlsInitialized;
|
static bool g_hiddbgHdlsInitialized;
|
||||||
static TransferMemory g_hiddbgHdlsTmem;
|
static TransferMemory g_hiddbgHdlsTmem;
|
||||||
@ -49,8 +48,6 @@ Result hiddbgInitialize(void) {
|
|||||||
|
|
||||||
Result rc = smGetService(&g_hiddbgSrv, "hid:dbg");
|
Result rc = smGetService(&g_hiddbgSrv, "hid:dbg");
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_hiddbgSrv.handle, &g_hiddbgPtrbufsize);
|
|
||||||
|
|
||||||
if (R_FAILED(rc)) hiddbgExit();
|
if (R_FAILED(rc)) hiddbgExit();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -463,7 +460,7 @@ Result hiddbgGetAbstractedPadsState(u64 *AbstractedPadHandles, HiddbgAbstractedP
|
|||||||
} *raw;
|
} *raw;
|
||||||
|
|
||||||
ipcAddRecvStatic(&c, AbstractedPadHandles, sizeof(u64)*count, 0);
|
ipcAddRecvStatic(&c, AbstractedPadHandles, sizeof(u64)*count, 0);
|
||||||
ipcAddRecvSmart(&c, g_hiddbgPtrbufsize, states, sizeof(HiddbgAbstractedPadState)*count, 0);
|
ipcAddRecvSmart(&c, g_hiddbgSrv.pointer_buffer_size, states, sizeof(HiddbgAbstractedPadState)*count, 0);
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
|
raw = serviceIpcPrepareHeader(&g_hiddbgSrv, &c, sizeof(*raw));
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
#include "services/sm.h"
|
#include "services/sm.h"
|
||||||
|
|
||||||
static Service g_i2cSrv;
|
static Service g_i2cSrv;
|
||||||
static size_t g_i2cSrvPtrBufSize;
|
|
||||||
static u64 g_refCnt;
|
static u64 g_refCnt;
|
||||||
|
|
||||||
Result i2cInitialize(void) {
|
Result i2cInitialize(void) {
|
||||||
@ -19,8 +18,6 @@ Result i2cInitialize(void) {
|
|||||||
|
|
||||||
rc = smGetService(&g_i2cSrv, "i2c");
|
rc = smGetService(&g_i2cSrv, "i2c");
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(g_i2cSrv.handle, &g_i2cSrvPtrBufSize);
|
|
||||||
|
|
||||||
if (R_FAILED(rc)) i2cExit();
|
if (R_FAILED(rc)) i2cExit();
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
@ -28,7 +25,6 @@ Result i2cInitialize(void) {
|
|||||||
|
|
||||||
void i2cExit(void) {
|
void i2cExit(void) {
|
||||||
if (atomicDecrement64(&g_refCnt) == 0) {
|
if (atomicDecrement64(&g_refCnt) == 0) {
|
||||||
g_i2cSrvPtrBufSize = 0;
|
|
||||||
serviceClose(&g_i2cSrv);
|
serviceClose(&g_i2cSrv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -78,7 +74,7 @@ Result i2cOpenSession(I2cSession *out, I2cDevice dev) {
|
|||||||
Result i2csessionSendAuto(I2cSession *s, const void *buf, size_t size, I2cTransactionOption option) {
|
Result i2csessionSendAuto(I2cSession *s, const void *buf, size_t size, I2cTransactionOption option) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddSendSmart(&c, g_i2cSrvPtrBufSize, buf, size, 0);
|
ipcAddSendSmart(&c, s->s.pointer_buffer_size, buf, size, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -113,7 +109,7 @@ Result i2csessionSendAuto(I2cSession *s, const void *buf, size_t size, I2cTransa
|
|||||||
Result i2csessionReceiveAuto(I2cSession *s, void *buf, size_t size, I2cTransactionOption option) {
|
Result i2csessionReceiveAuto(I2cSession *s, void *buf, size_t size, I2cTransactionOption option) {
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddRecvSmart(&c, g_i2cSrvPtrBufSize, buf, size, 0);
|
ipcAddRecvSmart(&c, s->s.pointer_buffer_size, buf, size, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
@ -149,7 +145,7 @@ Result i2csessionExecuteCommandList(I2cSession *s, void *dst, size_t dst_size, c
|
|||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
ipcAddSendStatic(&c, cmd_list, cmd_list_size, 0);
|
ipcAddSendStatic(&c, cmd_list, cmd_list_size, 0);
|
||||||
ipcAddRecvSmart(&c, g_i2cSrvPtrBufSize, dst, dst_size, 0);
|
ipcAddRecvSmart(&c, s->s.pointer_buffer_size, dst, dst_size, 0);
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
u64 magic;
|
u64 magic;
|
||||||
|
@ -51,8 +51,7 @@ Result nvInitialize(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
if (R_SUCCEEDED(rc)) {
|
||||||
g_nvIpcBufferSize = 0;
|
g_nvIpcBufferSize = g_nvSrv.pointer_buffer_size;
|
||||||
rc = ipcQueryPointerBufferSize(g_nvSrv.handle, &g_nvIpcBufferSize);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc))
|
if (R_SUCCEEDED(rc))
|
||||||
rc = tmemCreate(&g_nvTransfermem, __nx_nv_transfermem_size, Perm_None);
|
rc = tmemCreate(&g_nvTransfermem, __nx_nv_transfermem_size, Perm_None);
|
||||||
@ -63,7 +62,7 @@ Result nvInitialize(void)
|
|||||||
// Clone the session handle - the cloned session is used to execute certain commands in parallel
|
// Clone the session handle - the cloned session is used to execute certain commands in parallel
|
||||||
Handle nv_clone = INVALID_HANDLE;
|
Handle nv_clone = INVALID_HANDLE;
|
||||||
if (R_SUCCEEDED(rc))
|
if (R_SUCCEEDED(rc))
|
||||||
rc = ipcCloneSession(g_nvSrv.handle, 1, &nv_clone);
|
rc = ipcCloneSession(g_nvSrv.session, 1, &nv_clone);
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc))
|
if (R_SUCCEEDED(rc))
|
||||||
serviceCreate(&g_nvSrvClone, nv_clone);
|
serviceCreate(&g_nvSrvClone, nv_clone);
|
||||||
|
@ -68,37 +68,11 @@ Result smInitialize(void)
|
|||||||
|
|
||||||
Handle tmp;
|
Handle tmp;
|
||||||
if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, smEncodeName("")) == 0x415) {
|
if (R_SUCCEEDED(rc) && smGetServiceOriginal(&tmp, smEncodeName("")) == 0x415) {
|
||||||
IpcCommand c;
|
const struct {
|
||||||
ipcInitialize(&c);
|
u64 pid_placeholder;
|
||||||
ipcSendPid(&c);
|
} in = { 0 };
|
||||||
|
|
||||||
struct {
|
rc = serviceDispatchIn(&g_smSrv, 0, in, .in_send_pid = true);
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 zero;
|
|
||||||
u64 reserved[2];
|
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
|
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 0;
|
|
||||||
raw->zero = 0;
|
|
||||||
|
|
||||||
rc = serviceIpcDispatch(&g_smSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp;
|
|
||||||
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
|
|
||||||
|
|
||||||
resp = r.Raw;
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (R_FAILED(rc))
|
if (R_FAILED(rc))
|
||||||
@ -140,141 +114,55 @@ Result smGetService(Service* service_out, const char* name)
|
|||||||
{
|
{
|
||||||
u64 name_encoded = smEncodeName(name);
|
u64 name_encoded = smEncodeName(name);
|
||||||
Handle handle = smGetServiceOverride(name_encoded);
|
Handle handle = smGetServiceOverride(name_encoded);
|
||||||
Result rc;
|
|
||||||
|
|
||||||
if (handle != INVALID_HANDLE)
|
if (handle != INVALID_HANDLE)
|
||||||
{
|
{
|
||||||
service_out->type = ServiceType_Override;
|
serviceCreate(service_out, handle);
|
||||||
service_out->handle = handle;
|
service_out->own_handle = 0;
|
||||||
rc = 0;
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
rc = smGetServiceOriginal(&handle, name_encoded);
|
|
||||||
|
|
||||||
|
Result rc = smGetServiceOriginal(&handle, name_encoded);
|
||||||
if (R_SUCCEEDED(rc))
|
if (R_SUCCEEDED(rc))
|
||||||
{
|
serviceCreate(service_out, handle);
|
||||||
service_out->type = ServiceType_Normal;
|
|
||||||
service_out->handle = handle;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
Result smGetServiceOriginal(Handle* handle_out, u64 name)
|
Result smGetServiceOriginal(Handle* handle_out, u64 name)
|
||||||
{
|
{
|
||||||
IpcCommand c;
|
const struct {
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 service_name;
|
u64 service_name;
|
||||||
u64 reserved[2];
|
} in = { name };
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
|
return serviceDispatchIn(&g_smSrv, 1, in,
|
||||||
|
.out_handle_attrs = { SfOutHandleAttr_HipcMove },
|
||||||
raw->magic = SFCI_MAGIC;
|
.out_handles = handle_out,
|
||||||
raw->cmd_id = 1;
|
);
|
||||||
raw->service_name = name;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_smSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp;
|
|
||||||
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
|
|
||||||
|
|
||||||
resp = r.Raw;
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
*handle_out = r.Handles[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
Result smRegisterService(Handle* handle_out, const char* name, bool is_light, int max_sessions)
|
||||||
}
|
{
|
||||||
|
const struct {
|
||||||
Result smRegisterService(Handle* handle_out, const char* name, bool is_light, int max_sessions) {
|
|
||||||
IpcCommand c;
|
|
||||||
ipcInitialize(&c);
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 service_name;
|
u64 service_name;
|
||||||
u32 is_light;
|
u32 is_light;
|
||||||
u32 max_sessions;
|
u32 max_sessions;
|
||||||
} *raw;
|
} in = { smEncodeName(name), !!is_light, max_sessions };
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
|
return serviceDispatchIn(&g_smSrv, 2, in,
|
||||||
|
.out_handle_attrs = { SfOutHandleAttr_HipcMove },
|
||||||
raw->magic = SFCI_MAGIC;
|
.out_handles = handle_out,
|
||||||
raw->cmd_id = 2;
|
);
|
||||||
raw->service_name = smEncodeName(name);
|
|
||||||
raw->is_light = !!is_light;
|
|
||||||
raw->max_sessions = max_sessions;
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_smSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp;
|
|
||||||
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
|
|
||||||
|
|
||||||
resp = r.Raw;
|
|
||||||
rc = resp->result;
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
*handle_out = r.Handles[0];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return rc;
|
Result smUnregisterService(const char* name)
|
||||||
}
|
{
|
||||||
|
|
||||||
Result smUnregisterService(const char* name) {
|
|
||||||
IpcCommand c;
|
IpcCommand c;
|
||||||
ipcInitialize(&c);
|
ipcInitialize(&c);
|
||||||
|
|
||||||
struct {
|
const struct {
|
||||||
u64 magic;
|
|
||||||
u64 cmd_id;
|
|
||||||
u64 service_name;
|
u64 service_name;
|
||||||
u64 reserved;
|
} in = { smEncodeName(name) };
|
||||||
} *raw;
|
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&g_smSrv, &c, sizeof(*raw));
|
return serviceDispatchIn(&g_smSrv, 3, in);
|
||||||
|
|
||||||
raw->magic = SFCI_MAGIC;
|
|
||||||
raw->cmd_id = 3;
|
|
||||||
raw->service_name = smEncodeName(name);
|
|
||||||
|
|
||||||
Result rc = serviceIpcDispatch(&g_smSrv);
|
|
||||||
|
|
||||||
if (R_SUCCEEDED(rc)) {
|
|
||||||
IpcParsedCommand r;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u64 magic;
|
|
||||||
u64 result;
|
|
||||||
} *resp;
|
|
||||||
serviceIpcParse(&g_smSrv, &r, sizeof(*resp));
|
|
||||||
|
|
||||||
resp = r.Raw;
|
|
||||||
rc = resp->result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return rc;
|
|
||||||
}
|
}
|
||||||
|
@ -725,8 +725,6 @@ Result usbHsIfOpenUsbEp(UsbHsClientIfSession* s, UsbHsClientEpSession* ep, u16 m
|
|||||||
if (R_SUCCEEDED(rc)) rc = _usbHsGetEvent(&ep->s, &ep->eventXfer, 2);
|
if (R_SUCCEEDED(rc)) rc = _usbHsGetEvent(&ep->s, &ep->eventXfer, 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (hosversionAtLeast(3,0,0) && R_SUCCEEDED(rc)) rc = ipcQueryPointerBufferSize(ep->s.handle, &ep->ptrbufsize);
|
|
||||||
|
|
||||||
if (R_FAILED(rc)) {
|
if (R_FAILED(rc)) {
|
||||||
serviceClose(&ep->s);
|
serviceClose(&ep->s);
|
||||||
eventClose(&ep->eventXfer);
|
eventClose(&ep->eventXfer);
|
||||||
@ -854,7 +852,7 @@ static Result _usbHsEpGetXferReport(UsbHsClientEpSession* s, UsbHsXferReport* re
|
|||||||
ipcAddRecvBuffer(&c, reports, sizeof(UsbHsXferReport) * max_reports, BufferType_Normal);
|
ipcAddRecvBuffer(&c, reports, sizeof(UsbHsXferReport) * max_reports, BufferType_Normal);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ipcAddRecvSmart(&c, s->ptrbufsize, reports, sizeof(UsbHsXferReport) * max_reports, 0);
|
ipcAddRecvSmart(&c, s->s.pointer_buffer_size, reports, sizeof(UsbHsXferReport) * max_reports, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
|
raw = serviceIpcPrepareHeader(&s->s, &c, sizeof(*raw));
|
||||||
|
Loading…
Reference in New Issue
Block a user