1 /*
2 * Copyright 2024 Intel Corporation
3 * SPDX-License-Identifier: MIT
4 */
5
6 #include "error_decode_xe_lib.h"
7
8 #include <stdlib.h>
9 #include <string.h>
10
11 #include "error_decode_lib.h"
12 #include "util/macros.h"
13
14 static const char *
read_parameter_helper(const char * line,const char * parameter)15 read_parameter_helper(const char *line, const char *parameter)
16 {
17 if (!strstr(line, parameter))
18 return NULL;
19
20 while (*line != ':')
21 line++;
22 /* skip ':' and ' ' */
23 line += 2;
24
25 return line;
26 }
27
28 /* parse lines like 'batch_addr[0]: 0x0000effeffff5000 */
29 bool
error_decode_xe_read_u64_hexacimal_parameter(const char * line,const char * parameter,uint64_t * value)30 error_decode_xe_read_u64_hexacimal_parameter(const char *line, const char *parameter, uint64_t *value)
31 {
32 line = read_parameter_helper(line, parameter);
33 if (!line)
34 return false;
35
36 *value = (uint64_t)strtoull(line, NULL, 0);
37 return true;
38 }
39
40 /* parse lines like 'PCI ID: 0x9a49' */
41 bool
error_decode_xe_read_hexacimal_parameter(const char * line,const char * parameter,uint32_t * value)42 error_decode_xe_read_hexacimal_parameter(const char *line, const char *parameter, uint32_t *value)
43 {
44 line = read_parameter_helper(line, parameter);
45 if (!line)
46 return false;
47
48 *value = (int)strtoul(line, NULL, 0);
49 return true;
50 }
51
52 /* parse lines like 'rcs0 (physical), logical instance=0' */
53 bool
error_decode_xe_read_engine_name(const char * line,char * ring_name)54 error_decode_xe_read_engine_name(const char *line, char *ring_name)
55 {
56 int i;
57
58 if (!strstr(line, " (physical), logical instance="))
59 return false;
60
61 i = 0;
62 for (i = 0; *line != ' '; i++, line++)
63 ring_name[i] = *line;
64
65 ring_name[i] = 0;
66 return true;
67 }
68
69 /*
70 * when a topic string is parsed it sets new_topic and returns true, otherwise
71 * does nothing.
72 */
73 bool
error_decode_xe_decode_topic(const char * line,enum xe_topic * new_topic)74 error_decode_xe_decode_topic(const char *line, enum xe_topic *new_topic)
75 {
76 static const char *xe_topic_strings[] = {
77 "**** Xe Device Coredump ****",
78 "**** GuC CT ****",
79 "**** Job ****",
80 "**** HW Engines ****",
81 "**** VM state ****",
82 "**** Contexts ****",
83 };
84 bool topic_changed = false;
85
86 for (int i = 0; i < ARRAY_SIZE(xe_topic_strings); i++) {
87 if (strncmp(xe_topic_strings[i], line, strlen(xe_topic_strings[i])) == 0) {
88 topic_changed = true;
89 *new_topic = i;
90 break;
91 }
92 }
93
94 return topic_changed;
95 }
96
97 /* return type of VM topic lines like '[200000].data: x...' and points
98 * value_ptr to first char of data of topic type
99 */
100 enum xe_vm_topic_type
error_decode_xe_read_vm_line(const char * line,uint64_t * address,const char ** value_ptr)101 error_decode_xe_read_vm_line(const char *line, uint64_t *address, const char **value_ptr)
102 {
103 enum xe_vm_topic_type type;
104 char text_addr[64];
105 int i;
106
107 if (*line != '[')
108 return XE_VM_TOPIC_TYPE_UNKNOWN;
109
110 for (i = 0, line++; *line != ']'; i++, line++)
111 text_addr[i] = *line;
112
113 text_addr[i] = 0;
114 *address = (uint64_t)strtoull(text_addr, NULL, 16);
115
116 /* at this point line points to last address digit so +3 to point to type */
117 line += 2;
118 switch (*line) {
119 case 'd':
120 type = XE_VM_TOPIC_TYPE_DATA;
121 break;
122 case 'l':
123 type = XE_VM_TOPIC_TYPE_LENGTH;
124 break;
125 case 'e':
126 type = XE_VM_TOPIC_TYPE_ERROR;
127 break;
128 default:
129 printf("type char: %c\n", *line);
130 return XE_VM_TOPIC_TYPE_UNKNOWN;
131 }
132
133 for (; *line != ':'; line++);
134
135 *value_ptr = line + 2;
136 return type;
137 }
138
139 /*
140 * similar to read_xe_vm_line() but it parses '[HWCTX].data: ...'
141 */
142 enum xe_vm_topic_type
error_decode_xe_read_hw_sp_or_ctx_line(const char * line,const char ** value_ptr,bool * is_hw_ctx)143 error_decode_xe_read_hw_sp_or_ctx_line(const char *line, const char **value_ptr, bool *is_hw_ctx)
144 {
145 enum xe_vm_topic_type type;
146 char text_addr[64];
147 bool is_hw_sp;
148 int i;
149
150 if (*line != '\t')
151 return XE_VM_TOPIC_TYPE_UNKNOWN;
152
153 line++;
154 if (*line != '[')
155 return XE_VM_TOPIC_TYPE_UNKNOWN;
156
157 for (i = 0, line++; *line != ']'; i++, line++)
158 text_addr[i] = *line;
159
160 text_addr[i] = 0;
161 *is_hw_ctx = strncmp(text_addr, "HWCTX", strlen("HWCTX")) == 0;
162 is_hw_sp = strncmp(text_addr, "HWSP", strlen("HWSP")) == 0;
163 if (*is_hw_ctx == false && is_hw_sp == false)
164 return XE_VM_TOPIC_TYPE_UNKNOWN;
165
166 /* at this point line points to last address digit so +3 to point to type */
167 line += 2;
168 switch (*line) {
169 case 'd':
170 type = XE_VM_TOPIC_TYPE_DATA;
171 break;
172 case 'l':
173 type = XE_VM_TOPIC_TYPE_LENGTH;
174 break;
175 case 'e':
176 type = XE_VM_TOPIC_TYPE_ERROR;
177 break;
178 default:
179 printf("type char: %c\n", *line);
180 return XE_VM_TOPIC_TYPE_UNKNOWN;
181 }
182
183 for (; *line != ':'; line++);
184
185 *value_ptr = line + 2;
186 return type;
187 }
188
error_decode_xe_vm_init(struct xe_vm * xe_vm)189 void error_decode_xe_vm_init(struct xe_vm *xe_vm)
190 {
191 xe_vm->entries = NULL;
192 xe_vm->entries_len = 0;
193 memset(&xe_vm->hw_context, 0, sizeof(xe_vm->hw_context));
194 }
195
error_decode_xe_vm_fini(struct xe_vm * xe_vm)196 void error_decode_xe_vm_fini(struct xe_vm *xe_vm)
197 {
198 uint32_t i;
199
200 for (i = 0; i < xe_vm->entries_len; i++)
201 free((uint32_t *)xe_vm->entries[i].data);
202
203 free((uint32_t *)xe_vm->hw_context.data);
204 free(xe_vm->entries);
205 }
206
207 static void
xe_vm_entry_set(struct xe_vm_entry * entry,const uint64_t address,const uint32_t length,const uint32_t * data)208 xe_vm_entry_set(struct xe_vm_entry *entry, const uint64_t address,
209 const uint32_t length, const uint32_t *data)
210 {
211 entry->address = address;
212 entry->length = length;
213 entry->data = data;
214 }
215
216 void
error_decode_xe_vm_hw_ctx_set(struct xe_vm * xe_vm,const uint32_t length,const uint32_t * data)217 error_decode_xe_vm_hw_ctx_set(struct xe_vm *xe_vm, const uint32_t length,
218 const uint32_t *data)
219 {
220 xe_vm_entry_set(&xe_vm->hw_context, 0, length, data);
221 }
222
223 /*
224 * error_decode_xe_vm_fini() will take care to free data
225 */
226 bool
error_decode_xe_vm_append(struct xe_vm * xe_vm,const uint64_t address,const uint32_t length,const uint32_t * data)227 error_decode_xe_vm_append(struct xe_vm *xe_vm, const uint64_t address,
228 const uint32_t length, const uint32_t *data)
229 {
230 size_t len = sizeof(*xe_vm->entries) * (xe_vm->entries_len + 1);
231
232 xe_vm->entries = realloc(xe_vm->entries, len);
233 if (!xe_vm->entries)
234 return false;
235
236 xe_vm_entry_set(&xe_vm->entries[xe_vm->entries_len], address, length, data);
237 xe_vm->entries_len++;
238 return true;
239 }
240
241 const struct xe_vm_entry *
error_decode_xe_vm_entry_get(struct xe_vm * xe_vm,const uint64_t address)242 error_decode_xe_vm_entry_get(struct xe_vm *xe_vm, const uint64_t address)
243 {
244 uint32_t i;
245
246 for (i = 0; i < xe_vm->entries_len; i++) {
247 struct xe_vm_entry *entry = &xe_vm->entries[i];
248
249 if (entry->address == address)
250 return entry;
251
252 if (address > entry->address &&
253 address < (entry->address + entry->length))
254 return entry;
255 }
256
257 return NULL;
258 }
259
260 uint32_t *
error_decode_xe_vm_entry_address_get_data(const struct xe_vm_entry * entry,const uint64_t address)261 error_decode_xe_vm_entry_address_get_data(const struct xe_vm_entry *entry,
262 const uint64_t address)
263 {
264 uint32_t offset = (address - entry->address) / sizeof(uint32_t);
265 return (uint32_t *)&entry->data[offset];
266 }
267
268 uint32_t
error_decode_xe_vm_entry_address_get_len(const struct xe_vm_entry * entry,const uint64_t address)269 error_decode_xe_vm_entry_address_get_len(const struct xe_vm_entry *entry,
270 const uint64_t address)
271 {
272 return entry->length - (address - entry->address);
273 }
274
275 bool
error_decode_xe_ascii85_decode_allocated(const char * in,uint32_t * out,uint32_t vm_entry_bytes_len)276 error_decode_xe_ascii85_decode_allocated(const char *in, uint32_t *out, uint32_t vm_entry_bytes_len)
277 {
278 const uint32_t dword_len = vm_entry_bytes_len / sizeof(uint32_t);
279 uint32_t i;
280
281 for (i = 0; (*in >= '!') && (*in <= 'z') && (i < dword_len); i++)
282 in = ascii85_decode_char(in, &out[i]);
283
284 if (dword_len != i)
285 printf("mismatch dword_len=%u i=%u\n", dword_len, i);
286
287 return dword_len == i && (*in < '!' || *in > 'z');
288 }
289