xref: /openbmc/libcper/sections/cper-section-ccix-per.c (revision 50b966f7afa31fe39fda70e10eb9139cce39e025)
1 /**
2  * Describes functions for converting CCIX PER log CPER sections from binary and JSON format
3  * into an intermediate format.
4  *
5  * Author: Lawrence.Tang@arm.com
6  **/
7 #include <stdio.h>
8 #include <string.h>
9 #include <json.h>
10 #include <libcper/base64.h>
11 #include <libcper/Cper.h>
12 #include <libcper/cper-utils.h>
13 #include <libcper/sections/cper-section-ccix-per.h>
14 #include <libcper/log.h>
15 
16 //Converts a single CCIX PER log CPER section into JSON IR.
cper_section_ccix_per_to_ir(const UINT8 * section,UINT32 size)17 json_object *cper_section_ccix_per_to_ir(const UINT8 *section, UINT32 size)
18 {
19 	if (size < sizeof(EFI_CCIX_PER_LOG_DATA)) {
20 		return NULL;
21 	}
22 
23 	EFI_CCIX_PER_LOG_DATA *ccix_error = (EFI_CCIX_PER_LOG_DATA *)section;
24 
25 	if (size < ccix_error->Length) {
26 		return NULL;
27 	}
28 
29 	json_object *section_ir = json_object_new_object();
30 	ValidationTypes ui64Type = { UINT_64T,
31 				     .value.ui64 = ccix_error->ValidBits };
32 
33 	//Length (bytes) for the entire structure.
34 	json_object_object_add(section_ir, "length",
35 			       json_object_new_uint64(ccix_error->Length));
36 
37 	//CCIX source/port IDs.
38 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
39 		json_object_object_add(
40 			section_ir, "ccixSourceID",
41 			json_object_new_int(ccix_error->CcixSourceId));
42 	}
43 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
44 		json_object_object_add(
45 			section_ir, "ccixPortID",
46 			json_object_new_int(ccix_error->CcixPortId));
47 	}
48 
49 	//CCIX PER Log.
50 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
51 		//This is formatted as described in Section 7.3.2 of CCIX Base Specification (Rev 1.0).
52 		const UINT8 *cur_pos = (const UINT8 *)(ccix_error + 1);
53 		int remaining_length =
54 			ccix_error->Length - sizeof(EFI_CCIX_PER_LOG_DATA);
55 		if (remaining_length > 0) {
56 			int32_t encoded_len = 0;
57 
58 			char *encoded = base64_encode((UINT8 *)cur_pos,
59 						      remaining_length,
60 						      &encoded_len);
61 			if (encoded == NULL) {
62 				cper_print_log(
63 					"Failed to allocate encode output buffer. \n");
64 			} else {
65 				json_object_object_add(
66 					section_ir, "ccixPERLog",
67 					json_object_new_string_len(
68 						encoded, encoded_len));
69 				free(encoded);
70 			}
71 		}
72 	}
73 
74 	return section_ir;
75 }
76 
77 //Converts a single CCIX PER CPER-JSON section into CPER binary, outputting to the given stream.
ir_section_ccix_per_to_cper(json_object * section,FILE * out)78 void ir_section_ccix_per_to_cper(json_object *section, FILE *out)
79 {
80 	EFI_CCIX_PER_LOG_DATA *section_cper = (EFI_CCIX_PER_LOG_DATA *)calloc(
81 		1, sizeof(EFI_CCIX_PER_LOG_DATA));
82 
83 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
84 	struct json_object *obj = NULL;
85 
86 	//Length.
87 	section_cper->Length = json_object_get_uint64(
88 		json_object_object_get(section, "length"));
89 
90 	//Validation bits.
91 	section_cper->ValidBits = ir_to_bitfield(
92 		json_object_object_get(section, "validationBits"), 3,
93 		CCIX_PER_ERROR_VALID_BITFIELD_NAMES);
94 
95 	//CCIX source/port IDs.
96 	if (json_object_object_get_ex(section, "ccixSourceID", &obj)) {
97 		section_cper->CcixSourceId = (UINT8)json_object_get_int(obj);
98 		add_to_valid_bitfield(&ui64Type, 0);
99 	}
100 	if (json_object_object_get_ex(section, "ccixPortID", &obj)) {
101 		section_cper->CcixPortId = (UINT8)json_object_get_int(obj);
102 		add_to_valid_bitfield(&ui64Type, 1);
103 	}
104 
105 	bool perlog_exists = false;
106 	if (json_object_object_get_ex(section, "ccixPERLog", &obj)) {
107 		perlog_exists = true;
108 		add_to_valid_bitfield(&ui64Type, 2);
109 	}
110 	section_cper->ValidBits = ui64Type.value.ui64;
111 
112 	//Write header out to stream.
113 	fwrite(section_cper, sizeof(EFI_CCIX_PER_LOG_DATA), 1, out);
114 	fflush(out);
115 
116 	//Write CCIX PER log itself to stream.
117 	if (perlog_exists) {
118 		json_object *encoded = obj;
119 		int32_t decoded_len = 0;
120 
121 		UINT8 *decoded = base64_decode(
122 			json_object_get_string(encoded),
123 			json_object_get_string_len(encoded), &decoded_len);
124 		if (decoded == NULL) {
125 			cper_print_log(
126 				"Failed to allocate decode output buffer. \n");
127 		} else {
128 			fwrite(decoded, decoded_len, 1, out);
129 			fflush(out);
130 			free(decoded);
131 		}
132 	}
133 	//Free resources.
134 	free(section_cper);
135 }
136