xref: /openbmc/libcper/tests/ir-tests.c (revision 55968b12e1e0aaaf0e70215e47d8a93706dab21b)
1 /**
2  * Defines tests for validating CPER-JSON IR output from the cper-parse library.
3  *
4  * Author: Lawrence.Tang@arm.com
5  **/
6 
7 #include "test-utils.h"
8 #include "string.h"
9 #include "assert.h"
10 #include <ctype.h>
11 #include <json.h>
12 #include <libcper/cper-parse.h>
13 #include <libcper/generator/cper-generate.h>
14 #include <libcper/generator/sections/gen-section.h>
15 #include <libcper/json-schema.h>
16 #include <libcper/sections/cper-section.h>
17 
18 #include "base64_test.h"
19 
20 /*
21 * Test templates.
22 */
23 static const GEN_VALID_BITS_TEST_TYPE allValidbitsSet = ALL_VALID;
24 static const GEN_VALID_BITS_TEST_TYPE fixedValidbitsSet = SOME_VALID;
25 static const int GEN_EXAMPLES = 0;
26 
27 static const char *cper_ext = "cperhex";
28 static const char *json_ext = "json";
29 
30 struct file_info {
31 	char *cper_out;
32 	char *json_out;
33 };
34 
free_file_info(struct file_info * info)35 void free_file_info(struct file_info *info)
36 {
37 	if (info == NULL) {
38 		return;
39 	}
40 	free(info->cper_out);
41 	free(info->json_out);
42 	free(info);
43 }
44 
file_info_init(const char * section_name)45 struct file_info *file_info_init(const char *section_name)
46 {
47 	struct file_info *info = NULL;
48 	char *buf = NULL;
49 	size_t size;
50 	int ret;
51 
52 	info = (struct file_info *)calloc(1, sizeof(struct file_info));
53 	if (info == NULL) {
54 		goto fail;
55 	}
56 
57 	size = strlen(LIBCPER_EXAMPLES) + 1 + strlen(section_name) + 1 +
58 	       strlen(cper_ext) + 1;
59 	info->cper_out = (char *)malloc(size);
60 	ret = snprintf(info->cper_out, size, "%s/%s.%s", LIBCPER_EXAMPLES,
61 		       section_name, cper_ext);
62 	if (ret != (int)size - 1) {
63 		printf("snprintf0 failed\n");
64 		goto fail;
65 	}
66 	size = strlen(LIBCPER_EXAMPLES) + 1 + strlen(section_name) + 1 +
67 	       strlen(json_ext) + 1;
68 	info->json_out = (char *)malloc(size);
69 	ret = snprintf(info->json_out, size, "%s/%s.%s", LIBCPER_EXAMPLES,
70 		       section_name, json_ext);
71 	if (ret != (int)size - 1) {
72 		printf("snprintf3 failed\n");
73 		goto fail;
74 	}
75 	free(buf);
76 	return info;
77 
78 fail:
79 	free(buf);
80 	free_file_info(info);
81 	return NULL;
82 }
83 
cper_create_examples(const char * section_name)84 void cper_create_examples(const char *section_name)
85 {
86 	//Generate full CPER record for the given type.
87 	json_object *ir = NULL;
88 	size_t size;
89 	size_t file_size;
90 	FILE *outFile = NULL;
91 	unsigned char *file_data;
92 	FILE *record = NULL;
93 	char *buf = NULL;
94 	struct file_info *info = file_info_init(section_name);
95 	if (info == NULL) {
96 		goto done;
97 	}
98 
99 	record = generate_record_memstream(&section_name, 1, &buf, &size, 0,
100 					   fixedValidbitsSet);
101 
102 	// Write example CPER to disk
103 	outFile = fopen(info->cper_out, "wb");
104 	if (outFile == NULL) {
105 		printf("Failed to create/open CPER output file: %s\n",
106 		       info->cper_out);
107 		goto done;
108 	}
109 
110 	fseek(record, 0, SEEK_END);
111 	file_size = ftell(record);
112 	rewind(record);
113 	file_data = malloc(file_size);
114 	if (fread(file_data, 1, file_size, record) != file_size) {
115 		printf("Failed to read CPER data from memstream.");
116 		fclose(outFile);
117 		assert(0);
118 
119 		goto done;
120 	}
121 	for (size_t index = 0; index < file_size; index++) {
122 		char hex_str[3];
123 		int out = snprintf(hex_str, sizeof(hex_str), "%02x",
124 				   file_data[index]);
125 		if (out != 2) {
126 			printf("snprintf1 failed\n");
127 			goto done;
128 		}
129 		fwrite(hex_str, sizeof(char), 2, outFile);
130 		if (index % 30 == 29) {
131 			fwrite("\n", sizeof(char), 1, outFile);
132 		}
133 	}
134 	fclose(outFile);
135 
136 	//Convert to IR, free resources.
137 	rewind(record);
138 	ir = cper_to_ir(record);
139 	if (ir == NULL) {
140 		printf("Empty JSON from CPER bin2\n");
141 		assert(0);
142 		goto done;
143 	}
144 
145 	//Write json output to disk
146 	json_object_to_file_ext(info->json_out, ir, JSON_C_TO_STRING_PRETTY);
147 	json_object_put(ir);
148 
149 done:
150 	free_file_info(info);
151 	if (record != NULL) {
152 		fclose(record);
153 	}
154 	if (outFile != NULL) {
155 		fclose(outFile);
156 	}
157 	free(buf);
158 }
159 
hex2int(char ch)160 int hex2int(char ch)
161 {
162 	if ((ch >= '0') && (ch <= '9')) {
163 		return ch - '0';
164 	}
165 	if ((ch >= 'A') && (ch <= 'F')) {
166 		return ch - 'A' + 10;
167 	}
168 	if ((ch >= 'a') && (ch <= 'f')) {
169 		return ch - 'a' + 10;
170 	}
171 	return -1;
172 }
173 
string_to_binary(const char * source,size_t length,unsigned char ** retval)174 int string_to_binary(const char *source, size_t length, unsigned char **retval)
175 {
176 	size_t retval_size = length * 2;
177 	*retval = malloc(retval_size);
178 	int uppernibble = 1;
179 
180 	size_t ret_index = 0;
181 
182 	for (size_t i = 0; i < length; i++) {
183 		char c = source[i];
184 		if (c == '\n') {
185 			continue;
186 		}
187 		int val = hex2int(c);
188 		if (val < 0) {
189 			printf("Invalid hex character in test file: %c\n", c);
190 			return -1;
191 		}
192 
193 		if (uppernibble) {
194 			(*retval)[ret_index] = (unsigned char)(val << 4);
195 		} else {
196 			(*retval)[ret_index] += (unsigned char)val;
197 			ret_index++;
198 		}
199 		uppernibble = !uppernibble;
200 	}
201 	return ret_index;
202 }
203 
204 //Tests fixed CPER sections for IR validity with an example set.
cper_example_section_ir_test(const char * section_name)205 void cper_example_section_ir_test(const char *section_name)
206 {
207 	//Open CPER record for the given type.
208 	struct file_info *info = file_info_init(section_name);
209 	if (info == NULL) {
210 		return;
211 	}
212 
213 	FILE *cper_file = fopen(info->cper_out, "rb");
214 	if (cper_file == NULL) {
215 		printf("Failed to open CPER file: %s\n", info->cper_out);
216 		free_file_info(info);
217 		assert(0);
218 		return;
219 	}
220 	fseek(cper_file, 0, SEEK_END);
221 	size_t length = ftell(cper_file);
222 	fseek(cper_file, 0, SEEK_SET);
223 	char *buffer = (char *)malloc(length);
224 	if (!buffer) {
225 		free_file_info(info);
226 		return;
227 	}
228 	if (fread(buffer, 1, length, cper_file) != length) {
229 		printf("Failed to read CPER file: %s\n", info->cper_out);
230 		free(buffer);
231 		free_file_info(info);
232 		return;
233 	}
234 	fclose(cper_file);
235 
236 	unsigned char *cper_bin;
237 	int cper_bin_len = string_to_binary(buffer, length, &cper_bin);
238 	if (cper_bin_len <= 0) {
239 		free(buffer);
240 		free_file_info(info);
241 		assert(0);
242 		return;
243 	}
244 	printf("cper_bin: %s\n", cper_bin);
245 	printf("cper_bin_len: %d\n", cper_bin_len);
246 
247 	//Convert to IR, free resources.
248 	json_object *ir = cper_buf_to_ir(cper_bin, cper_bin_len);
249 	if (ir == NULL) {
250 		printf("Empty JSON from CPER bin3\n");
251 		free(cper_bin);
252 		free(buffer);
253 		free_file_info(info);
254 		assert(0);
255 		return;
256 	}
257 
258 	json_object *expected = json_object_from_file(info->json_out);
259 	assert(expected != NULL);
260 	if (expected == NULL) {
261 		free(buffer);
262 		free(cper_bin);
263 		free_file_info(info);
264 		const char *str = json_object_to_json_string(ir);
265 
266 		const char *expected_str = json_object_to_json_string(expected);
267 		assert(strcmp(str, expected_str) == 0);
268 		return;
269 	}
270 
271 	assert(json_object_equal(ir, expected));
272 	free(buffer);
273 	free(cper_bin);
274 	json_object_put(ir);
275 	json_object_put(expected);
276 	free_file_info(info);
277 }
278 
279 //Tests a single randomly generated CPER section of the given type to ensure CPER-JSON IR validity.
cper_log_section_ir_test(const char * section_name,int single_section,GEN_VALID_BITS_TEST_TYPE validBitsType)280 void cper_log_section_ir_test(const char *section_name, int single_section,
281 			      GEN_VALID_BITS_TEST_TYPE validBitsType)
282 {
283 	//Generate full CPER record for the given type.
284 	char *buf;
285 	size_t size;
286 	FILE *record = generate_record_memstream(&section_name, 1, &buf, &size,
287 						 single_section, validBitsType);
288 
289 	//Convert to IR, free resources.
290 	json_object *ir;
291 	if (single_section) {
292 		ir = cper_single_section_to_ir(record);
293 	} else {
294 		ir = cper_to_ir(record);
295 	}
296 
297 	fclose(record);
298 	free(buf);
299 
300 	//Validate against schema.
301 	int valid = schema_validate_from_file(ir, single_section,
302 					      /*all_valid_bits*/ 1);
303 	json_object_put(ir);
304 
305 	if (valid < 0) {
306 		printf("IR validation test failed (single section mode = %d)\n",
307 		       single_section);
308 		assert(0);
309 	}
310 }
311 
to_hex(const unsigned char * input,size_t size,char ** out)312 int to_hex(const unsigned char *input, size_t size, char **out)
313 {
314 	*out = (char *)malloc(size * 2);
315 	if (out == NULL) {
316 		return -1;
317 	}
318 	int out_index = 0;
319 	for (size_t i = 0; i < size; i++) {
320 		unsigned char c = input[i];
321 		char hex_str[3];
322 		int n = snprintf(hex_str, sizeof(hex_str), "%02x", c);
323 		if (n != 2) {
324 			printf("snprintf2 failed with code %d\n", n);
325 			return -1;
326 		}
327 		(*out)[out_index] = hex_str[0];
328 		out_index++;
329 		(*out)[out_index] = hex_str[1];
330 		out_index++;
331 	}
332 	return out_index;
333 }
334 
335 //Checks for binary round-trip equality for a given randomly generated CPER record.
cper_log_section_binary_test(const char * section_name,int single_section,GEN_VALID_BITS_TEST_TYPE validBitsType)336 void cper_log_section_binary_test(const char *section_name, int single_section,
337 				  GEN_VALID_BITS_TEST_TYPE validBitsType)
338 {
339 	//Generate CPER record for the given type.
340 	char *buf;
341 	size_t size;
342 	FILE *record = generate_record_memstream(&section_name, 1, &buf, &size,
343 						 single_section, validBitsType);
344 	if (record == NULL) {
345 		printf("Could not generate memstream for binary test");
346 		return;
347 	}
348 
349 	//Convert to IR.
350 	json_object *ir;
351 	if (single_section) {
352 		ir = cper_single_section_to_ir(record);
353 	} else {
354 		ir = cper_to_ir(record);
355 	}
356 
357 	//Now convert back to binary, and get a stream out.
358 	char *cper_buf;
359 	size_t cper_buf_size;
360 	FILE *stream = open_memstream(&cper_buf, &cper_buf_size);
361 	if (single_section) {
362 		ir_single_section_to_cper(ir, stream);
363 	} else {
364 		ir_to_cper(ir, stream);
365 	}
366 	fclose(stream);
367 
368 	printf("size: %zu, cper_buf_size: %zu\n", size, cper_buf_size);
369 
370 	char *buf_hex;
371 	int buf_hex_len = to_hex((unsigned char *)buf, size, &buf_hex);
372 	char *cper_buf_hex;
373 	int cper_buf_hex_len =
374 		to_hex((unsigned char *)cper_buf, cper_buf_size, &cper_buf_hex);
375 
376 	printf("%.*s\n", cper_buf_hex_len, cper_buf_hex);
377 	printf("%.*s\n", buf_hex_len, buf_hex);
378 	assert(buf_hex_len == cper_buf_hex_len);
379 	assert(memcmp(buf_hex, cper_buf_hex, buf_hex_len) == 0);
380 
381 	free(buf_hex);
382 	free(cper_buf_hex);
383 
384 	//Free everything up.
385 	fclose(record);
386 	free(buf);
387 	free(cper_buf);
388 	json_object_put(ir);
389 }
390 
391 //Tests randomly generated CPER sections for IR validity of a given type, in both single section mode and full CPER log mode.
cper_log_section_dual_ir_test(const char * section_name)392 void cper_log_section_dual_ir_test(const char *section_name)
393 {
394 	cper_log_section_ir_test(section_name, 0, allValidbitsSet);
395 	cper_log_section_ir_test(section_name, 1, allValidbitsSet);
396 	//Validate against examples
397 	cper_example_section_ir_test(section_name);
398 }
399 
400 //Tests randomly generated CPER sections for binary compatibility of a given type, in both single section mode and full CPER log mode.
cper_log_section_dual_binary_test(const char * section_name)401 void cper_log_section_dual_binary_test(const char *section_name)
402 {
403 	cper_log_section_binary_test(section_name, 0, allValidbitsSet);
404 	cper_log_section_binary_test(section_name, 1, allValidbitsSet);
405 }
406 
407 /*
408 * Non-single section assertions.
409 */
CompileTimeAssertions_TwoWayConversion()410 void CompileTimeAssertions_TwoWayConversion()
411 {
412 	for (size_t i = 0; i < section_definitions_len; i++) {
413 		//If a conversion one way exists, a conversion the other way must exist.
414 		if (section_definitions[i].ToCPER != NULL) {
415 			assert(section_definitions[i].ToIR != NULL);
416 		}
417 		if (section_definitions[i].ToIR != NULL) {
418 			assert(section_definitions[i].ToCPER != NULL);
419 		}
420 	}
421 }
422 
CompileTimeAssertions_ShortcodeNoSpaces()423 void CompileTimeAssertions_ShortcodeNoSpaces()
424 {
425 	for (size_t i = 0; i < generator_definitions_len; i++) {
426 		for (int j = 0;
427 		     generator_definitions[i].ShortName[j + 1] != '\0'; j++) {
428 			assert(isspace(generator_definitions[i].ShortName[j]) ==
429 			       0);
430 		}
431 	}
432 }
433 
434 /*
435 * Single section tests.
436 */
437 
438 //Generic processor tests.
GenericProcessorTests_IRValid()439 void GenericProcessorTests_IRValid()
440 {
441 	cper_log_section_dual_ir_test("generic");
442 }
GenericProcessorTests_BinaryEqual()443 void GenericProcessorTests_BinaryEqual()
444 {
445 	cper_log_section_dual_binary_test("generic");
446 }
447 
448 //IA32/x64 tests.
IA32x64Tests_IRValid()449 void IA32x64Tests_IRValid()
450 {
451 	cper_log_section_dual_ir_test("ia32x64");
452 }
IA32x64Tests_BinaryEqual()453 void IA32x64Tests_BinaryEqual()
454 {
455 	cper_log_section_dual_binary_test("ia32x64");
456 }
457 
458 // void IPFTests_IRValid() {
459 //     cper_log_section_dual_ir_test("ipf");
460 // }
461 
462 //ARM tests.
ArmTests_IRValid()463 void ArmTests_IRValid()
464 {
465 	cper_log_section_dual_ir_test("arm");
466 }
ArmTests_BinaryEqual()467 void ArmTests_BinaryEqual()
468 {
469 	cper_log_section_dual_binary_test("arm");
470 }
471 
472 //Memory tests.
MemoryTests_IRValid()473 void MemoryTests_IRValid()
474 {
475 	cper_log_section_dual_ir_test("memory");
476 }
MemoryTests_BinaryEqual()477 void MemoryTests_BinaryEqual()
478 {
479 	cper_log_section_dual_binary_test("memory");
480 }
481 
482 //Memory 2 tests.
Memory2Tests_IRValid()483 void Memory2Tests_IRValid()
484 {
485 	cper_log_section_dual_ir_test("memory2");
486 }
Memory2Tests_BinaryEqual()487 void Memory2Tests_BinaryEqual()
488 {
489 	cper_log_section_dual_binary_test("memory2");
490 }
491 
492 //PCIe tests.
PCIeTests_IRValid()493 void PCIeTests_IRValid()
494 {
495 	cper_log_section_dual_ir_test("pcie");
496 }
PCIeTests_BinaryEqual()497 void PCIeTests_BinaryEqual()
498 {
499 	cper_log_section_dual_binary_test("pcie");
500 }
501 
502 //Firmware tests.
FirmwareTests_IRValid()503 void FirmwareTests_IRValid()
504 {
505 	cper_log_section_dual_ir_test("firmware");
506 }
FirmwareTests_BinaryEqual()507 void FirmwareTests_BinaryEqual()
508 {
509 	cper_log_section_dual_binary_test("firmware");
510 }
511 
512 //PCI Bus tests.
PCIBusTests_IRValid()513 void PCIBusTests_IRValid()
514 {
515 	cper_log_section_dual_ir_test("pcibus");
516 }
PCIBusTests_BinaryEqual()517 void PCIBusTests_BinaryEqual()
518 {
519 	cper_log_section_dual_binary_test("pcibus");
520 }
521 
522 //PCI Device tests.
PCIDevTests_IRValid()523 void PCIDevTests_IRValid()
524 {
525 	cper_log_section_dual_ir_test("pcidev");
526 }
PCIDevTests_BinaryEqual()527 void PCIDevTests_BinaryEqual()
528 {
529 	cper_log_section_dual_binary_test("pcidev");
530 }
531 
532 //Generic DMAr tests.
DMArGenericTests_IRValid()533 void DMArGenericTests_IRValid()
534 {
535 	cper_log_section_dual_ir_test("dmargeneric");
536 }
DMArGenericTests_BinaryEqual()537 void DMArGenericTests_BinaryEqual()
538 {
539 	cper_log_section_dual_binary_test("dmargeneric");
540 }
541 
542 //VT-d DMAr tests.
DMArVtdTests_IRValid()543 void DMArVtdTests_IRValid()
544 {
545 	cper_log_section_dual_ir_test("dmarvtd");
546 }
DMArVtdTests_BinaryEqual()547 void DMArVtdTests_BinaryEqual()
548 {
549 	cper_log_section_dual_binary_test("dmarvtd");
550 }
551 
552 //IOMMU DMAr tests.
DMArIOMMUTests_IRValid()553 void DMArIOMMUTests_IRValid()
554 {
555 	cper_log_section_dual_ir_test("dmariommu");
556 }
DMArIOMMUTests_BinaryEqual()557 void DMArIOMMUTests_BinaryEqual()
558 {
559 	cper_log_section_dual_binary_test("dmariommu");
560 }
561 
562 //CCIX PER tests.
CCIXPERTests_IRValid()563 void CCIXPERTests_IRValid()
564 {
565 	cper_log_section_dual_ir_test("ccixper");
566 }
CCIXPERTests_BinaryEqual()567 void CCIXPERTests_BinaryEqual()
568 {
569 	cper_log_section_dual_binary_test("ccixper");
570 }
571 
572 //CXL Protocol tests.
CXLProtocolTests_IRValid()573 void CXLProtocolTests_IRValid()
574 {
575 	cper_log_section_dual_ir_test("cxlprotocol");
576 }
CXLProtocolTests_BinaryEqual()577 void CXLProtocolTests_BinaryEqual()
578 {
579 	cper_log_section_dual_binary_test("cxlprotocol");
580 }
581 
582 //CXL Component tests.
CXLComponentTests_IRValid()583 void CXLComponentTests_IRValid()
584 {
585 	cper_log_section_dual_ir_test("cxlcomponent-media");
586 }
CXLComponentTests_BinaryEqual()587 void CXLComponentTests_BinaryEqual()
588 {
589 	cper_log_section_dual_binary_test("cxlcomponent-media");
590 }
591 
592 //NVIDIA section tests.
NVIDIASectionTests_IRValid()593 void NVIDIASectionTests_IRValid()
594 {
595 	cper_log_section_dual_ir_test("nvidia");
596 }
NVIDIASectionTests_BinaryEqual()597 void NVIDIASectionTests_BinaryEqual()
598 {
599 	cper_log_section_dual_binary_test("nvidia");
600 }
601 
NVIDIACMETSectionTests_IRValid()602 void NVIDIACMETSectionTests_IRValid()
603 {
604 	cper_example_section_ir_test("nvidia_cmet_info");
605 }
606 
607 //Unknown section tests.
UnknownSectionTests_IRValid()608 void UnknownSectionTests_IRValid()
609 {
610 	cper_log_section_dual_ir_test("unknown");
611 }
UnknownSectionTests_BinaryEqual()612 void UnknownSectionTests_BinaryEqual()
613 {
614 	cper_log_section_dual_binary_test("unknown");
615 }
616 
617 //Entrypoint for the testing program.
main()618 int main()
619 {
620 	if (GEN_EXAMPLES) {
621 		cper_create_examples("arm");
622 		cper_create_examples("ia32x64");
623 		cper_create_examples("memory");
624 		cper_create_examples("memory2");
625 		cper_create_examples("pcie");
626 		cper_create_examples("firmware");
627 		cper_create_examples("pcibus");
628 		cper_create_examples("pcidev");
629 		cper_create_examples("dmargeneric");
630 		cper_create_examples("dmarvtd");
631 		cper_create_examples("dmariommu");
632 		cper_create_examples("ccixper");
633 		cper_create_examples("cxlprotocol");
634 		cper_create_examples("cxlcomponent-media");
635 		cper_create_examples("nvidia");
636 		cper_create_examples("unknown");
637 	}
638 	test_base64_encode_good();
639 	test_base64_decode_good();
640 	GenericProcessorTests_IRValid();
641 	GenericProcessorTests_BinaryEqual();
642 	IA32x64Tests_IRValid();
643 	IA32x64Tests_BinaryEqual();
644 	ArmTests_IRValid();
645 	ArmTests_BinaryEqual();
646 	MemoryTests_IRValid();
647 	MemoryTests_BinaryEqual();
648 	Memory2Tests_IRValid();
649 	Memory2Tests_BinaryEqual();
650 	PCIeTests_IRValid();
651 	PCIeTests_BinaryEqual();
652 	FirmwareTests_IRValid();
653 	FirmwareTests_BinaryEqual();
654 	PCIBusTests_IRValid();
655 	PCIBusTests_BinaryEqual();
656 	PCIDevTests_IRValid();
657 	PCIDevTests_BinaryEqual();
658 	DMArGenericTests_IRValid();
659 	DMArGenericTests_BinaryEqual();
660 	DMArVtdTests_IRValid();
661 	DMArVtdTests_BinaryEqual();
662 	DMArIOMMUTests_IRValid();
663 	DMArIOMMUTests_BinaryEqual();
664 	CCIXPERTests_IRValid();
665 	CCIXPERTests_BinaryEqual();
666 	CXLProtocolTests_IRValid();
667 	CXLProtocolTests_BinaryEqual();
668 	CXLComponentTests_IRValid();
669 	CXLComponentTests_BinaryEqual();
670 	NVIDIASectionTests_IRValid();
671 	NVIDIASectionTests_BinaryEqual();
672 	NVIDIACMETSectionTests_IRValid();
673 	UnknownSectionTests_IRValid();
674 	UnknownSectionTests_BinaryEqual();
675 	CompileTimeAssertions_TwoWayConversion();
676 	CompileTimeAssertions_ShortcodeNoSpaces();
677 
678 	printf("\n\nTest completed successfully.\n");
679 
680 	return 0;
681 }
682