1bf215546Sopenharmony_ci/* 2bf215546Sopenharmony_ci * Copyright (C) 2021-2022 Alyssa Rosenzweig <alyssa@rosenzweig.io> 3bf215546Sopenharmony_ci * 4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"), 6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation 7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions: 10bf215546Sopenharmony_ci * 11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next 12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 13bf215546Sopenharmony_ci * Software. 14bf215546Sopenharmony_ci * 15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20bf215546Sopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21bf215546Sopenharmony_ci * SOFTWARE. 22bf215546Sopenharmony_ci */ 23bf215546Sopenharmony_ci#include <stdio.h> 24bf215546Sopenharmony_ci#include <stdint.h> 25bf215546Sopenharmony_ci#include <unistd.h> 26bf215546Sopenharmony_ci#include <dlfcn.h> 27bf215546Sopenharmony_ci#include <assert.h> 28bf215546Sopenharmony_ci#include <inttypes.h> 29bf215546Sopenharmony_ci 30bf215546Sopenharmony_ci#include <mach/mach.h> 31bf215546Sopenharmony_ci#include <IOKit/IOKitLib.h> 32bf215546Sopenharmony_ci 33bf215546Sopenharmony_ci#include "util/compiler.h" 34bf215546Sopenharmony_ci#include "io.h" 35bf215546Sopenharmony_ci#include "decode.h" 36bf215546Sopenharmony_ci#include "util.h" 37bf215546Sopenharmony_ci#include "hexdump.h" 38bf215546Sopenharmony_ci#include "dyld_interpose.h" 39bf215546Sopenharmony_ci 40bf215546Sopenharmony_ci/* 41bf215546Sopenharmony_ci * Wrap IOKit entrypoints to intercept communication between the AGX kernel 42bf215546Sopenharmony_ci * extension and userspace clients. IOKit prototypes are public from the IOKit 43bf215546Sopenharmony_ci * source release. 44bf215546Sopenharmony_ci */ 45bf215546Sopenharmony_ci 46bf215546Sopenharmony_cimach_port_t metal_connection = 0; 47bf215546Sopenharmony_ci 48bf215546Sopenharmony_cikern_return_t 49bf215546Sopenharmony_ciwrap_Method(mach_port_t connection, uint32_t selector, const uint64_t* input, 50bf215546Sopenharmony_ci uint32_t inputCnt, const void *inputStruct, size_t inputStructCnt, 51bf215546Sopenharmony_ci uint64_t *output, uint32_t *outputCnt, void *outputStruct, 52bf215546Sopenharmony_ci size_t *outputStructCntP) 53bf215546Sopenharmony_ci{ 54bf215546Sopenharmony_ci /* Heuristic guess which connection is Metal, skip over I/O from everything 55bf215546Sopenharmony_ci * else. This is technically wrong but it works in practice, and reduces the 56bf215546Sopenharmony_ci * surface area we need to wrap. 57bf215546Sopenharmony_ci */ 58bf215546Sopenharmony_ci if (selector == AGX_SELECTOR_SET_API) { 59bf215546Sopenharmony_ci metal_connection = connection; 60bf215546Sopenharmony_ci } else if (metal_connection != connection) { 61bf215546Sopenharmony_ci return IOConnectCallMethod(connection, selector, input, inputCnt, 62bf215546Sopenharmony_ci inputStruct, inputStructCnt, output, outputCnt, 63bf215546Sopenharmony_ci outputStruct, outputStructCntP); 64bf215546Sopenharmony_ci } 65bf215546Sopenharmony_ci 66bf215546Sopenharmony_ci printf("Selector %u, %X, %X\n", selector, connection, metal_connection); 67bf215546Sopenharmony_ci 68bf215546Sopenharmony_ci /* Check the arguments make sense */ 69bf215546Sopenharmony_ci assert((input != NULL) == (inputCnt != 0)); 70bf215546Sopenharmony_ci assert((inputStruct != NULL) == (inputStructCnt != 0)); 71bf215546Sopenharmony_ci assert((output != NULL) == (outputCnt != 0)); 72bf215546Sopenharmony_ci assert((outputStruct != NULL) == (outputStructCntP != 0)); 73bf215546Sopenharmony_ci 74bf215546Sopenharmony_ci /* Dump inputs */ 75bf215546Sopenharmony_ci switch (selector) { 76bf215546Sopenharmony_ci case AGX_SELECTOR_SET_API: 77bf215546Sopenharmony_ci assert(input == NULL && output == NULL && outputStruct == NULL); 78bf215546Sopenharmony_ci assert(inputStruct != NULL && inputStructCnt == 16); 79bf215546Sopenharmony_ci assert(((uint8_t *) inputStruct)[15] == 0x0); 80bf215546Sopenharmony_ci 81bf215546Sopenharmony_ci printf("%X: SET_API(%s)\n", connection, (const char *) inputStruct); 82bf215546Sopenharmony_ci break; 83bf215546Sopenharmony_ci 84bf215546Sopenharmony_ci case AGX_SELECTOR_ALLOCATE_MEM: { 85bf215546Sopenharmony_ci const struct agx_allocate_resource_req *req = inputStruct; 86bf215546Sopenharmony_ci struct agx_allocate_resource_req *req2 = (void *) inputStruct; 87bf215546Sopenharmony_ci req2->mode = (req->mode & 0x800) | 0x430; 88bf215546Sopenharmony_ci 89bf215546Sopenharmony_ci bool suballocated = req->mode & 0x800; 90bf215546Sopenharmony_ci 91bf215546Sopenharmony_ci printf("Resource allocation:\n"); 92bf215546Sopenharmony_ci printf(" Mode: 0x%X%s\n", req->mode & ~0x800, 93bf215546Sopenharmony_ci suballocated ? " (suballocated) " : ""); 94bf215546Sopenharmony_ci printf(" CPU fixed: 0x%" PRIx64 "\n", req->cpu_fixed); 95bf215546Sopenharmony_ci printf(" CPU fixed (parent): 0x%" PRIx64 "\n", req->cpu_fixed_parent); 96bf215546Sopenharmony_ci printf(" Size: 0x%X\n", req->size); 97bf215546Sopenharmony_ci printf(" Flags: 0x%X\n", req->flags); 98bf215546Sopenharmony_ci 99bf215546Sopenharmony_ci if (suballocated) { 100bf215546Sopenharmony_ci printf(" Parent: %u\n", req->parent); 101bf215546Sopenharmony_ci } else { 102bf215546Sopenharmony_ci assert(req->parent == 0); 103bf215546Sopenharmony_ci } 104bf215546Sopenharmony_ci 105bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(req->unk0); ++i) { 106bf215546Sopenharmony_ci if (req->unk0[i]) 107bf215546Sopenharmony_ci printf(" UNK%u: 0x%X\n", 0 + i, req->unk0[i]); 108bf215546Sopenharmony_ci } 109bf215546Sopenharmony_ci 110bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(req->unk6); ++i) { 111bf215546Sopenharmony_ci if (req->unk6[i]) 112bf215546Sopenharmony_ci printf(" UNK%u: 0x%X\n", 6 + i, req->unk6[i]); 113bf215546Sopenharmony_ci } 114bf215546Sopenharmony_ci 115bf215546Sopenharmony_ci if (req->unk17) 116bf215546Sopenharmony_ci printf(" UNK17: 0x%X\n", req->unk17); 117bf215546Sopenharmony_ci 118bf215546Sopenharmony_ci if (req->unk19) 119bf215546Sopenharmony_ci printf(" UNK19: 0x%X\n", req->unk19); 120bf215546Sopenharmony_ci 121bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(req->unk21); ++i) { 122bf215546Sopenharmony_ci if (req->unk21[i]) 123bf215546Sopenharmony_ci printf(" UNK%u: 0x%X\n", 21 + i, req->unk21[i]); 124bf215546Sopenharmony_ci } 125bf215546Sopenharmony_ci 126bf215546Sopenharmony_ci break; 127bf215546Sopenharmony_ci } 128bf215546Sopenharmony_ci 129bf215546Sopenharmony_ci case AGX_SELECTOR_SUBMIT_COMMAND_BUFFERS: 130bf215546Sopenharmony_ci assert(output == NULL && outputStruct == NULL); 131bf215546Sopenharmony_ci assert(inputStructCnt == sizeof(struct agx_submit_cmdbuf_req)); 132bf215546Sopenharmony_ci assert(inputCnt == 1); 133bf215546Sopenharmony_ci 134bf215546Sopenharmony_ci printf("%X: SUBMIT_COMMAND_BUFFERS command queue id:%llx %p\n", 135bf215546Sopenharmony_ci connection, input[0], inputStruct); 136bf215546Sopenharmony_ci 137bf215546Sopenharmony_ci const struct agx_submit_cmdbuf_req *req = inputStruct; 138bf215546Sopenharmony_ci 139bf215546Sopenharmony_ci agxdecode_cmdstream(req->command_buffer_shmem_id, 140bf215546Sopenharmony_ci req->segment_list_shmem_id, true); 141bf215546Sopenharmony_ci 142bf215546Sopenharmony_ci if (getenv("ASAHI_DUMP")) 143bf215546Sopenharmony_ci agxdecode_dump_mappings(req->segment_list_shmem_id); 144bf215546Sopenharmony_ci 145bf215546Sopenharmony_ci agxdecode_next_frame(); 146bf215546Sopenharmony_ci FALLTHROUGH; 147bf215546Sopenharmony_ci 148bf215546Sopenharmony_ci default: 149bf215546Sopenharmony_ci printf("%X: call %s (out %p, %zu)", connection, 150bf215546Sopenharmony_ci wrap_selector_name(selector), outputStructCntP, 151bf215546Sopenharmony_ci outputStructCntP ? *outputStructCntP : 0); 152bf215546Sopenharmony_ci 153bf215546Sopenharmony_ci for (uint64_t u = 0; u < inputCnt; ++u) 154bf215546Sopenharmony_ci printf(" %llx", input[u]); 155bf215546Sopenharmony_ci 156bf215546Sopenharmony_ci if(inputStructCnt) { 157bf215546Sopenharmony_ci printf(", struct:\n"); 158bf215546Sopenharmony_ci hexdump(stdout, inputStruct, inputStructCnt, true); 159bf215546Sopenharmony_ci } else { 160bf215546Sopenharmony_ci printf("\n"); 161bf215546Sopenharmony_ci } 162bf215546Sopenharmony_ci 163bf215546Sopenharmony_ci break; 164bf215546Sopenharmony_ci } 165bf215546Sopenharmony_ci 166bf215546Sopenharmony_ci /* Invoke the real method */ 167bf215546Sopenharmony_ci kern_return_t ret = 168bf215546Sopenharmony_ci IOConnectCallMethod(connection, selector, input, inputCnt, inputStruct, 169bf215546Sopenharmony_ci inputStructCnt, output, outputCnt, outputStruct, 170bf215546Sopenharmony_ci outputStructCntP); 171bf215546Sopenharmony_ci 172bf215546Sopenharmony_ci if (ret != 0) 173bf215546Sopenharmony_ci printf("return %u\n", ret); 174bf215546Sopenharmony_ci 175bf215546Sopenharmony_ci /* Track allocations for later analysis (dumping, disassembly, etc) */ 176bf215546Sopenharmony_ci switch (selector) { 177bf215546Sopenharmony_ci case AGX_SELECTOR_CREATE_SHMEM: { 178bf215546Sopenharmony_ci assert(inputCnt == 2); 179bf215546Sopenharmony_ci assert((*outputStructCntP) == 0x10); 180bf215546Sopenharmony_ci uint64_t *inp = (uint64_t *) input; 181bf215546Sopenharmony_ci 182bf215546Sopenharmony_ci uint8_t type = inp[1]; 183bf215546Sopenharmony_ci 184bf215546Sopenharmony_ci assert(type <= 2); 185bf215546Sopenharmony_ci if (type == 2) 186bf215546Sopenharmony_ci printf("(cmdbuf with error reporting)\n"); 187bf215546Sopenharmony_ci 188bf215546Sopenharmony_ci uint64_t *ptr = (uint64_t *) outputStruct; 189bf215546Sopenharmony_ci uint32_t *words = (uint32_t *) (ptr + 1); 190bf215546Sopenharmony_ci 191bf215546Sopenharmony_ci agxdecode_track_alloc(&(struct agx_bo) { 192bf215546Sopenharmony_ci .handle = words[1], 193bf215546Sopenharmony_ci .ptr.cpu = (void *) *ptr, 194bf215546Sopenharmony_ci .size = words[0], 195bf215546Sopenharmony_ci .type = inp[1] ? AGX_ALLOC_CMDBUF : AGX_ALLOC_MEMMAP 196bf215546Sopenharmony_ci }); 197bf215546Sopenharmony_ci 198bf215546Sopenharmony_ci break; 199bf215546Sopenharmony_ci } 200bf215546Sopenharmony_ci 201bf215546Sopenharmony_ci case AGX_SELECTOR_ALLOCATE_MEM: { 202bf215546Sopenharmony_ci assert((*outputStructCntP) == 0x50); 203bf215546Sopenharmony_ci const struct agx_allocate_resource_req *req = inputStruct; 204bf215546Sopenharmony_ci struct agx_allocate_resource_resp *resp = outputStruct; 205bf215546Sopenharmony_ci if (resp->cpu && req->cpu_fixed) 206bf215546Sopenharmony_ci assert(resp->cpu == req->cpu_fixed); 207bf215546Sopenharmony_ci printf("Response:\n"); 208bf215546Sopenharmony_ci printf(" GPU VA: 0x%" PRIx64 "\n", resp->gpu_va); 209bf215546Sopenharmony_ci printf(" CPU VA: 0x%" PRIx64 "\n", resp->cpu); 210bf215546Sopenharmony_ci printf(" Handle: %u\n", resp->handle); 211bf215546Sopenharmony_ci printf(" Root size: 0x%" PRIx64 "\n", resp->root_size); 212bf215546Sopenharmony_ci printf(" Suballocation size: 0x%" PRIx64 "\n", resp->sub_size); 213bf215546Sopenharmony_ci printf(" GUID: 0x%X\n", resp->guid); 214bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(resp->unk4); ++i) { 215bf215546Sopenharmony_ci if (resp->unk4[i]) 216bf215546Sopenharmony_ci printf(" UNK%u: 0x%X\n", 4 + i, resp->unk4[i]); 217bf215546Sopenharmony_ci } 218bf215546Sopenharmony_ci for (unsigned i = 0; i < ARRAY_SIZE(resp->unk11); ++i) { 219bf215546Sopenharmony_ci if (resp->unk11[i]) 220bf215546Sopenharmony_ci printf(" UNK%u: 0x%X\n", 11 + i, resp->unk11[i]); 221bf215546Sopenharmony_ci } 222bf215546Sopenharmony_ci 223bf215546Sopenharmony_ci if (req->parent) 224bf215546Sopenharmony_ci assert(resp->sub_size <= resp->root_size); 225bf215546Sopenharmony_ci else 226bf215546Sopenharmony_ci assert(resp->sub_size == resp->root_size); 227bf215546Sopenharmony_ci 228bf215546Sopenharmony_ci agxdecode_track_alloc(&(struct agx_bo) { 229bf215546Sopenharmony_ci .type = AGX_ALLOC_REGULAR, 230bf215546Sopenharmony_ci .size = resp->sub_size, 231bf215546Sopenharmony_ci .handle = resp->handle, 232bf215546Sopenharmony_ci .ptr.gpu = resp->gpu_va, 233bf215546Sopenharmony_ci .ptr.cpu = (void *) resp->cpu, 234bf215546Sopenharmony_ci }); 235bf215546Sopenharmony_ci 236bf215546Sopenharmony_ci break; 237bf215546Sopenharmony_ci } 238bf215546Sopenharmony_ci 239bf215546Sopenharmony_ci case AGX_SELECTOR_FREE_MEM: { 240bf215546Sopenharmony_ci assert(inputCnt == 1); 241bf215546Sopenharmony_ci assert(inputStruct == NULL); 242bf215546Sopenharmony_ci assert(output == NULL); 243bf215546Sopenharmony_ci assert(outputStruct == NULL); 244bf215546Sopenharmony_ci 245bf215546Sopenharmony_ci agxdecode_track_free(&(struct agx_bo) { 246bf215546Sopenharmony_ci .type = AGX_ALLOC_REGULAR, 247bf215546Sopenharmony_ci .handle = input[0] 248bf215546Sopenharmony_ci }); 249bf215546Sopenharmony_ci 250bf215546Sopenharmony_ci break; 251bf215546Sopenharmony_ci } 252bf215546Sopenharmony_ci 253bf215546Sopenharmony_ci default: 254bf215546Sopenharmony_ci /* Dump the outputs */ 255bf215546Sopenharmony_ci if(outputCnt) { 256bf215546Sopenharmony_ci printf("%u scalars: ", *outputCnt); 257bf215546Sopenharmony_ci 258bf215546Sopenharmony_ci for (uint64_t u = 0; u < *outputCnt; ++u) 259bf215546Sopenharmony_ci printf("%llx ", output[u]); 260bf215546Sopenharmony_ci 261bf215546Sopenharmony_ci printf("\n"); 262bf215546Sopenharmony_ci } 263bf215546Sopenharmony_ci 264bf215546Sopenharmony_ci if(outputStructCntP) { 265bf215546Sopenharmony_ci printf(" struct\n"); 266bf215546Sopenharmony_ci hexdump(stdout, outputStruct, *outputStructCntP, true); 267bf215546Sopenharmony_ci 268bf215546Sopenharmony_ci if (selector == 2) { 269bf215546Sopenharmony_ci /* Dump linked buffer as well */ 270bf215546Sopenharmony_ci void **o = outputStruct; 271bf215546Sopenharmony_ci hexdump(stdout, *o, 64, true); 272bf215546Sopenharmony_ci } 273bf215546Sopenharmony_ci } 274bf215546Sopenharmony_ci 275bf215546Sopenharmony_ci printf("\n"); 276bf215546Sopenharmony_ci break; 277bf215546Sopenharmony_ci } 278bf215546Sopenharmony_ci 279bf215546Sopenharmony_ci return ret; 280bf215546Sopenharmony_ci} 281bf215546Sopenharmony_ci 282bf215546Sopenharmony_cikern_return_t 283bf215546Sopenharmony_ciwrap_AsyncMethod(mach_port_t connection, uint32_t selector, 284bf215546Sopenharmony_ci mach_port_t wakePort, uint64_t *reference, 285bf215546Sopenharmony_ci uint32_t referenceCnt, const uint64_t *input, 286bf215546Sopenharmony_ci uint32_t inputCnt, const void *inputStruct, 287bf215546Sopenharmony_ci size_t inputStructCnt, uint64_t *output, uint32_t *outputCnt, 288bf215546Sopenharmony_ci void *outputStruct, size_t *outputStructCntP) 289bf215546Sopenharmony_ci{ 290bf215546Sopenharmony_ci /* Check the arguments make sense */ 291bf215546Sopenharmony_ci assert((input != NULL) == (inputCnt != 0)); 292bf215546Sopenharmony_ci assert((inputStruct != NULL) == (inputStructCnt != 0)); 293bf215546Sopenharmony_ci assert((output != NULL) == (outputCnt != 0)); 294bf215546Sopenharmony_ci assert((outputStruct != NULL) == (outputStructCntP != 0)); 295bf215546Sopenharmony_ci 296bf215546Sopenharmony_ci printf("%X: call %X, wake port %X (out %p, %zu)", connection, selector, 297bf215546Sopenharmony_ci wakePort, outputStructCntP, outputStructCntP ? *outputStructCntP : 0); 298bf215546Sopenharmony_ci 299bf215546Sopenharmony_ci for (uint64_t u = 0; u < inputCnt; ++u) 300bf215546Sopenharmony_ci printf(" %llx", input[u]); 301bf215546Sopenharmony_ci 302bf215546Sopenharmony_ci if(inputStructCnt) { 303bf215546Sopenharmony_ci printf(", struct:\n"); 304bf215546Sopenharmony_ci hexdump(stdout, inputStruct, inputStructCnt, true); 305bf215546Sopenharmony_ci } else { 306bf215546Sopenharmony_ci printf("\n"); 307bf215546Sopenharmony_ci } 308bf215546Sopenharmony_ci 309bf215546Sopenharmony_ci printf(", references: "); 310bf215546Sopenharmony_ci for (unsigned i = 0; i < referenceCnt; ++i) 311bf215546Sopenharmony_ci printf(" %llx", reference[i]); 312bf215546Sopenharmony_ci printf("\n"); 313bf215546Sopenharmony_ci 314bf215546Sopenharmony_ci kern_return_t ret = IOConnectCallAsyncMethod(connection, selector, wakePort, 315bf215546Sopenharmony_ci reference, referenceCnt, input, inputCnt, inputStruct, inputStructCnt, 316bf215546Sopenharmony_ci output, outputCnt, outputStruct, outputStructCntP); 317bf215546Sopenharmony_ci 318bf215546Sopenharmony_ci printf("return %u", ret); 319bf215546Sopenharmony_ci 320bf215546Sopenharmony_ci if(outputCnt) { 321bf215546Sopenharmony_ci printf("%u scalars: ", *outputCnt); 322bf215546Sopenharmony_ci 323bf215546Sopenharmony_ci for (uint64_t u = 0; u < *outputCnt; ++u) 324bf215546Sopenharmony_ci printf("%llx ", output[u]); 325bf215546Sopenharmony_ci 326bf215546Sopenharmony_ci printf("\n"); 327bf215546Sopenharmony_ci } 328bf215546Sopenharmony_ci 329bf215546Sopenharmony_ci if(outputStructCntP) { 330bf215546Sopenharmony_ci printf(" struct\n"); 331bf215546Sopenharmony_ci hexdump(stdout, outputStruct, *outputStructCntP, true); 332bf215546Sopenharmony_ci 333bf215546Sopenharmony_ci if (selector == 2) { 334bf215546Sopenharmony_ci /* Dump linked buffer as well */ 335bf215546Sopenharmony_ci void **o = outputStruct; 336bf215546Sopenharmony_ci hexdump(stdout, *o, 64, true); 337bf215546Sopenharmony_ci } 338bf215546Sopenharmony_ci } 339bf215546Sopenharmony_ci 340bf215546Sopenharmony_ci printf("\n"); 341bf215546Sopenharmony_ci return ret; 342bf215546Sopenharmony_ci} 343bf215546Sopenharmony_ci 344bf215546Sopenharmony_cikern_return_t 345bf215546Sopenharmony_ciwrap_StructMethod(mach_port_t connection, uint32_t selector, 346bf215546Sopenharmony_ci const void *inputStruct, size_t inputStructCnt, 347bf215546Sopenharmony_ci void *outputStruct, size_t *outputStructCntP) 348bf215546Sopenharmony_ci{ 349bf215546Sopenharmony_ci return wrap_Method(connection, selector, NULL, 0, inputStruct, 350bf215546Sopenharmony_ci inputStructCnt, NULL, NULL, outputStruct, 351bf215546Sopenharmony_ci outputStructCntP); 352bf215546Sopenharmony_ci} 353bf215546Sopenharmony_ci 354bf215546Sopenharmony_cikern_return_t 355bf215546Sopenharmony_ciwrap_AsyncStructMethod(mach_port_t connection, uint32_t selector, 356bf215546Sopenharmony_ci mach_port_t wakePort, uint64_t *reference, 357bf215546Sopenharmony_ci uint32_t referenceCnt, const void *inputStruct, 358bf215546Sopenharmony_ci size_t inputStructCnt, void *outputStruct, 359bf215546Sopenharmony_ci size_t *outputStructCnt) 360bf215546Sopenharmony_ci{ 361bf215546Sopenharmony_ci return wrap_AsyncMethod(connection, selector, wakePort, reference, 362bf215546Sopenharmony_ci referenceCnt, NULL, 0, inputStruct, inputStructCnt, 363bf215546Sopenharmony_ci NULL, NULL, outputStruct, outputStructCnt); 364bf215546Sopenharmony_ci} 365bf215546Sopenharmony_ci 366bf215546Sopenharmony_cikern_return_t 367bf215546Sopenharmony_ciwrap_ScalarMethod(mach_port_t connection, uint32_t selector, 368bf215546Sopenharmony_ci const uint64_t *input, uint32_t inputCnt, uint64_t *output, 369bf215546Sopenharmony_ci uint32_t *outputCnt) 370bf215546Sopenharmony_ci{ 371bf215546Sopenharmony_ci return wrap_Method(connection, selector, input, inputCnt, NULL, 0, output, 372bf215546Sopenharmony_ci outputCnt, NULL, NULL); 373bf215546Sopenharmony_ci} 374bf215546Sopenharmony_ci 375bf215546Sopenharmony_cikern_return_t 376bf215546Sopenharmony_ciwrap_AsyncScalarMethod(mach_port_t connection, uint32_t selector, 377bf215546Sopenharmony_ci mach_port_t wakePort, uint64_t *reference, 378bf215546Sopenharmony_ci uint32_t referenceCnt, const uint64_t *input, 379bf215546Sopenharmony_ci uint32_t inputCnt, uint64_t *output, uint32_t *outputCnt) 380bf215546Sopenharmony_ci{ 381bf215546Sopenharmony_ci return wrap_AsyncMethod(connection, selector, wakePort, reference, 382bf215546Sopenharmony_ci referenceCnt, input, inputCnt, NULL, 0, output, 383bf215546Sopenharmony_ci outputCnt, NULL, NULL); 384bf215546Sopenharmony_ci} 385bf215546Sopenharmony_ci 386bf215546Sopenharmony_cimach_port_t 387bf215546Sopenharmony_ciwrap_DataQueueAllocateNotificationPort() 388bf215546Sopenharmony_ci{ 389bf215546Sopenharmony_ci mach_port_t ret = IODataQueueAllocateNotificationPort(); 390bf215546Sopenharmony_ci printf("Allocated notif port %X\n", ret); 391bf215546Sopenharmony_ci return ret; 392bf215546Sopenharmony_ci} 393bf215546Sopenharmony_ci 394bf215546Sopenharmony_cikern_return_t 395bf215546Sopenharmony_ciwrap_SetNotificationPort(io_connect_t connect, uint32_t type, 396bf215546Sopenharmony_ci mach_port_t port, uintptr_t reference) 397bf215546Sopenharmony_ci{ 398bf215546Sopenharmony_ci printf("Set noficiation port connect=%X, type=%X, port=%X, reference=%" 399bf215546Sopenharmony_ci PRIx64"\n", connect, type, port, (uint64_t) reference); 400bf215546Sopenharmony_ci 401bf215546Sopenharmony_ci return IOConnectSetNotificationPort(connect, type, port, reference); 402bf215546Sopenharmony_ci} 403bf215546Sopenharmony_ci 404bf215546Sopenharmony_ciIOReturn 405bf215546Sopenharmony_ciwrap_DataQueueWaitForAvailableData(IODataQueueMemory *dataQueue, 406bf215546Sopenharmony_ci mach_port_t notificationPort) 407bf215546Sopenharmony_ci{ 408bf215546Sopenharmony_ci printf("Waiting for data queue at notif port %X\n", notificationPort); 409bf215546Sopenharmony_ci IOReturn ret = IODataQueueWaitForAvailableData(dataQueue, notificationPort); 410bf215546Sopenharmony_ci printf("ret=%X\n", ret); 411bf215546Sopenharmony_ci return ret; 412bf215546Sopenharmony_ci} 413bf215546Sopenharmony_ci 414bf215546Sopenharmony_ciIODataQueueEntry * 415bf215546Sopenharmony_ciwrap_DataQueuePeek(IODataQueueMemory *dataQueue) 416bf215546Sopenharmony_ci{ 417bf215546Sopenharmony_ci printf("Peeking data queue\n"); 418bf215546Sopenharmony_ci return IODataQueuePeek(dataQueue); 419bf215546Sopenharmony_ci} 420bf215546Sopenharmony_ci 421bf215546Sopenharmony_ciIOReturn 422bf215546Sopenharmony_ciwrap_DataQueueDequeue(IODataQueueMemory *dataQueue, void *data, uint32_t *dataSize) 423bf215546Sopenharmony_ci{ 424bf215546Sopenharmony_ci printf("Dequeueing (dataQueue=%p, data=%p, buffer %u)\n", dataQueue, data, *dataSize); 425bf215546Sopenharmony_ci IOReturn ret = IODataQueueDequeue(dataQueue, data, dataSize); 426bf215546Sopenharmony_ci printf("Return \"%s\", got %u bytes\n", mach_error_string(ret), *dataSize); 427bf215546Sopenharmony_ci 428bf215546Sopenharmony_ci uint8_t *data8 = data; 429bf215546Sopenharmony_ci for (unsigned i = 0; i < *dataSize; ++i) { 430bf215546Sopenharmony_ci printf("%02X ", data8[i]); 431bf215546Sopenharmony_ci } 432bf215546Sopenharmony_ci printf("\n"); 433bf215546Sopenharmony_ci 434bf215546Sopenharmony_ci return ret; 435bf215546Sopenharmony_ci} 436bf215546Sopenharmony_ci 437bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_Method, IOConnectCallMethod); 438bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_AsyncMethod, IOConnectCallAsyncMethod); 439bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_StructMethod, IOConnectCallStructMethod); 440bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_AsyncStructMethod, IOConnectCallAsyncStructMethod); 441bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_ScalarMethod, IOConnectCallScalarMethod); 442bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_AsyncScalarMethod, IOConnectCallAsyncScalarMethod); 443bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_SetNotificationPort, IOConnectSetNotificationPort); 444bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_DataQueueAllocateNotificationPort, IODataQueueAllocateNotificationPort); 445bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_DataQueueWaitForAvailableData, IODataQueueWaitForAvailableData); 446bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_DataQueuePeek, IODataQueuePeek); 447bf215546Sopenharmony_ciDYLD_INTERPOSE(wrap_DataQueueDequeue, IODataQueueDequeue); 448