libnx v4.9.0
Loading...
Searching...
No Matches
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
16typedef 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;
28
29typedef 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;
41
42typedef struct HipcSpecialHeader {
43 u32 send_pid : 1;
44 u32 num_copy_handles : 4;
45 u32 num_move_handles : 4;
46 u32 padding : 23;
48
49typedef 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
57typedef 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
66typedef struct HipcRecvListEntry {
67 u32 address_low;
68 u32 address_high : 16;
69 u32 size : 16;
71
72typedef 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;
82
83typedef struct HipcParsedRequest {
84 HipcMetadata meta;
85 HipcRequest data;
86 u64 pid;
88
89typedef 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;
100
101typedef enum HipcBufferMode {
102 HipcBufferMode_Normal = 0,
103 HipcBufferMode_NonSecure = 1,
104 HipcBufferMode_Invalid = 2,
105 HipcBufferMode_NonDevice = 3,
106} HipcBufferMode;
107
108NX_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
119NX_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
131NX_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
140NX_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
145NX_CONSTEXPR size_t hipcGetStaticSize(const HipcStaticDescriptor* desc)
146{
147 return desc->size;
148}
149
150NX_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
155NX_CONSTEXPR size_t hipcGetBufferSize(const HipcBufferDescriptor* desc)
156{
157 return desc->size_low | ((size_t)desc->size_high << 32);
158}
159
160NX_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
228NX_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
266NX_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
316NX_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}
Definition hipc.h:57
Definition hipc.h:29
Definition hipc.h:16
Definition hipc.h:83
Definition hipc.h:66
Definition hipc.h:72
Definition hipc.h:89
Definition hipc.h:42
Definition hipc.h:49
uint64_t u64
64-bit unsigned integer.
Definition types.h:22
uint8_t u8
8-bit unsigned integer.
Definition types.h:19
u32 Handle
Kernel object handle.
Definition types.h:43
#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