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 };
83 bool topic_changed = false;
84
85 for (int i = 0; i < ARRAY_SIZE(xe_topic_strings); i++) {
86 if (strncmp(xe_topic_strings[i], line, strlen(xe_topic_strings[i])) == 0) {
87 topic_changed = true;
88 *new_topic = i;
89 break;
90 }
91 }
92
93 return topic_changed;
94 }
95
96 /* return type of VM topic lines like '[200000].data: x...' and points
97 * value_ptr to first char of data of topic type
98 */
99 enum xe_vm_topic_type
error_decode_xe_read_vm_line(const char * line,uint64_t * address,const char ** value_ptr)100 error_decode_xe_read_vm_line(const char *line, uint64_t *address, const char **value_ptr)
101 {
102 enum xe_vm_topic_type type;
103 char text_addr[64];
104 int i;
105
106 if (*line != '[')
107 return XE_VM_TOPIC_TYPE_UNKNOWN;
108
109 for (i = 0, line++; *line != ']'; i++, line++)
110 text_addr[i] = *line;
111
112 text_addr[i] = 0;
113 *address = (uint64_t)strtoull(text_addr, NULL, 16);
114
115 /* at this point line points to last address digit so +3 to point to type */
116 line += 2;
117 switch (*line) {
118 case 'd':
119 type = XE_VM_TOPIC_TYPE_DATA;
120 break;
121 case 'l':
122 type = XE_VM_TOPIC_TYPE_LENGTH;
123 break;
124 case 'e':
125 type = XE_VM_TOPIC_TYPE_ERROR;
126 break;
127 default:
128 printf("type char: %c\n", *line);
129 return XE_VM_TOPIC_TYPE_UNKNOWN;
130 }
131
132 for (; *line != ':'; line++);
133
134 *value_ptr = line + 2;
135 return type;
136 }
137
138 /*
139 * similar to read_xe_vm_line() but it parses '[HWCTX].data: ...'
140 */
141 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)142 error_decode_xe_read_hw_sp_or_ctx_line(const char *line, const char **value_ptr, bool *is_hw_ctx)
143 {
144 enum xe_vm_topic_type type;
145 char text_addr[64];
146 bool is_hw_sp;
147 int i;
148
149 if (*line != '\t')
150 return XE_VM_TOPIC_TYPE_UNKNOWN;
151
152 line++;
153 if (*line != '[')
154 return XE_VM_TOPIC_TYPE_UNKNOWN;
155
156 for (i = 0, line++; *line != ']'; i++, line++)
157 text_addr[i] = *line;
158
159 text_addr[i] = 0;
160 *is_hw_ctx = strncmp(text_addr, "HWCTX", strlen("HWCTX")) == 0;
161 is_hw_sp = strncmp(text_addr, "HWSP", strlen("HWSP")) == 0;
162 if (*is_hw_ctx == false && is_hw_sp == false)
163 return XE_VM_TOPIC_TYPE_UNKNOWN;
164
165 /* at this point line points to last address digit so +3 to point to type */
166 line += 2;
167 switch (*line) {
168 case 'd':
169 type = XE_VM_TOPIC_TYPE_DATA;
170 break;
171 case 'l':
172 type = XE_VM_TOPIC_TYPE_LENGTH;
173 break;
174 case 'e':
175 type = XE_VM_TOPIC_TYPE_ERROR;
176 break;
177 default:
178 printf("type char: %c\n", *line);
179 return XE_VM_TOPIC_TYPE_UNKNOWN;
180 }
181
182 for (; *line != ':'; line++);
183
184 *value_ptr = line + 2;
185 return type;
186 }
187
error_decode_xe_vm_init(struct xe_vm * xe_vm)188 void error_decode_xe_vm_init(struct xe_vm *xe_vm)
189 {
190 xe_vm->entries = NULL;
191 xe_vm->entries_len = 0;
192 memset(&xe_vm->hw_context, 0, sizeof(xe_vm->hw_context));
193 }
194
error_decode_xe_vm_fini(struct xe_vm * xe_vm)195 void error_decode_xe_vm_fini(struct xe_vm *xe_vm)
196 {
197 uint32_t i;
198
199 for (i = 0; i < xe_vm->entries_len; i++)
200 free((uint32_t *)xe_vm->entries[i].data);
201
202 free((uint32_t *)xe_vm->hw_context.data);
203 free(xe_vm->entries);
204 }
205
206 static void
xe_vm_entry_set(struct xe_vm_entry * entry,const uint64_t address,const uint32_t length,const uint32_t * data)207 xe_vm_entry_set(struct xe_vm_entry *entry, const uint64_t address,
208 const uint32_t length, const uint32_t *data)
209 {
210 entry->address = address;
211 entry->length = length;
212 entry->data = data;
213 }
214
215 void
error_decode_xe_vm_hw_ctx_set(struct xe_vm * xe_vm,const uint32_t length,const uint32_t * data)216 error_decode_xe_vm_hw_ctx_set(struct xe_vm *xe_vm, const uint32_t length,
217 const uint32_t *data)
218 {
219 xe_vm_entry_set(&xe_vm->hw_context, 0, length, data);
220 }
221
222 /*
223 * error_decode_xe_vm_fini() will take care to free data
224 */
225 bool
error_decode_xe_vm_append(struct xe_vm * xe_vm,const uint64_t address,const uint32_t length,const uint32_t * data)226 error_decode_xe_vm_append(struct xe_vm *xe_vm, const uint64_t address,
227 const uint32_t length, const uint32_t *data)
228 {
229 size_t len = sizeof(*xe_vm->entries) * (xe_vm->entries_len + 1);
230
231 xe_vm->entries = realloc(xe_vm->entries, len);
232 if (!xe_vm->entries)
233 return false;
234
235 xe_vm_entry_set(&xe_vm->entries[xe_vm->entries_len], address, length, data);
236 xe_vm->entries_len++;
237 return true;
238 }
239
240 const struct xe_vm_entry *
error_decode_xe_vm_entry_get(struct xe_vm * xe_vm,const uint64_t address)241 error_decode_xe_vm_entry_get(struct xe_vm *xe_vm, const uint64_t address)
242 {
243 uint32_t i;
244
245 for (i = 0; i < xe_vm->entries_len; i++) {
246 struct xe_vm_entry *entry = &xe_vm->entries[i];
247
248 if (entry->address == address)
249 return entry;
250
251 if (address > entry->address &&
252 address < (entry->address + entry->length))
253 return entry;
254 }
255
256 return NULL;
257 }
258
259 uint32_t *
error_decode_xe_vm_entry_address_get_data(const struct xe_vm_entry * entry,const uint64_t address)260 error_decode_xe_vm_entry_address_get_data(const struct xe_vm_entry *entry,
261 const uint64_t address)
262 {
263 uint32_t offset = (address - entry->address) / sizeof(uint32_t);
264 return (uint32_t *)&entry->data[offset];
265 }
266
267 uint32_t
error_decode_xe_vm_entry_address_get_len(const struct xe_vm_entry * entry,const uint64_t address)268 error_decode_xe_vm_entry_address_get_len(const struct xe_vm_entry *entry,
269 const uint64_t address)
270 {
271 return entry->length - (address - entry->address);
272 }
273
274 bool
error_decode_xe_ascii85_decode_allocated(const char * in,uint32_t * out,uint32_t vm_entry_bytes_len)275 error_decode_xe_ascii85_decode_allocated(const char *in, uint32_t *out, uint32_t vm_entry_bytes_len)
276 {
277 const uint32_t dword_len = vm_entry_bytes_len / sizeof(uint32_t);
278 uint32_t i;
279
280 for (i = 0; (*in >= '!') && (*in <= 'z') && (i < dword_len); i++)
281 in = ascii85_decode_char(in, &out[i]);
282
283 if (dword_len != i)
284 printf("mismatch dword_len=%u i=%u\n", dword_len, i);
285
286 return dword_len == i && (*in < '!' || *in > 'z');
287 }
288