libnx  v4.6.0
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 
13 typedef enum TipcCommandType {
14  TipcCommandType_Close = 15,
15 } TipcCommandType;
16 
17 /// tipc Service object structure
18 typedef struct TipcService {
19  Handle session;
20 } TipcService;
21 
22 typedef 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 
38 typedef 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 
69 NX_CONSTEXPR void tipcRequestInBuffer(HipcRequest* req, const void* buffer, size_t size, HipcBufferMode mode)
70 {
71  *req->send_buffers++ = hipcMakeBuffer(buffer, size, mode);
72 }
73 
74 NX_CONSTEXPR void tipcRequestOutBuffer(HipcRequest* req, void* buffer, size_t size, HipcBufferMode mode)
75 {
76  *req->recv_buffers++ = hipcMakeBuffer(buffer, size, mode);
77 }
78 
79 NX_CONSTEXPR void tipcRequestInOutBuffer(HipcRequest* req, void* buffer, size_t size, HipcBufferMode mode)
80 {
81  *req->exch_buffers++ = hipcMakeBuffer(buffer, size, mode);
82 }
83 
84 NX_CONSTEXPR void tipcRequestHandle(HipcRequest* req, Handle handle)
85 {
86  *req->copy_handles++ = handle;
87 }
88 
89 NX_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 
105 NX_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 
127 NX_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 
174 NX_CONSTEXPR Handle tipcResponseGetCopyHandle(HipcResponse* res)
175 {
176  return *res->copy_handles++;
177 }
178 
179 NX_CONSTEXPR Handle tipcResponseGetMoveHandle(HipcResponse* res)
180 {
181  return *res->move_handles++;
182 }
183 
184 NX_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 
199 NX_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 
230 NX_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,
234  TipcDispatchParams disp
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