1 /** 2 * Describes functions for converting PCI/PCI-X bus 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 <libcper/Cper.h> 11 #include <libcper/cper-utils.h> 12 #include <libcper/sections/cper-section-pci-bus.h> 13 #include <libcper/log.h> 14 15 //Converts a single PCI/PCI-X bus CPER section into JSON IR. 16 json_object *cper_section_pci_bus_to_ir(const UINT8 *section, UINT32 size) 17 { 18 if (size < sizeof(EFI_PCI_PCIX_BUS_ERROR_DATA)) { 19 return NULL; 20 } 21 22 EFI_PCI_PCIX_BUS_ERROR_DATA *bus_error = 23 (EFI_PCI_PCIX_BUS_ERROR_DATA *)section; 24 json_object *section_ir = json_object_new_object(); 25 26 //Validation bits. 27 ValidationTypes ui64Type = { UINT_64T, 28 .value.ui64 = bus_error->ValidFields }; 29 30 //Error status. 31 if (isvalid_prop_to_ir(&ui64Type, 0)) { 32 json_object *error_status = cper_generic_error_status_to_ir( 33 &bus_error->ErrorStatus); 34 json_object_object_add(section_ir, "errorStatus", error_status); 35 } 36 37 //PCI bus error type. 38 if (isvalid_prop_to_ir(&ui64Type, 1)) { 39 json_object *error_type = integer_to_readable_pair( 40 bus_error->Type, 8, PCI_BUS_ERROR_TYPES_KEYS, 41 PCI_BUS_ERROR_TYPES_VALUES, "Unknown (Reserved)"); 42 json_object_object_add(section_ir, "errorType", error_type); 43 } 44 45 //Bus ID. 46 if (isvalid_prop_to_ir(&ui64Type, 2)) { 47 json_object *bus_id = json_object_new_object(); 48 json_object_object_add(bus_id, "busNumber", 49 json_object_new_int(bus_error->BusId & 50 0xFF)); 51 json_object_object_add(bus_id, "segmentNumber", 52 json_object_new_int(bus_error->BusId >> 53 8)); 54 json_object_object_add(section_ir, "busID", bus_id); 55 } 56 57 //Miscellaneous numeric fields. 58 //Byte 7, bit 0. 59 UINT8 command_type = (bus_error->BusCommand >> 56) & 0x1; 60 if (isvalid_prop_to_ir(&ui64Type, 3)) { 61 json_object_object_add( 62 section_ir, "busAddress", 63 json_object_new_uint64(bus_error->BusAddress)); 64 } 65 if (isvalid_prop_to_ir(&ui64Type, 4)) { 66 json_object_object_add( 67 section_ir, "busData", 68 json_object_new_uint64(bus_error->BusData)); 69 } 70 if (isvalid_prop_to_ir(&ui64Type, 5)) { 71 json_object_object_add( 72 section_ir, "busCommandType", 73 json_object_new_string(command_type == 0 ? "PCI" : 74 "PCI-X")); 75 } 76 char hexstring_buf[EFI_UINT64_HEX_STRING_LEN]; 77 78 if (isvalid_prop_to_ir(&ui64Type, 6)) { 79 json_object_object_add( 80 section_ir, "busRequestorID", 81 json_object_new_uint64(bus_error->RequestorId)); 82 83 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%016llX", 84 bus_error->RequestorId); 85 json_object_object_add(section_ir, "busRequestorIDHex", 86 json_object_new_string(hexstring_buf)); 87 } 88 89 if (isvalid_prop_to_ir(&ui64Type, 7)) { 90 json_object_object_add( 91 section_ir, "busCompleterID", 92 json_object_new_uint64(bus_error->ResponderId)); 93 snprintf(hexstring_buf, EFI_UINT64_HEX_STRING_LEN, "0x%016llX", 94 bus_error->ResponderId); 95 json_object_object_add(section_ir, "busCompleterIDHex", 96 json_object_new_string(hexstring_buf)); 97 } 98 99 if (isvalid_prop_to_ir(&ui64Type, 8)) { 100 json_object_object_add( 101 section_ir, "targetID", 102 json_object_new_uint64(bus_error->TargetId)); 103 } 104 105 return section_ir; 106 } 107 108 //Converts a single provided PCI/PCI-X bus CPER-JSON section into CPER binary, outputting to the 109 //provided stream. 110 void ir_section_pci_bus_to_cper(json_object *section, FILE *out) 111 { 112 EFI_PCI_PCIX_BUS_ERROR_DATA *section_cper = 113 (EFI_PCI_PCIX_BUS_ERROR_DATA *)calloc( 114 1, sizeof(EFI_PCI_PCIX_BUS_ERROR_DATA)); 115 116 //Validation bits. 117 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 }; 118 struct json_object *obj = NULL; 119 120 //Error status. 121 if (json_object_object_get_ex(section, "errorStatus", &obj)) { 122 ir_generic_error_status_to_cper(obj, 123 §ion_cper->ErrorStatus); 124 add_to_valid_bitfield(&ui64Type, 0); 125 } 126 127 //Bus ID. 128 if (json_object_object_get_ex(section, "busID", &obj)) { 129 json_object *bus_id = json_object_object_get(section, "busID"); 130 UINT16 bus_number = (UINT8)json_object_get_int( 131 json_object_object_get(bus_id, "busNumber")); 132 UINT16 segment_number = (UINT8)json_object_get_int( 133 json_object_object_get(bus_id, "segmentNumber")); 134 section_cper->BusId = bus_number + (segment_number << 8); 135 add_to_valid_bitfield(&ui64Type, 2); 136 } 137 138 //Remaining fields. 139 UINT64 pcix_command = (UINT64)0x1 << 56; 140 141 if (json_object_object_get_ex(section, "errorType", &obj)) { 142 section_cper->Type = (UINT16)readable_pair_to_integer(obj); 143 add_to_valid_bitfield(&ui64Type, 1); 144 } 145 if (json_object_object_get_ex(section, "busAddress", &obj)) { 146 section_cper->BusAddress = json_object_get_uint64( 147 json_object_object_get(section, "busAddress")); 148 add_to_valid_bitfield(&ui64Type, 3); 149 } 150 if (json_object_object_get_ex(section, "busData", &obj)) { 151 section_cper->BusData = json_object_get_uint64(obj); 152 add_to_valid_bitfield(&ui64Type, 4); 153 } 154 if (json_object_object_get_ex(section, "busCommandType", &obj)) { 155 const char *bus_command = json_object_get_string(obj); 156 section_cper->BusCommand = 157 strcmp(bus_command, "PCI") == 0 ? 0 : pcix_command; 158 add_to_valid_bitfield(&ui64Type, 5); 159 } 160 if (json_object_object_get_ex(section, "busRequestorID", &obj)) { 161 section_cper->RequestorId = json_object_get_uint64(obj); 162 add_to_valid_bitfield(&ui64Type, 6); 163 } 164 if (json_object_object_get_ex(section, "busCompleterID", &obj)) { 165 section_cper->ResponderId = json_object_get_uint64(obj); 166 add_to_valid_bitfield(&ui64Type, 7); 167 } 168 if (json_object_object_get_ex(section, "targetID", &obj)) { 169 section_cper->TargetId = json_object_get_uint64(obj); 170 add_to_valid_bitfield(&ui64Type, 8); 171 } 172 section_cper->ValidFields = ui64Type.value.ui64; 173 174 //Write to stream, free resources. 175 fwrite(section_cper, sizeof(EFI_PCI_PCIX_BUS_ERROR_DATA), 1, out); 176 fflush(out); 177 free(section_cper); 178 } 179