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