1/*
2 * Copyright (c) 2023 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29#if CONFIG_EXCLAVES
30
31#if __has_include(<Tightbeam/tightbeam.h>)
32
33#include <stdint.h>
34
35#include <Tightbeam/tightbeam.h>
36#include <Tightbeam/tightbeam_private.h>
37
38#include <Exclaves/Exclaves.h>
39#include <IOKit/IOTypes.h>
40#include <mach/exclaves.h>
41#include <kern/startup.h>
42#include <stdint.h>
43#include <kern/startup.h>
44
45#include "kern/exclaves.tightbeam.h"
46#include "exclaves_debug.h"
47#include "exclaves_driverkit.h"
48#include "exclaves_resource.h"
49
50/* Registry ID of service being used in HelloDriverInterrupts */
51static uint64_t exclaves_hello_driverkit_interrupts_service_id = -1ull;
52
53
54/* -------------------------------------------------------------------------- */
55#pragma mark Upcalls
56
57tb_error_t
58exclaves_driverkit_upcall_irq_register(const uint64_t id, const int32_t index,
59 tb_error_t (^completion)(xnuupcalls_xnuupcalls_irq_register__result_s))
60{
61 exclaves_debug_printf(show_iokit_upcalls,
62 "[iokit_upcalls] register_irq %d from id %llu \n", index, id);
63 struct IOExclaveInterruptUpcallArgs args;
64 args.index = index;
65 args.type = kIOExclaveInterruptUpcallTypeRegister;
66 // If upcall is from HelloDriverInterrupts test, create detached IOIES
67 args.data.register_args.test_irq =
68 (id == exclaves_hello_driverkit_interrupts_service_id);
69
70 xnuupcalls_xnuupcalls_irq_register__result_s result = {};
71 if (!IOExclaveInterruptUpcallHandler(id, &args)) {
72 xnuupcalls_xnuupcalls_irq_register__result_init_failure(&result,
73 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
74 } else {
75 xnuupcalls_xnuupcalls_irq_register__result_init_success(&result);
76 }
77
78 return completion(result);
79}
80
81tb_error_t
82exclaves_driverkit_upcall_irq_remove(const uint64_t id, const int32_t index,
83 tb_error_t (^completion)(xnuupcalls_xnuupcalls_irq_remove__result_s))
84{
85 exclaves_debug_printf(show_iokit_upcalls,
86 "[iokit_upcalls] remove_irq %d from id %llu \n", index, id);
87 struct IOExclaveInterruptUpcallArgs args;
88 args.index = index;
89 args.type = kIOExclaveInterruptUpcallTypeRemove;
90
91 xnuupcalls_xnuupcalls_irq_remove__result_s result = {};
92 if (!IOExclaveInterruptUpcallHandler(id, &args)) {
93 xnuupcalls_xnuupcalls_irq_remove__result_init_failure(&result,
94 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
95 } else {
96 xnuupcalls_xnuupcalls_irq_remove__result_init_success(&result);
97 }
98
99 return completion(result);
100}
101
102
103tb_error_t
104exclaves_driverkit_upcall_irq_enable(const uint64_t id, const int32_t index,
105 tb_error_t (^completion)(xnuupcalls_xnuupcalls_irq_enable__result_s))
106{
107 exclaves_debug_printf(show_iokit_upcalls,
108 "[iokit_upcalls] enable_irq %d from id %llu \n", index, id);
109 struct IOExclaveInterruptUpcallArgs args;
110 args.index = index;
111 args.type = kIOExclaveInterruptUpcallTypeEnable;
112 args.data.enable_args.enable = true;
113
114 xnuupcalls_xnuupcalls_irq_enable__result_s result = {};
115 if (!IOExclaveInterruptUpcallHandler(id, &args)) {
116 xnuupcalls_xnuupcalls_irq_enable__result_init_failure(&result,
117 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
118 } else {
119 xnuupcalls_xnuupcalls_irq_enable__result_init_success(&result);
120 }
121
122 return completion(result);
123}
124
125tb_error_t
126exclaves_driverkit_upcall_irq_disable(const uint64_t id, const int32_t index,
127 tb_error_t (^completion)(xnuupcalls_xnuupcalls_irq_disable__result_s))
128{
129 exclaves_debug_printf(show_iokit_upcalls,
130 "[iokit_upcalls] disable_irq %d from id %llu \n", index, id);
131 struct IOExclaveInterruptUpcallArgs args;
132 args.index = index;
133 args.type = kIOExclaveInterruptUpcallTypeEnable;
134 args.data.enable_args.enable = false;
135
136 xnuupcalls_xnuupcalls_irq_disable__result_s result = {};
137 if (!IOExclaveInterruptUpcallHandler(id, &args)) {
138 xnuupcalls_xnuupcalls_irq_disable__result_init_failure(&result,
139 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
140 } else {
141 xnuupcalls_xnuupcalls_irq_disable__result_init_success(&result);
142 }
143
144 return completion(result);
145}
146
147tb_error_t
148exclaves_driverkit_upcall_timer_register(const uint64_t id,
149 tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_register__result_s))
150{
151 exclaves_debug_printf(show_iokit_upcalls,
152 "[iokit_upcalls] %s from id %llu\n", __func__, id);
153 struct IOExclaveTimerUpcallArgs args;
154 args.type = kIOExclaveTimerUpcallTypeRegister;
155
156 xnuupcalls_xnuupcalls_timer_register__result_s result = {};
157 if (!IOExclaveTimerUpcallHandler(id, &args)) {
158 xnuupcalls_xnuupcalls_timer_register__result_init_failure(&result,
159 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
160 } else {
161 xnuupcalls_xnuupcalls_timer_register__result_init_success(&result,
162 args.timer_id);
163 }
164
165 return completion(result);
166}
167
168tb_error_t
169exclaves_driverkit_upcall_timer_remove(const uint64_t id, const uint32_t timer_id,
170 tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_remove__result_s))
171{
172 exclaves_debug_printf(show_iokit_upcalls,
173 "[iokit_upcalls] %s from id %llu\n", __func__, id);
174 struct IOExclaveTimerUpcallArgs args;
175 args.timer_id = timer_id;
176 args.type = kIOExclaveTimerUpcallTypeRemove;
177
178 xnuupcalls_xnuupcalls_timer_remove__result_s result = {};
179 if (!IOExclaveTimerUpcallHandler(id, &args)) {
180 xnuupcalls_xnuupcalls_timer_remove__result_init_failure(&result,
181 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
182 } else {
183 xnuupcalls_xnuupcalls_timer_remove__result_init_success(&result);
184 }
185
186 return completion(result);
187}
188
189extern tb_error_t
190exclaves_driverkit_upcall_timer_enable(const uint64_t id, const uint32_t timer_id,
191 tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_enable__result_s))
192{
193 exclaves_debug_printf(show_iokit_upcalls,
194 "[iokit_upcalls] %s from id %llu\n", __func__, id);
195 struct IOExclaveTimerUpcallArgs args;
196 args.timer_id = timer_id;
197 args.type = kIOExclaveTimerUpcallTypeEnable;
198 args.data.enable_args.enable = true;
199
200 xnuupcalls_xnuupcalls_timer_enable__result_s result = {};
201 if (!IOExclaveTimerUpcallHandler(id, &args)) {
202 xnuupcalls_xnuupcalls_timer_enable__result_init_failure(&result,
203 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
204 } else {
205 xnuupcalls_xnuupcalls_timer_enable__result_init_success(&result);
206 }
207
208 return completion(result);
209}
210
211tb_error_t
212exclaves_driverkit_upcall_timer_disable(const uint64_t id, const uint32_t timer_id,
213 tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_disable__result_s))
214{
215 exclaves_debug_printf(show_iokit_upcalls,
216 "[iokit_upcalls] %s from id %llu\n", __func__, id);
217 struct IOExclaveTimerUpcallArgs args;
218 args.timer_id = timer_id;
219 args.type = kIOExclaveTimerUpcallTypeEnable;
220 args.data.enable_args.enable = false;
221
222 xnuupcalls_xnuupcalls_timer_disable__result_s result = {};
223 if (!IOExclaveTimerUpcallHandler(id, &args)) {
224 xnuupcalls_xnuupcalls_timer_disable__result_init_failure(&result,
225 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
226 } else {
227 xnuupcalls_xnuupcalls_timer_disable__result_init_success(&result);
228 }
229
230 return completion(result);
231}
232
233tb_error_t
234exclaves_driverkit_upcall_timer_set_timeout(const uint64_t id,
235 const uint32_t timer_id,
236 const struct xnuupcalls_drivertimerspecification_s *duration,
237 tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_set_timeout__result_s))
238{
239 exclaves_debug_printf(show_iokit_upcalls,
240 "[iokit_upcalls] %s from id %llu\n", __func__, id);
241
242 xnuupcalls_xnuupcalls_timer_set_timeout__result_s result = {};
243
244 if (!duration) {
245 exclaves_debug_printf(show_iokit_upcalls,
246 "[iokit_upcalls] %s invalid duration\n", __func__);
247 xnuupcalls_xnuupcalls_timer_set_timeout__result_init_failure(&result,
248 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
249 return completion(result);
250 }
251
252 struct IOExclaveTimerUpcallArgs args;
253 args.timer_id = timer_id;
254 args.type = kIOExclaveTimerUpcallTypeSetTimeout;
255
256 switch (duration->type) {
257 case XNUUPCALLS_DRIVERTIMERTYPE_ABSOLUTE:
258 args.data.set_timeout_args.clock_continuous = false;
259 break;
260 case XNUUPCALLS_DRIVERTIMERTYPE_CONTINUOUS:
261 args.data.set_timeout_args.clock_continuous = true;
262 break;
263 default:
264 exclaves_debug_printf(show_iokit_upcalls,
265 "[iokit_upcalls] %s unknown clock type %u\n",
266 __func__, duration->type);
267 xnuupcalls_xnuupcalls_timer_set_timeout__result_init_failure(&result,
268 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
269 return completion(result);
270 }
271
272 // Convert to abs time
273 AbsoluteTime end, nsecs;
274 clock_interval_to_absolutetime_interval(duration->tv_nsec,
275 kNanosecondScale, &nsecs);
276 clock_interval_to_absolutetime_interval(duration->tv_sec,
277 kSecondScale, &end);
278 ADD_ABSOLUTETIME(&end, &nsecs);
279 args.data.set_timeout_args.duration = end;
280
281 if (!IOExclaveTimerUpcallHandler(id, &args)) {
282 xnuupcalls_xnuupcalls_timer_set_timeout__result_init_failure(&result,
283 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
284 } else {
285 xnuupcalls_xnuupcalls_timer_set_timeout__result_init_success(&result,
286 args.data.set_timeout_args.kr == kIOReturnSuccess);
287 }
288
289 return completion(result);
290}
291
292tb_error_t
293exclaves_driverkit_upcall_timer_cancel_timeout(const uint64_t id,
294 const uint32_t timer_id,
295 tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_cancel_timeout__result_s))
296{
297 exclaves_debug_printf(show_iokit_upcalls,
298 "[iokit_upcalls] %s from id %llu\n", __func__, id);
299 struct IOExclaveTimerUpcallArgs args;
300 args.timer_id = timer_id;
301 args.type = kIOExclaveTimerUpcallTypeCancelTimeout;
302
303 xnuupcalls_xnuupcalls_timer_cancel_timeout__result_s result = {};
304 if (!IOExclaveTimerUpcallHandler(id, &args)) {
305 xnuupcalls_xnuupcalls_timer_cancel_timeout__result_init_failure(&result,
306 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
307 } else {
308 xnuupcalls_xnuupcalls_timer_cancel_timeout__result_init_success(&result);
309 }
310
311 return completion(result);
312}
313
314tb_error_t
315exclaves_driverkit_upcall_lock_wl(const uint64_t id,
316 tb_error_t (^completion)(xnuupcalls_xnuupcalls_lock_wl__result_s))
317{
318 exclaves_debug_printf(show_iokit_upcalls,
319 "[iokit_upcalls] lock_wl from id %llu\n", id);
320
321 xnuupcalls_xnuupcalls_lock_wl__result_s result = {};
322 if (!IOExclaveLockWorkloop(id, true)) {
323 xnuupcalls_xnuupcalls_lock_wl__result_init_failure(&result,
324 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
325 } else {
326 xnuupcalls_xnuupcalls_lock_wl__result_init_success(&result);
327 }
328
329 return completion(result);
330}
331
332tb_error_t
333exclaves_driverkit_upcall_unlock_wl(const uint64_t id,
334 tb_error_t (^completion)(xnuupcalls_xnuupcalls_unlock_wl__result_s))
335{
336 exclaves_debug_printf(show_iokit_upcalls,
337 "[iokit_upcalls] unlock_wl from id %llu\n", id);
338
339 xnuupcalls_xnuupcalls_unlock_wl__result_s result = {};
340 if (!IOExclaveLockWorkloop(id, false)) {
341 xnuupcalls_xnuupcalls_unlock_wl__result_init_failure(&result,
342 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
343 } else {
344 xnuupcalls_xnuupcalls_unlock_wl__result_init_success(&result);
345 }
346
347 return completion(result);
348}
349
350extern tb_error_t
351exclaves_driverkit_upcall_async_notification_signal(const uint64_t id,
352 const uint32_t notificationID,
353 tb_error_t (^completion)(xnuupcalls_xnuupcalls_async_notification_signal__result_s))
354{
355 exclaves_debug_printf(show_iokit_upcalls,
356 "[iokit_upcalls] async_notification_signal from id %llu\n", id);
357 struct IOExclaveAsyncNotificationUpcallArgs args;
358 args.type = AsyncNotificationUpcallTypeSignal;
359 args.notificationID = notificationID;
360
361 xnuupcalls_xnuupcalls_async_notification_signal__result_s result = {};
362 if (!IOExclaveAsyncNotificationUpcallHandler(id, &args)) {
363 xnuupcalls_xnuupcalls_async_notification_signal__result_init_failure(&result,
364 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
365 } else {
366 xnuupcalls_xnuupcalls_async_notification_signal__result_init_success(&result);
367 }
368
369 return completion(result);
370}
371
372tb_error_t
373exclaves_driverkit_upcall_mapper_activate(const uint64_t id,
374 const uint32_t mapperIndex,
375 tb_error_t (^completion)(xnuupcalls_xnuupcalls_mapper_activate__result_s))
376{
377 exclaves_debug_printf(show_iokit_upcalls,
378 "[iokit_upcalls] mapper_activate from id %llu\n", id);
379 struct IOExclaveMapperOperationUpcallArgs args;
380 args.type = MapperActivate;
381 args.mapperIndex = mapperIndex;
382
383 xnuupcalls_xnuupcalls_mapper_activate__result_s result = {};
384 if (!IOExclaveMapperOperationUpcallHandler(id, &args)) {
385 xnuupcalls_xnuupcalls_mapper_activate__result_init_failure(&result,
386 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
387 } else {
388 xnuupcalls_xnuupcalls_mapper_activate__result_init_success(&result);
389 }
390
391 return completion(result);
392}
393
394tb_error_t
395exclaves_driverkit_upcall_mapper_deactivate(const uint64_t id,
396 const uint32_t mapperIndex,
397 tb_error_t (^completion)(xnuupcalls_xnuupcalls_mapper_deactivate__result_s))
398{
399 exclaves_debug_printf(show_iokit_upcalls,
400 "[iokit_upcalls] mapper_deactivate from id %llu\n", id);
401 struct IOExclaveMapperOperationUpcallArgs args;
402 args.type = MapperDeactivate;
403 args.mapperIndex = mapperIndex;
404
405 xnuupcalls_xnuupcalls_mapper_deactivate__result_s result = {};
406 if (!IOExclaveMapperOperationUpcallHandler(id, &args)) {
407 xnuupcalls_xnuupcalls_mapper_deactivate__result_init_failure(&result,
408 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
409 } else {
410 xnuupcalls_xnuupcalls_mapper_deactivate__result_init_success(&result);
411 }
412
413 return completion(result);
414}
415
416extern tb_error_t
417exclaves_driverkit_upcall_ane_setpowerstate(const uint64_t id,
418 const uint32_t desiredState,
419 tb_error_t (^completion)(xnuupcalls_xnuupcalls_ane_setpowerstate__result_s))
420{
421 exclaves_debug_printf(show_iokit_upcalls,
422 "[iokit_upcalls] ane_setpowerstate from id %llu\n", id);
423 struct IOExclaveANEUpcallArgs args;
424 bool ret = false;
425 args.type = kIOExclaveANEUpcallTypeSetPowerState;
426 args.setpowerstate_args.desired_state = desiredState;
427
428 xnuupcalls_xnuupcalls_ane_setpowerstate__result_s result = {};
429 if (!IOExclaveANEUpcallHandler(id, &args, &ret)) {
430 xnuupcalls_xnuupcalls_ane_setpowerstate__result_init_failure(&result,
431 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
432 } else {
433 xnuupcalls_xnuupcalls_ane_setpowerstate__result_init_success(&result,
434 ret);
435 }
436 return completion(result);
437}
438
439tb_error_t
440exclaves_driverkit_upcall_ane_worksubmit(const uint64_t id, const uint64_t requestID,
441 const uint32_t taskDescriptorCount, const uint64_t submitTimestamp,
442 tb_error_t (^completion)(xnuupcalls_xnuupcalls_ane_worksubmit__result_s))
443{
444 exclaves_debug_printf(show_iokit_upcalls,
445 "[iokit_upcalls] ane_worksubmit from id %llu\n", id);
446 struct IOExclaveANEUpcallArgs args;
447 bool ret = false;
448 args.type = kIOExclaveANEUpcallTypeWorkSubmit;
449 args.work_args.arg0 = requestID;
450 args.work_args.arg1 = taskDescriptorCount;
451 args.work_args.arg2 = submitTimestamp;
452
453 xnuupcalls_xnuupcalls_ane_worksubmit__result_s result = {};
454 if (!IOExclaveANEUpcallHandler(id, &args, &ret)) {
455 xnuupcalls_xnuupcalls_ane_worksubmit__result_init_failure(&result,
456 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
457 } else {
458 xnuupcalls_xnuupcalls_ane_worksubmit__result_init_success(&result,
459 ret);
460 }
461 return completion(result);
462}
463
464tb_error_t
465exclaves_driverkit_upcall_ane_workbegin(const uint64_t id, const uint64_t requestID,
466 const uint64_t beginTimestamp,
467 tb_error_t (^completion)(xnuupcalls_xnuupcalls_ane_workbegin__result_s))
468{
469 exclaves_debug_printf(show_iokit_upcalls,
470 "[iokit_upcalls] ane_workbegin from id %llu\n", id);
471 struct IOExclaveANEUpcallArgs args;
472 bool ret = false;
473 args.type = kIOExclaveANEUpcallTypeWorkBegin;
474 args.work_args.arg0 = requestID;
475 args.work_args.arg1 = beginTimestamp;
476 args.work_args.arg2 = 0;
477
478 xnuupcalls_xnuupcalls_ane_workbegin__result_s result = {};
479 if (!IOExclaveANEUpcallHandler(id, &args, &ret)) {
480 xnuupcalls_xnuupcalls_ane_workbegin__result_init_failure(&result,
481 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
482 } else {
483 xnuupcalls_xnuupcalls_ane_workbegin__result_init_success(&result,
484 ret);
485 }
486 return completion(result);
487}
488
489tb_error_t
490exclaves_driverkit_upcall_ane_workend(const uint64_t id, const uint64_t requestID,
491 tb_error_t (^completion)(xnuupcalls_xnuupcalls_ane_workend__result_s))
492{
493 exclaves_debug_printf(show_iokit_upcalls,
494 "[iokit_upcalls] ane_workend from id %llu\n", id);
495 struct IOExclaveANEUpcallArgs args;
496 bool ret = false;
497 args.type = kIOExclaveANEUpcallTypeWorkEnd;
498 args.work_args.arg0 = requestID;
499 args.work_args.arg1 = 0;
500 args.work_args.arg2 = 0;
501
502 xnuupcalls_xnuupcalls_ane_workend__result_s result = {};
503 if (!IOExclaveANEUpcallHandler(id, &args, &ret)) {
504 xnuupcalls_xnuupcalls_ane_workend__result_init_failure(&result,
505 XNUUPCALLS_DRIVERUPCALLERROR_FAILURE);
506 } else {
507 xnuupcalls_xnuupcalls_ane_workend__result_init_success(&result,
508 ret);
509 }
510 return completion(result);
511}
512
513tb_error_t
514exclaves_driverkit_upcall_notification_signal(const uint64_t id,
515 const uint32_t mask,
516 tb_error_t (^completion)(xnuupcalls_xnuupcalls_notification_signal__result_s))
517{
518 exclaves_debug_printf(show_notification_upcalls,
519 "[notification_upcalls] notification_signal "
520 "id %llx mask %x\n", id, mask);
521 exclaves_resource_t *notification_resource =
522 exclaves_notification_lookup_by_id(EXCLAVES_DOMAIN_KERNEL, id);
523
524 xnuupcalls_xnuupcalls_notification_signal__result_s result = {};
525
526 if (notification_resource != NULL) {
527 exclaves_debug_printf(show_notification_upcalls,
528 "[notification_upcalls] notification_signal "
529 "id %llx mask %x -> found resource\n", id, mask);
530 exclaves_notification_signal(notification_resource, mask);
531 xnuupcalls_xnuupcalls_notification_signal__result_init_success(&result);
532 } else {
533 exclaves_debug_printf(show_notification_upcalls,
534 "[notification_upcalls] notification_signal "
535 "id %llx mask %x -> no notification resource found\n",
536 id, mask);
537 xnuupcalls_xnuupcalls_notification_signal__result_init_failure(&result,
538 XNUUPCALLS_NOTIFICATIONERROR_NOTFOUND);
539 }
540
541 return completion(result);
542}
543
544/* -------------------------------------------------------------------------- */
545#pragma mark Tests
546
547#if DEVELOPMENT || DEBUG
548
549#define EXCLAVES_HELLO_DRIVER_INTERRUPTS_INDEX 0
550#define EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(test) if (test) { break; }
551
552#define EXCLAVES_ID_HELLO_INTERRUPTS_EP \
553 (exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, \
554 "com.apple.service.HelloDriverInterrupts"))
555
556typedef enum hello_driverkit_interrupts_test_type {
557 TEST_IRQ_REGISTER,
558 TEST_IRQ_REMOVE,
559 TEST_IRQ_ENABLE,
560 TEST_IRQ_CHECK,
561 TEST_IRQ_DISABLE,
562 TEST_TIMER_REGISTER,
563 TEST_TIMER_REMOVE,
564 TEST_TIMER_ENABLE,
565 TEST_TIMER_DISABLE,
566 TEST_TIMER_SETTIMEOUT,
567 TEST_TIMER_CHECK,
568 TEST_TIMER_CANCELTIMEOUT,
569 TEST_MULTI_TIMER_SETUP,
570 TEST_MULTI_TIMER_CLEANUP,
571 HELLO_DRIVER_INTERRUPTS_NUM_TESTS
572} hello_driverkit_interrupts_test_type_t;
573static const char *hello_driverkit_interrupts_test_string[] = {
574 "IRQ_REGISTER",
575 "IRQ_REMOVE",
576 "IRQ_ENABLE",
577 "IRQ_CHECK",
578 "IRQ_DISABLE",
579 "TIMER_REGISTER",
580 "TIMER_REMOVE",
581 "TIMER_ENABLE",
582 "TIMER_DISABLE",
583 "TIMER_SETTIMEOUT",
584 "TIMER_CHECK",
585 "TIMER_CANCELTIMEOUT",
586 "MULTI_TIMER_SETUP",
587 "MULTI_TIMER_CLEANUP"
588};
589
590static int
591hello_driverkit_interrupts(hello_driverkit_interrupts_test_type_t test_type)
592{
593 exclaves_debug_printf(show_test_output, "****** START: %s ******\n",
594 hello_driverkit_interrupts_test_string[test_type]);
595
596 int err = 0;
597 assert(test_type < HELLO_DRIVER_INTERRUPTS_NUM_TESTS);
598
599 tb_endpoint_t ep = tb_endpoint_create_with_value(
600 TB_TRANSPORT_TYPE_XNU, EXCLAVES_ID_HELLO_INTERRUPTS_EP, 0);
601
602 tb_client_connection_t client =
603 tb_client_connection_create_with_endpoint(ep);
604
605 tb_client_connection_activate(client);
606
607 tb_message_t message = NULL;
608 tb_transport_message_buffer_t tpt_buf = NULL;
609
610 message = kalloc_type(struct tb_message_s, Z_WAITOK | Z_ZERO | Z_NOFAIL);
611 tpt_buf = kalloc_type(struct tb_transport_message_buffer_s,
612 Z_WAITOK | Z_ZERO | Z_NOFAIL);
613
614 // Encode TB buffer with test_type
615 tb_error_t tb_err = TB_ERROR_SUCCESS;
616 tb_err = tb_client_connection_message_construct(client, message,
617 tpt_buf, sizeof(uint8_t), 0);
618 if (tb_err != TB_ERROR_SUCCESS) {
619 err = 1;
620 goto out;
621 }
622 exclaves_debug_printf(show_test_output, "%s: Tightbeam constructing message: %u\n", __func__,
623 (uint8_t) test_type);
624 tb_message_encode_u8(message, (uint8_t) test_type);
625
626 tb_message_complete(message);
627 exclaves_debug_printf(show_test_output, "%s: Tightbeam message completed\n", __func__);
628
629 tb_message_t response = NULL;
630
631 // Perform downcall
632 tb_err = tb_connection_send_query(client, message, &response,
633 TB_CONNECTION_WAIT_FOR_REPLY);
634 if (tb_err != TB_ERROR_SUCCESS) {
635 err = 2;
636 goto out;
637 }
638 exclaves_debug_printf(show_test_output, "%s: Tightbeam message send success, reply: ", __func__);
639
640 // Decode downcall reply
641 uint8_t reply = 0;
642 tb_message_decode_u8(response, &reply);
643 exclaves_debug_printf(show_test_output, "%u\n", reply);
644
645 if (reply != 0) {
646 err = 3;
647 goto out;
648 }
649 tb_client_connection_message_destruct(client, message);
650
651out:
652 if (err == 0) {
653 exclaves_debug_printf(show_test_output, "****** SUCCESS: %s ******\n",
654 hello_driverkit_interrupts_test_string[test_type]);
655 } else {
656 exclaves_debug_printf(show_test_output, "****** FAILURE: %s (%d) ******\n",
657 hello_driverkit_interrupts_test_string[test_type], err);
658 }
659
660 kfree_type(struct tb_message_s, message);
661 kfree_type(struct tb_transport_message_buffer_s, tpt_buf);
662
663 return err;
664}
665
666
667static int
668exclaves_hello_driverkit_interrupts(uint64_t registryID, int64_t *out)
669{
670 if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) {
671 exclaves_debug_printf(show_test_output,
672 "%s: SKIPPED: Exclaves not available\n", __func__);
673 *out = -1;
674 return 0;
675 }
676
677 bool success = false;
678 exclaves_debug_printf(show_test_output, "%s: STARTING\n", __func__);
679
680 // Interrupts
681 struct IOExclaveTestSignalInterruptParam *signal_param = kalloc_type(
682 struct IOExclaveTestSignalInterruptParam, Z_WAITOK | Z_ZERO | Z_NOFAIL);
683 thread_call_t signal_thread = thread_call_allocate(
684 (thread_call_func_t) &IOExclaveTestSignalInterrupt, signal_param);
685
686 do {
687 /* Interrupt tests */
688
689 // Set AppleExclaveExampleKext registryID as service under test
690 exclaves_hello_driverkit_interrupts_service_id = registryID;
691 signal_param->id = registryID;
692 signal_param->index = EXCLAVES_HELLO_DRIVER_INTERRUPTS_INDEX;
693
694 exclaves_debug_printf(show_test_output,
695 "%s: SKIPPING INTERRUPT TESTS (rdar://107842497)\n", __func__);
696
697 /* Timer tests */
698
699 exclaves_debug_printf(show_test_output,
700 "%s: TIMER TESTS\n", __func__);
701 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
702 hello_driverkit_interrupts(TEST_TIMER_REGISTER))
703 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
704 hello_driverkit_interrupts(TEST_TIMER_ENABLE))
705 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
706 hello_driverkit_interrupts(TEST_TIMER_SETTIMEOUT))
707 // Wait for timer to fire
708 delay_for_interval(2000, 1000 * 1000 /* kMilliSecondScale */);
709 // Check timer was recieved by exclave
710 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
711 hello_driverkit_interrupts(TEST_TIMER_CHECK))
712 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
713 hello_driverkit_interrupts(TEST_TIMER_DISABLE))
714 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
715 hello_driverkit_interrupts(TEST_TIMER_REMOVE))
716
717 success = true;
718 } while (false);
719
720 // Cleanup
721 exclaves_hello_driverkit_interrupts_service_id = -1ull;
722 thread_call_free(signal_thread);
723 signal_thread = NULL;
724 kfree_type(struct IOExclaveTestSignalInterruptParam, signal_param);
725
726 if (success) {
727 exclaves_debug_printf(show_test_output, "%s: SUCCESS\n", __func__);
728 *out = 1;
729 } else {
730 exclaves_debug_printf(show_errors, "%s: FAILED\n", __func__);
731 *out = 0;
732 }
733 return 0;
734}
735
736static int
737exclaves_hello_driverkit_interrupts_test(int64_t in, int64_t *out)
738{
739 // in should be AppleExclaveExampleKext's registry ID
740 return exclaves_hello_driverkit_interrupts((uint64_t)in, out);
741}
742
743
744SYSCTL_TEST_REGISTER(exclaves_hello_driver_interrupts_test,
745 exclaves_hello_driverkit_interrupts_test);
746
747
748static int
749exclaves_hello_driverkit_multi_timers(int64_t *out)
750{
751 if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) {
752 exclaves_debug_printf(show_test_output,
753 "%s: SKIPPED: Exclaves not available\n", __func__);
754 *out = -1;
755 return 0;
756 }
757
758 bool success = false;
759 exclaves_debug_printf(show_test_output, "%s: STARTING\n", __func__);
760
761 do {
762 exclaves_debug_printf(show_test_output,
763 "%s: TIMER TESTS\n", __func__);
764 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
765 hello_driverkit_interrupts(TEST_MULTI_TIMER_SETUP))
766 // Multiple timers are setup with the same timeout
767 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
768 hello_driverkit_interrupts(TEST_TIMER_SETTIMEOUT))
769 // Wait for timers to fire
770 delay_for_interval(2000, 1000 * 1000 /* kMilliSecondScale */);
771 // Check if all timer interrupts were recieved by exclave
772 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
773 hello_driverkit_interrupts(TEST_TIMER_CHECK))
774 EXCLAVES_HELLO_DRIVER_INTERRUPTS_CHECK_RET(
775 hello_driverkit_interrupts(TEST_MULTI_TIMER_CLEANUP))
776
777 success = true;
778 } while (false);
779
780 if (success) {
781 exclaves_debug_printf(show_test_output, "%s: SUCCESS\n", __func__);
782 *out = 1;
783 } else {
784 exclaves_debug_printf(show_errors, "%s: FAILED\n", __func__);
785 *out = 0;
786 }
787 return 0;
788}
789
790
791static int
792exclaves_hello_driverkit_multi_timers_test(__unused int64_t in, int64_t *out)
793{
794 return exclaves_hello_driverkit_multi_timers(out);
795}
796
797
798SYSCTL_TEST_REGISTER(exclaves_hello_driver_multi_timers_test,
799 exclaves_hello_driverkit_multi_timers_test);
800
801#endif /* DEVELOPMENT || DEBUG */
802
803#endif /* __has_include(<Tightbeam/tightbeam.h>) */
804
805#endif /* CONFIG_EXCLAVES */
806