| 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 | #include <mach/exclaves.h> |
| 30 | #include "exclaves_upcalls.h" |
| 31 | |
| 32 | #if CONFIG_EXCLAVES |
| 33 | |
| 34 | #if __has_include(<Tightbeam/tightbeam.h>) |
| 35 | |
| 36 | #include <mach/exclaves_l4.h> |
| 37 | |
| 38 | #include <stdint.h> |
| 39 | |
| 40 | #include <Tightbeam/tightbeam.h> |
| 41 | #include <Tightbeam/tightbeam_private.h> |
| 42 | |
| 43 | #include <kern/kalloc.h> |
| 44 | #include <kern/locks.h> |
| 45 | #include <kern/task.h> |
| 46 | |
| 47 | #include <xnuproxy/exclaves.h> |
| 48 | |
| 49 | #include "kern/exclaves.tightbeam.h" |
| 50 | |
| 51 | #include "exclaves_boot.h" |
| 52 | #include "exclaves_debug.h" |
| 53 | #include "exclaves_driverkit.h" |
| 54 | #include "exclaves_storage.h" |
| 55 | #include "exclaves_test_stackshot.h" |
| 56 | #include "exclaves_conclave.h" |
| 57 | #include "exclaves_memory.h" |
| 58 | |
| 59 | #include <sys/errno.h> |
| 60 | |
| 61 | #define EXCLAVES_ID_HELLO_EXCLAVE_EP \ |
| 62 | (exclaves_service_lookup(EXCLAVES_DOMAIN_KERNEL, \ |
| 63 | "com.apple.service.HelloExclave")) |
| 64 | |
| 65 | #define EXCLAVES_ID_TIGHTBEAM_UPCALL \ |
| 66 | ((exclaves_id_t)XNUPROXY_UPCALL_TIGHTBEAM) |
| 67 | |
| 68 | extern lck_mtx_t exclaves_boot_lock; |
| 69 | |
| 70 | typedef struct exclaves_upcall_handler_registration { |
| 71 | exclaves_upcall_handler_t handler; |
| 72 | void *context; |
| 73 | } exclaves_upcall_handler_registration_t; |
| 74 | |
| 75 | static exclaves_upcall_handler_registration_t |
| 76 | exclaves_upcall_handlers[NUM_XNUPROXY_UPCALLS]; |
| 77 | |
| 78 | #if DEVELOPMENT || DEBUG |
| 79 | static kern_return_t |
| 80 | exclaves_test_hello_upcall_handler(void *, exclaves_tag_t *, exclaves_badge_t); |
| 81 | #endif /* DEVELOPMENT || DEBUG */ |
| 82 | |
| 83 | extern kern_return_t exclaves_xnu_proxy_send(xnuproxy_msg_t *, |
| 84 | Exclaves_L4_Word_t *); |
| 85 | |
| 86 | /* -------------------------------------------------------------------------- */ |
| 87 | #pragma mark Upcall Callouts |
| 88 | |
| 89 | static tb_error_t |
| 90 | exclaves_helloupcall(const uint64_t arg, tb_error_t (^completion)(uint64_t)); |
| 91 | |
| 92 | /* |
| 93 | * Tightbeam upcall callout table. |
| 94 | * Don't add inline functionality here, instead call directly into your |
| 95 | * sub-system. |
| 96 | */ |
| 97 | |
| 98 | static const xnuupcalls_xnuupcalls__server_s exclaves_tightbeam_upcalls = { |
| 99 | /* BEGIN IGNORE CODESTYLE */ |
| 100 | /* Uncrustify doesn't deal well with Blocks. */ |
| 101 | .helloupcall = ^(const uint64_t arg, tb_error_t (^completion)(uint64_t)) { |
| 102 | return exclaves_helloupcall(arg, completion); |
| 103 | }, |
| 104 | |
| 105 | .alloc = ^(const uint32_t npages, xnuupcalls_pagekind_s kind, |
| 106 | tb_error_t (^completion)(xnuupcalls_pagelist_s)) { |
| 107 | return exclaves_memory_upcall_alloc(npages, kind, completion); |
| 108 | }, |
| 109 | |
| 110 | .free = ^(const uint32_t pages[_Nonnull EXCLAVES_MEMORY_MAX_REQUEST], |
| 111 | const uint32_t npages, const xnuupcalls_pagekind_s kind, |
| 112 | tb_error_t (^completion)(void)) { |
| 113 | return exclaves_memory_upcall_free(pages, npages, kind, completion); |
| 114 | }, |
| 115 | |
| 116 | .root = ^(const uint8_t exclaveid[_Nonnull 32], |
| 117 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_root__result_s)) { |
| 118 | return exclaves_storage_upcall_root(exclaveid, completion); |
| 119 | }, |
| 120 | |
| 121 | .open = ^(const enum xnuupcalls_fstag_s fstag, const uint64_t rootid, |
| 122 | const uint8_t name[_Nonnull 256], |
| 123 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_open__result_s)) { |
| 124 | return exclaves_storage_upcall_open(fstag, rootid, name, completion); |
| 125 | }, |
| 126 | |
| 127 | .close = ^(const enum xnuupcalls_fstag_s fstag, const uint64_t fileid, |
| 128 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_close__result_s)) { |
| 129 | return exclaves_storage_upcall_close(fstag, fileid, completion); |
| 130 | }, |
| 131 | |
| 132 | .create = ^(const enum xnuupcalls_fstag_s fstag, const uint64_t rootid, |
| 133 | const uint8_t name[_Nonnull 256], |
| 134 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_create__result_s)) { |
| 135 | return exclaves_storage_upcall_create(fstag, rootid, name, completion); |
| 136 | }, |
| 137 | |
| 138 | .read = ^(const enum xnuupcalls_fstag_s fstag, const uint64_t fileid, |
| 139 | const struct xnuupcalls_iodesc_s *descriptor, |
| 140 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_read__result_s)) { |
| 141 | return exclaves_storage_upcall_read(fstag, fileid, descriptor, completion); |
| 142 | }, |
| 143 | |
| 144 | .write = ^(const enum xnuupcalls_fstag_s fstag, const uint64_t fileid, |
| 145 | const struct xnuupcalls_iodesc_s *descriptor, |
| 146 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_write__result_s)) { |
| 147 | return exclaves_storage_upcall_write(fstag, fileid, descriptor, completion); |
| 148 | }, |
| 149 | |
| 150 | .remove = ^(const enum xnuupcalls_fstag_s fstag, const uint64_t rootid, |
| 151 | const uint8_t name[_Nonnull 256], |
| 152 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_remove__result_s)) { |
| 153 | return exclaves_storage_upcall_remove(fstag, rootid, name, completion); |
| 154 | }, |
| 155 | |
| 156 | .sync = ^(const enum xnuupcalls_fstag_s fstag, |
| 157 | const enum xnuupcalls_syncop_s op, |
| 158 | const uint64_t fileid, |
| 159 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_sync__result_s)) { |
| 160 | return exclaves_storage_upcall_sync(fstag, op, fileid, completion); |
| 161 | }, |
| 162 | |
| 163 | .readdir = ^(const enum xnuupcalls_fstag_s fstag, |
| 164 | const uint64_t fileid, const uint64_t buf, |
| 165 | const uint32_t length, |
| 166 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_readdir__result_s)) { |
| 167 | return exclaves_storage_upcall_readdir(fstag, fileid, buf, length, completion); |
| 168 | }, |
| 169 | |
| 170 | .getsize = ^(const enum xnuupcalls_fstag_s fstag, const uint64_t fileid, |
| 171 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_getsize__result_s)) { |
| 172 | return exclaves_storage_upcall_getsize(fstag, fileid, completion); |
| 173 | }, |
| 174 | |
| 175 | .sealstate = ^(const enum xnuupcalls_fstag_s fstag, |
| 176 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_sealstate__result_s)) { |
| 177 | return exclaves_storage_upcall_sealstate(fstag, completion); |
| 178 | }, |
| 179 | |
| 180 | .irq_register = ^(const uint64_t id, const int32_t index, |
| 181 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_irq_register__result_s)) { |
| 182 | return exclaves_driverkit_upcall_irq_register(id, index, completion); |
| 183 | }, |
| 184 | |
| 185 | .irq_remove = ^(const uint64_t id, const int32_t index, |
| 186 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_irq_remove__result_s)) { |
| 187 | return exclaves_driverkit_upcall_irq_remove(id, index, completion); |
| 188 | }, |
| 189 | |
| 190 | .irq_enable = ^(const uint64_t id, const int32_t index, |
| 191 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_irq_enable__result_s)) { |
| 192 | return exclaves_driverkit_upcall_irq_enable(id, index, completion); |
| 193 | }, |
| 194 | |
| 195 | .irq_disable = ^(const uint64_t id, const int32_t index, |
| 196 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_irq_disable__result_s)) { |
| 197 | return exclaves_driverkit_upcall_irq_disable(id, index, completion); |
| 198 | }, |
| 199 | |
| 200 | .timer_register = ^(const uint64_t id, |
| 201 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_register__result_s)) { |
| 202 | return exclaves_driverkit_upcall_timer_register(id, completion); |
| 203 | }, |
| 204 | |
| 205 | .timer_remove = ^(const uint64_t id, const uint32_t timer_id, |
| 206 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_remove__result_s)) { |
| 207 | return exclaves_driverkit_upcall_timer_remove(id, timer_id, completion); |
| 208 | }, |
| 209 | |
| 210 | .timer_enable = ^(const uint64_t id, const uint32_t timer_id, |
| 211 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_enable__result_s)) { |
| 212 | return exclaves_driverkit_upcall_timer_enable(id, timer_id, completion); |
| 213 | }, |
| 214 | |
| 215 | .timer_disable = ^(const uint64_t id, const uint32_t timer_id, |
| 216 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_disable__result_s)) { |
| 217 | return exclaves_driverkit_upcall_timer_disable(id, timer_id, completion); |
| 218 | }, |
| 219 | |
| 220 | .timer_set_timeout = ^(const uint64_t id, const uint32_t timer_id, |
| 221 | const struct xnuupcalls_drivertimerspecification_s *duration, |
| 222 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_set_timeout__result_s)) { |
| 223 | return exclaves_driverkit_upcall_timer_set_timeout(id, timer_id, duration, completion); |
| 224 | }, |
| 225 | |
| 226 | .timer_cancel_timeout = ^(const uint64_t id, const uint32_t timer_id, |
| 227 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_timer_cancel_timeout__result_s)) { |
| 228 | return exclaves_driverkit_upcall_timer_cancel_timeout(id, timer_id, completion); |
| 229 | }, |
| 230 | |
| 231 | .lock_wl = ^(const uint64_t id, |
| 232 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_lock_wl__result_s)) { |
| 233 | return exclaves_driverkit_upcall_lock_wl(id, completion); |
| 234 | }, |
| 235 | |
| 236 | .unlock_wl = ^(const uint64_t id, |
| 237 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_unlock_wl__result_s)) { |
| 238 | return exclaves_driverkit_upcall_unlock_wl(id, completion); |
| 239 | }, |
| 240 | |
| 241 | .async_notification_signal = ^(const uint64_t id, |
| 242 | const uint32_t notificationID, |
| 243 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_async_notification_signal__result_s)) { |
| 244 | return exclaves_driverkit_upcall_async_notification_signal(id, |
| 245 | notificationID, completion); |
| 246 | }, |
| 247 | |
| 248 | .mapper_activate = ^(const uint64_t id, const uint32_t mapperIndex, |
| 249 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_mapper_activate__result_s)) { |
| 250 | return exclaves_driverkit_upcall_mapper_activate(id, |
| 251 | mapperIndex, completion); |
| 252 | }, |
| 253 | |
| 254 | .mapper_deactivate = ^(const uint64_t id, const uint32_t mapperIndex, |
| 255 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_mapper_deactivate__result_s)) { |
| 256 | return exclaves_driverkit_upcall_mapper_deactivate(id, |
| 257 | mapperIndex, completion); |
| 258 | }, |
| 259 | |
| 260 | .notification_signal = ^(const uint64_t id, const uint32_t mask, |
| 261 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_notification_signal__result_s)) { |
| 262 | return exclaves_driverkit_upcall_notification_signal(id, mask, |
| 263 | completion); |
| 264 | }, |
| 265 | |
| 266 | .ane_setpowerstate = ^(const uint64_t id, const uint32_t desiredState, |
| 267 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_ane_setpowerstate__result_s)) { |
| 268 | return exclaves_driverkit_upcall_ane_setpowerstate(id, desiredState, |
| 269 | completion); |
| 270 | }, |
| 271 | |
| 272 | .ane_worksubmit = ^(const uint64_t id, const uint64_t requestID, |
| 273 | const uint32_t taskDescriptorCount, const uint64_t submitTimestamp, |
| 274 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_ane_worksubmit__result_s)) { |
| 275 | return exclaves_driverkit_upcall_ane_worksubmit(id, requestID, |
| 276 | taskDescriptorCount, submitTimestamp, completion); |
| 277 | }, |
| 278 | |
| 279 | .ane_workbegin = ^(const uint64_t id, const uint64_t requestID, |
| 280 | const uint64_t beginTimestamp, |
| 281 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_ane_workbegin__result_s)) { |
| 282 | return exclaves_driverkit_upcall_ane_workbegin(id, requestID, |
| 283 | beginTimestamp, completion); |
| 284 | }, |
| 285 | |
| 286 | .ane_workend = ^(const uint64_t id, const uint64_t requestID, |
| 287 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_ane_workend__result_s)) { |
| 288 | return exclaves_driverkit_upcall_ane_workend(id, requestID, completion); |
| 289 | }, |
| 290 | |
| 291 | .conclave_suspend = ^(const uint32_t flags, |
| 292 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_conclave_suspend__result_s)) { |
| 293 | return exclaves_conclave_upcall_suspend(flags, completion); |
| 294 | }, |
| 295 | |
| 296 | .conclave_stop = ^(const uint32_t flags, |
| 297 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_conclave_stop__result_s)) { |
| 298 | return exclaves_conclave_upcall_stop(flags, completion); |
| 299 | }, |
| 300 | .conclave_crash_info = ^(const xnuupcalls_conclavesharedbuffer_s *shared_buf, |
| 301 | const uint32_t length, |
| 302 | tb_error_t (^completion)(xnuupcalls_xnuupcalls_conclave_crash_info__result_s)) { |
| 303 | return exclaves_conclave_upcall_crash_info(shared_buf, length, completion); |
| 304 | }, |
| 305 | /* END IGNORE CODESTYLE */ |
| 306 | }; |
| 307 | |
| 308 | kern_return_t |
| 309 | exclaves_register_upcall_handler(exclaves_id_t upcall_id, void *upcall_context, |
| 310 | exclaves_upcall_handler_t upcall_handler) |
| 311 | { |
| 312 | assert3u(upcall_id, <, NUM_XNUPROXY_UPCALLS); |
| 313 | assert(upcall_handler != NULL); |
| 314 | |
| 315 | lck_mtx_assert(&exclaves_boot_lock, LCK_MTX_ASSERT_OWNED); |
| 316 | assert(exclaves_upcall_handlers[upcall_id].handler == NULL); |
| 317 | |
| 318 | exclaves_upcall_handlers[upcall_id] = |
| 319 | (exclaves_upcall_handler_registration_t){ |
| 320 | .handler = upcall_handler, |
| 321 | .context = upcall_context, |
| 322 | }; |
| 323 | |
| 324 | return KERN_SUCCESS; |
| 325 | } |
| 326 | |
| 327 | kern_return_t |
| 328 | exclaves_upcall_early_init(void) |
| 329 | { |
| 330 | lck_mtx_assert(&exclaves_boot_lock, LCK_MTX_ASSERT_OWNED); |
| 331 | |
| 332 | #if DEVELOPMENT || DEBUG |
| 333 | kern_return_t kr; |
| 334 | kr = exclaves_register_upcall_handler( |
| 335 | XNUPROXY_UPCALL_HELLOUPCALL, NULL, |
| 336 | exclaves_test_hello_upcall_handler); |
| 337 | assert3u(kr, ==, KERN_SUCCESS); |
| 338 | #endif /* DEVELOPMENT || DEBUG */ |
| 339 | |
| 340 | tb_endpoint_t tb_upcall_ep = tb_endpoint_create_with_value( |
| 341 | TB_TRANSPORT_TYPE_XNU, EXCLAVES_ID_TIGHTBEAM_UPCALL, |
| 342 | TB_ENDPOINT_OPTIONS_NONE); |
| 343 | #pragma clang diagnostic push |
| 344 | #pragma clang diagnostic ignored "-Wcast-qual" /* FIXME: rdar://103647654 */ |
| 345 | tb_error_t error = xnuupcalls_xnuupcalls__server_start(tb_upcall_ep, |
| 346 | (xnuupcalls_xnuupcalls__server_s *)&exclaves_tightbeam_upcalls); |
| 347 | #pragma clang diagnostic pop |
| 348 | |
| 349 | return error == TB_ERROR_SUCCESS ? KERN_SUCCESS : KERN_FAILURE; |
| 350 | } |
| 351 | |
| 352 | static kern_return_t |
| 353 | exclaves_upcall_init(void) |
| 354 | { |
| 355 | lck_mtx_assert(&exclaves_boot_lock, LCK_MTX_ASSERT_OWNED); |
| 356 | |
| 357 | #if XNUPROXY_MSG_VERSION >= 2 |
| 358 | kern_return_t kkr; |
| 359 | xnuproxy_msg_t msg = { |
| 360 | .cmd = XNUPROXY_CMD_UPCALL_READY, |
| 361 | }; |
| 362 | kkr = exclaves_xnu_proxy_send(&msg, NULL); |
| 363 | assert3u(kkr, ==, KERN_SUCCESS); |
| 364 | #endif /* XNUPROXY_MSG_VERSION >= 2 */ |
| 365 | |
| 366 | return kkr; |
| 367 | } |
| 368 | |
| 369 | EXCLAVES_BOOT_TASK(exclaves_upcall_init, EXCLAVES_BOOT_RANK_FIRST); |
| 370 | |
| 371 | OS_NOINLINE |
| 372 | kern_return_t |
| 373 | exclaves_call_upcall_handler(exclaves_id_t upcall_id) |
| 374 | { |
| 375 | kern_return_t kr = KERN_INVALID_CAPABILITY; |
| 376 | |
| 377 | __assert_only thread_t thread = current_thread(); |
| 378 | assert3u(thread->th_exclaves_state & TH_EXCLAVES_UPCALL, !=, 0); |
| 379 | |
| 380 | exclaves_tag_t tag = Exclaves_L4_GetMessageTag(); |
| 381 | |
| 382 | Exclaves_L4_IpcBuffer_t *ipcb = Exclaves_L4_IpcBuffer(); |
| 383 | exclaves_badge_t badge = XNUPROXY_CR_UPCALL_BADGE(ipcb); |
| 384 | |
| 385 | exclaves_upcall_handler_registration_t upcall_handler = {}; |
| 386 | |
| 387 | if (upcall_id < NUM_XNUPROXY_UPCALLS) { |
| 388 | upcall_handler = exclaves_upcall_handlers[upcall_id]; |
| 389 | } |
| 390 | if (upcall_handler.handler) { |
| 391 | kr = upcall_handler.handler(upcall_handler.context, &tag, badge); |
| 392 | Exclaves_L4_SetMessageTag(tag); |
| 393 | } |
| 394 | |
| 395 | return kr; |
| 396 | } |
| 397 | |
| 398 | /* -------------------------------------------------------------------------- */ |
| 399 | #pragma mark Testing |
| 400 | |
| 401 | |
| 402 | static tb_error_t |
| 403 | exclaves_helloupcall(const uint64_t arg, tb_error_t (^completion)(uint64_t)) |
| 404 | { |
| 405 | #if DEVELOPMENT || DEBUG |
| 406 | exclaves_debug_printf(show_test_output, |
| 407 | "%s: Hello Tightbeam Upcall!\n" , __func__); |
| 408 | tb_error_t ret = completion(~arg); |
| 409 | STACKSHOT_TESTPOINT(TP_UPCALL); |
| 410 | /* Emit kdebug event for kperf sampling testing */ |
| 411 | KDBG(BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 0xaa)); |
| 412 | return ret; |
| 413 | #else |
| 414 | (void)arg; |
| 415 | (void)completion; |
| 416 | |
| 417 | return TB_ERROR_SUCCESS; |
| 418 | #endif /* DEVELOPMENT || DEBUG */ |
| 419 | } |
| 420 | |
| 421 | #if DEVELOPMENT || DEBUG |
| 422 | |
| 423 | static kern_return_t |
| 424 | exclaves_test_upcall_handler(void *context, exclaves_tag_t *tag, |
| 425 | exclaves_badge_t badge) |
| 426 | { |
| 427 | #pragma unused(context, badge) |
| 428 | Exclaves_L4_IpcBuffer_t *ipcb = Exclaves_L4_IpcBuffer(); |
| 429 | assert(ipcb != NULL); |
| 430 | |
| 431 | Exclaves_L4_Word_t mrs = Exclaves_L4_MessageTag_Mrs(*tag); |
| 432 | assert(mrs < Exclaves_L4_IpcBuffer_Mrs); |
| 433 | Exclaves_L4_Word_t crs = Exclaves_L4_MessageTag_Crs(*tag); |
| 434 | assert(crs == 0); |
| 435 | Exclaves_L4_Word_t label = Exclaves_L4_MessageTag_Label(*tag); |
| 436 | |
| 437 | /* setup test reply message */ |
| 438 | *tag = Exclaves_L4_MessageTag(mrs, 0, ~label, Exclaves_L4_False); |
| 439 | for (int i = 0; i < mrs; i++) { |
| 440 | Exclaves_L4_SetMessageMr(i, ~Exclaves_L4_GetMessageMr(i)); |
| 441 | } |
| 442 | |
| 443 | return KERN_SUCCESS; |
| 444 | } |
| 445 | |
| 446 | static int |
| 447 | exclaves_hello_upcall_test(__unused int64_t in, int64_t *out) |
| 448 | { |
| 449 | kern_return_t kr = KERN_SUCCESS; |
| 450 | |
| 451 | if (exclaves_get_status() != EXCLAVES_STATUS_AVAILABLE) { |
| 452 | exclaves_debug_printf(show_test_output, |
| 453 | "%s: SKIPPED: Exclaves not available\n" , __func__); |
| 454 | *out = -1; |
| 455 | return 0; |
| 456 | } |
| 457 | |
| 458 | exclaves_debug_printf(show_test_output, "%s: STARTING\n" , __func__); |
| 459 | |
| 460 | Exclaves_L4_IpcBuffer_t *ipcb; |
| 461 | kr = exclaves_allocate_ipc_buffer((void**)&ipcb); |
| 462 | assert(kr == KERN_SUCCESS); |
| 463 | assert(ipcb != NULL); |
| 464 | |
| 465 | const Exclaves_L4_Word_t request = 0xdecafbadfeedfaceul; |
| 466 | Exclaves_L4_SetMessageMr(0, request); |
| 467 | exclaves_tag_t tag = Exclaves_L4_MessageTag(1, 0, 0x1330ul, |
| 468 | Exclaves_L4_False); |
| 469 | |
| 470 | exclaves_debug_printf(show_test_output, |
| 471 | "exclaves: exclaves_endpoint_call() sending request 0x%lx, " |
| 472 | "tag 0x%llx, label 0x%lx\n" , request, tag, |
| 473 | Exclaves_L4_MessageTag_Label(tag)); |
| 474 | |
| 475 | exclaves_error_t error; |
| 476 | kr = exclaves_endpoint_call(IPC_PORT_NULL, EXCLAVES_ID_HELLO_EXCLAVE_EP, |
| 477 | &tag, &error); |
| 478 | assert(kr == KERN_SUCCESS); |
| 479 | |
| 480 | Exclaves_L4_Word_t reply = Exclaves_L4_GetMessageMr(0); |
| 481 | exclaves_debug_printf(show_test_output, |
| 482 | "exclaves: exclaves_endpoint_call() returned reply 0x%lx, " |
| 483 | "tag 0x%llx, label 0x%lx, error 0x%llx\n" , reply, tag, |
| 484 | Exclaves_L4_MessageTag_Label(tag), error); |
| 485 | |
| 486 | assert(error == Exclaves_L4_Success); |
| 487 | assert(Exclaves_L4_MessageTag_Mrs(tag) == 1); |
| 488 | assert(reply == ((request >> 32) | (request << 32))); |
| 489 | assert((uint16_t)Exclaves_L4_MessageTag_Label(tag) == (uint16_t)0x1331ul); |
| 490 | |
| 491 | kr = exclaves_free_ipc_buffer(); |
| 492 | assert(kr == KERN_SUCCESS); |
| 493 | |
| 494 | exclaves_debug_printf(show_test_output, "%s: SUCCESS\n" , __func__); |
| 495 | *out = 1; |
| 496 | |
| 497 | return 0; |
| 498 | } |
| 499 | SYSCTL_TEST_REGISTER(exclaves_hello_upcall_test, exclaves_hello_upcall_test); |
| 500 | |
| 501 | static kern_return_t |
| 502 | exclaves_test_hello_upcall_handler(void *context, exclaves_tag_t *tag, |
| 503 | exclaves_badge_t badge) |
| 504 | { |
| 505 | /* HelloUpcall test handler */ |
| 506 | assert(context == NULL); |
| 507 | exclaves_debug_printf(show_test_output, "%s: Hello Upcall!\n" , __func__); |
| 508 | task_stop_conclave_upcall(); |
| 509 | STACKSHOT_TESTPOINT(TP_UPCALL); |
| 510 | /* Emit kdebug event for kperf sampling testing */ |
| 511 | KDBG(BSDDBG_CODE(DBG_BSD_KDEBUG_TEST, 0xaa)); |
| 512 | return exclaves_test_upcall_handler(context, tag, badge); |
| 513 | } |
| 514 | #endif /* DEVELOPMENT || DEBUG */ |
| 515 | |
| 516 | #endif /* __has_include(<Tightbeam/tightbeam.h>) */ |
| 517 | |
| 518 | #else /* CONFIG_EXCLAVES */ |
| 519 | |
| 520 | kern_return_t |
| 521 | exclaves_call_upcall_handler(exclaves_id_t upcall_id) |
| 522 | { |
| 523 | (void)upcall_id; |
| 524 | return KERN_NOT_SUPPORTED; |
| 525 | } |
| 526 | |
| 527 | kern_return_t |
| 528 | exclaves_register_upcall_handler(exclaves_id_t upcall_id, void *upcall_context, |
| 529 | exclaves_upcall_handler_t upcall_handler) |
| 530 | { |
| 531 | (void)upcall_id; |
| 532 | (void)upcall_context; |
| 533 | (void)upcall_handler; |
| 534 | |
| 535 | return KERN_NOT_SUPPORTED; |
| 536 | } |
| 537 | |
| 538 | #endif /* CONFIG_EXCLAVES */ |
| 539 | |