18 u16 pointer_buffer_size;
22 SfBufferAttr_In =
BIT(0),
23 SfBufferAttr_Out =
BIT(1),
24 SfBufferAttr_HipcMapAlias =
BIT(2),
25 SfBufferAttr_HipcPointer =
BIT(3),
26 SfBufferAttr_FixedSize =
BIT(4),
27 SfBufferAttr_HipcAutoSelect =
BIT(5),
28 SfBufferAttr_HipcMapTransferAllowsNonSecure =
BIT(6),
29 SfBufferAttr_HipcMapTransferAllowsNonDevice =
BIT(7),
48 typedef enum SfOutHandleAttr {
49 SfOutHandleAttr_None = 0,
50 SfOutHandleAttr_HipcCopy = 1,
51 SfOutHandleAttr_HipcMove = 2,
55 SfOutHandleAttr attr0;
56 SfOutHandleAttr attr1;
57 SfOutHandleAttr attr2;
58 SfOutHandleAttr attr3;
59 SfOutHandleAttr attr4;
60 SfOutHandleAttr attr5;
61 SfOutHandleAttr attr6;
62 SfOutHandleAttr attr7;
142 s->pointer_buffer_size = 0;
143 cmifQueryPointerBufferSize(h, &s->pointer_buffer_size);
158 s->pointer_buffer_size = parent->pointer_buffer_size;
172 if (object_id != 0) {
173 s->session = parent->session;
175 s->object_id = object_id;
176 s->pointer_buffer_size = parent->pointer_buffer_size;
186 #define serviceAssumeDomain(_s) do { \
187 if (!(_s)->object_id) \
188 __builtin_unreachable(); \
197 #if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
199 __builtin_unreachable();
202 if (s->own_handle || s->object_id) {
203 cmifMakeCloseRequest(
armGetTls(), s->own_handle ? 0 : s->object_id);
218 #if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
220 __builtin_unreachable();
224 out_s->own_handle = 1;
225 out_s->object_id = s->object_id;
226 out_s->pointer_buffer_size = s->pointer_buffer_size;
227 return cmifCloneCurrentObject(s->session, &out_s->session);
238 #if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
240 __builtin_unreachable();
244 out_s->own_handle = 1;
245 out_s->object_id = s->object_id;
246 out_s->pointer_buffer_size = s->pointer_buffer_size;
247 return cmifCloneCurrentObjectEx(s->session, tag, &out_s->session);
257 if (!s->own_handle) {
259 Result rc = cmifCloneCurrentObjectEx(s->session, 0, &s->session);
265 return cmifConvertCurrentObjectToDomain(s->session, &s->object_id);
271 const bool is_in = (attr & SfBufferAttr_In) != 0;
272 const bool is_out = (attr & SfBufferAttr_Out) != 0;
274 if (attr & SfBufferAttr_HipcAutoSelect) {
276 fmt->num_in_auto_buffers ++;
278 fmt->num_out_auto_buffers ++;
279 }
else if (attr & SfBufferAttr_HipcPointer) {
281 fmt->num_in_pointers ++;
283 if (attr & SfBufferAttr_FixedSize)
284 fmt->num_out_fixed_pointers ++;
286 fmt->num_out_pointers ++;
288 }
else if (attr & SfBufferAttr_HipcMapAlias) {
290 fmt->num_inout_buffers ++;
292 fmt->num_in_buffers ++;
294 fmt->num_out_buffers ++;
301 const bool is_in = (attr & SfBufferAttr_In);
302 const bool is_out = (attr & SfBufferAttr_Out);
304 if (attr & SfBufferAttr_HipcAutoSelect) {
305 HipcBufferMode mode = HipcBufferMode_Normal;
306 if (attr & SfBufferAttr_HipcMapTransferAllowsNonSecure)
307 mode = HipcBufferMode_NonSecure;
308 if (attr & SfBufferAttr_HipcMapTransferAllowsNonDevice)
309 mode = HipcBufferMode_NonDevice;
311 cmifRequestInAutoBuffer(req, buf->ptr, buf->size, mode);
313 cmifRequestOutAutoBuffer(req, (
void*)buf->ptr, buf->size, mode);
314 }
else if (attr & SfBufferAttr_HipcPointer) {
316 cmifRequestInPointer(req, buf->ptr, buf->size);
318 if (attr & SfBufferAttr_FixedSize)
319 cmifRequestOutFixedPointer(req, (
void*)buf->ptr, buf->size);
321 cmifRequestOutPointer(req, (
void*)buf->ptr, buf->size);
323 }
else if (attr & SfBufferAttr_HipcMapAlias) {
324 HipcBufferMode mode = HipcBufferMode_Normal;
325 if (attr & SfBufferAttr_HipcMapTransferAllowsNonSecure)
326 mode = HipcBufferMode_NonSecure;
327 if (attr & SfBufferAttr_HipcMapTransferAllowsNonDevice)
328 mode = HipcBufferMode_NonDevice;
331 cmifRequestInOutBuffer(req, (
void*)buf->ptr, buf->size, mode);
333 cmifRequestInBuffer(req, buf->ptr, buf->size, mode);
335 cmifRequestOutBuffer(req, (
void*)buf->ptr, buf->size, mode);
342 u32 num_objects,
const Service*
const* objects,
345 #if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
347 __builtin_unreachable();
351 fmt.object_id = s->object_id;
352 fmt.request_id = request_id;
353 fmt.context = context;
354 fmt.data_size = data_size;
355 fmt.server_pointer_size = s->pointer_buffer_size;
356 fmt.num_objects = num_objects;
357 fmt.num_handles = num_handles;
358 fmt.send_pid = send_pid;
360 _serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr0);
361 _serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr1);
362 _serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr2);
363 _serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr3);
364 _serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr4);
365 _serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr5);
366 _serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr6);
367 _serviceRequestFormatProcessBuffer(&fmt, buffer_attrs.attr7);
372 for (
u32 i = 0; i < num_objects; i ++)
373 cmifRequestObject(&req, objects[i]->object_id);
375 for (
u32 i = 0; i < num_handles; i ++)
376 cmifRequestHandle(&req, handles[i]);
378 _serviceRequestProcessBuffer(&req, &buffers[0], buffer_attrs.attr0);
379 _serviceRequestProcessBuffer(&req, &buffers[1], buffer_attrs.attr1);
380 _serviceRequestProcessBuffer(&req, &buffers[2], buffer_attrs.attr2);
381 _serviceRequestProcessBuffer(&req, &buffers[3], buffer_attrs.attr3);
382 _serviceRequestProcessBuffer(&req, &buffers[4], buffer_attrs.attr4);
383 _serviceRequestProcessBuffer(&req, &buffers[5], buffer_attrs.attr5);
384 _serviceRequestProcessBuffer(&req, &buffers[6], buffer_attrs.attr6);
385 _serviceRequestProcessBuffer(&req, &buffers[7], buffer_attrs.attr7);
394 case SfOutHandleAttr_None:
396 case SfOutHandleAttr_HipcCopy:
397 *out = cmifResponseGetCopyHandle(res);
399 case SfOutHandleAttr_HipcMove:
400 *out = cmifResponseGetMoveHandle(res);
410 #if defined(NX_SERVICE_ASSUME_NON_DOMAIN)
412 __builtin_unreachable();
416 bool is_domain = s->object_id != 0;
422 *out_data = res.data;
424 for (
u32 i = 0; i < num_out_objects; i ++) {
431 _serviceResponseGetHandle(&res, out_handle_attrs.attr0, &out_handles[0]);
432 _serviceResponseGetHandle(&res, out_handle_attrs.attr1, &out_handles[1]);
433 _serviceResponseGetHandle(&res, out_handle_attrs.attr2, &out_handles[2]);
434 _serviceResponseGetHandle(&res, out_handle_attrs.attr3, &out_handles[3]);
435 _serviceResponseGetHandle(&res, out_handle_attrs.attr4, &out_handles[4]);
436 _serviceResponseGetHandle(&res, out_handle_attrs.attr5, &out_handles[5]);
437 _serviceResponseGetHandle(&res, out_handle_attrs.attr6, &out_handles[6]);
438 _serviceResponseGetHandle(&res, out_handle_attrs.attr7, &out_handles[7]);
445 const void* in_data,
u32 in_data_size,
446 void* out_data,
u32 out_data_size,
453 void* in = serviceMakeRequest(&srv, request_id, disp.context,
454 in_data_size, disp.in_send_pid,
455 disp.buffer_attrs, disp.buffers,
456 disp.in_num_objects, disp.in_objects,
457 disp.in_num_handles, disp.in_handles);
460 __builtin_memcpy(in, in_data, in_data_size);
465 rc = serviceParseResponse(&srv,
467 disp.out_num_objects, disp.out_objects,
468 disp.out_handle_attrs, disp.out_handles);
471 __builtin_memcpy(out_data, out, out_data_size);
479 #define serviceMacroDetectIsSameType(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
480 #define serviceMacroDetectIsPointerOrArray(p) (__builtin_classify_type(p) == 5)
481 #define serviceMacroDecay(p) (&*__builtin_choose_expr(serviceMacroDetectIsPointerOrArray(p), p, NULL))
482 #define serviceMacroDetectIsPointer(p) serviceMacroDetectIsSameType(p, serviceMacroDecay(p))
488 namespace libnx::impl {
490 template<
typename T>
struct is_pointer {
static constexpr
bool value =
false; };
491 template<
typename T>
struct is_pointer<T*> {
static constexpr
bool value =
true; };
492 template<
typename T>
struct is_pointer<T*
const> {
static constexpr
bool value =
true; };
493 template<
typename T>
struct is_pointer<T*
volatile> {
static constexpr
bool value =
true; };
494 template<
typename T>
struct is_pointer<T*
const volatile> {
static constexpr
bool value =
true; };
500 #define serviceMacroDetectIsPointer(p) (::libnx::impl::is_pointer<decltype(p)>::value)
504 #define serviceDispatch(_s,_rid,...) \
505 serviceDispatchImpl((_s),(_rid),NULL,0,NULL,0,(SfDispatchParams){ __VA_ARGS__ })
507 #define serviceDispatchIn(_s,_rid,_in,...) \
508 ({ static_assert(!(serviceMacroDetectIsPointer(_in))); \
509 serviceDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(SfDispatchParams){ __VA_ARGS__ }); })
511 #define serviceDispatchOut(_s,_rid,_out,...) \
512 ({ static_assert(!(serviceMacroDetectIsPointer(_out))); \
513 serviceDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ }); })
515 #define serviceDispatchInOut(_s,_rid,_in,_out,...) \
516 ({ static_assert(!(serviceMacroDetectIsPointer(_in))); \
517 static_assert(!(serviceMacroDetectIsPointer(_out))); \
518 serviceDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(SfDispatchParams){ __VA_ARGS__ }); })
Common Message Interface Framework protocol.
Horizon Inter-Process Communication protocol.
#define R_FAILED(res)
Checks whether a result code indicates failure.
Definition: result.h:12
#define R_SUCCEEDED(res)
Checks whether a result code indicates success.
Definition: result.h:10
static bool serviceIsOverride(Service *s)
Returns whether a service is overriden in the homebrew environment.
Definition: service.h:101
static Result serviceClone(Service *s, Service *out_s)
Clones a service.
Definition: service.h:216
static bool serviceIsDomainSubservice(Service *s)
Returns whether a service is a domain subservice.
Definition: service.h:119
static Result serviceCloneEx(Service *s, u32 tag, Service *out_s)
Clones a service with a session manager tag.
Definition: service.h:236
static void serviceCreateNonDomainSubservice(Service *s, Service *parent, Handle h)
Creates a non-domain subservice object from a parent service.
Definition: service.h:152
static Result serviceConvertToDomain(Service *s)
Converts a regular service to a domain.
Definition: service.h:255
static bool serviceIsActive(Service *s)
Returns whether a service has been initialized.
Definition: service.h:92
static void serviceCreateDomainSubservice(Service *s, Service *parent, u32 object_id)
Creates a domain subservice object from a parent service.
Definition: service.h:170
static bool serviceIsDomain(Service *s)
Returns whether a service is a domain.
Definition: service.h:110
static u32 serviceGetObjectId(Service *s)
For a domain/domain subservice, return the associated object ID.
Definition: service.h:128
static void serviceClose(Service *s)
Closes a service.
Definition: service.h:195
static void serviceCreate(Service *s, Handle h)
Creates a service object from an IPC session handle.
Definition: service.h:137
Service object structure.
Definition: service.h:14
Result svcCloseHandle(Handle handle)
Closes a handle, decrementing the reference count of the corresponding kernel object.
Result svcSendSyncRequest(Handle session)
Sends an IPC synchronization request to a session.
static void * armGetTls(void)
Gets the thread local storage buffer.
Definition: tls.h:14
#define NX_INLINE
Flags a function as (always) inline.
Definition: types.h:86
#define BIT(n)
Creates a bitmask from a bit number.
Definition: types.h:54
#define INVALID_HANDLE
Invalid handle.
Definition: types.h:96
u32 Handle
Kernel object handle.
Definition: types.h:43
uint16_t u16
16-bit unsigned integer.
Definition: types.h:20
u32 Result
Function error code result type.
Definition: types.h:44
#define NX_CONSTEXPR
Flags a function as constexpr in C++14 and above; or as (always) inline otherwise.
Definition: types.h:92
uint32_t u32
32-bit unsigned integer.
Definition: types.h:21