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", 14 "Informational" }; 15 16 //Converts the given generic CPER error status to JSON IR. 17 json_object * 18 cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS *error_status) 19 { 20 json_object *error_status_ir = json_object_new_object(); 21 22 //Error type. 23 json_object_object_add(error_status_ir, "errorType", 24 integer_to_readable_pair_with_desc( 25 error_status->Type, 18, 26 CPER_GENERIC_ERROR_TYPES_KEYS, 27 CPER_GENERIC_ERROR_TYPES_VALUES, 28 CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS, 29 "Unknown (Reserved)")); 30 31 //Boolean bit fields. 32 json_object_object_add( 33 error_status_ir, "addressSignal", 34 json_object_new_boolean(error_status->AddressSignal)); 35 json_object_object_add( 36 error_status_ir, "controlSignal", 37 json_object_new_boolean(error_status->ControlSignal)); 38 json_object_object_add( 39 error_status_ir, "dataSignal", 40 json_object_new_boolean(error_status->DataSignal)); 41 json_object_object_add( 42 error_status_ir, "detectedByResponder", 43 json_object_new_boolean(error_status->DetectedByResponder)); 44 json_object_object_add( 45 error_status_ir, "detectedByRequester", 46 json_object_new_boolean(error_status->DetectedByRequester)); 47 json_object_object_add( 48 error_status_ir, "firstError", 49 json_object_new_boolean(error_status->FirstError)); 50 json_object_object_add( 51 error_status_ir, "overflowDroppedLogs", 52 json_object_new_boolean(error_status->OverflowNotLogged)); 53 54 return error_status_ir; 55 } 56 57 //Converts the given CPER-JSON generic error status into a CPER structure. 58 void ir_generic_error_status_to_cper( 59 json_object *error_status, EFI_GENERIC_ERROR_STATUS *error_status_cper) 60 { 61 error_status_cper->Type = readable_pair_to_integer( 62 json_object_object_get(error_status, "errorType")); 63 error_status_cper->AddressSignal = json_object_get_boolean( 64 json_object_object_get(error_status, "addressSignal")); 65 error_status_cper->ControlSignal = json_object_get_boolean( 66 json_object_object_get(error_status, "controlSignal")); 67 error_status_cper->DataSignal = json_object_get_boolean( 68 json_object_object_get(error_status, "dataSignal")); 69 error_status_cper->DetectedByResponder = json_object_get_boolean( 70 json_object_object_get(error_status, "detectedByResponder")); 71 error_status_cper->DetectedByRequester = json_object_get_boolean( 72 json_object_object_get(error_status, "detectedByRequester")); 73 error_status_cper->FirstError = json_object_get_boolean( 74 json_object_object_get(error_status, "firstError")); 75 error_status_cper->OverflowNotLogged = json_object_get_boolean( 76 json_object_object_get(error_status, "overflowDroppedLogs")); 77 } 78 79 //Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order. 80 json_object *uniform_struct64_to_ir(UINT64 *start, int len, const char *names[]) 81 { 82 json_object *result = json_object_new_object(); 83 84 UINT64 *cur = start; 85 for (int i = 0; i < len; i++) { 86 json_object_object_add(result, names[i], 87 json_object_new_uint64(*cur)); 88 cur++; 89 } 90 91 return result; 92 } 93 94 //Converts a single uniform struct of UINT32s into intermediate JSON IR format, given names for each field in byte order. 95 json_object *uniform_struct_to_ir(UINT32 *start, int len, const char *names[]) 96 { 97 json_object *result = json_object_new_object(); 98 99 UINT32 *cur = start; 100 for (int i = 0; i < len; i++) { 101 json_object_object_add(result, names[i], 102 json_object_new_uint64(*cur)); 103 cur++; 104 } 105 106 return result; 107 } 108 109 //Converts a single object containing UINT32s into a uniform struct. 110 void ir_to_uniform_struct64(json_object *ir, UINT64 *start, int len, 111 const char *names[]) 112 { 113 UINT64 *cur = start; 114 for (int i = 0; i < len; i++) { 115 *cur = json_object_get_uint64( 116 json_object_object_get(ir, names[i])); 117 cur++; 118 } 119 } 120 121 //Converts a single object containing UINT32s into a uniform struct. 122 void ir_to_uniform_struct(json_object *ir, UINT32 *start, int len, 123 const char *names[]) 124 { 125 UINT32 *cur = start; 126 for (int i = 0; i < len; i++) { 127 *cur = (UINT32)json_object_get_uint64( 128 json_object_object_get(ir, names[i])); 129 cur++; 130 } 131 } 132 133 //Converts a single integer value to an object containing a value, and a readable name if possible. 134 json_object *integer_to_readable_pair(UINT64 value, int len, const int keys[], 135 const char *values[], 136 const char *default_value) 137 { 138 json_object *result = json_object_new_object(); 139 json_object_object_add(result, "value", json_object_new_uint64(value)); 140 141 //Search for human readable name, add. 142 const char *name = default_value; 143 for (int i = 0; i < len; i++) { 144 if ((UINT64)keys[i] == value) { 145 name = values[i]; 146 } 147 } 148 149 json_object_object_add(result, "name", json_object_new_string(name)); 150 return result; 151 } 152 153 //Converts a single integer value to an object containing a value, readable name and description if possible. 154 json_object *integer_to_readable_pair_with_desc(int value, int len, 155 const int keys[], 156 const char *values[], 157 const char *descriptions[], 158 const char *default_value) 159 { 160 json_object *result = json_object_new_object(); 161 json_object_object_add(result, "value", json_object_new_int(value)); 162 163 //Search for human readable name, add. 164 const char *name = default_value; 165 for (int i = 0; i < len; i++) { 166 if (keys[i] == value) { 167 name = values[i]; 168 json_object_object_add( 169 result, "description", 170 json_object_new_string(descriptions[i])); 171 } 172 } 173 174 json_object_object_add(result, "name", json_object_new_string(name)); 175 return result; 176 } 177 178 //Returns a single UINT64 value from the given readable pair object. 179 //Assumes the integer value is held in the "value" field. 180 UINT64 readable_pair_to_integer(json_object *pair) 181 { 182 return json_object_get_uint64(json_object_object_get(pair, "value")); 183 } 184 185 //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left. 186 json_object *bitfield_to_ir(UINT64 bitfield, int num_fields, 187 const char *names[]) 188 { 189 json_object *result = json_object_new_object(); 190 for (int i = 0; i < num_fields; i++) { 191 json_object_object_add(result, names[i], 192 json_object_new_boolean((bitfield >> i) & 193 0x1)); 194 } 195 196 return result; 197 } 198 199 //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0. 200 UINT64 ir_to_bitfield(json_object *ir, int num_fields, const char *names[]) 201 { 202 UINT64 result = 0x0; 203 for (int i = 0; i < num_fields; i++) { 204 if (json_object_get_boolean( 205 json_object_object_get(ir, names[i]))) { 206 result |= (0x1 << i); 207 } 208 } 209 210 return result; 211 } 212 213 //Converts the given UINT64 array into a JSON IR array, given the length. 214 json_object *uint64_array_to_ir_array(UINT64 *array, int len) 215 { 216 json_object *array_ir = json_object_new_array(); 217 for (int i = 0; i < len; i++) { 218 json_object_array_add(array_ir, 219 json_object_new_uint64(array[i])); 220 } 221 return array_ir; 222 } 223 224 //Converts a single UINT16 revision number into JSON IR representation. 225 json_object *revision_to_ir(UINT16 revision) 226 { 227 json_object *revision_info = json_object_new_object(); 228 json_object_object_add(revision_info, "major", 229 json_object_new_int(revision >> 8)); 230 json_object_object_add(revision_info, "minor", 231 json_object_new_int(revision & 0xFF)); 232 return revision_info; 233 } 234 235 //Returns the appropriate string for the given integer severity. 236 const char *severity_to_string(UINT32 severity) 237 { 238 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown"; 239 } 240 241 //Converts a single EFI timestamp to string, at the given output. 242 //Output must be at least TIMESTAMP_LENGTH bytes long. 243 void timestamp_to_string(char *out, EFI_ERROR_TIME_STAMP *timestamp) 244 { 245 sprintf(out, "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu.000", 246 bcd_to_int(timestamp->Century) % 247 100, //Cannot go to three digits. 248 bcd_to_int(timestamp->Year) % 100, //Cannot go to three digits. 249 bcd_to_int(timestamp->Month), bcd_to_int(timestamp->Day), 250 bcd_to_int(timestamp->Hours), bcd_to_int(timestamp->Minutes), 251 bcd_to_int(timestamp->Seconds)); 252 } 253 254 //Converts a single timestamp string to an EFI timestamp. 255 void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp) 256 { 257 //Ignore invalid timestamps. 258 if (timestamp == NULL) { 259 return; 260 } 261 262 sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu.000", 263 &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours, 264 &out->Minutes, &out->Seconds); 265 266 //Convert back to BCD. 267 out->Century = int_to_bcd(out->Century); 268 out->Year = int_to_bcd(out->Year); 269 out->Month = int_to_bcd(out->Month); 270 out->Day = int_to_bcd(out->Day); 271 out->Hours = int_to_bcd(out->Hours); 272 out->Minutes = int_to_bcd(out->Minutes); 273 out->Seconds = int_to_bcd(out->Seconds); 274 } 275 276 //Helper function to convert an EDK EFI GUID into a string for intermediate use. 277 void guid_to_string(char *out, EFI_GUID *guid) 278 { 279 sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 280 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], 281 guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], 282 guid->Data4[5], guid->Data4[6], guid->Data4[7]); 283 } 284 285 //Helper function to convert a string into an EDK EFI GUID. 286 void string_to_guid(EFI_GUID *out, const char *guid) 287 { 288 //Ignore invalid GUIDs. 289 if (guid == NULL) { 290 return; 291 } 292 293 sscanf(guid, 294 "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 295 &out->Data1, &out->Data2, &out->Data3, out->Data4, 296 out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4, 297 out->Data4 + 5, out->Data4 + 6, out->Data4 + 7); 298 } 299 300 //Returns one if two EFI GUIDs are equal, zero otherwise. 301 int guid_equal(EFI_GUID *a, EFI_GUID *b) 302 { 303 //Check top base 3 components. 304 if (a->Data1 != b->Data1 || a->Data2 != b->Data2 || 305 a->Data3 != b->Data3) { 306 return 0; 307 } 308 309 //Check Data4 array for equality. 310 for (int i = 0; i < 8; i++) { 311 if (a->Data4[i] != b->Data4[i]) { 312 return 0; 313 } 314 } 315 316 return 1; 317 } 318