1 /**
2 * Describes functions for converting CXL protocol 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 <string.h>
9 #include <libcper/base64.h>
10 #include <libcper/Cper.h>
11 #include <libcper/cper-utils.h>
12 #include <libcper/sections/cper-section-cxl-protocol.h>
13
14 //Converts a single CXL protocol error CPER section into JSON IR.
cper_section_cxl_protocol_to_ir(void * section)15 json_object *cper_section_cxl_protocol_to_ir(void *section)
16 {
17 EFI_CXL_PROTOCOL_ERROR_DATA *cxl_protocol_error =
18 (EFI_CXL_PROTOCOL_ERROR_DATA *)section;
19 json_object *section_ir = json_object_new_object();
20
21 //Validation bits.
22 json_object *validation =
23 bitfield_to_ir(cxl_protocol_error->ValidBits, 7,
24 CXL_PROTOCOL_ERROR_VALID_BITFIELD_NAMES);
25 json_object_object_add(section_ir, "validationBits", validation);
26
27 //Type of detecting agent.
28 json_object *agent_type = integer_to_readable_pair(
29 cxl_protocol_error->CxlAgentType, 2,
30 CXL_PROTOCOL_ERROR_AGENT_TYPES_KEYS,
31 CXL_PROTOCOL_ERROR_AGENT_TYPES_VALUES, "Unknown (Reserved)");
32 json_object_object_add(section_ir, "agentType", agent_type);
33
34 //CXL agent address, depending on the agent type.
35 json_object *agent_address = json_object_new_object();
36 if (cxl_protocol_error->CxlAgentType ==
37 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
38 //Address is a CXL1.1 device agent.
39 json_object_object_add(
40 agent_address, "functionNumber",
41 json_object_new_uint64(
42 cxl_protocol_error->CxlAgentAddress
43 .DeviceAddress.FunctionNumber));
44 json_object_object_add(
45 agent_address, "deviceNumber",
46 json_object_new_uint64(
47 cxl_protocol_error->CxlAgentAddress
48 .DeviceAddress.DeviceNumber));
49 json_object_object_add(
50 agent_address, "busNumber",
51 json_object_new_uint64(
52 cxl_protocol_error->CxlAgentAddress
53 .DeviceAddress.BusNumber));
54 json_object_object_add(
55 agent_address, "segmentNumber",
56 json_object_new_uint64(
57 cxl_protocol_error->CxlAgentAddress
58 .DeviceAddress.SegmentNumber));
59 } else if (cxl_protocol_error->CxlAgentType ==
60 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
61 //Address is a CXL port RCRB base address.
62 json_object_object_add(
63 agent_address, "value",
64 json_object_new_uint64(
65 cxl_protocol_error->CxlAgentAddress
66 .PortRcrbBaseAddress));
67 }
68 json_object_object_add(section_ir, "cxlAgentAddress", agent_address);
69
70 //Device ID.
71 json_object *device_id = json_object_new_object();
72 json_object_object_add(
73 device_id, "vendorID",
74 json_object_new_uint64(cxl_protocol_error->DeviceId.VendorId));
75 json_object_object_add(
76 device_id, "deviceID",
77 json_object_new_uint64(cxl_protocol_error->DeviceId.DeviceId));
78 json_object_object_add(
79 device_id, "subsystemVendorID",
80 json_object_new_uint64(
81 cxl_protocol_error->DeviceId.SubsystemVendorId));
82 json_object_object_add(
83 device_id, "subsystemDeviceID",
84 json_object_new_uint64(
85 cxl_protocol_error->DeviceId.SubsystemDeviceId));
86 json_object_object_add(
87 device_id, "classCode",
88 json_object_new_uint64(cxl_protocol_error->DeviceId.ClassCode));
89 json_object_object_add(
90 device_id, "slotNumber",
91 json_object_new_uint64(
92 cxl_protocol_error->DeviceId.SlotNumber));
93 json_object_object_add(section_ir, "deviceID", device_id);
94
95 char *encoded;
96 //Device serial & capability structure (if CXL 1.1 device).
97 if (cxl_protocol_error->CxlAgentType ==
98 CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
99 json_object_object_add(
100 section_ir, "deviceSerial",
101 json_object_new_uint64(
102 cxl_protocol_error->DeviceSerial));
103
104 //The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure
105 //(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem
106 //to be a way to differentiate these, so this is left as a b64 dump.
107
108 int32_t encoded_len = 0;
109
110 encoded = base64_encode(
111 (UINT8 *)cxl_protocol_error->CapabilityStructure.PcieCap,
112 60, &encoded_len);
113 if (encoded == NULL) {
114 printf("Failed to allocate encode output buffer. \n");
115 return NULL;
116 }
117 json_object_object_add(section_ir, "capabilityStructure",
118 json_object_new_string_len(encoded,
119 encoded_len));
120 free(encoded);
121 }
122
123 //CXL DVSEC & error log length.
124 json_object_object_add(
125 section_ir, "dvsecLength",
126 json_object_new_int(cxl_protocol_error->CxlDvsecLength));
127 json_object_object_add(
128 section_ir, "errorLogLength",
129 json_object_new_int(cxl_protocol_error->CxlErrorLogLength));
130
131 //CXL DVSEC
132 //For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec.
133 //For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec.
134 const char *cur_pos = (const char *)(cxl_protocol_error + 1);
135 int32_t encoded_len = 0;
136
137 encoded = base64_encode((UINT8 *)cur_pos,
138 cxl_protocol_error->CxlDvsecLength,
139 &encoded_len);
140 if (encoded == NULL) {
141 return NULL;
142 }
143 json_object_object_add(section_ir, "cxlDVSEC",
144 json_object_new_string_len(encoded,
145 encoded_len));
146
147 free(encoded);
148
149 cur_pos += cxl_protocol_error->CxlDvsecLength;
150
151 //CXL Error Log
152 //This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
153
154 encoded_len = 0;
155 encoded = base64_encode((UINT8 *)cur_pos,
156 cxl_protocol_error->CxlErrorLogLength,
157 &encoded_len);
158
159 if (encoded == NULL) {
160 printf("Failed to allocate encode output buffer. \n");
161 return NULL;
162 }
163 json_object_object_add(section_ir, "cxlErrorLog",
164 json_object_new_string_len(encoded,
165 encoded_len));
166 free(encoded);
167
168 return section_ir;
169 }
170
171 //Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream.
ir_section_cxl_protocol_to_cper(json_object * section,FILE * out)172 void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out)
173 {
174 EFI_CXL_PROTOCOL_ERROR_DATA *section_cper =
175 (EFI_CXL_PROTOCOL_ERROR_DATA *)calloc(
176 1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA));
177
178 //Validation bits.
179 section_cper->ValidBits = ir_to_bitfield(
180 json_object_object_get(section, "validationBits"), 7,
181 CXL_PROTOCOL_ERROR_VALID_BITFIELD_NAMES);
182
183 //Detecting agent type.
184 section_cper->CxlAgentType = readable_pair_to_integer(
185 json_object_object_get(section, "agentType"));
186
187 //Based on the agent type, set the address.
188 json_object *address =
189 json_object_object_get(section, "cxlAgentAddress");
190 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
191 //Address is split by function, device, bus & segment.
192 UINT64 function = json_object_get_uint64(
193 json_object_object_get(address, "functionNumber"));
194 UINT64 device = json_object_get_uint64(
195 json_object_object_get(address, "deviceNumber"));
196 UINT64 bus = json_object_get_uint64(
197 json_object_object_get(address, "busNumber"));
198 UINT64 segment = json_object_get_uint64(
199 json_object_object_get(address, "segmentNumber"));
200 section_cper->CxlAgentAddress.DeviceAddress.FunctionNumber =
201 function;
202 section_cper->CxlAgentAddress.DeviceAddress.DeviceNumber =
203 device;
204 section_cper->CxlAgentAddress.DeviceAddress.BusNumber = bus;
205 section_cper->CxlAgentAddress.DeviceAddress.SegmentNumber =
206 segment;
207 } else if (section_cper->CxlAgentType ==
208 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) {
209 //Plain RCRB base address.
210 section_cper->CxlAgentAddress.PortRcrbBaseAddress =
211 json_object_get_uint64(
212 json_object_object_get(address, "value"));
213 }
214
215 //Device ID information.
216 json_object *device_id = json_object_object_get(section, "deviceID");
217 section_cper->DeviceId.VendorId = json_object_get_uint64(
218 json_object_object_get(device_id, "vendorID"));
219 section_cper->DeviceId.DeviceId = json_object_get_uint64(
220 json_object_object_get(device_id, "deviceID"));
221 section_cper->DeviceId.SubsystemVendorId = json_object_get_uint64(
222 json_object_object_get(device_id, "subsystemVendorID"));
223 section_cper->DeviceId.SubsystemDeviceId = json_object_get_uint64(
224 json_object_object_get(device_id, "subsystemDeviceID"));
225 section_cper->DeviceId.ClassCode = json_object_get_uint64(
226 json_object_object_get(device_id, "classCode"));
227 section_cper->DeviceId.SlotNumber = json_object_get_uint64(
228 json_object_object_get(device_id, "slotNumber"));
229
230 //If CXL 1.1 device, the serial number & PCI capability structure.
231 UINT8 *decoded;
232 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
233 section_cper->DeviceSerial = json_object_get_uint64(
234 json_object_object_get(section, "deviceSerial"));
235
236 json_object *encoded =
237 json_object_object_get(section, "capabilityStructure");
238
239 int32_t decoded_len = 0;
240
241 decoded = base64_decode(json_object_get_string(encoded),
242 json_object_get_string_len(encoded),
243 &decoded_len);
244
245 if (decoded == NULL) {
246 printf("Failed to allocate decode output buffer. \n");
247 } else {
248 memcpy(section_cper->CapabilityStructure.PcieCap,
249 decoded, decoded_len);
250 free(decoded);
251 }
252 }
253
254 //DVSEC length & error log length.
255 section_cper->CxlDvsecLength = (UINT16)json_object_get_int(
256 json_object_object_get(section, "dvsecLength"));
257 section_cper->CxlErrorLogLength = (UINT16)json_object_get_int(
258 json_object_object_get(section, "errorLogLength"));
259
260 //Write header to stream.
261 fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out);
262 fflush(out);
263
264 //DVSEC out to stream.
265 json_object *encoded = json_object_object_get(section, "cxlDVSEC");
266
267 int32_t decoded_len = 0;
268
269 decoded = base64_decode(json_object_get_string(encoded),
270 json_object_get_string_len(encoded),
271 &decoded_len);
272 if (decoded == NULL) {
273 printf("Failed to allocate decode output buffer. \n");
274 } else {
275 fwrite(decoded, decoded_len, 1, out);
276 fflush(out);
277 free(decoded);
278 }
279
280 //Error log out to stream.
281 encoded = json_object_object_get(section, "cxlErrorLog");
282 decoded_len = 0;
283
284 decoded = base64_decode(json_object_get_string(encoded),
285 json_object_get_string_len(encoded),
286 &decoded_len);
287 if (decoded == NULL) {
288 printf("Failed to allocate decode output buffer. \n");
289 } else {
290 fwrite(decoded, decoded_len, 1, out);
291 fflush(out);
292 free(decoded);
293 }
294
295 free(section_cper);
296 }
297