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 "libbase64.h" 10 #include "../edk/Cper.h" 11 #include "../cper-utils.h" 12 #include "cper-section-cxl-protocol.h" 13 14 //Converts a single CXL protocol error CPER section into JSON IR. 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 //Device serial & capability structure (if CXL 1.1 device). 96 if (cxl_protocol_error->CxlAgentType == 97 CXL_PROTOCOL_ERROR_DEVICE_AGENT) { 98 json_object_object_add( 99 section_ir, "deviceSerial", 100 json_object_new_uint64( 101 cxl_protocol_error->DeviceSerial)); 102 103 //The PCIe capability structure provided here could either be PCIe 1.1 Capability Structure 104 //(36-byte, padded to 60 bytes) or PCIe 2.0 Capability Structure (60-byte). There does not seem 105 //to be a way to differentiate these, so this is left as a b64 dump. 106 char *encoded = malloc(2 * 60); 107 size_t encoded_len = 0; 108 if (!encoded) { 109 printf("Failed to allocate encode output buffer. \n"); 110 } else { 111 base64_encode((const char *)cxl_protocol_error 112 ->CapabilityStructure.PcieCap, 113 60, encoded, &encoded_len, 0); 114 json_object_object_add(section_ir, 115 "capabilityStructure", 116 json_object_new_string_len( 117 encoded, encoded_len)); 118 free(encoded); 119 } 120 } 121 122 //CXL DVSEC & error log length. 123 json_object_object_add( 124 section_ir, "dvsecLength", 125 json_object_new_int(cxl_protocol_error->CxlDvsecLength)); 126 json_object_object_add( 127 section_ir, "errorLogLength", 128 json_object_new_int(cxl_protocol_error->CxlErrorLogLength)); 129 130 //CXL DVSEC 131 //For CXL 1.1 devices, this is the "CXL DVSEC For Flex Bus Device" structure as in CXL 1.1 spec. 132 //For CXL 1.1 host downstream ports, this is the "CXL DVSEC For Flex Bus Port" structure as in CXL 1.1 spec. 133 const char *cur_pos = (const char *)(cxl_protocol_error + 1); 134 char *encoded = malloc(2 * cxl_protocol_error->CxlDvsecLength); 135 size_t encoded_len = 0; 136 if (!encoded) { 137 printf("Failed to allocate encode output buffer. \n"); 138 } else { 139 base64_encode(cur_pos, cxl_protocol_error->CxlDvsecLength, 140 encoded, &encoded_len, 0); 141 json_object_object_add(section_ir, "cxlDVSEC", 142 json_object_new_string_len(encoded, 143 encoded_len)); 144 145 free(encoded); 146 } 147 cur_pos += cxl_protocol_error->CxlDvsecLength; 148 149 //CXL Error Log 150 //This is the "CXL RAS Capability Structure" as in CXL 1.1 spec. 151 encoded = malloc(2 * cxl_protocol_error->CxlErrorLogLength); 152 encoded_len = 0; 153 if (!encoded) { 154 printf("Failed to allocate encode output buffer. \n"); 155 } else { 156 base64_encode(cur_pos, cxl_protocol_error->CxlErrorLogLength, 157 encoded, &encoded_len, 0); 158 json_object_object_add(section_ir, "cxlErrorLog", 159 json_object_new_string_len(encoded, 160 encoded_len)); 161 free(encoded); 162 } 163 return section_ir; 164 } 165 166 //Converts a single CXL protocol CPER-JSON section into CPER binary, outputting to the given stream. 167 void ir_section_cxl_protocol_to_cper(json_object *section, FILE *out) 168 { 169 EFI_CXL_PROTOCOL_ERROR_DATA *section_cper = 170 (EFI_CXL_PROTOCOL_ERROR_DATA *)calloc( 171 1, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA)); 172 173 //Validation bits. 174 section_cper->ValidBits = ir_to_bitfield( 175 json_object_object_get(section, "validationBits"), 7, 176 CXL_PROTOCOL_ERROR_VALID_BITFIELD_NAMES); 177 178 //Detecting agent type. 179 section_cper->CxlAgentType = readable_pair_to_integer( 180 json_object_object_get(section, "agentType")); 181 182 //Based on the agent type, set the address. 183 json_object *address = 184 json_object_object_get(section, "cxlAgentAddress"); 185 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) { 186 //Address is split by function, device, bus & segment. 187 UINT64 function = json_object_get_uint64( 188 json_object_object_get(address, "functionNumber")); 189 UINT64 device = json_object_get_uint64( 190 json_object_object_get(address, "deviceNumber")); 191 UINT64 bus = json_object_get_uint64( 192 json_object_object_get(address, "busNumber")); 193 UINT64 segment = json_object_get_uint64( 194 json_object_object_get(address, "segmentNumber")); 195 section_cper->CxlAgentAddress.DeviceAddress.FunctionNumber = 196 function; 197 section_cper->CxlAgentAddress.DeviceAddress.DeviceNumber = 198 device; 199 section_cper->CxlAgentAddress.DeviceAddress.BusNumber = bus; 200 section_cper->CxlAgentAddress.DeviceAddress.SegmentNumber = 201 segment; 202 } else if (section_cper->CxlAgentType == 203 CXL_PROTOCOL_ERROR_HOST_DOWNSTREAM_PORT_AGENT) { 204 //Plain RCRB base address. 205 section_cper->CxlAgentAddress.PortRcrbBaseAddress = 206 json_object_get_uint64( 207 json_object_object_get(address, "value")); 208 } 209 210 //Device ID information. 211 json_object *device_id = json_object_object_get(section, "deviceID"); 212 section_cper->DeviceId.VendorId = json_object_get_uint64( 213 json_object_object_get(device_id, "vendorID")); 214 section_cper->DeviceId.DeviceId = json_object_get_uint64( 215 json_object_object_get(device_id, "deviceID")); 216 section_cper->DeviceId.SubsystemVendorId = json_object_get_uint64( 217 json_object_object_get(device_id, "subsystemVendorID")); 218 section_cper->DeviceId.SubsystemDeviceId = json_object_get_uint64( 219 json_object_object_get(device_id, "subsystemDeviceID")); 220 section_cper->DeviceId.ClassCode = json_object_get_uint64( 221 json_object_object_get(device_id, "classCode")); 222 section_cper->DeviceId.SlotNumber = json_object_get_uint64( 223 json_object_object_get(device_id, "slotNumber")); 224 225 //If CXL 1.1 device, the serial number & PCI capability structure. 226 if (section_cper->CxlAgentType == CXL_PROTOCOL_ERROR_DEVICE_AGENT) { 227 section_cper->DeviceSerial = json_object_get_uint64( 228 json_object_object_get(section, "deviceSerial")); 229 230 json_object *encoded = 231 json_object_object_get(section, "capabilityStructure"); 232 char *decoded = malloc(json_object_get_string_len(encoded)); 233 size_t decoded_len = 0; 234 if (!decoded) { 235 printf("Failed to allocate decode output buffer. \n"); 236 } else { 237 base64_decode(json_object_get_string(encoded), 238 json_object_get_string_len(encoded), 239 decoded, &decoded_len, 0); 240 memcpy(section_cper->CapabilityStructure.PcieCap, 241 decoded, decoded_len); 242 free(decoded); 243 } 244 } 245 246 //DVSEC length & error log length. 247 section_cper->CxlDvsecLength = (UINT16)json_object_get_int( 248 json_object_object_get(section, "dvsecLength")); 249 section_cper->CxlErrorLogLength = (UINT16)json_object_get_int( 250 json_object_object_get(section, "errorLogLength")); 251 252 //Write header to stream. 253 fwrite(section_cper, sizeof(EFI_CXL_PROTOCOL_ERROR_DATA), 1, out); 254 fflush(out); 255 256 //DVSEC out to stream. 257 json_object *encoded = json_object_object_get(section, "cxlDVSEC"); 258 char *decoded = malloc(json_object_get_string_len(encoded)); 259 size_t decoded_len = 0; 260 if (!decoded) { 261 printf("Failed to allocate decode output buffer. \n"); 262 } else { 263 base64_decode(json_object_get_string(encoded), 264 json_object_get_string_len(encoded), decoded, 265 &decoded_len, 0); 266 fwrite(decoded, decoded_len, 1, out); 267 fflush(out); 268 free(decoded); 269 } 270 271 //Error log out to stream. 272 encoded = json_object_object_get(section, "cxlErrorLog"); 273 decoded = malloc(json_object_get_string_len(encoded)); 274 decoded_len = 0; 275 if (!decoded) { 276 printf("Failed to allocate decode output buffer. \n"); 277 } else { 278 base64_decode(json_object_get_string(encoded), 279 json_object_get_string_len(encoded), decoded, 280 &decoded_len, 0); 281 fwrite(decoded, decoded_len, 1, out); 282 fflush(out); 283 free(decoded); 284 } 285 286 free(section_cper); 287 } 288