blob: 141f26b5fa661502886b82919fec1d930ef5c605 [file] [log] [blame]
Lawrence Tangb98ec662022-07-06 16:50:21 +01001/**
2 * Describes functions for converting CXL protocol error CPER sections from binary and JSON format
3 * into an intermediate format.
Ed Tanousfedd4572024-07-12 13:56:00 -07004 *
Lawrence Tangb98ec662022-07-06 16:50:21 +01005 * Author: Lawrence.Tang@arm.com
6 **/
7#include <stdio.h>
Lawrence Tangaec83902022-07-18 09:41:08 +01008#include <string.h>
Thu Nguyene42fb482024-10-15 14:43:11 +00009#include <libcper/base64.h>
10#include <libcper/Cper.h>
11#include <libcper/cper-utils.h>
12#include <libcper/sections/cper-section-cxl-protocol.h>
Lawrence Tangb98ec662022-07-06 16:50:21 +010013
14//Converts a single CXL protocol error CPER section into JSON IR.
John Chungf8fc7052024-05-03 20:05:29 +080015json_object *cper_section_cxl_protocol_to_ir(void *section)
Lawrence Tangb98ec662022-07-06 16:50:21 +010016{
Lawrence Tange407b4c2022-07-21 13:54:01 +010017 EFI_CXL_PROTOCOL_ERROR_DATA *cxl_protocol_error =
18 (EFI_CXL_PROTOCOL_ERROR_DATA *)section;
19 json_object *section_ir = json_object_new_object();
Lawrence Tangb98ec662022-07-06 16:50:21 +010020
Lawrence Tange407b4c2022-07-21 13:54:01 +010021 //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);
Lawrence Tangb98ec662022-07-06 16:50:21 +010026
Lawrence Tange407b4c2022-07-21 13:54:01 +010027 //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);
Lawrence Tangb98ec662022-07-06 16:50:21 +010033
Lawrence Tange407b4c2022-07-21 13:54:01 +010034 //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);
Lawrence Tangb98ec662022-07-06 16:50:21 +010069
Lawrence Tange407b4c2022-07-21 13:54:01 +010070 //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);
Lawrence Tangb98ec662022-07-06 16:50:21 +010094
Ed Tanousa7d2cdd2024-07-15 11:07:27 -070095 char *encoded;
Lawrence Tange407b4c2022-07-21 13:54:01 +010096 //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));
Lawrence Tang368e0b42022-07-07 14:31:06 +0100103
Lawrence Tange407b4c2022-07-21 13:54:01 +0100104 //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.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700107
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) {
John Chungf8fc7052024-05-03 20:05:29 +0800114 printf("Failed to allocate encode output buffer. \n");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700115 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +0800116 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700117 json_object_object_add(section_ir, "capabilityStructure",
118 json_object_new_string_len(encoded,
119 encoded_len));
120 free(encoded);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100121 }
Lawrence Tangb98ec662022-07-06 16:50:21 +0100122
Lawrence Tange407b4c2022-07-21 13:54:01 +0100123 //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));
Lawrence Tangb98ec662022-07-06 16:50:21 +0100130
Lawrence Tange407b4c2022-07-21 13:54:01 +0100131 //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.
John Chungf8fc7052024-05-03 20:05:29 +0800134 const char *cur_pos = (const char *)(cxl_protocol_error + 1);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700135 int32_t encoded_len = 0;
John Chungf8fc7052024-05-03 20:05:29 +0800136
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700137 encoded = base64_encode((UINT8 *)cur_pos,
138 cxl_protocol_error->CxlDvsecLength,
139 &encoded_len);
140 if (encoded == NULL) {
141 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +0800142 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700143 json_object_object_add(section_ir, "cxlDVSEC",
144 json_object_new_string_len(encoded,
145 encoded_len));
146
147 free(encoded);
148
Lawrence Tange407b4c2022-07-21 13:54:01 +0100149 cur_pos += cxl_protocol_error->CxlDvsecLength;
Lawrence Tang368e0b42022-07-07 14:31:06 +0100150
Lawrence Tange407b4c2022-07-21 13:54:01 +0100151 //CXL Error Log
152 //This is the "CXL RAS Capability Structure" as in CXL 1.1 spec.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700153
John Chungf8fc7052024-05-03 20:05:29 +0800154 encoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700155 encoded = base64_encode((UINT8 *)cur_pos,
156 cxl_protocol_error->CxlErrorLogLength,
157 &encoded_len);
158
159 if (encoded == NULL) {
John Chungf8fc7052024-05-03 20:05:29 +0800160 printf("Failed to allocate encode output buffer. \n");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700161 return NULL;
John Chungf8fc7052024-05-03 20:05:29 +0800162 }
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700163 json_object_object_add(section_ir, "cxlErrorLog",
164 json_object_new_string_len(encoded,
165 encoded_len));
166 free(encoded);
167
Lawrence Tange407b4c2022-07-21 13:54:01 +0100168 return section_ir;
Lawrence Tangaec83902022-07-18 09:41:08 +0100169}
170
171//Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100172void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out)
Lawrence Tangaec83902022-07-18 09:41:08 +0100173{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100174 EFI_CXL_PROTOCOL_ERROR_DATA *section_cper =
175 (EFI_CXL_PROTOCOL_ERROR_DATA *)calloc(
176 1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA));
Lawrence Tangaec83902022-07-18 09:41:08 +0100177
Lawrence Tange407b4c2022-07-21 13:54:01 +0100178 //Validation bits.
179 section_cper->ValidBits = ir_to_bitfield(
180 json_object_object_get(section, "validationBits"), 7,
181 CXL_PROTOCOL_ERROR_VALID_BITFIELD_NAMES);
Lawrence Tangaec83902022-07-18 09:41:08 +0100182
Lawrence Tange407b4c2022-07-21 13:54:01 +0100183 //Detecting agent type.
184 section_cper->CxlAgentType = readable_pair_to_integer(
185 json_object_object_get(section, "agentType"));
Lawrence Tangaec83902022-07-18 09:41:08 +0100186
Lawrence Tange407b4c2022-07-21 13:54:01 +0100187 //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 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100214
Lawrence Tange407b4c2022-07-21 13:54:01 +0100215 //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"));
Lawrence Tangaec83902022-07-18 09:41:08 +0100229
Lawrence Tange407b4c2022-07-21 13:54:01 +0100230 //If CXL 1.1 device, the serial number & PCI capability structure.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700231 UINT8 *decoded;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100232 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) {
233 section_cper->DeviceSerial = json_object_get_uint64(
234 json_object_object_get(section, "deviceSerial"));
Lawrence Tangaec83902022-07-18 09:41:08 +0100235
Lawrence Tange407b4c2022-07-21 13:54:01 +0100236 json_object *encoded =
237 json_object_object_get(section, "capabilityStructure");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700238
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) {
John Chungf8fc7052024-05-03 20:05:29 +0800246 printf("Failed to allocate decode output buffer. \n");
247 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800248 memcpy(section_cper->CapabilityStructure.PcieCap,
249 decoded, decoded_len);
250 free(decoded);
251 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100252 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100253
Lawrence Tange407b4c2022-07-21 13:54:01 +0100254 //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"));
Lawrence Tangaec83902022-07-18 09:41:08 +0100259
Lawrence Tange407b4c2022-07-21 13:54:01 +0100260 //Write header to stream.
261 fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out);
262 fflush(out);
Lawrence Tangaec83902022-07-18 09:41:08 +0100263
Lawrence Tange407b4c2022-07-21 13:54:01 +0100264 //DVSEC out to stream.
265 json_object *encoded = json_object_object_get(section, "cxlDVSEC");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700266
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) {
John Chungf8fc7052024-05-03 20:05:29 +0800273 printf("Failed to allocate decode output buffer. \n");
274 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800275 fwrite(decoded, decoded_len, 1, out);
276 fflush(out);
277 free(decoded);
278 }
Lawrence Tangaec83902022-07-18 09:41:08 +0100279
Lawrence Tange407b4c2022-07-21 13:54:01 +0100280 //Error log out to stream.
281 encoded = json_object_object_get(section, "cxlErrorLog");
John Chungf8fc7052024-05-03 20:05:29 +0800282 decoded_len = 0;
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700283
284 decoded = base64_decode(json_object_get_string(encoded),
285 json_object_get_string_len(encoded),
286 &decoded_len);
287 if (decoded == NULL) {
John Chungf8fc7052024-05-03 20:05:29 +0800288 printf("Failed to allocate decode output buffer. \n");
289 } else {
John Chungf8fc7052024-05-03 20:05:29 +0800290 fwrite(decoded, decoded_len, 1, out);
291 fflush(out);
292 free(decoded);
293 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100294
295 free(section_cper);
John Chungf8fc7052024-05-03 20:05:29 +0800296}