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 */ |
51 | static uint64_t exclaves_hello_driverkit_interrupts_service_id = -1ull; |
52 | |
53 | |
54 | /* -------------------------------------------------------------------------- */ |
55 | #pragma mark Upcalls |
56 | |
57 | tb_error_t |
58 | exclaves_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 | |
81 | tb_error_t |
82 | exclaves_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 | |
103 | tb_error_t |
104 | exclaves_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 | |
125 | tb_error_t |
126 | exclaves_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 | |
147 | tb_error_t |
148 | exclaves_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 | |
168 | tb_error_t |
169 | exclaves_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 | |
189 | extern tb_error_t |
190 | exclaves_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 | |
211 | tb_error_t |
212 | exclaves_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 | |
233 | tb_error_t |
234 | exclaves_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 | |
292 | tb_error_t |
293 | exclaves_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 | |
314 | tb_error_t |
315 | exclaves_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 | |
332 | tb_error_t |
333 | exclaves_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 | |
350 | extern tb_error_t |
351 | exclaves_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 | |
372 | tb_error_t |
373 | exclaves_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 | |
394 | tb_error_t |
395 | exclaves_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 | |
416 | extern tb_error_t |
417 | exclaves_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 | |
439 | tb_error_t |
440 | exclaves_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 | |
464 | tb_error_t |
465 | exclaves_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 | |
489 | tb_error_t |
490 | exclaves_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 | |
513 | tb_error_t |
514 | exclaves_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 | |
556 | typedef 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; |
573 | static 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 | |
590 | static int |
591 | hello_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 | |
651 | out: |
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 | |
667 | static int |
668 | exclaves_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 | |
736 | static int |
737 | exclaves_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 | |
744 | SYSCTL_TEST_REGISTER(exclaves_hello_driver_interrupts_test, |
745 | exclaves_hello_driverkit_interrupts_test); |
746 | |
747 | |
748 | static int |
749 | exclaves_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 | |
791 | static int |
792 | exclaves_hello_driverkit_multi_timers_test(__unused int64_t in, int64_t *out) |
793 | { |
794 | return exclaves_hello_driverkit_multi_timers(out); |
795 | } |
796 | |
797 | |
798 | SYSCTL_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 | |