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, 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 (keys[i] == value) 145 name = values[i]; 146 } 147 148 json_object_object_add(result, "name", json_object_new_string(name)); 149 return result; 150 } 151 152 //Converts a single integer value to an object containing a value, readable name and description if possible. 153 json_object *integer_to_readable_pair_with_desc(int value, int len, int keys[], 154 const char *values[], 155 const char *descriptions[], 156 const char *default_value) 157 { 158 json_object *result = json_object_new_object(); 159 json_object_object_add(result, "value", json_object_new_int(value)); 160 161 //Search for human readable name, add. 162 const char *name = default_value; 163 for (int i = 0; i < len; i++) { 164 if (keys[i] == value) { 165 name = values[i]; 166 json_object_object_add( 167 result, "description", 168 json_object_new_string(descriptions[i])); 169 } 170 } 171 172 json_object_object_add(result, "name", json_object_new_string(name)); 173 return result; 174 } 175 176 //Returns a single UINT64 value from the given readable pair object. 177 //Assumes the integer value is held in the "value" field. 178 UINT64 readable_pair_to_integer(json_object *pair) 179 { 180 return json_object_get_uint64(json_object_object_get(pair, "value")); 181 } 182 183 //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left. 184 json_object *bitfield_to_ir(UINT64 bitfield, int num_fields, 185 const char *names[]) 186 { 187 json_object *result = json_object_new_object(); 188 for (int i = 0; i < num_fields; i++) { 189 json_object_object_add(result, names[i], 190 json_object_new_boolean((bitfield >> i) & 191 0b1)); 192 } 193 194 return result; 195 } 196 197 //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0. 198 UINT64 ir_to_bitfield(json_object *ir, int num_fields, const char *names[]) 199 { 200 UINT64 result = 0x0; 201 for (int i = 0; i < num_fields; i++) { 202 if (json_object_get_boolean( 203 json_object_object_get(ir, names[i]))) 204 result |= (0x1 << i); 205 } 206 207 return result; 208 } 209 210 //Converts the given UINT64 array into a JSON IR array, given the length. 211 json_object *uint64_array_to_ir_array(UINT64 *array, int len) 212 { 213 json_object *array_ir = json_object_new_array(); 214 for (int i = 0; i < len; i++) 215 json_object_array_add(array_ir, 216 json_object_new_uint64(array[i])); 217 return array_ir; 218 } 219 220 //Converts a single UINT16 revision number into JSON IR representation. 221 json_object *revision_to_ir(UINT16 revision) 222 { 223 json_object *revision_info = json_object_new_object(); 224 json_object_object_add(revision_info, "major", 225 json_object_new_int(revision >> 8)); 226 json_object_object_add(revision_info, "minor", 227 json_object_new_int(revision & 0xFF)); 228 return revision_info; 229 } 230 231 //Returns the appropriate string for the given integer severity. 232 const char *severity_to_string(UINT32 severity) 233 { 234 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown"; 235 } 236 237 //Converts a single EFI timestamp to string, at the given output. 238 //Output must be at least TIMESTAMP_LENGTH bytes long. 239 void timestamp_to_string(char *out, EFI_ERROR_TIME_STAMP *timestamp) 240 { 241 sprintf(out, "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu.000", 242 bcd_to_int(timestamp->Century) % 243 100, //Cannot go to three digits. 244 bcd_to_int(timestamp->Year) % 100, //Cannot go to three digits. 245 bcd_to_int(timestamp->Month), bcd_to_int(timestamp->Day), 246 bcd_to_int(timestamp->Hours), bcd_to_int(timestamp->Minutes), 247 bcd_to_int(timestamp->Seconds)); 248 } 249 250 //Converts a single timestamp string to an EFI timestamp. 251 void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp) 252 { 253 //Ignore invalid timestamps. 254 if (timestamp == NULL) 255 return; 256 257 sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu.000", 258 &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours, 259 &out->Minutes, &out->Seconds); 260 261 //Convert back to BCD. 262 out->Century = int_to_bcd(out->Century); 263 out->Year = int_to_bcd(out->Year); 264 out->Month = int_to_bcd(out->Month); 265 out->Day = int_to_bcd(out->Day); 266 out->Hours = int_to_bcd(out->Hours); 267 out->Minutes = int_to_bcd(out->Minutes); 268 out->Seconds = int_to_bcd(out->Seconds); 269 } 270 271 //Helper function to convert an EDK EFI GUID into a string for intermediate use. 272 void guid_to_string(char *out, EFI_GUID *guid) 273 { 274 sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 275 guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], 276 guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], 277 guid->Data4[5], guid->Data4[6], guid->Data4[7]); 278 } 279 280 //Helper function to convert a string into an EDK EFI GUID. 281 void string_to_guid(EFI_GUID *out, const char *guid) 282 { 283 //Ignore invalid GUIDs. 284 if (guid == NULL) 285 return; 286 287 sscanf(guid, 288 "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 289 &out->Data1, &out->Data2, &out->Data3, out->Data4, 290 out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4, 291 out->Data4 + 5, out->Data4 + 6, out->Data4 + 7); 292 } 293 294 //Returns one if two EFI GUIDs are equal, zero otherwise. 295 int guid_equal(EFI_GUID *a, EFI_GUID *b) 296 { 297 //Check top base 3 components. 298 if (a->Data1 != b->Data1 || a->Data2 != b->Data2 || 299 a->Data3 != b->Data3) { 300 return 0; 301 } 302 303 //Check Data4 array for equality. 304 for (int i = 0; i < 8; i++) { 305 if (a->Data4[i] != b->Data4[i]) 306 return 0; 307 } 308 309 return 1; 310 }