libnx v4.9.0
Loading...
Searching...
No Matches
tipc.h
Go to the documentation of this file.
1/**
2 * @file tipc.h
3 * @brief Tiny IPC protocol
4 * @author fincs
5 * @author SciresM
6 * @copyright libnx Authors
7 */
8#pragma once
9#include "hipc.h"
10#include "cmif.h"
11#include "service.h"
12
13typedef enum TipcCommandType {
14 TipcCommandType_Close = 15,
15} TipcCommandType;
16
17/// tipc Service object structure
18typedef struct TipcService {
19 Handle session;
21
22typedef struct TipcDispatchParams {
23 SfBufferAttrs buffer_attrs;
24 SfBuffer buffers[8];
25
26 bool in_send_pid;
27
28 u32 in_num_handles;
29 Handle in_handles[8];
30
31 u32 out_num_objects;
32 TipcService* out_objects;
33
34 SfOutHandleAttrs out_handle_attrs;
35 Handle* out_handles;
37
38typedef struct TipcRequestFormat {
39 u32 request_id;
40 u32 data_size;
41 u32 num_in_buffers;
42 u32 num_out_buffers;
43 u32 num_inout_buffers;
44 u32 num_handles;
45 u32 send_pid;
47
48/**
49 * @brief Creates a tipc service object from an IPC session handle.
50 * @param[out] s TIPC service object.
51 * @param[in] h IPC session handle.
52 */
54 s->session = h;
55}
56
57/**
58 * @brief Closes a tipc service.
59 * @param[in] s TIPC service object.
60 */
62{
63 hipcMakeRequestInline(armGetTls(), .type = TipcCommandType_Close);
64 svcSendSyncRequest(s->session);
65 svcCloseHandle(s->session);
66 *s = (TipcService){};
67}
68
69NX_CONSTEXPR void tipcRequestInBuffer(HipcRequest* req, const void* buffer, size_t size, HipcBufferMode mode)
70{
71 *req->send_buffers++ = hipcMakeBuffer(buffer, size, mode);
72}
73
74NX_CONSTEXPR void tipcRequestOutBuffer(HipcRequest* req, void* buffer, size_t size, HipcBufferMode mode)
75{
76 *req->recv_buffers++ = hipcMakeBuffer(buffer, size, mode);
77}
78
79NX_CONSTEXPR void tipcRequestInOutBuffer(HipcRequest* req, void* buffer, size_t size, HipcBufferMode mode)
80{
81 *req->exch_buffers++ = hipcMakeBuffer(buffer, size, mode);
82}
83
84NX_CONSTEXPR void tipcRequestHandle(HipcRequest* req, Handle handle)
85{
86 *req->copy_handles++ = handle;
87}
88
89NX_CONSTEXPR void _tipcRequestFormatProcessBuffer(TipcRequestFormat* fmt, u32 attr)
90{
91 if (!attr) return;
92 const bool is_in = (attr & SfBufferAttr_In) != 0;
93 const bool is_out = (attr & SfBufferAttr_Out) != 0;
94
95 if (attr & SfBufferAttr_HipcMapAlias) {
96 if (is_in && is_out)
97 fmt->num_inout_buffers ++;
98 else if (is_in)
99 fmt->num_in_buffers ++;
100 else if (is_out)
101 fmt->num_out_buffers ++;
102 }
103}
104
105NX_CONSTEXPR void _tipcRequestProcessBuffer(HipcRequest* req, const SfBuffer* buf, u32 attr)
106{
107 if (!attr) return;
108 const bool is_in = (attr & SfBufferAttr_In);
109 const bool is_out = (attr & SfBufferAttr_Out);
110
111 if (attr & SfBufferAttr_HipcMapAlias) {
112 HipcBufferMode mode = HipcBufferMode_Normal;
113 if (attr & SfBufferAttr_HipcMapTransferAllowsNonSecure)
114 mode = HipcBufferMode_NonSecure;
115 if (attr & SfBufferAttr_HipcMapTransferAllowsNonDevice)
116 mode = HipcBufferMode_NonDevice;
117
118 if (is_in && is_out)
119 tipcRequestInOutBuffer(req, (void*)buf->ptr, buf->size, mode);
120 else if (is_in)
121 tipcRequestInBuffer(req, buf->ptr, buf->size, mode);
122 else if (is_out)
123 tipcRequestOutBuffer(req, (void*)buf->ptr, buf->size, mode);
124 }
125}
126
127NX_INLINE void* tipcMakeRequest(
128 u32 request_id, u32 data_size, bool send_pid,
129 const SfBufferAttrs buffer_attrs, const SfBuffer* buffers,
130 u32 num_handles, const Handle* handles) {
131 TipcRequestFormat fmt = {};
132 fmt.request_id = request_id + 16;
133 fmt.data_size = data_size;
134 fmt.num_handles = num_handles;
135 fmt.send_pid = send_pid;
136
137 _tipcRequestFormatProcessBuffer(&fmt, buffer_attrs.attr0);
138 _tipcRequestFormatProcessBuffer(&fmt, buffer_attrs.attr1);
139 _tipcRequestFormatProcessBuffer(&fmt, buffer_attrs.attr2);
140 _tipcRequestFormatProcessBuffer(&fmt, buffer_attrs.attr3);
141 _tipcRequestFormatProcessBuffer(&fmt, buffer_attrs.attr4);
142 _tipcRequestFormatProcessBuffer(&fmt, buffer_attrs.attr5);
143 _tipcRequestFormatProcessBuffer(&fmt, buffer_attrs.attr6);
144 _tipcRequestFormatProcessBuffer(&fmt, buffer_attrs.attr7);
145
146 HipcRequest req = hipcMakeRequestInline(armGetTls(),
147 .type = fmt.request_id,
148 .num_send_statics = 0,
149 .num_send_buffers = fmt.num_in_buffers,
150 .num_recv_buffers = fmt.num_out_buffers,
151 .num_exch_buffers = fmt.num_inout_buffers,
152 .num_data_words = (data_size + 3) / 4,
153 .num_recv_statics = 0,
154 .send_pid = fmt.send_pid,
155 .num_copy_handles = fmt.num_handles,
156 .num_move_handles = 0,
157 );
158
159 for (u32 i = 0; i < num_handles; i ++)
160 tipcRequestHandle(&req, handles[i]);
161
162 _tipcRequestProcessBuffer(&req, &buffers[0], buffer_attrs.attr0);
163 _tipcRequestProcessBuffer(&req, &buffers[1], buffer_attrs.attr1);
164 _tipcRequestProcessBuffer(&req, &buffers[2], buffer_attrs.attr2);
165 _tipcRequestProcessBuffer(&req, &buffers[3], buffer_attrs.attr3);
166 _tipcRequestProcessBuffer(&req, &buffers[4], buffer_attrs.attr4);
167 _tipcRequestProcessBuffer(&req, &buffers[5], buffer_attrs.attr5);
168 _tipcRequestProcessBuffer(&req, &buffers[6], buffer_attrs.attr6);
169 _tipcRequestProcessBuffer(&req, &buffers[7], buffer_attrs.attr7);
170
171 return req.data_words;
172}
173
174NX_CONSTEXPR Handle tipcResponseGetCopyHandle(HipcResponse* res)
175{
176 return *res->copy_handles++;
177}
178
179NX_CONSTEXPR Handle tipcResponseGetMoveHandle(HipcResponse* res)
180{
181 return *res->move_handles++;
182}
183
184NX_CONSTEXPR void _tipcResponseGetHandle(HipcResponse* res, SfOutHandleAttr type, Handle* out)
185{
186 switch (type) {
187 default:
188 case SfOutHandleAttr_None:
189 break;
190 case SfOutHandleAttr_HipcCopy:
191 *out = tipcResponseGetCopyHandle(res);
192 break;
193 case SfOutHandleAttr_HipcMove:
194 *out = tipcResponseGetMoveHandle(res);
195 break;
196 }
197}
198
199NX_INLINE Result tipcParseResponse(
200 u32 out_size, void** out_data,
201 u32 num_out_objects, TipcService* out_objects,
202 const SfOutHandleAttrs out_handle_attrs, Handle* out_handles
203) {
204
205 HipcResponse res = hipcParseResponse(armGetTls());
206
207 Result rc = *res.data_words++;
208 if (R_FAILED(rc))
209 return rc;
210
211 if (out_size)
212 *out_data = res.data_words;
213
214 for (u32 i = 0; i < num_out_objects; i ++) {
215 tipcCreate(&out_objects[i], tipcResponseGetMoveHandle(&res));
216 }
217
218 _tipcResponseGetHandle(&res, out_handle_attrs.attr0, &out_handles[0]);
219 _tipcResponseGetHandle(&res, out_handle_attrs.attr1, &out_handles[1]);
220 _tipcResponseGetHandle(&res, out_handle_attrs.attr2, &out_handles[2]);
221 _tipcResponseGetHandle(&res, out_handle_attrs.attr3, &out_handles[3]);
222 _tipcResponseGetHandle(&res, out_handle_attrs.attr4, &out_handles[4]);
223 _tipcResponseGetHandle(&res, out_handle_attrs.attr5, &out_handles[5]);
224 _tipcResponseGetHandle(&res, out_handle_attrs.attr6, &out_handles[6]);
225 _tipcResponseGetHandle(&res, out_handle_attrs.attr7, &out_handles[7]);
226
227 return 0;
228}
229
230NX_INLINE Result tipcDispatchImpl(
231 TipcService* s, u32 request_id,
232 const void* in_data, u32 in_data_size,
233 void* out_data, u32 out_data_size,
235)
236{
237 void* in = tipcMakeRequest(request_id,
238 in_data_size, disp.in_send_pid,
239 disp.buffer_attrs, disp.buffers,
240 disp.in_num_handles, disp.in_handles);
241
242 if (in_data_size)
243 __builtin_memcpy(in, in_data, in_data_size);
244
245 Result rc = svcSendSyncRequest(s->session);
246 if (R_SUCCEEDED(rc)) {
247 void* out = NULL;
248 rc = tipcParseResponse(out_data_size, &out,
249 disp.out_num_objects, disp.out_objects,
250 disp.out_handle_attrs, disp.out_handles);
251
252 if (R_SUCCEEDED(rc) && out_data && out_data_size)
253 __builtin_memcpy(out_data, out, out_data_size);
254 }
255
256 return rc;
257}
258
259#define tipcDispatch(_s,_rid,...) \
260 tipcDispatchImpl((_s),(_rid),NULL,0,NULL,0,(TipcDispatchParams){ __VA_ARGS__ })
261
262#define tipcDispatchIn(_s,_rid,_in,...) \
263 tipcDispatchImpl((_s),(_rid),&(_in),sizeof(_in),NULL,0,(TipcDispatchParams){ __VA_ARGS__ })
264
265#define tipcDispatchOut(_s,_rid,_out,...) \
266 tipcDispatchImpl((_s),(_rid),NULL,0,&(_out),sizeof(_out),(TipcDispatchParams){ __VA_ARGS__ })
267
268#define tipcDispatchInOut(_s,_rid,_in,_out,...) \
269 tipcDispatchImpl((_s),(_rid),&(_in),sizeof(_in),&(_out),sizeof(_out),(TipcDispatchParams){ __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
Service wrapper object.
Definition hipc.h:72
Definition hipc.h:89
Definition service.h:32
Definition service.h:43
Definition service.h:54
Definition tipc.h:22
Definition tipc.h:38
tipc Service object structure
Definition tipc.h:18
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 tipcCreate(TipcService *s, Handle h)
Creates a tipc service object from an IPC session handle.
Definition tipc.h:53
static void tipcClose(TipcService *s)
Closes a tipc service.
Definition tipc.h:61
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
u32 Handle
Kernel object handle.
Definition types.h:43
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