Created
March 13, 2021 20:08
-
-
Save HookedBehemoth/be020ce50841939e778486d4ee613fb0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* @file service.h | |
* @brief Service wrapper object | |
* @author fincs | |
* @author SciresM | |
* @copyright libnx Authors | |
*/ | |
#pragma once | |
#include <switch/sf/service.h> | |
NX_INLINE void* serviceUserBufferMakeRequest( | |
void *user_buffer, | |
Service* s, u32 request_id, u32 context, 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 | |
) { | |
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN) | |
if (s->object_id) | |
__builtin_unreachable(); | |
#endif | |
CmifRequestFormat fmt = {}; | |
fmt.object_id = s->object_id; | |
fmt.request_id = request_id; | |
fmt.context = context; | |
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(user_buffer, 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_INLINE Result serviceUserBufferParseResponse( | |
void *user_buffer, | |
Service* s, u32 out_size, void** out_data, | |
u32 num_out_objects, Service* out_objects, | |
const SfOutHandleAttrs out_handle_attrs, Handle* out_handles | |
) { | |
#if defined(NX_SERVICE_ASSUME_NON_DOMAIN) | |
if (s->object_id) | |
__builtin_unreachable(); | |
#endif | |
CmifResponse res = {}; | |
bool is_domain = s->object_id != 0; | |
Result rc = cmifParseResponse(&res, user_buffer, 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. | |
serviceCreateNonDomainSubservice(&out_objects[i], s, 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 serviceUserBufferDispatchImpl( | |
void *user_buffer, size_t user_buffer_size, | |
Service* s, u32 request_id, | |
const void* in_data, u32 in_data_size, | |
void* out_data, u32 out_data_size, | |
SfDispatchParams disp | |
) | |
{ | |
// Make a copy of the service struct, so that the compiler can assume that it won't be modified by function calls. | |
Service srv = *s; | |
void* in = serviceUserBufferMakeRequest(user_buffer, | |
&srv, request_id, disp.context, | |
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 = svcSendSyncRequestWithUserBuffer(user_buffer, user_buffer_size, disp.target_session == INVALID_HANDLE ? s->session : disp.target_session); | |
if (R_SUCCEEDED(rc)) { | |
void* out = NULL; | |
rc = serviceUserBufferParseResponse(user_buffer, | |
&srv, | |
out_data_size, &out, | |
disp.out_num_objects, disp.out_objects, | |
disp.out_handle_attrs, disp.out_handles); | |
if (R_SUCCEEDED(rc) && out_data && out_data_size) | |
__builtin_memcpy(out_data, out, out_data_size); | |
} | |
return rc; | |
} | |
#define serviceUserBufferDispatch(_b, _s,_rid,...) \ | |
serviceUserBufferDispatchImpl((_b),sizeof(_b),(_s),(_rid),NULL,0,NULL,0,(SfDispatchParams){ __VA_ARGS__ }) | |
#define serviceUserBufferDispatchIn(_b, _s,_rid,_in,...) \ | |
serviceUserBufferDispatchImpl((_b),sizeof(_b),(_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfDispatchParams){ __VA_ARGS__ }) | |
#define serviceUserBufferDispatchOut(_b, _s,_rid,_out,...) \ | |
serviceUserBufferDispatchImpl((_b),sizeof(_b),(_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ }) | |
#define serviceUserBufferDispatchInOut(_b, _s,_rid,_in,_out,...) \ | |
serviceUserBufferDispatchImpl((_b),sizeof(_b),(_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment