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