1 /** 2 * Describes functions for converting CXL component 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 <json.h> 9 #include <libcper/base64.h> 10 #include <libcper/Cper.h> 11 #include <libcper/cper-utils.h> 12 #include <libcper/sections/cper-section-cxl-component.h> 13 #include <libcper/log.h> 14 15 //Converts a single CXL component error CPER section into JSON IR. 16 json_object *cper_section_cxl_component_to_ir(const UINT8 *section, UINT32 size) 17 { 18 if (size < sizeof(EFI_CXL_COMPONENT_EVENT_HEADER)) { 19 return NULL; 20 } 21 22 EFI_CXL_COMPONENT_EVENT_HEADER *cxl_error = 23 (EFI_CXL_COMPONENT_EVENT_HEADER *)section; 24 if (cxl_error->Length < sizeof(EFI_CXL_COMPONENT_EVENT_HEADER)) { 25 return NULL; 26 } 27 if (size < cxl_error->Length) { 28 return NULL; 29 } 30 json_object *section_ir = json_object_new_object(); 31 32 //Length (bytes) for the entire structure. 33 json_object_object_add(section_ir, "length", 34 json_object_new_uint64(cxl_error->Length)); 35 36 //Validation bits. 37 ValidationTypes ui64Type = { UINT_64T, 38 .value.ui64 = cxl_error->ValidBits }; 39 40 //Device ID. 41 if (isvalid_prop_to_ir(&ui64Type, 0)) { 42 json_object *device_id = json_object_new_object(); 43 json_object_object_add( 44 device_id, "vendorID", 45 json_object_new_int(cxl_error->DeviceId.VendorId)); 46 json_object_object_add( 47 device_id, "deviceID", 48 json_object_new_int(cxl_error->DeviceId.DeviceId)); 49 json_object_object_add( 50 device_id, "functionNumber", 51 json_object_new_int( 52 cxl_error->DeviceId.FunctionNumber)); 53 json_object_object_add( 54 device_id, "deviceNumber", 55 json_object_new_int(cxl_error->DeviceId.DeviceNumber)); 56 json_object_object_add( 57 device_id, "busNumber", 58 json_object_new_int(cxl_error->DeviceId.BusNumber)); 59 json_object_object_add( 60 device_id, "segmentNumber", 61 json_object_new_int(cxl_error->DeviceId.SegmentNumber)); 62 json_object_object_add( 63 device_id, "slotNumber", 64 json_object_new_int(cxl_error->DeviceId.SlotNumber)); 65 json_object_object_add(section_ir, "deviceID", device_id); 66 } 67 68 //Device serial. 69 if (isvalid_prop_to_ir(&ui64Type, 1)) { 70 json_object_object_add( 71 section_ir, "deviceSerial", 72 json_object_new_uint64(cxl_error->DeviceSerial)); 73 } 74 75 //The specification for this is defined within the CXL Specification Section 8.2.9.1. 76 if (isvalid_prop_to_ir(&ui64Type, 2)) { 77 const UINT8 *cur_pos = (const UINT8 *)(cxl_error + 1); 78 int remaining_len = cxl_error->Length - 79 sizeof(EFI_CXL_COMPONENT_EVENT_HEADER); 80 if (remaining_len > 0) { 81 int32_t encoded_len = 0; 82 83 char *encoded = base64_encode(cur_pos, remaining_len, 84 &encoded_len); 85 if (encoded == NULL) { 86 cper_print_log( 87 "Failed to allocate encode output buffer. \n"); 88 json_object_put(section_ir); 89 return NULL; 90 } 91 json_object *event_log = json_object_new_object(); 92 93 json_object_object_add(event_log, "data", 94 json_object_new_string_len( 95 encoded, encoded_len)); 96 97 free(encoded); 98 json_object_object_add( 99 section_ir, "cxlComponentEventLog", event_log); 100 } 101 } 102 103 return section_ir; 104 } 105 106 //Converts a single given CXL Component CPER-JSON section into CPER binary, outputting to the 107 //given stream. 108 void ir_section_cxl_component_to_cper(json_object *section, FILE *out) 109 { 110 EFI_CXL_COMPONENT_EVENT_HEADER *section_cper = 111 (EFI_CXL_COMPONENT_EVENT_HEADER *)calloc( 112 1, sizeof(EFI_CXL_COMPONENT_EVENT_HEADER)); 113 114 //Length of the structure. 115 section_cper->Length = json_object_get_uint64( 116 json_object_object_get(section, "length")); 117 118 //Validation bits. 119 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 }; 120 struct json_object *obj = NULL; 121 122 //Device ID information. 123 if (json_object_object_get_ex(section, "deviceID", &obj)) { 124 json_object *device_id = obj; 125 section_cper->DeviceId.VendorId = json_object_get_uint64( 126 json_object_object_get(device_id, "vendorID")); 127 section_cper->DeviceId.DeviceId = json_object_get_uint64( 128 json_object_object_get(device_id, "deviceID")); 129 section_cper->DeviceId.FunctionNumber = json_object_get_uint64( 130 json_object_object_get(device_id, "functionNumber")); 131 section_cper->DeviceId.DeviceNumber = json_object_get_uint64( 132 json_object_object_get(device_id, "deviceNumber")); 133 section_cper->DeviceId.BusNumber = json_object_get_uint64( 134 json_object_object_get(device_id, "busNumber")); 135 section_cper->DeviceId.SegmentNumber = json_object_get_uint64( 136 json_object_object_get(device_id, "segmentNumber")); 137 section_cper->DeviceId.SlotNumber = json_object_get_uint64( 138 json_object_object_get(device_id, "slotNumber")); 139 add_to_valid_bitfield(&ui64Type, 0); 140 } 141 142 //Device serial number. 143 if (json_object_object_get_ex(section, "deviceSerial", &obj)) { 144 section_cper->DeviceSerial = json_object_get_uint64(obj); 145 add_to_valid_bitfield(&ui64Type, 1); 146 } 147 148 //CXL component event log, decoded from base64. 149 json_object *event_log = NULL; 150 if (json_object_object_get_ex(section, "cxlComponentEventLog", &obj)) { 151 event_log = obj; 152 add_to_valid_bitfield(&ui64Type, 2); 153 } 154 section_cper->ValidBits = ui64Type.value.ui64; 155 156 //Write header out to stream. 157 fwrite(section_cper, sizeof(EFI_CXL_COMPONENT_EVENT_HEADER), 1, out); 158 fflush(out); 159 160 if (event_log != NULL) { 161 json_object *encoded = 162 json_object_object_get(event_log, "data"); 163 164 int32_t decoded_len = 0; 165 166 UINT8 *decoded = base64_decode( 167 json_object_get_string(encoded), 168 json_object_get_string_len(encoded), &decoded_len); 169 170 if (decoded == NULL) { 171 cper_print_log( 172 "Failed to allocate decode output buffer. \n"); 173 } else { 174 fwrite(decoded, decoded_len, 1, out); 175 fflush(out); 176 free(decoded); 177 } 178 } 179 180 free(section_cper); 181 } 182