1 /*
2 * Copyright 2021 Alyssa Rosenzweig
3 * SPDX-License-Identifier: MIT
4 */
5
6 #pragma once
7
8 #include <stdbool.h>
9 #include "agx_bo.h"
10
11 #if __APPLE__
12 #include <IOKit/IODataQueueClient.h>
13 #include <mach/mach.h>
14 #endif
15
16 /*
17 * This file contains necessary defines for the macOS (IOKit) interface to the
18 * AGX accelerator, required to build a userspace graphics driver on macOS.
19 *
20 * They are not used under Linux.
21 *
22 * Information is this file was originally determined independently. More
23 * recently, names have been augmented via the oob_timestamp code sample from
24 * Project Zero [1]
25 *
26 * [1] https://bugs.chromium.org/p/project-zero/issues/detail?id=1986
27 */
28
29 #define AGX_SERVICE_TYPE 0x100005
30
31 enum agx_selector {
32 AGX_SELECTOR_GET_GLOBAL_IDS = 0x6,
33 AGX_SELECTOR_SET_API = 0x7,
34 AGX_SELECTOR_CREATE_COMMAND_QUEUE = 0x8,
35 AGX_SELECTOR_FREE_COMMAND_QUEUE = 0x9,
36 AGX_SELECTOR_ALLOCATE_MEM = 0xA,
37 AGX_SELECTOR_FREE_MEM = 0xB,
38 AGX_SELECTOR_CREATE_SHMEM = 0xF,
39 AGX_SELECTOR_FREE_SHMEM = 0x10,
40 AGX_SELECTOR_CREATE_NOTIFICATION_QUEUE = 0x11,
41 AGX_SELECTOR_FREE_NOTIFICATION_QUEUE = 0x12,
42 AGX_SELECTOR_SUBMIT_COMMAND_BUFFERS = 0x1E,
43 AGX_SELECTOR_GET_VERSION = 0x23,
44 AGX_NUM_SELECTORS = 0x32
45 };
46
47 static const char *selector_table[AGX_NUM_SELECTORS] = {
48 "unk0",
49 "unk1",
50 "unk2",
51 "unk3",
52 "unk4",
53 "unk5",
54 "GET_GLOBAL_IDS",
55 "SET_API",
56 "CREATE_COMMAND_QUEUE",
57 "FREE_COMMAND_QUEUE",
58 "ALLOCATE_MEM",
59 "FREE_MEM",
60 "unkC",
61 "unkD",
62 "unkE",
63 "CREATE_SHMEM",
64 "FREE_SHMEM",
65 "CREATE_NOTIFICATION_QUEUE",
66 "FREE_NOTIFICATION_QUEUE",
67 "unk13",
68 "unk14",
69 "unk15",
70 "unk16",
71 "unk17",
72 "unk18",
73 "unk19",
74 "unk1A",
75 "unk1B",
76 "unk1C",
77 "unk1D",
78 "SUBMIT_COMMAND_BUFFERS",
79 "unk1F",
80 "unk20",
81 "unk21",
82 "unk22",
83 "GET_VERSION",
84 "unk24",
85 "unk25",
86 "unk26",
87 "unk27",
88 "unk28",
89 "unk29",
90 "unk2A",
91 "unk2B",
92 "unk2C",
93 "unk2D",
94 "unk2E",
95 "unk2F",
96 "unk30",
97 "unk31"};
98
99 static inline const char *
wrap_selector_name(uint32_t selector)100 wrap_selector_name(uint32_t selector)
101 {
102 return (selector < AGX_NUM_SELECTORS) ? selector_table[selector] : "unk??";
103 }
104
105 struct agx_create_command_queue_resp {
106 uint64_t id;
107 uint32_t unk2; // 90 0A 08 27
108 uint32_t unk3; // 0
109 } __attribute__((packed));
110
111 struct agx_create_shmem_resp {
112 /* IOAccelDeviceShmemData */
113 void *map;
114 uint32_t size;
115 uint32_t id;
116 } __attribute__((packed));
117
118 struct agx_create_notification_queue_resp {
119 #ifdef __APPLE__
120 IODataQueueMemory *queue;
121 #else
122 void *queue;
123 #endif
124 uint32_t unk2; // 1
125 uint32_t unk3; // 0
126 } __attribute__((packed));
127
128 struct IOAccelCommandQueueSubmitArgs_Header {
129 uint32_t unk0;
130 uint32_t count;
131 };
132
133 struct IOAccelCommandQueueSubmitArgs_Command {
134 uint32_t command_buffer_shmem_id;
135 uint32_t segment_list_shmem_id;
136 uint64_t unk1B; // 0, new in 12.x
137 uint64_t notify_1;
138 uint64_t notify_2;
139 uint32_t unk2;
140 uint32_t unk3;
141 } __attribute__((packed));
142
143 /* Memory allocation isn't really understood yet. By comparing SHADER/CMDBUF_32
144 * vs everything else, it appears the 0x40000000 bit indicates the GPU VA must
145 * be be in the first 4GiB */
146
147 enum agx_memory_type {
148 AGX_MEMORY_TYPE_NORMAL = 0x00000000, /* used for user allocations */
149 AGX_MEMORY_TYPE_UNK = 0x08000000, /* unknown */
150 AGX_MEMORY_TYPE_CMDBUF_64 = 0x18000000, /* used for command buffer storage */
151 AGX_MEMORY_TYPE_SHADER =
152 0x48000000, /* used for shader memory, with VA = 0 */
153 AGX_MEMORY_TYPE_CMDBUF_32 =
154 0x58000000, /* used for command buffers, with VA < 32-bit */
155 AGX_MEMORY_TYPE_FRAMEBUFFER = 0x00888F00, /* used for framebuffer backing */
156 };
157
158 static inline const char *
agx_memory_type_name(uint32_t type)159 agx_memory_type_name(uint32_t type)
160 {
161 switch (type) {
162 case AGX_MEMORY_TYPE_NORMAL:
163 return "normal";
164 case AGX_MEMORY_TYPE_UNK:
165 return "unk";
166 case AGX_MEMORY_TYPE_CMDBUF_64:
167 return "cmdbuf_64";
168 case AGX_MEMORY_TYPE_SHADER:
169 return "shader";
170 case AGX_MEMORY_TYPE_CMDBUF_32:
171 return "cmdbuf_32";
172 case AGX_MEMORY_TYPE_FRAMEBUFFER:
173 return "framebuffer";
174 default:
175 return NULL;
176 }
177 }
178
179 struct agx_allocate_resource_req {
180 uint32_t unk0[5];
181 uint32_t mode;
182 uint32_t unk6[6];
183 uint64_t cpu_fixed;
184 uint64_t cpu_fixed_parent;
185 uint32_t size;
186 uint32_t unk17;
187
188 /* Handle of the parent resource when a suballocation is requested.
189 * Based on an assertion failure, this corresponds to:
190 *
191 * -[IOGPUMetalBuffer
192 * initWithPrimaryBuffer:heapIndex:bufferIndex:bufferOffset:length:args:argsSize:]
193 */
194 uint32_t parent;
195
196 uint32_t unk19;
197 uint32_t flags;
198 uint32_t unk21[3];
199 } __attribute__((packed));
200
201 struct agx_allocate_resource_resp {
202 /* Returned GPU virtual address */
203 uint64_t gpu_va;
204
205 /* Returned CPU virtual address */
206 uint64_t cpu;
207
208 uint32_t unk4[3];
209
210 /* Handle used to identify the resource in the segment list */
211 uint32_t handle;
212
213 /* Size of the root resource from which we are allocated. If this is not a
214 * suballocation, this is equal to the size.
215 */
216 uint64_t root_size;
217
218 /* Globally unique identifier for the resource, shown in Instruments */
219 uint32_t guid;
220
221 uint32_t unk11[7];
222
223 /* Maximum size of the suballocation. For a suballocation, this equals:
224 *
225 * sub_size = root_size - (sub_cpu - root_cpu)
226 *
227 * For root allocations, this equals the size.
228 */
229 uint64_t sub_size;
230 } __attribute__((packed));
231
232 struct agx_notification_queue {
233 #ifdef __APPLE__
234 mach_port_t port;
235 IODataQueueMemory *queue;
236 #else
237 unsigned port;
238 void *queue;
239 #endif
240 unsigned id;
241 };
242
243 struct agx_command_queue {
244 unsigned id;
245 struct agx_notification_queue notif;
246 };
247
248 struct agx_map_header {
249 /* IOAccelSegmentListHeader */
250 uint64_t cmdbuf_id; // GUID
251 uint32_t segment_count;
252 uint16_t length;
253 uint16_t unk; // 0x8000
254 uint64_t encoder_id; // GUID
255
256 /* IOAccelSegmentResourceListHeader */
257 uint32_t kernel_commands_start_offset;
258 uint32_t kernel_commands_end_offset;
259 uint32_t padding[2];
260 uint32_t total_resources;
261 uint32_t resource_group_count;
262 } __attribute__((packed));
263
264 /* IOAccelSegmentResourceList_ResourceGroup */
265 struct agx_map_entry {
266 uint32_t resource_id[6];
267 uint32_t resource_unk[6];
268 uint16_t resource_flags[6];
269 uint16_t unka; // ff ff
270 uint16_t resource_count;
271 } __attribute__((packed));
272
273 uint64_t agx_get_global_id(struct agx_device *dev);
274