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