1 /** 2 * Describes utility functions for parsing CPER into JSON IR. 3 * 4 * Author: Lawrence.Tang@arm.com 5 **/ 6 7 #include <stdio.h> 8 #include "json.h" 9 #include "edk/Cper.h" 10 #include "cper-utils.h" 11 12 //The available severity types for CPER. 13 const char* CPER_SEVERITY_TYPES[4] = {"Recoverable", "Fatal", "Corrected", "Informational"}; 14 15 //Converts the given generic CPER error status to JSON IR. 16 json_object* cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS* error_status) 17 { 18 json_object* error_status_ir = json_object_new_object(); 19 20 //Error type. 21 json_object_object_add(error_status_ir, "errorType", integer_to_readable_pair_with_desc(error_status->Type, 18, 22 CPER_GENERIC_ERROR_TYPES_KEYS, 23 CPER_GENERIC_ERROR_TYPES_VALUES, 24 CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS, 25 "Unknown (Reserved)")); 26 27 //Boolean bit fields. 28 json_object_object_add(error_status_ir, "addressSignal", json_object_new_boolean(error_status->AddressSignal)); 29 json_object_object_add(error_status_ir, "controlSignal", json_object_new_boolean(error_status->ControlSignal)); 30 json_object_object_add(error_status_ir, "dataSignal", json_object_new_boolean(error_status->DataSignal)); 31 json_object_object_add(error_status_ir, "detectedByResponder", json_object_new_boolean(error_status->DetectedByResponder)); 32 json_object_object_add(error_status_ir, "detectedByRequester", json_object_new_boolean(error_status->DetectedByRequester)); 33 json_object_object_add(error_status_ir, "firstError", json_object_new_boolean(error_status->FirstError)); 34 json_object_object_add(error_status_ir, "overflowDroppedLogs", json_object_new_boolean(error_status->OverflowNotLogged)); 35 36 return error_status_ir; 37 } 38 39 //Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order. 40 json_object* uniform_struct64_to_ir(UINT64* start, int len, const char* names[]) 41 { 42 json_object* result = json_object_new_object(); 43 44 UINT64* cur = start; 45 for (int i=0; i<len; i++) 46 { 47 json_object_object_add(result, names[i], json_object_new_uint64(*cur)); 48 cur++; 49 } 50 51 return result; 52 } 53 54 //Converts a single uniform struct of UINT32s into intermediate JSON IR format, given names for each field in byte order. 55 json_object* uniform_struct_to_ir(UINT32* start, int len, const char* names[]) 56 { 57 json_object* result = json_object_new_object(); 58 59 UINT32* cur = start; 60 for (int i=0; i<len; i++) 61 { 62 json_object_object_add(result, names[i], json_object_new_uint64(*cur)); 63 cur++; 64 } 65 66 return result; 67 } 68 69 //Converts a single integer value to an object containing a value, and a readable name if possible. 70 json_object* integer_to_readable_pair(UINT64 value, int len, int keys[], const char* values[], const char* default_value) 71 { 72 json_object* result = json_object_new_object(); 73 json_object_object_add(result, "value", json_object_new_uint64(value)); 74 75 //Search for human readable name, add. 76 const char* name = default_value; 77 for (int i=0; i<len; i++) 78 { 79 if (keys[i] == value) 80 name = values[i]; 81 } 82 83 json_object_object_add(result, "name", json_object_new_string(name)); 84 return result; 85 } 86 87 //Converts a single integer value to an object containing a value, readable name and description if possible. 88 json_object* integer_to_readable_pair_with_desc(int value, int len, int keys[], const char* values[], 89 const char* descriptions[], const char* default_value) 90 { 91 json_object* result = json_object_new_object(); 92 json_object_object_add(result, "value", json_object_new_int(value)); 93 94 //Search for human readable name, add. 95 const char* name = default_value; 96 for (int i=0; i<len; i++) 97 { 98 if (keys[i] == value) 99 { 100 name = values[i]; 101 json_object_object_add(result, "description", json_object_new_string(descriptions[i])); 102 } 103 } 104 105 json_object_object_add(result, "name", json_object_new_string(name)); 106 return result; 107 } 108 109 //Returns a single UINT64 value from the given readable pair object. 110 //Assumes the integer value is held in the "value" field. 111 UINT64 readable_pair_to_integer(json_object* pair) 112 { 113 return json_object_get_uint64(json_object_object_get(pair, "value")); 114 } 115 116 //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left. 117 json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[]) 118 { 119 json_object* result = json_object_new_object(); 120 for (int i=0; i<num_fields; i++) 121 { 122 json_object_object_add(result, names[i], json_object_new_boolean((bitfield >> i) & 0b1)); 123 } 124 125 return result; 126 } 127 128 //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0. 129 UINT64 ir_to_bitfield(json_object* ir, int num_fields, const char* names[]) 130 { 131 UINT64 result = 0x0; 132 for (int i=0; i<num_fields; i++) 133 { 134 if (json_object_get_boolean(json_object_object_get(ir, names[i]))) 135 result |= (0x1 << i); 136 } 137 138 return result; 139 } 140 141 //Converts the given UINT64 array into a JSON IR array, given the length. 142 json_object* uint64_array_to_ir_array(UINT64* array, int len) 143 { 144 json_object* array_ir = json_object_new_array(); 145 for (int i=0; i<len; i++) 146 json_object_array_add(array_ir, json_object_new_uint64(array[i])); 147 return array_ir; 148 } 149 150 //Converts a single UINT16 revision number into JSON IR representation. 151 json_object* revision_to_ir(UINT16 revision) 152 { 153 json_object* revision_info = json_object_new_object(); 154 json_object_object_add(revision_info, "major", json_object_new_int(revision >> 8)); 155 json_object_object_add(revision_info, "minor", json_object_new_int(revision & 0xFF)); 156 return revision_info; 157 } 158 159 //Returns the appropriate string for the given integer severity. 160 const char* severity_to_string(UINT8 severity) 161 { 162 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown"; 163 } 164 165 //Converts a single EFI timestamp to string, at the given output. 166 //Output must be at least TIMESTAMP_LENGTH bytes long. 167 void timestamp_to_string(char* out, EFI_ERROR_TIME_STAMP* timestamp) 168 { 169 sprintf(out, "%02d%02d-%02d-%02dT%02d:%02d:%02d.000", 170 timestamp->Century, 171 timestamp->Year, 172 timestamp->Month, 173 timestamp->Day, 174 timestamp->Hours, 175 timestamp->Minutes, 176 timestamp->Seconds); 177 } 178 179 //Converts a single timestamp string to an EFI timestamp. 180 void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp) 181 { 182 sscanf(timestamp, "%02d%02d-%02d-%02dT%02d:%02d:%02d.000", 183 &out->Century, 184 &out->Year, 185 &out->Month, 186 &out->Day, 187 &out->Hours, 188 &out->Minutes, 189 &out->Seconds); 190 } 191 192 //Helper function to convert an EDK EFI GUID into a string for intermediate use. 193 void guid_to_string(char* out, EFI_GUID* guid) 194 { 195 sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 196 guid->Data1, 197 guid->Data2, 198 guid->Data3, 199 guid->Data4[0], 200 guid->Data4[1], 201 guid->Data4[2], 202 guid->Data4[3], 203 guid->Data4[4], 204 guid->Data4[5], 205 guid->Data4[6], 206 guid->Data4[7]); 207 } 208 209 //Helper function to convert a string into an EDK EFI GUID. 210 void string_to_guid(EFI_GUID* out, const char* guid) 211 { 212 sscanf(guid, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 213 &out->Data1, 214 &out->Data2, 215 &out->Data3, 216 out->Data4, 217 out->Data4 + 1, 218 out->Data4 + 2, 219 out->Data4 + 3, 220 out->Data4 + 4, 221 out->Data4 + 5, 222 out->Data4 + 6, 223 out->Data4 + 7); 224 } 225 226 //Returns one if two EFI GUIDs are equal, zero otherwise. 227 int guid_equal(EFI_GUID* a, EFI_GUID* b) 228 { 229 //Check top base 3 components. 230 if (a->Data1 != b->Data1 231 || a->Data2 != b->Data2 232 || a->Data3 != b->Data3) 233 { 234 return 0; 235 } 236 237 //Check Data4 array for equality. 238 for (int i=0; i<8; i++) 239 { 240 if (a->Data4[i] != b->Data4[i]) 241 return 0; 242 } 243 244 return 1; 245 } 246 247 //Converts the given BCD byte to a standard integer. 248 int bcd_to_int(UINT8 bcd) 249 { 250 return ((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F); 251 }