1 /*
2  * Copyright © 2014 Advanced Micro Devices, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use, copy,
8  * modify, merge, publish, distribute, sublicense, and/or sell copies
9  * of the Software, and to permit persons to whom the Software is
10  * furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including
13  * the next paragraph) shall be included in all copies or substantial
14  * portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include "libhsakmt.h"
27 #include "linux/kfd_ioctl.h"
28 #include <stdlib.h>
29 #include <string.h>
30 
31 static bool *is_device_debugged;
32 int debug_get_reg_status(uint32_t node_id, bool *is_debugged);
33 
init_device_debugging_memory(unsigned int NumNodes)34 HSAKMT_STATUS init_device_debugging_memory(unsigned int NumNodes)
35 {
36 	unsigned int i;
37 
38 	is_device_debugged = malloc(NumNodes * sizeof(bool));
39 	if (!is_device_debugged)
40 		return HSAKMT_STATUS_NO_MEMORY;
41 
42 	for (i = 0; i < NumNodes; i++)
43 		is_device_debugged[i] = false;
44 
45 	return HSAKMT_STATUS_SUCCESS;
46 }
47 
destroy_device_debugging_memory(void)48 void destroy_device_debugging_memory(void)
49 {
50 	if (is_device_debugged) {
51 		free(is_device_debugged);
52 		is_device_debugged = NULL;
53 	}
54 }
55 
hsaKmtDbgRegister(HSAuint32 NodeId)56 HSAKMT_STATUS HSAKMTAPI hsaKmtDbgRegister(HSAuint32 NodeId)
57 {
58 	HSAKMT_STATUS result;
59 	uint32_t gpu_id;
60 
61 	CHECK_KFD_OPEN();
62 
63 	if (!is_device_debugged)
64 		return HSAKMT_STATUS_NO_MEMORY;
65 
66 	result = validate_nodeid(NodeId, &gpu_id);
67 	if (result != HSAKMT_STATUS_SUCCESS)
68 		return result;
69 
70 	struct kfd_ioctl_dbg_register_args args = {0};
71 
72 	args.gpu_id = gpu_id;
73 
74 	long err = kmtIoctl(kfd_fd, AMDKFD_IOC_DBG_REGISTER, &args);
75 
76 	if (err == 0)
77 		result = HSAKMT_STATUS_SUCCESS;
78 	else
79 		result = HSAKMT_STATUS_ERROR;
80 
81 	return result;
82 }
83 
hsaKmtDbgUnregister(HSAuint32 NodeId)84 HSAKMT_STATUS HSAKMTAPI hsaKmtDbgUnregister(HSAuint32 NodeId)
85 {
86 	uint32_t gpu_id;
87 	HSAKMT_STATUS result;
88 
89 	CHECK_KFD_OPEN();
90 
91 	if (!is_device_debugged)
92 		return HSAKMT_STATUS_NO_MEMORY;
93 
94 	result = validate_nodeid(NodeId, &gpu_id);
95 	if (result != HSAKMT_STATUS_SUCCESS)
96 		return result;
97 
98 	struct kfd_ioctl_dbg_unregister_args args = {0};
99 
100 	args.gpu_id = gpu_id;
101 	long err = kmtIoctl(kfd_fd, AMDKFD_IOC_DBG_UNREGISTER, &args);
102 
103 	if (err)
104 		return HSAKMT_STATUS_ERROR;
105 
106 	return HSAKMT_STATUS_SUCCESS;
107 }
108 
hsaKmtDbgWavefrontControl(HSAuint32 NodeId,HSA_DBG_WAVEOP Operand,HSA_DBG_WAVEMODE Mode,HSAuint32 TrapId,HsaDbgWaveMessage * DbgWaveMsgRing)109 HSAKMT_STATUS HSAKMTAPI hsaKmtDbgWavefrontControl(HSAuint32 NodeId,
110 						  HSA_DBG_WAVEOP Operand,
111 						  HSA_DBG_WAVEMODE Mode,
112 						  HSAuint32 TrapId,
113 						  HsaDbgWaveMessage *DbgWaveMsgRing)
114 {
115 	HSAKMT_STATUS result;
116 	uint32_t gpu_id;
117 
118 	struct kfd_ioctl_dbg_wave_control_args *args;
119 
120 	CHECK_KFD_OPEN();
121 
122 	result = validate_nodeid(NodeId, &gpu_id);
123 	if (result != HSAKMT_STATUS_SUCCESS)
124 		return result;
125 
126 
127 /* Determine Size of the ioctl buffer */
128 	uint32_t buff_size = sizeof(Operand) + sizeof(Mode) + sizeof(TrapId) +
129 			     sizeof(DbgWaveMsgRing->DbgWaveMsg) +
130 			     sizeof(DbgWaveMsgRing->MemoryVA) + sizeof(*args);
131 
132 	args = (struct kfd_ioctl_dbg_wave_control_args *)malloc(buff_size);
133 	if (!args)
134 		return HSAKMT_STATUS_ERROR;
135 
136 	memset(args, 0, buff_size);
137 
138 	args->gpu_id = gpu_id;
139 	args->buf_size_in_bytes = buff_size;
140 
141 	/* increment pointer to the start of the non fixed part */
142 	unsigned char *run_ptr = (unsigned char *)args + sizeof(*args);
143 
144 	/* save variable content pointer for kfd */
145 	args->content_ptr = (uint64_t)run_ptr;
146 
147 	/* insert items, and increment pointer accordingly */
148 	*((HSA_DBG_WAVEOP *)run_ptr) = Operand;
149 	run_ptr += sizeof(Operand);
150 
151 	*((HSA_DBG_WAVEMODE *)run_ptr) = Mode;
152 	run_ptr += sizeof(Mode);
153 
154 	*((HSAuint32 *)run_ptr) = TrapId;
155 	run_ptr += sizeof(TrapId);
156 
157 	*((HsaDbgWaveMessageAMD *)run_ptr) = DbgWaveMsgRing->DbgWaveMsg;
158 	run_ptr += sizeof(DbgWaveMsgRing->DbgWaveMsg);
159 
160 	*((void **)run_ptr) = DbgWaveMsgRing->MemoryVA;
161 	run_ptr += sizeof(DbgWaveMsgRing->MemoryVA);
162 
163 	/* send to kernel */
164 	long err = kmtIoctl(kfd_fd, AMDKFD_IOC_DBG_WAVE_CONTROL, args);
165 
166 	free(args);
167 
168 	if (err)
169 		return HSAKMT_STATUS_ERROR;
170 
171 	return HSAKMT_STATUS_SUCCESS;
172 }
173 
hsaKmtDbgAddressWatch(HSAuint32 NodeId,HSAuint32 NumWatchPoints,HSA_DBG_WATCH_MODE WatchMode[],void * WatchAddress[],HSAuint64 WatchMask[],HsaEvent * WatchEvent[])174 HSAKMT_STATUS HSAKMTAPI hsaKmtDbgAddressWatch(HSAuint32 NodeId,
175 					      HSAuint32 NumWatchPoints,
176 					      HSA_DBG_WATCH_MODE WatchMode[],
177 					      void *WatchAddress[],
178 					      HSAuint64 WatchMask[],
179 					      HsaEvent *WatchEvent[])
180 {
181 	HSAKMT_STATUS result;
182 	uint32_t gpu_id;
183 
184 	/* determine the size of the watch mask and event buffers
185 	 * the value is NULL if and only if no vector data should be attached
186 	 */
187 	uint32_t watch_mask_items = WatchMask[0] > 0 ? NumWatchPoints:1;
188 	uint32_t watch_event_items = WatchEvent != NULL ? NumWatchPoints:0;
189 
190 	struct kfd_ioctl_dbg_address_watch_args *args;
191 	HSAuint32		 i = 0;
192 
193 	CHECK_KFD_OPEN();
194 
195 	result = validate_nodeid(NodeId, &gpu_id);
196 	if (result != HSAKMT_STATUS_SUCCESS)
197 		return result;
198 
199 	if (NumWatchPoints > MAX_ALLOWED_NUM_POINTS)
200 		return HSAKMT_STATUS_INVALID_PARAMETER;
201 
202 	/* Size and structure of the ioctl buffer is dynamic in this case
203 	 * Here we calculate the buff size.
204 	 */
205 	uint32_t buff_size = sizeof(NumWatchPoints) +
206 		(sizeof(WatchMode[0]) + sizeof(WatchAddress[0])) *
207 			NumWatchPoints +
208 		watch_mask_items * sizeof(HSAuint64) +
209 		watch_event_items * sizeof(HsaEvent *) + sizeof(*args);
210 
211 	args = (struct kfd_ioctl_dbg_address_watch_args *) malloc(buff_size);
212 	if (!args)
213 		return HSAKMT_STATUS_ERROR;
214 
215 	memset(args, 0, buff_size);
216 
217 	args->gpu_id = gpu_id;
218 	args->buf_size_in_bytes = buff_size;
219 
220 
221 	/* increment pointer to the start of the non fixed part */
222 	unsigned char *run_ptr = (unsigned char *)args + sizeof(*args);
223 
224 	/* save variable content pointer for kfd */
225 	args->content_ptr = (uint64_t)run_ptr;
226 	/* insert items, and increment pointer accordingly */
227 
228 	*((HSAuint32 *)run_ptr) = NumWatchPoints;
229 	run_ptr += sizeof(NumWatchPoints);
230 
231 	for (i = 0; i < NumWatchPoints; i++) {
232 		*((HSA_DBG_WATCH_MODE *)run_ptr) = WatchMode[i];
233 		run_ptr += sizeof(WatchMode[i]);
234 	}
235 
236 	for (i = 0; i < NumWatchPoints; i++) {
237 		*((void **)run_ptr) = WatchAddress[i];
238 		run_ptr += sizeof(WatchAddress[i]);
239 	}
240 
241 	for (i = 0; i < watch_mask_items; i++) {
242 		*((HSAuint64 *)run_ptr) = WatchMask[i];
243 		run_ptr += sizeof(WatchMask[i]);
244 	}
245 
246 	for (i = 0; i < watch_event_items; i++)	{
247 		*((HsaEvent **)run_ptr) = WatchEvent[i];
248 		run_ptr += sizeof(WatchEvent[i]);
249 	}
250 
251 	/* send to kernel */
252 	long err = kmtIoctl(kfd_fd, AMDKFD_IOC_DBG_ADDRESS_WATCH, args);
253 
254 	free(args);
255 
256 	if (err)
257 		return HSAKMT_STATUS_ERROR;
258 	return HSAKMT_STATUS_SUCCESS;
259 }
260 
debug_get_reg_status(uint32_t node_id,bool * is_debugged)261 int debug_get_reg_status(uint32_t node_id, bool *is_debugged)
262 {
263 	*is_debugged = NULL;
264 	if (!is_device_debugged)
265 		return -1;
266 
267 	*is_debugged = is_device_debugged[node_id];
268 	return 0;
269 }
270