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