libnx  v4.2.0
hipc.h
Go to the documentation of this file.
1 /**
2  * @file hipc.h
3  * @brief Horizon Inter-Process Communication protocol
4  * @author fincs
5  * @author SciresM
6  * @copyright libnx Authors
7  */
8 #pragma once
9 #include "../result.h"
10 #include "../arm/tls.h"
11 #include "../kernel/svc.h"
12 
13 #define HIPC_AUTO_RECV_STATIC UINT8_MAX
14 #define HIPC_RESPONSE_NO_PID UINT32_MAX
15 
16 typedef struct HipcMetadata {
17  u32 type;
18  u32 num_send_statics;
19  u32 num_send_buffers;
20  u32 num_recv_buffers;
21  u32 num_exch_buffers;
22  u32 num_data_words;
23  u32 num_recv_statics; // also accepts HIPC_AUTO_RECV_STATIC
24  u32 send_pid;
25  u32 num_copy_handles;
26  u32 num_move_handles;
27 } HipcMetadata;
28 
29 typedef struct HipcHeader {
30  u32 type : 16;
31  u32 num_send_statics : 4;
32  u32 num_send_buffers : 4;
33  u32 num_recv_buffers : 4;
34  u32 num_exch_buffers : 4;
35  u32 num_data_words : 10;
36  u32 recv_static_mode : 4;
37  u32 padding : 6;
38  u32 recv_list_offset : 11; // Unused.
39  u32 has_special_header : 1;
40 } HipcHeader;
41 
42 typedef struct HipcSpecialHeader {
43  u32 send_pid : 1;
44  u32 num_copy_handles : 4;
45  u32 num_move_handles : 4;
46  u32 padding : 23;
48 
49 typedef struct HipcStaticDescriptor {
50  u32 index : 6;
51  u32 address_high : 6;
52  u32 address_mid : 4;
53  u32 size : 16;
54  u32 address_low;
56 
57 typedef struct HipcBufferDescriptor {
58  u32 size_low;
59  u32 address_low;
60  u32 mode : 2;
61  u32 address_high : 22;
62  u32 size_high : 4;
63  u32 address_mid : 4;
65 
66 typedef struct HipcRecvListEntry {
67  u32 address_low;
68  u32 address_high : 16;
69  u32 size : 16;
71 
72 typedef struct HipcRequest {
73  HipcStaticDescriptor* send_statics;
74  HipcBufferDescriptor* send_buffers;
75  HipcBufferDescriptor* recv_buffers;
76  HipcBufferDescriptor* exch_buffers;
77  u32* data_words;
78  HipcRecvListEntry* recv_list;
79  Handle* copy_handles;
80  Handle* move_handles;
81 } HipcRequest;
82 
83 typedef struct HipcParsedRequest {
84  HipcMetadata meta;
85  HipcRequest data;
86  u64 pid;
88 
89 typedef struct HipcResponse {
90  u64 pid;
91  u32 num_statics;
92  u32 num_data_words;
93  u32 num_copy_handles;
94  u32 num_move_handles;
95  HipcStaticDescriptor* statics;
96  u32* data_words;
97  Handle* copy_handles;
98  Handle* move_handles;
99 } HipcResponse;
100 
101 typedef enum HipcBufferMode {
102  HipcBufferMode_Normal = 0,
103  HipcBufferMode_NonSecure = 1,
104  HipcBufferMode_Invalid = 2,
105  HipcBufferMode_NonDevice = 3,
106 } HipcBufferMode;
107 
108 NX_CONSTEXPR HipcStaticDescriptor hipcMakeSendStatic(const void* buffer, size_t size, u8 index)
109 {
110  return (HipcStaticDescriptor){
111  .index = index,
112  .address_high = (u32)((uintptr_t)buffer >> 36),
113  .address_mid = (u32)((uintptr_t)buffer >> 32),
114  .size = (u32)size,
115  .address_low = (u32)(uintptr_t)buffer,
116  };
117 }
118 
119 NX_CONSTEXPR HipcBufferDescriptor hipcMakeBuffer(const void* buffer, size_t size, HipcBufferMode mode)
120 {
121  return (HipcBufferDescriptor){
122  .size_low = (u32)size,
123  .address_low = (u32)(uintptr_t)buffer,
124  .mode = mode,
125  .address_high = (u32)((uintptr_t)buffer >> 36),
126  .size_high = (u32)(size >> 32),
127  .address_mid = (u32)((uintptr_t)buffer >> 32),
128  };
129 }
130 
131 NX_CONSTEXPR HipcRecvListEntry hipcMakeRecvStatic(void* buffer, size_t size)
132 {
133  return (HipcRecvListEntry){
134  .address_low = (u32)((uintptr_t)buffer),
135  .address_high = (u32)((uintptr_t)buffer >> 32),
136  .size = (u32)size,
137  };
138 }
139 
140 NX_CONSTEXPR void* hipcGetStaticAddress(const HipcStaticDescriptor* desc)
141 {
142  return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36));
143 }
144 
145 NX_CONSTEXPR size_t hipcGetStaticSize(const HipcStaticDescriptor* desc)
146 {
147  return desc->size;
148 }
149 
150 NX_CONSTEXPR void* hipcGetBufferAddress(const HipcBufferDescriptor* desc)
151 {
152  return (void*)(desc->address_low | ((uintptr_t)desc->address_mid << 32) | ((uintptr_t)desc->address_high << 36));
153 }
154 
155 NX_CONSTEXPR size_t hipcGetBufferSize(const HipcBufferDescriptor* desc)
156 {
157  return desc->size_low | ((size_t)desc->size_high << 32);
158 }
159 
160 NX_CONSTEXPR HipcRequest hipcCalcRequestLayout(HipcMetadata meta, void* base)
161 {
162  // Copy handles
163  Handle* copy_handles = NULL;
164  if (meta.num_copy_handles) {
165  copy_handles = (Handle*)base;
166  base = copy_handles + meta.num_copy_handles;
167  }
168 
169  // Move handles
170  Handle* move_handles = NULL;
171  if (meta.num_move_handles) {
172  move_handles = (Handle*)base;
173  base = move_handles + meta.num_move_handles;
174  }
175 
176  // Send statics
177  HipcStaticDescriptor* send_statics = NULL;
178  if (meta.num_send_statics) {
179  send_statics = (HipcStaticDescriptor*)base;
180  base = send_statics + meta.num_send_statics;
181  }
182 
183  // Send buffers
184  HipcBufferDescriptor* send_buffers = NULL;
185  if (meta.num_send_buffers) {
186  send_buffers = (HipcBufferDescriptor*)base;
187  base = send_buffers + meta.num_send_buffers;
188  }
189 
190  // Recv buffers
191  HipcBufferDescriptor* recv_buffers = NULL;
192  if (meta.num_recv_buffers) {
193  recv_buffers = (HipcBufferDescriptor*)base;
194  base = recv_buffers + meta.num_recv_buffers;
195  }
196 
197  // Exch buffers
198  HipcBufferDescriptor* exch_buffers = NULL;
199  if (meta.num_exch_buffers) {
200  exch_buffers = (HipcBufferDescriptor*)base;
201  base = exch_buffers + meta.num_exch_buffers;
202  }
203 
204  // Data words
205  u32* data_words = NULL;
206  if (meta.num_data_words) {
207  data_words = (u32*)base;
208  base = data_words + meta.num_data_words;
209  }
210 
211  // Recv list
212  HipcRecvListEntry* recv_list = NULL;
213  if (meta.num_recv_statics)
214  recv_list = (HipcRecvListEntry*)base;
215 
216  return (HipcRequest){
217  .send_statics = send_statics,
218  .send_buffers = send_buffers,
219  .recv_buffers = recv_buffers,
220  .exch_buffers = exch_buffers,
221  .data_words = data_words,
222  .recv_list = recv_list,
223  .copy_handles = copy_handles,
224  .move_handles = move_handles,
225  };
226 }
227 
228 NX_CONSTEXPR HipcRequest hipcMakeRequest(void* base, HipcMetadata meta)
229 {
230  // Write message header
231  bool has_special_header = meta.send_pid || meta.num_copy_handles || meta.num_move_handles;
232  HipcHeader* hdr = (HipcHeader*)base;
233  base = hdr+1;
234  *hdr = (HipcHeader){
235  .type = meta.type,
236  .num_send_statics = meta.num_send_statics,
237  .num_send_buffers = meta.num_send_buffers,
238  .num_recv_buffers = meta.num_recv_buffers,
239  .num_exch_buffers = meta.num_exch_buffers,
240  .num_data_words = meta.num_data_words,
241  .recv_static_mode = meta.num_recv_statics ? (meta.num_recv_statics != HIPC_AUTO_RECV_STATIC ? 2u + meta.num_recv_statics : 2u) : 0u,
242  .padding = 0,
243  .recv_list_offset = 0,
244  .has_special_header = has_special_header,
245  };
246 
247  // Write special header
248  if (has_special_header) {
249  HipcSpecialHeader* sphdr = (HipcSpecialHeader*)base;
250  base = sphdr+1;
251  *sphdr = (HipcSpecialHeader){
252  .send_pid = meta.send_pid,
253  .num_copy_handles = meta.num_copy_handles,
254  .num_move_handles = meta.num_move_handles,
255  };
256  if (meta.send_pid)
257  base = (u8*)base + sizeof(u64);
258  }
259 
260  // Calculate layout
261  return hipcCalcRequestLayout(meta, base);
262 }
263 
264 #define hipcMakeRequestInline(_base,...) hipcMakeRequest((_base),(HipcMetadata){ __VA_ARGS__ })
265 
266 NX_CONSTEXPR HipcParsedRequest hipcParseRequest(void* base)
267 {
268  // Parse message header
269  HipcHeader hdr = {};
270  __builtin_memcpy(&hdr, base, sizeof(hdr));
271  base = (u8*)base + sizeof(hdr);
272  u32 num_recv_statics = 0;
273  u64 pid = 0;
274 
275  // Parse recv static mode
276  if (hdr.recv_static_mode) {
277  if (hdr.recv_static_mode == 2u)
278  num_recv_statics = HIPC_AUTO_RECV_STATIC;
279  else if (hdr.recv_static_mode > 2u)
280  num_recv_statics = hdr.recv_static_mode - 2u;
281  }
282 
283  // Parse special header
284  HipcSpecialHeader sphdr = {};
285  if (hdr.has_special_header) {
286  __builtin_memcpy(&sphdr, base, sizeof(sphdr));
287  base = (u8*)base + sizeof(sphdr);
288 
289  // Read PID descriptor
290  if (sphdr.send_pid) {
291  pid = *(u64*)base;
292  base = (u8*)base + sizeof(u64);
293  }
294  }
295 
296  const HipcMetadata meta = {
297  .type = hdr.type,
298  .num_send_statics = hdr.num_send_statics,
299  .num_send_buffers = hdr.num_send_buffers,
300  .num_recv_buffers = hdr.num_recv_buffers,
301  .num_exch_buffers = hdr.num_exch_buffers,
302  .num_data_words = hdr.num_data_words,
303  .num_recv_statics = num_recv_statics,
304  .send_pid = sphdr.send_pid,
305  .num_copy_handles = sphdr.num_copy_handles,
306  .num_move_handles = sphdr.num_move_handles,
307  };
308 
309  return (HipcParsedRequest){
310  .meta = meta,
311  .data = hipcCalcRequestLayout(meta, base),
312  .pid = pid,
313  };
314 }
315 
316 NX_CONSTEXPR HipcResponse hipcParseResponse(void* base)
317 {
318  // Parse header
319  HipcHeader hdr = {};
320  __builtin_memcpy(&hdr, base, sizeof(hdr));
321  base = (u8*)base + sizeof(hdr);
322 
323  // Initialize response
324  HipcResponse response = {};
325  response.num_statics = hdr.num_send_statics;
326  response.num_data_words = hdr.num_data_words;
327  response.pid = HIPC_RESPONSE_NO_PID;
328 
329  // Parse special header
330  if (hdr.has_special_header)
331  {
332  HipcSpecialHeader sphdr = {};
333  __builtin_memcpy(&sphdr, base, sizeof(sphdr));
334  base = (u8*)base + sizeof(sphdr);
335 
336  // Update response
337  response.num_copy_handles = sphdr.num_copy_handles;
338  response.num_move_handles = sphdr.num_move_handles;
339 
340  // Parse PID descriptor
341  if (sphdr.send_pid) {
342  response.pid = *(u64*)base;
343  base = (u8*)base + sizeof(u64);
344  }
345  }
346 
347  // Copy handles
348  response.copy_handles = (Handle*)base;
349  base = response.copy_handles + response.num_copy_handles;
350 
351  // Move handles
352  response.move_handles = (Handle*)base;
353  base = response.move_handles + response.num_move_handles;
354 
355  // Send statics
356  response.statics = (HipcStaticDescriptor*)base;
357  base = response.statics + response.num_statics;
358 
359  // Data words
360  response.data_words = (u32*)base;
361 
362  return response;
363 }
HipcBufferDescriptor
Definition: hipc.h:57
HipcRecvListEntry
Definition: hipc.h:66
u8
uint8_t u8
8-bit unsigned integer.
Definition: types.h:19
NX_CONSTEXPR
#define NX_CONSTEXPR
Flags a function as constexpr in C++14 and above; or as (always) inline otherwise.
Definition: types.h:88
HipcSpecialHeader
Definition: hipc.h:42
u32
uint32_t u32
32-bit unsigned integer.
Definition: types.h:21
HipcStaticDescriptor
Definition: hipc.h:49
HipcMetadata
Definition: hipc.h:16
u64
uint64_t u64
64-bit unsigned integer.
Definition: types.h:22
HipcResponse
Definition: hipc.h:89
HipcParsedRequest
Definition: hipc.h:83
HipcHeader
Definition: hipc.h:29
HipcRequest
Definition: hipc.h:72
Handle
u32 Handle
Kernel object handle.
Definition: types.h:43