xref: /openbmc/libcper/cper-utils.c (revision 3f810e5b3c2b8eb217ebc47dd4b17b9ec5ccea24)
1 /**
2  * Describes utility functions for parsing CPER into JSON IR.
3  *
4  * Author: Lawrence.Tang@arm.com
5  **/
6 
7 #include <ctype.h>
8 #include <stdio.h>
9 #include <json.h>
10 #include <string.h>
11 #include <libcper/Cper.h>
12 #include <libcper/cper-utils.h>
13 #include <libcper/log.h>
14 #include <libcper/base64.h>
15 
16 //The available severity types for CPER.
17 const char *CPER_SEVERITY_TYPES[4] = { "Recoverable", "Fatal", "Corrected",
18 				       "Informational" };
19 
20 //Converts the given generic CPER error status to JSON IR.
21 json_object *
cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS * error_status)22 cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS *error_status)
23 {
24 	json_object *error_status_ir = json_object_new_object();
25 
26 	//Error type.
27 	json_object_object_add(error_status_ir, "errorType",
28 			       integer_to_readable_pair_with_desc(
29 				       error_status->Type, 18,
30 				       CPER_GENERIC_ERROR_TYPES_KEYS,
31 				       CPER_GENERIC_ERROR_TYPES_VALUES,
32 				       CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS,
33 				       "Unknown (Reserved)"));
34 
35 	//Boolean bit fields.
36 	add_bool(error_status_ir, "addressSignal", error_status->AddressSignal);
37 	add_bool(error_status_ir, "controlSignal", error_status->ControlSignal);
38 	add_bool(error_status_ir, "dataSignal", error_status->DataSignal);
39 	add_bool(error_status_ir, "detectedByResponder",
40 		 error_status->DetectedByResponder);
41 	add_bool(error_status_ir, "detectedByRequester",
42 		 error_status->DetectedByRequester);
43 	add_bool(error_status_ir, "firstError", error_status->FirstError);
44 	add_bool(error_status_ir, "overflowDroppedLogs",
45 		 error_status->OverflowNotLogged);
46 
47 	return error_status_ir;
48 }
49 
50 //Converts the given CPER-JSON generic error status into a CPER structure.
ir_generic_error_status_to_cper(json_object * error_status,EFI_GENERIC_ERROR_STATUS * error_status_cper)51 void ir_generic_error_status_to_cper(
52 	json_object *error_status, EFI_GENERIC_ERROR_STATUS *error_status_cper)
53 {
54 	error_status_cper->Type = readable_pair_to_integer(
55 		json_object_object_get(error_status, "errorType"));
56 	error_status_cper->AddressSignal = json_object_get_boolean(
57 		json_object_object_get(error_status, "addressSignal"));
58 	error_status_cper->ControlSignal = json_object_get_boolean(
59 		json_object_object_get(error_status, "controlSignal"));
60 	error_status_cper->DataSignal = json_object_get_boolean(
61 		json_object_object_get(error_status, "dataSignal"));
62 	error_status_cper->DetectedByResponder = json_object_get_boolean(
63 		json_object_object_get(error_status, "detectedByResponder"));
64 	error_status_cper->DetectedByRequester = json_object_get_boolean(
65 		json_object_object_get(error_status, "detectedByRequester"));
66 	error_status_cper->FirstError = json_object_get_boolean(
67 		json_object_object_get(error_status, "firstError"));
68 	error_status_cper->OverflowNotLogged = json_object_get_boolean(
69 		json_object_object_get(error_status, "overflowDroppedLogs"));
70 }
71 
72 //Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order.
uniform_struct64_to_ir(UINT64 * start,int len,const char * names[])73 json_object *uniform_struct64_to_ir(UINT64 *start, int len, const char *names[])
74 {
75 	json_object *result = json_object_new_object();
76 
77 	UINT64 *cur = start;
78 	for (int i = 0; i < len; i++) {
79 		add_uint(result, names[i], *cur);
80 		cur++;
81 	}
82 
83 	return result;
84 }
85 
86 //Converts a single uniform struct of UINT32s into intermediate JSON IR format, given names for each field in byte order.
uniform_struct_to_ir(UINT32 * start,int len,const char * names[])87 json_object *uniform_struct_to_ir(UINT32 *start, int len, const char *names[])
88 {
89 	json_object *result = json_object_new_object();
90 
91 	UINT32 *cur = start;
92 	for (int i = 0; i < len; i++) {
93 		UINT32 value;
94 		memcpy(&value, cur, sizeof(UINT32));
95 		add_uint(result, names[i], value);
96 		cur++;
97 	}
98 
99 	return result;
100 }
101 
102 //Converts a single object containing UINT32s into a uniform struct.
ir_to_uniform_struct64(json_object * ir,UINT64 * start,int len,const char * names[])103 void ir_to_uniform_struct64(json_object *ir, UINT64 *start, int len,
104 			    const char *names[])
105 {
106 	UINT64 *cur = start;
107 	for (int i = 0; i < len; i++) {
108 		*cur = json_object_get_uint64(
109 			json_object_object_get(ir, names[i]));
110 		cur++;
111 	}
112 }
113 
114 //Converts a single object containing UINT32s into a uniform struct.
ir_to_uniform_struct(json_object * ir,UINT32 * start,int len,const char * names[])115 void ir_to_uniform_struct(json_object *ir, UINT32 *start, int len,
116 			  const char *names[])
117 {
118 	UINT32 *cur = start;
119 	for (int i = 0; i < len; i++) {
120 		*cur = (UINT32)json_object_get_uint64(
121 			json_object_object_get(ir, names[i]));
122 		cur++;
123 	}
124 }
125 
126 //Converts a single integer value to an object containing a value, and a readable name if possible.
integer_to_readable_pair(UINT64 value,int len,const int keys[],const char * values[],const char * default_value)127 json_object *integer_to_readable_pair(UINT64 value, int len, const int keys[],
128 				      const char *values[],
129 				      const char *default_value)
130 {
131 	json_object *result = json_object_new_object();
132 	add_uint(result, "value", value);
133 
134 	//Search for human readable name, add.
135 	const char *name = default_value;
136 	for (int i = 0; i < len; i++) {
137 		if ((UINT64)keys[i] == value) {
138 			name = values[i];
139 		}
140 	}
141 
142 	add_string(result, "name", name);
143 	return result;
144 }
145 
146 //Converts a single integer value to an object containing a value, readable name and description if possible.
integer_to_readable_pair_with_desc(int value,int len,const int keys[],const char * values[],const char * descriptions[],const char * default_value)147 json_object *integer_to_readable_pair_with_desc(int value, int len,
148 						const int keys[],
149 						const char *values[],
150 						const char *descriptions[],
151 						const char *default_value)
152 {
153 	json_object *result = json_object_new_object();
154 	add_int(result, "value", value);
155 
156 	//Search for human readable name, add.
157 	const char *name = default_value;
158 	for (int i = 0; i < len; i++) {
159 		if (keys[i] == value) {
160 			name = values[i];
161 			add_string(result, "description", descriptions[i]);
162 		}
163 	}
164 
165 	add_string(result, "name", name);
166 	return result;
167 }
168 
169 //Returns a single UINT64 value from the given readable pair object.
170 //Assumes the integer value is held in the "value" field.
readable_pair_to_integer(json_object * pair)171 UINT64 readable_pair_to_integer(json_object *pair)
172 {
173 	return json_object_get_uint64(json_object_object_get(pair, "value"));
174 }
175 
176 //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left.
bitfield_to_ir(UINT64 bitfield,int num_fields,const char * names[])177 json_object *bitfield_to_ir(UINT64 bitfield, int num_fields,
178 			    const char *names[])
179 {
180 	json_object *result = json_object_new_object();
181 	for (int i = 0; i < num_fields; i++) {
182 		add_bool(result, names[i], (bitfield >> i) & 0x1);
183 	}
184 
185 	return result;
186 }
187 
188 //Filters properties based on Validation Bits.
189 // Refer to CPER spec for vbit_idx to be passed here.
add_to_valid_bitfield(ValidationTypes * val,int vbit_idx)190 void add_to_valid_bitfield(ValidationTypes *val, int vbit_idx)
191 {
192 	switch (val->size) {
193 	case UINT_8T:
194 		val->value.ui8 |= (0x01 << vbit_idx);
195 		break;
196 	case UINT_16T:
197 		val->value.ui16 |= (0x01 << vbit_idx);
198 		break;
199 	case UINT_32T:
200 		val->value.ui32 |= (0x01 << vbit_idx);
201 		break;
202 	case UINT_64T:
203 		val->value.ui64 |= (0x01 << vbit_idx);
204 		break;
205 	default:
206 		cper_print_log(
207 			"IR to CPER: Unknown validation bits size passed, Enum IntType=%d",
208 			val->size);
209 	}
210 }
211 
212 //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0.
ir_to_bitfield(json_object * ir,int num_fields,const char * names[])213 UINT64 ir_to_bitfield(json_object *ir, int num_fields, const char *names[])
214 {
215 	UINT64 result = 0x0;
216 	for (int i = 0; i < num_fields; i++) {
217 		if (json_object_get_boolean(
218 			    json_object_object_get(ir, names[i]))) {
219 			result |= (0x1 << i);
220 		}
221 	}
222 
223 	return result;
224 }
225 
226 // Filters properties based on Validation Bits.
227 // Refer to CPER spec for vbit_idx to be passed here.
228 // Overload function for 16, 32, 64b
isvalid_prop_to_ir(ValidationTypes * val,int vbit_idx)229 bool isvalid_prop_to_ir(ValidationTypes *val, int vbit_idx)
230 {
231 // If the option is enabled, output invalid properties
232 // as well as valid ones.
233 #ifdef OUTPUT_ALL_PROPERTIES
234 	return true;
235 #endif //OUTPUT_ALL_PROPERTIES
236 	UINT64 vbit_mask = 0x01 << vbit_idx;
237 	switch (val->size) {
238 	case UINT_16T:
239 		return (vbit_mask & val->value.ui16);
240 
241 	case UINT_32T:
242 		return (vbit_mask & val->value.ui32);
243 
244 	case UINT_64T:
245 		return (vbit_mask & val->value.ui64);
246 
247 	default:
248 		cper_print_log(
249 			"CPER to IR:Unknown validation bits size passed. Enum IntType: %d",
250 			val->size);
251 	}
252 	return 0;
253 }
254 
print_val(ValidationTypes * val)255 void print_val(ValidationTypes *val)
256 {
257 	switch (val->size) {
258 	case UINT_8T:
259 		cper_print_log("Validation bits: %x\n", val->value.ui8);
260 		break;
261 	case UINT_16T:
262 		cper_print_log("Validation bits: %x\n", val->value.ui16);
263 		break;
264 
265 	case UINT_32T:
266 		cper_print_log("Validation bits: %x\n", val->value.ui32);
267 		break;
268 
269 	case UINT_64T:
270 		cper_print_log("Validation bits: %llx\n", val->value.ui64);
271 		break;
272 
273 	default:
274 		cper_print_log(
275 			"CPER to IR:Unknown validation bits size passed. Enum IntType: %d",
276 			val->size);
277 	}
278 }
279 
280 //Converts the given UINT64 array into a JSON IR array, given the length.
uint64_array_to_ir_array(UINT64 * array,int len)281 json_object *uint64_array_to_ir_array(UINT64 *array, int len)
282 {
283 	json_object *array_ir = json_object_new_array();
284 	for (int i = 0; i < len; i++) {
285 		json_object_array_add(array_ir,
286 				      json_object_new_uint64(array[i]));
287 	}
288 	return array_ir;
289 }
290 
291 //Converts a single UINT16 revision number into JSON IR representation.
revision_to_ir(UINT16 revision)292 json_object *revision_to_ir(UINT16 revision)
293 {
294 	json_object *revision_info = json_object_new_object();
295 	add_int(revision_info, "major", revision >> 8);
296 	add_int(revision_info, "minor", revision & 0xFF);
297 	return revision_info;
298 }
299 
300 //Returns the appropriate string for the given integer severity.
severity_to_string(UINT32 severity)301 const char *severity_to_string(UINT32 severity)
302 {
303 	return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown";
304 }
305 
306 //Converts a single EFI timestamp to string, at the given output.
307 //Output must be at least TIMESTAMP_LENGTH bytes long.
timestamp_to_string(char * out,int out_len,EFI_ERROR_TIME_STAMP * timestamp)308 int timestamp_to_string(char *out, int out_len, EFI_ERROR_TIME_STAMP *timestamp)
309 {
310 	//Cannot go to three digits.
311 	int century = bcd_to_int(timestamp->Century) % 100;
312 	if (century >= 100) {
313 		return -1;
314 	}
315 	int year = bcd_to_int(timestamp->Year) % 100;
316 	if (year >= 100) {
317 		return -1;
318 	}
319 	int month = bcd_to_int(timestamp->Month);
320 	if (month > 12) {
321 		return -1;
322 	}
323 	int day = bcd_to_int(timestamp->Day);
324 	if (day > 31) {
325 		return -1;
326 	}
327 	int hours = bcd_to_int(timestamp->Hours);
328 	if (hours > 24) {
329 		return -1;
330 	}
331 	int minutes = bcd_to_int(timestamp->Minutes);
332 	if (minutes > 60) {
333 		return -1;
334 	}
335 	int seconds = bcd_to_int(timestamp->Seconds);
336 	if (seconds >= 60) {
337 		return -1;
338 	}
339 	int written = snprintf(
340 		out, out_len,
341 		"%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu+00:00",
342 		century, year, month, day, hours, minutes, seconds);
343 
344 	if (written < 0 || written >= out_len) {
345 		cper_print_log("Timestamp buffer of insufficient size\n");
346 		return -1;
347 	}
348 	return 0;
349 }
350 
351 //Converts a single timestamp string to an EFI timestamp.
string_to_timestamp(EFI_ERROR_TIME_STAMP * out,const char * timestamp)352 void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp)
353 {
354 	//Ignore invalid timestamps.
355 	if (timestamp == NULL) {
356 		return;
357 	}
358 
359 	sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu+00:00",
360 	       &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours,
361 	       &out->Minutes, &out->Seconds);
362 
363 	//Convert back to BCD.
364 	out->Century = int_to_bcd(out->Century);
365 	out->Year = int_to_bcd(out->Year);
366 	out->Month = int_to_bcd(out->Month);
367 	out->Day = int_to_bcd(out->Day);
368 	out->Hours = int_to_bcd(out->Hours);
369 	out->Minutes = int_to_bcd(out->Minutes);
370 	out->Seconds = int_to_bcd(out->Seconds);
371 }
372 
373 //Helper function to convert an EDK EFI GUID into a string for intermediate use.
guid_to_string(char * out,size_t out_len,EFI_GUID * guid)374 int guid_to_string(char *out, size_t out_len, EFI_GUID *guid)
375 {
376 	size_t len = snprintf(
377 		out, out_len,
378 		"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->Data1,
379 		guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
380 		guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5],
381 		guid->Data4[6], guid->Data4[7]);
382 	if (len != out_len) {
383 		return -1;
384 	}
385 	return len;
386 }
387 
388 //Helper function to convert a string into an EDK EFI GUID.
string_to_guid(EFI_GUID * out,const char * guid)389 void string_to_guid(EFI_GUID *out, const char *guid)
390 {
391 	//Ignore invalid GUIDs.
392 	if (guid == NULL) {
393 		return;
394 	}
395 
396 	sscanf(guid,
397 	       "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
398 	       &out->Data1, &out->Data2, &out->Data3, out->Data4,
399 	       out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4,
400 	       out->Data4 + 5, out->Data4 + 6, out->Data4 + 7);
401 }
402 
403 //Returns one if two EFI GUIDs are equal, zero otherwise.
guid_equal(const EFI_GUID * a,const EFI_GUID * b)404 int guid_equal(const EFI_GUID *a, const EFI_GUID *b)
405 {
406 	//Check top base 3 components.
407 	if (a->Data1 != b->Data1 || a->Data2 != b->Data2 ||
408 	    a->Data3 != b->Data3) {
409 		return 0;
410 	}
411 
412 	//Check Data4 array for equality.
413 	for (int i = 0; i < 8; i++) {
414 		if (a->Data4[i] != b->Data4[i]) {
415 			return 0;
416 		}
417 	}
418 
419 	return 1;
420 }
421 
select_guid_from_list(EFI_GUID * guid,EFI_GUID * guid_list[],int len)422 int select_guid_from_list(EFI_GUID *guid, EFI_GUID *guid_list[], int len)
423 {
424 	int i = 0;
425 	for (; i < len; i++) {
426 		if (guid_equal(guid, guid_list[i])) {
427 			break;
428 		}
429 	}
430 	// It's unlikely fuzzing can reliably come up with a correct guid, given how
431 	// much entropy there is.  If we're in fuzzing mode, and if we haven't found
432 	// a match, try to force a match so we get some coverage.  Note, we still
433 	// want coverage of the section failed to convert code, so treat index ==
434 	// size as section failed to convert.
435 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
436 	if (i == len) {
437 		i = guid->Data1 % (len + 1);
438 	}
439 #endif
440 
441 	return i;
442 }
443 
cper_printable_string_length(const char * str,int number_chars)444 int cper_printable_string_length(const char *str, int number_chars)
445 {
446 	if (str == NULL) {
447 		return -1; // Return 0 for a null pointer input
448 	}
449 
450 	int fru_text_len = 0;
451 	for (; fru_text_len < number_chars; fru_text_len++) {
452 		char c = str[fru_text_len];
453 		if (c == '\0') {
454 			break;
455 		}
456 		if (!isprint(c)) {
457 			fru_text_len = -1;
458 			break;
459 		}
460 	}
461 
462 	if (fru_text_len == 0 || fru_text_len == number_chars) {
463 		// string was not null terminated
464 		return -1;
465 	}
466 
467 	return fru_text_len;
468 }
469 
hex_string_to_bytes(const char * hex_string,size_t hex_string_len,UINT8 * bytes,size_t bytes_len)470 size_t hex_string_to_bytes(const char *hex_string, size_t hex_string_len,
471 			   UINT8 *bytes, size_t bytes_len)
472 {
473 	if (hex_string == NULL || bytes == NULL) {
474 		return -1;
475 	}
476 
477 	size_t index = 0;
478 	UINT8 value = 0;
479 	while (index < hex_string_len) {
480 		char c = hex_string[index];
481 		if (c >= '0' && c <= '9') {
482 			value += (c - '0');
483 		} else if (c >= 'A' && c <= 'F') {
484 			value += (10 + (c - 'A'));
485 		} else if (c >= 'a' && c <= 'f') {
486 			value += (10 + (c - 'a'));
487 		} else {
488 			return -1;
489 		}
490 		if (index % 2 == 1) {
491 			bytes[index / 2] = value;
492 			value = 0;
493 		} else {
494 			value <<= 4;
495 		}
496 
497 		index++;
498 	}
499 
500 	// Failed to write all bytes
501 	if (index != bytes_len * 2) {
502 		return -1;
503 	}
504 
505 	return bytes_len;
506 }
507 
add_untrusted_string(json_object * ir,const char * field_name,const char * str,int len)508 void add_untrusted_string(json_object *ir, const char *field_name,
509 			  const char *str, int len)
510 {
511 	int fru_text_len = cper_printable_string_length(str, len);
512 	if (fru_text_len >= 0) {
513 		add_string_len(ir, field_name, str, fru_text_len);
514 	}
515 }
516 
add_guid(json_object * ir,const char * field_name,EFI_GUID * guid)517 void add_guid(json_object *ir, const char *field_name, EFI_GUID *guid)
518 {
519 	char platform_string[GUID_STRING_LENGTH + 1];
520 	if (!guid_to_string(platform_string, sizeof(platform_string), guid)) {
521 		return;
522 	}
523 	add_string_len(ir, field_name, platform_string,
524 		       sizeof(platform_string) - 1);
525 }
add_string(json_object * register_ir,const char * field_name,const char * value)526 void add_string(json_object *register_ir, const char *field_name,
527 		const char *value)
528 {
529 	json_object_object_add(register_ir, field_name,
530 			       json_object_new_string(value));
531 }
532 
add_string_len(json_object * register_ir,const char * field_name,const char * value,int len)533 void add_string_len(json_object *register_ir, const char *field_name,
534 		    const char *value, int len)
535 {
536 	json_object_object_add(register_ir, field_name,
537 			       json_object_new_string_len(value, len));
538 }
539 
free_char_ptr(char ** char_ptr)540 void free_char_ptr(char **char_ptr)
541 {
542 	free(*char_ptr);
543 }
544 
add_binary_base64(json_object * register_ir,const char * field_name,const UINT8 * value,int32_t len)545 void add_binary_base64(json_object *register_ir, const char *field_name,
546 		       const UINT8 *value, int32_t len)
547 {
548 	if (value == NULL || len <= 0) {
549 		return;
550 	}
551 	int32_t encoded_len = 0;
552 	char *encoded __attribute__((cleanup(free_char_ptr))) =
553 		base64_encode(value, len, &encoded_len);
554 	if (encoded == NULL) {
555 		return;
556 	}
557 	add_string_len(register_ir, field_name, encoded, encoded_len);
558 }
559 
add_uint(json_object * register_ir,const char * field_name,uint64_t value)560 void add_uint(json_object *register_ir, const char *field_name, uint64_t value)
561 {
562 	json_object_object_add(register_ir, field_name,
563 			       json_object_new_uint64(value));
564 }
565 
add_int(json_object * register_ir,const char * field_name,int64_t value)566 void add_int(json_object *register_ir, const char *field_name, int64_t value)
567 {
568 	json_object_object_add(register_ir, field_name,
569 			       json_object_new_int(value));
570 }
571 
add_int_hex_common(json_object * register_ir,const char * field_name,UINT64 value,int len)572 static void add_int_hex_common(json_object *register_ir, const char *field_name,
573 			       UINT64 value, int len)
574 {
575 	char hexstring_buf[EFI_UINT64_HEX_STRING_LEN];
576 	snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%0*llX", len,
577 		 value);
578 	add_string(register_ir, field_name, hexstring_buf);
579 }
580 
add_int_hex_8(json_object * register_ir,const char * field_name,UINT8 value)581 void add_int_hex_8(json_object *register_ir, const char *field_name,
582 		   UINT8 value)
583 {
584 	add_int_hex_common(register_ir, field_name, value, 2);
585 }
586 
add_int_hex_16(json_object * register_ir,const char * field_name,UINT16 value)587 void add_int_hex_16(json_object *register_ir, const char *field_name,
588 		    UINT16 value)
589 {
590 	add_int_hex_common(register_ir, field_name, value, 4);
591 }
592 
add_int_hex_24(json_object * register_ir,const char * field_name,UINT64 value)593 void add_int_hex_24(json_object *register_ir, const char *field_name,
594 		    UINT64 value)
595 {
596 	add_int_hex_common(register_ir, field_name, value, 6);
597 }
598 
add_int_hex_32(json_object * register_ir,const char * field_name,UINT64 value)599 void add_int_hex_32(json_object *register_ir, const char *field_name,
600 		    UINT64 value)
601 {
602 	add_int_hex_common(register_ir, field_name, value, 8);
603 }
604 
605 // TODO, deduplicate with get_value_hex_64/32
get_value_hex_8(json_object * obj,const char * field_name,UINT8 * value_out)606 void get_value_hex_8(json_object *obj, const char *field_name, UINT8 *value_out)
607 {
608 	json_object *value = json_object_object_get(obj, field_name);
609 	if (!value) {
610 		return;
611 	}
612 	const char *hex_string = json_object_get_string(value);
613 	if (!hex_string) {
614 		return;
615 	}
616 	UINT8 byte;
617 	size_t hex_string_len = strlen(hex_string);
618 	if (hex_string_len != 4) {
619 		return;
620 	}
621 	if (hex_string[0] != '0' || hex_string[1] != 'x') {
622 		return;
623 	}
624 
625 	if (hex_string_to_bytes(hex_string + 2, hex_string_len - 2, &byte, 1) !=
626 	    1) {
627 		return;
628 	}
629 	*value_out = byte;
630 }
631 
632 // TODO, deduplicate with get_value_hex_64
get_value_hex_32(json_object * obj,const char * field_name,UINT32 * value_out)633 void get_value_hex_32(json_object *obj, const char *field_name,
634 		      UINT32 *value_out)
635 {
636 	json_object *value = json_object_object_get(obj, field_name);
637 	if (!value) {
638 		return;
639 	}
640 	const char *hex_string = json_object_get_string(value);
641 	if (!hex_string) {
642 		return;
643 	}
644 	UINT8 bytes[4];
645 	size_t hex_string_len = strlen(hex_string);
646 	if (hex_string_len != 10) {
647 		return;
648 	}
649 	if (hex_string[0] != '0' || hex_string[1] != 'x') {
650 		return;
651 	}
652 
653 	if (hex_string_to_bytes(hex_string + 2, hex_string_len - 2, bytes,
654 				sizeof(bytes)) != 4) {
655 		return;
656 	}
657 	*value_out = (UINT32)bytes[0] << 24 | (UINT32)bytes[1] << 16 |
658 		     (UINT32)bytes[2] << 8 | (UINT32)bytes[3];
659 }
660 
get_value_hex_64(json_object * obj,const char * field_name,UINT64 * value_out)661 void get_value_hex_64(json_object *obj, const char *field_name,
662 		      UINT64 *value_out)
663 {
664 	json_object *value = json_object_object_get(obj, field_name);
665 	if (!value) {
666 		return;
667 	}
668 	const char *hex_string = json_object_get_string(value);
669 	if (!hex_string) {
670 		return;
671 	}
672 	UINT8 bytes[8];
673 	size_t hex_string_len = strlen(hex_string);
674 	if (hex_string_len != 18) {
675 		return;
676 	}
677 	if (hex_string[0] != '0' || hex_string[1] != 'x') {
678 		return;
679 	}
680 
681 	if (hex_string_to_bytes(hex_string + 2, hex_string_len - 2, bytes,
682 				sizeof(bytes)) != 8) {
683 		return;
684 	}
685 	*value_out = (UINT64)bytes[0] << 56 | (UINT64)bytes[1] << 48 |
686 		     (UINT64)bytes[2] << 40 | (UINT64)bytes[3] << 32 |
687 		     (UINT64)bytes[4] << 24 | (UINT64)bytes[5] << 16 |
688 		     (UINT64)bytes[6] << 8 | (UINT64)bytes[7];
689 }
690 
add_int_hex_64(json_object * register_ir,const char * field_name,UINT64 value)691 void add_int_hex_64(json_object *register_ir, const char *field_name,
692 		    UINT64 value)
693 {
694 	add_int_hex_common(register_ir, field_name, value, 16);
695 }
696 
add_bytes_hex(json_object * obj,const char * field_name,const UINT8 * bytes,size_t byte_len)697 void add_bytes_hex(json_object *obj, const char *field_name, const UINT8 *bytes,
698 		   size_t byte_len)
699 {
700 	if (obj == NULL || bytes == NULL || byte_len == 0) {
701 		return;
702 	}
703 
704 	size_t hex_len = byte_len * 2;
705 	char *hex_buf = (char *)malloc(hex_len + 1);
706 	if (hex_buf == NULL) {
707 		return;
708 	}
709 
710 	for (size_t i = 0; i < byte_len; i++) {
711 		snprintf(&hex_buf[i * 2], 3, "%02x", bytes[i]);
712 	}
713 	hex_buf[hex_len] = '\0';
714 
715 	json_object_object_add(obj, field_name,
716 			       json_object_new_string_len(hex_buf,
717 							  (int)hex_len));
718 	free(hex_buf);
719 }
720 
721 // Convert hex character to nibble value, returns -1 on invalid input
hex_char_to_nibble(char c)722 static int hex_char_to_nibble(char c)
723 {
724 	if (c >= '0' && c <= '9') {
725 		return c - '0';
726 	}
727 	if (c >= 'a' && c <= 'f') {
728 		return c - 'a' + 10;
729 	}
730 	if (c >= 'A' && c <= 'F') {
731 		return c - 'A' + 10;
732 	}
733 	return -1;
734 }
735 
736 // Returns malloc'd buffer (caller must free), or NULL on error
get_bytes_hex(json_object * obj,const char * field_name,size_t * out_len)737 UINT8 *get_bytes_hex(json_object *obj, const char *field_name, size_t *out_len)
738 {
739 	if (obj == NULL || out_len == NULL) {
740 		return NULL;
741 	}
742 
743 	json_object *field = json_object_object_get(obj, field_name);
744 	if (field == NULL || !json_object_is_type(field, json_type_string)) {
745 		return NULL;
746 	}
747 
748 	const char *hex_str = json_object_get_string(field);
749 	if (hex_str == NULL) {
750 		return NULL;
751 	}
752 	size_t hex_len = (size_t)json_object_get_string_len(field);
753 
754 	// Must have even number of hex characters
755 	if (hex_len % 2 != 0) {
756 		return NULL;
757 	}
758 
759 	size_t byte_len = hex_len / 2;
760 	UINT8 *bytes = (UINT8 *)malloc(byte_len);
761 	if (bytes == NULL) {
762 		return NULL;
763 	}
764 
765 	for (size_t i = 0; i < byte_len; i++) {
766 		int high = hex_char_to_nibble(hex_str[i * 2]);
767 		int low = hex_char_to_nibble(hex_str[i * 2 + 1]);
768 		if (high < 0 || low < 0) {
769 			free(bytes);
770 			return NULL;
771 		}
772 		bytes[i] = (UINT8)((high << 4) | low);
773 	}
774 
775 	*out_len = byte_len;
776 	return bytes;
777 }
778 
add_bool(json_object * register_ir,const char * field_name,UINT64 value)779 void add_bool(json_object *register_ir, const char *field_name, UINT64 value)
780 {
781 	json_object_object_add(register_ir, field_name,
782 			       json_object_new_boolean(value));
783 }
784 
add_bool_enum(json_object * register_ir,const char * field_name,const char * value_dict[2],UINT64 value_int)785 void add_bool_enum(json_object *register_ir, const char *field_name,
786 		   const char *value_dict[2], UINT64 value_int)
787 {
788 	const char *value = value_dict[0];
789 	if (value_int > 0) {
790 		value = value_dict[1];
791 	}
792 	add_string(register_ir, field_name, value);
793 }
794 
add_dict(json_object * register_ir,const char * field_name,UINT64 value,const char * dict[],size_t dict_size)795 void add_dict(json_object *register_ir, const char *field_name, UINT64 value,
796 	      const char *dict[], size_t dict_size)
797 {
798 	json_object *field_ir = json_object_new_object();
799 	json_object_object_add(register_ir, field_name, field_ir);
800 	add_uint(field_ir, "raw", value);
801 
802 	if (dict != NULL) {
803 		if (value < dict_size) {
804 			const char *name = dict[value];
805 			if (name != NULL) {
806 				const char *value_name = name;
807 
808 				add_string(field_ir, "value", value_name);
809 			}
810 		}
811 	}
812 }
813