xref: /openbmc/libcper/sections/cper-section-cxl-component.c (revision ad6c880fc739b6ca750c3ab594e270efd972c2ac)
1 /**
2  * Describes functions for converting CXL component error 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 <json.h>
9 #include <libcper/base64.h>
10 #include <libcper/Cper.h>
11 #include <libcper/cper-utils.h>
12 #include <libcper/sections/cper-section-cxl-component.h>
13 #include <libcper/log.h>
14 #include <string.h>
15 
16 //Converts a single CXL component error CPER section into JSON IR.
cper_section_cxl_component_to_ir(const UINT8 * section,UINT32 size,char ** desc_string)17 json_object *cper_section_cxl_component_to_ir(const UINT8 *section, UINT32 size,
18 					      char **desc_string)
19 {
20 	int outstr_len = 0;
21 	*desc_string = malloc(SECTION_DESC_STRING_SIZE);
22 	outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
23 			      "A CXL Component Error occurred");
24 	if (outstr_len < 0) {
25 		cper_print_log(
26 			"Error: Could not write to CXL Component description string\n");
27 	} else if (outstr_len > SECTION_DESC_STRING_SIZE) {
28 		cper_print_log(
29 			"Error: CXL Component description string truncated\n");
30 	}
31 
32 	if (size < sizeof(EFI_CXL_COMPONENT_EVENT_HEADER)) {
33 		return NULL;
34 	}
35 
36 	EFI_CXL_COMPONENT_EVENT_HEADER *cxl_error =
37 		(EFI_CXL_COMPONENT_EVENT_HEADER *)section;
38 	if (cxl_error->Length < sizeof(EFI_CXL_COMPONENT_EVENT_HEADER)) {
39 		return NULL;
40 	}
41 	if (size < cxl_error->Length) {
42 		return NULL;
43 	}
44 	json_object *section_ir = json_object_new_object();
45 
46 	//Length (bytes) for the entire structure.
47 	json_object_object_add(section_ir, "length",
48 			       json_object_new_uint64(cxl_error->Length));
49 
50 	//Validation bits.
51 	ValidationTypes ui64Type = { UINT_64T,
52 				     .value.ui64 = cxl_error->ValidBits };
53 
54 	//Device ID.
55 	if (isvalid_prop_to_ir(&ui64Type, 0)) {
56 		json_object *device_id = json_object_new_object();
57 		json_object_object_add(
58 			device_id, "vendorID",
59 			json_object_new_int(cxl_error->DeviceId.VendorId));
60 		json_object_object_add(
61 			device_id, "deviceID",
62 			json_object_new_int(cxl_error->DeviceId.DeviceId));
63 		json_object_object_add(
64 			device_id, "functionNumber",
65 			json_object_new_int(
66 				cxl_error->DeviceId.FunctionNumber));
67 		json_object_object_add(
68 			device_id, "deviceNumber",
69 			json_object_new_int(cxl_error->DeviceId.DeviceNumber));
70 		json_object_object_add(
71 			device_id, "busNumber",
72 			json_object_new_int(cxl_error->DeviceId.BusNumber));
73 		json_object_object_add(
74 			device_id, "segmentNumber",
75 			json_object_new_int(cxl_error->DeviceId.SegmentNumber));
76 		json_object_object_add(
77 			device_id, "slotNumber",
78 			json_object_new_int(cxl_error->DeviceId.SlotNumber));
79 		json_object_object_add(section_ir, "deviceID", device_id);
80 	}
81 
82 	//Device serial.
83 	if (isvalid_prop_to_ir(&ui64Type, 1)) {
84 		json_object_object_add(
85 			section_ir, "deviceSerial",
86 			json_object_new_uint64(cxl_error->DeviceSerial));
87 	}
88 
89 	//The specification for this is defined within the CXL Specification Section 8.2.9.1.
90 	if (isvalid_prop_to_ir(&ui64Type, 2)) {
91 		const UINT8 *cur_pos = (const UINT8 *)(cxl_error + 1);
92 		int remaining_len = cxl_error->Length -
93 				    sizeof(EFI_CXL_COMPONENT_EVENT_HEADER);
94 		if (remaining_len > 0) {
95 			int32_t encoded_len = 0;
96 
97 			char *encoded = base64_encode(cur_pos, remaining_len,
98 						      &encoded_len);
99 			if (encoded == NULL) {
100 				cper_print_log(
101 					"Failed to allocate encode output buffer. \n");
102 				json_object_put(section_ir);
103 				return NULL;
104 			}
105 			json_object *event_log = json_object_new_object();
106 
107 			json_object_object_add(event_log, "data",
108 					       json_object_new_string_len(
109 						       encoded, encoded_len));
110 
111 			free(encoded);
112 			json_object_object_add(
113 				section_ir, "cxlComponentEventLog", event_log);
114 		}
115 	}
116 
117 	return section_ir;
118 }
119 
120 //Converts a single given CXL Component CPER-JSON section into CPER binary, outputting to the
121 //given stream.
ir_section_cxl_component_to_cper(json_object * section,FILE * out)122 void ir_section_cxl_component_to_cper(json_object *section, FILE *out)
123 {
124 	EFI_CXL_COMPONENT_EVENT_HEADER *section_cper =
125 		(EFI_CXL_COMPONENT_EVENT_HEADER *)calloc(
126 			1, sizeof(EFI_CXL_COMPONENT_EVENT_HEADER));
127 
128 	//Length of the structure.
129 	section_cper->Length = json_object_get_uint64(
130 		json_object_object_get(section, "length"));
131 
132 	//Validation bits.
133 	ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
134 	struct json_object *obj = NULL;
135 
136 	//Device ID information.
137 	if (json_object_object_get_ex(section, "deviceID", &obj)) {
138 		json_object *device_id = obj;
139 		section_cper->DeviceId.VendorId = json_object_get_uint64(
140 			json_object_object_get(device_id, "vendorID"));
141 		section_cper->DeviceId.DeviceId = json_object_get_uint64(
142 			json_object_object_get(device_id, "deviceID"));
143 		section_cper->DeviceId.FunctionNumber = json_object_get_uint64(
144 			json_object_object_get(device_id, "functionNumber"));
145 		section_cper->DeviceId.DeviceNumber = json_object_get_uint64(
146 			json_object_object_get(device_id, "deviceNumber"));
147 		section_cper->DeviceId.BusNumber = json_object_get_uint64(
148 			json_object_object_get(device_id, "busNumber"));
149 		section_cper->DeviceId.SegmentNumber = json_object_get_uint64(
150 			json_object_object_get(device_id, "segmentNumber"));
151 		section_cper->DeviceId.SlotNumber = json_object_get_uint64(
152 			json_object_object_get(device_id, "slotNumber"));
153 		add_to_valid_bitfield(&ui64Type, 0);
154 	}
155 
156 	//Device serial number.
157 	if (json_object_object_get_ex(section, "deviceSerial", &obj)) {
158 		section_cper->DeviceSerial = json_object_get_uint64(obj);
159 		add_to_valid_bitfield(&ui64Type, 1);
160 	}
161 
162 	//CXL component event log, decoded from base64.
163 	json_object *event_log = NULL;
164 	if (json_object_object_get_ex(section, "cxlComponentEventLog", &obj)) {
165 		event_log = obj;
166 		add_to_valid_bitfield(&ui64Type, 2);
167 	}
168 	section_cper->ValidBits = ui64Type.value.ui64;
169 
170 	//Write header out to stream.
171 	fwrite(section_cper, sizeof(EFI_CXL_COMPONENT_EVENT_HEADER), 1, out);
172 	fflush(out);
173 
174 	if (event_log != NULL) {
175 		json_object *encoded =
176 			json_object_object_get(event_log, "data");
177 
178 		int32_t decoded_len = 0;
179 
180 		UINT8 *decoded = base64_decode(
181 			json_object_get_string(encoded),
182 			json_object_get_string_len(encoded), &decoded_len);
183 
184 		if (decoded == NULL) {
185 			cper_print_log(
186 				"Failed to allocate decode output buffer. \n");
187 		} else {
188 			fwrite(decoded, decoded_len, 1, out);
189 			fflush(out);
190 			free(decoded);
191 		}
192 	}
193 
194 	free(section_cper);
195 }
196