1 /** 2 * Describes functions for converting PCI/PCI-X device 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/Cper.h> 10 #include <libcper/cper-utils.h> 11 #include <libcper/sections/cper-section-pci-dev.h> 12 #include <libcper/log.h> 13 14 //Converts a single PCI/PCI-X device CPER section into JSON IR. 15 json_object *cper_section_pci_dev_to_ir(const UINT8 *section, UINT32 size) 16 { 17 if (size < sizeof(EFI_PCI_PCIX_DEVICE_ERROR_DATA)) { 18 return NULL; 19 } 20 21 EFI_PCI_PCIX_DEVICE_ERROR_DATA *dev_error = 22 (EFI_PCI_PCIX_DEVICE_ERROR_DATA *)section; 23 24 if (size < sizeof(EFI_PCI_PCIX_DEVICE_ERROR_DATA) + 25 ((dev_error->MemoryNumber + dev_error->IoNumber) * 26 sizeof(EFI_PCI_PCIX_DEVICE_ERROR_DATA_REGISTER))) { 27 return NULL; 28 } 29 30 json_object *section_ir = json_object_new_object(); 31 32 //Validation bits. 33 ValidationTypes ui64Type = { UINT_64T, 34 .value.ui64 = dev_error->ValidFields }; 35 36 //Error status. 37 if (isvalid_prop_to_ir(&ui64Type, 0)) { 38 json_object *error_status = cper_generic_error_status_to_ir( 39 &dev_error->ErrorStatus); 40 json_object_object_add(section_ir, "errorStatus", error_status); 41 } 42 43 //ID information. 44 if (isvalid_prop_to_ir(&ui64Type, 1)) { 45 json_object *id_info = json_object_new_object(); 46 json_object_object_add( 47 id_info, "vendorID", 48 json_object_new_uint64(dev_error->IdInfo.VendorId)); 49 json_object_object_add( 50 id_info, "deviceID", 51 json_object_new_uint64(dev_error->IdInfo.DeviceId)); 52 json_object_object_add( 53 id_info, "classCode", 54 json_object_new_uint64(dev_error->IdInfo.ClassCode)); 55 json_object_object_add( 56 id_info, "functionNumber", 57 json_object_new_uint64( 58 dev_error->IdInfo.FunctionNumber)); 59 json_object_object_add( 60 id_info, "deviceNumber", 61 json_object_new_uint64(dev_error->IdInfo.DeviceNumber)); 62 json_object_object_add( 63 id_info, "busNumber", 64 json_object_new_uint64(dev_error->IdInfo.BusNumber)); 65 json_object_object_add( 66 id_info, "segmentNumber", 67 json_object_new_uint64( 68 dev_error->IdInfo.SegmentNumber)); 69 json_object_object_add(section_ir, "idInfo", id_info); 70 } 71 72 //Number of following register data pairs. 73 if (isvalid_prop_to_ir(&ui64Type, 2)) { 74 json_object_object_add( 75 section_ir, "memoryNumber", 76 json_object_new_uint64(dev_error->MemoryNumber)); 77 } 78 if (isvalid_prop_to_ir(&ui64Type, 3)) { 79 json_object_object_add( 80 section_ir, "ioNumber", 81 json_object_new_uint64(dev_error->IoNumber)); 82 } 83 84 if (isvalid_prop_to_ir(&ui64Type, 4)) { 85 int num_data_pairs = 86 dev_error->MemoryNumber + dev_error->IoNumber; 87 88 //Register pairs, described by the numeric fields. 89 //The actual "pairs" of address and data aren't necessarily 8 bytes long, so can't assume the contents. 90 //Hence the naming "firstHalf" and "secondHalf" rather than "address" and "data". 91 json_object *register_data_pair_array = json_object_new_array(); 92 UINT64 *cur_pos = (UINT64 *)(dev_error + 1); 93 for (int i = 0; i < num_data_pairs; i++) { 94 //Save current pair to array. 95 json_object *register_data_pair = 96 json_object_new_object(); 97 json_object_object_add( 98 register_data_pair, "firstHalf", 99 json_object_new_uint64(*cur_pos)); 100 json_object_object_add( 101 register_data_pair, "secondHalf", 102 json_object_new_uint64(*(cur_pos + 1))); 103 json_object_array_add(register_data_pair_array, 104 register_data_pair); 105 106 //Move to next pair. 107 cur_pos += 2; 108 } 109 json_object_object_add(section_ir, "registerDataPairs", 110 register_data_pair_array); 111 } 112 113 return section_ir; 114 } 115 116 void ir_section_pci_dev_to_cper(json_object *section, FILE *out) 117 { 118 EFI_PCI_PCIX_DEVICE_ERROR_DATA *section_cper = 119 (EFI_PCI_PCIX_DEVICE_ERROR_DATA *)calloc( 120 1, sizeof(EFI_PCI_PCIX_DEVICE_ERROR_DATA)); 121 122 //Validation bits. 123 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 }; 124 struct json_object *obj = NULL; 125 126 //Error status. 127 if (json_object_object_get_ex(section, "errorStatus", &obj)) { 128 ir_generic_error_status_to_cper(obj, 129 §ion_cper->ErrorStatus); 130 add_to_valid_bitfield(&ui64Type, 0); 131 } 132 133 //Device ID information. 134 if (json_object_object_get_ex(section, "idInfo", &obj)) { 135 json_object *id_info = obj; 136 section_cper->IdInfo.VendorId = json_object_get_uint64( 137 json_object_object_get(id_info, "vendorID")); 138 section_cper->IdInfo.DeviceId = json_object_get_uint64( 139 json_object_object_get(id_info, "deviceID")); 140 section_cper->IdInfo.ClassCode = json_object_get_uint64( 141 json_object_object_get(id_info, "classCode")); 142 section_cper->IdInfo.FunctionNumber = json_object_get_uint64( 143 json_object_object_get(id_info, "functionNumber")); 144 section_cper->IdInfo.DeviceNumber = json_object_get_uint64( 145 json_object_object_get(id_info, "deviceNumber")); 146 section_cper->IdInfo.BusNumber = json_object_get_uint64( 147 json_object_object_get(id_info, "busNumber")); 148 section_cper->IdInfo.SegmentNumber = json_object_get_uint64( 149 json_object_object_get(id_info, "segmentNumber")); 150 add_to_valid_bitfield(&ui64Type, 1); 151 } 152 153 //Amount of following data pairs. 154 if (json_object_object_get_ex(section, "memoryNumber", &obj)) { 155 section_cper->MemoryNumber = 156 (UINT32)json_object_get_uint64(obj); 157 add_to_valid_bitfield(&ui64Type, 2); 158 } 159 if (json_object_object_get_ex(section, "ioNumber", &obj)) { 160 section_cper->IoNumber = (UINT32)json_object_get_uint64(obj); 161 add_to_valid_bitfield(&ui64Type, 3); 162 } 163 json_object *register_pairs = NULL; 164 if (json_object_object_get_ex(section, "registerDataPairs", &obj)) { 165 register_pairs = obj; 166 add_to_valid_bitfield(&ui64Type, 4); 167 } 168 169 section_cper->ValidFields = ui64Type.value.ui64; 170 171 //Write header out to stream, free it. 172 fwrite(section_cper, sizeof(EFI_PCI_PCIX_DEVICE_ERROR_DATA), 1, out); 173 fflush(out); 174 free(section_cper); 175 176 //Begin writing register pairs. 177 if (register_pairs != NULL) { 178 int num_pairs = json_object_array_length(register_pairs); 179 for (int i = 0; i < num_pairs; i++) { 180 //Get the pair array item out. 181 json_object *register_pair = 182 json_object_array_get_idx(register_pairs, i); 183 184 //Create the pair array. 185 UINT64 pair[2]; 186 pair[0] = json_object_get_uint64(json_object_object_get( 187 register_pair, "firstHalf")); 188 pair[1] = json_object_get_uint64(json_object_object_get( 189 register_pair, "secondHalf")); 190 191 //Push to stream. 192 fwrite(pair, sizeof(UINT64), 2, out); 193 fflush(out); 194 } 195 } 196 } 197