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 <libcper/Cper.h> 10 #include <libcper/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, int out_len, 244 EFI_ERROR_TIME_STAMP *timestamp) 245 { 246 int written = snprintf( 247 out, out_len, 248 "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu+00:00", 249 bcd_to_int(timestamp->Century) % 250 100, //Cannot go to three digits. 251 bcd_to_int(timestamp->Year) % 100, //Cannot go to three digits. 252 bcd_to_int(timestamp->Month), bcd_to_int(timestamp->Day), 253 bcd_to_int(timestamp->Hours), bcd_to_int(timestamp->Minutes), 254 bcd_to_int(timestamp->Seconds)); 255 256 if (written < 0 || written >= out_len) { 257 printf("Timestamp buffer of insufficient size\n"); 258 } 259 } 260 261 //Converts a single timestamp string to an EFI timestamp. 262 void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp) 263 { 264 //Ignore invalid timestamps. 265 if (timestamp == NULL) { 266 return; 267 } 268 269 sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu+00:00", 270 &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours, 271 &out->Minutes, &out->Seconds); 272 273 //Convert back to BCD. 274 out->Century = int_to_bcd(out->Century); 275 out->Year = int_to_bcd(out->Year); 276 out->Month = int_to_bcd(out->Month); 277 out->Day = int_to_bcd(out->Day); 278 out->Hours = int_to_bcd(out->Hours); 279 out->Minutes = int_to_bcd(out->Minutes); 280 out->Seconds = int_to_bcd(out->Seconds); 281 } 282 283 //Helper function to convert an EDK EFI GUID into a string for intermediate use. 284 void guid_to_string(char *out, EFI_GUID *guid) 285 { 286 sprintf(out, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", 287 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], 288 guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], 289 guid->Data4[5], guid->Data4[6], guid->Data4[7]); 290 } 291 292 //Helper function to convert a string into an EDK EFI GUID. 293 void string_to_guid(EFI_GUID *out, const char *guid) 294 { 295 //Ignore invalid GUIDs. 296 if (guid == NULL) { 297 return; 298 } 299 300 sscanf(guid, 301 "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 302 &out->Data1, &out->Data2, &out->Data3, out->Data4, 303 out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4, 304 out->Data4 + 5, out->Data4 + 6, out->Data4 + 7); 305 } 306 307 //Returns one if two EFI GUIDs are equal, zero otherwise. 308 int guid_equal(EFI_GUID *a, EFI_GUID *b) 309 { 310 //Check top base 3 components. 311 if (a->Data1 != b->Data1 || a->Data2 != b->Data2 || 312 a->Data3 != b->Data3) { 313 return 0; 314 } 315 316 //Check Data4 array for equality. 317 for (int i = 0; i < 8; i++) { 318 if (a->Data4[i] != b->Data4[i]) { 319 return 0; 320 } 321 } 322 323 return 1; 324 } 325