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