11b0b00e3SLawrence Tang /** 21b0b00e3SLawrence Tang * Describes utility functions for parsing CPER into JSON IR. 31b0b00e3SLawrence Tang * 41b0b00e3SLawrence Tang * Author: Lawrence.Tang@arm.com 51b0b00e3SLawrence Tang **/ 61b0b00e3SLawrence Tang 71b0b00e3SLawrence Tang #include <stdio.h> 85202bbb4SLawrence Tang #include <json.h> 91b0b00e3SLawrence Tang #include "edk/Cper.h" 101b0b00e3SLawrence Tang #include "cper-utils.h" 111b0b00e3SLawrence Tang 121b0b00e3SLawrence Tang //The available severity types for CPER. 13e407b4c8SLawrence Tang const char *CPER_SEVERITY_TYPES[4] = { "Recoverable", "Fatal", "Corrected", 14e407b4c8SLawrence Tang "Informational" }; 151b0b00e3SLawrence Tang 16a0865e38SLawrence Tang //Converts the given generic CPER error status to JSON IR. 17e407b4c8SLawrence Tang json_object * 18e407b4c8SLawrence Tang cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS *error_status) 19a0865e38SLawrence Tang { 20a0865e38SLawrence Tang json_object *error_status_ir = json_object_new_object(); 21a0865e38SLawrence Tang 22a0865e38SLawrence Tang //Error type. 23e407b4c8SLawrence Tang json_object_object_add(error_status_ir, "errorType", 24e407b4c8SLawrence Tang integer_to_readable_pair_with_desc( 25e407b4c8SLawrence Tang error_status->Type, 18, 26a0865e38SLawrence Tang CPER_GENERIC_ERROR_TYPES_KEYS, 27a0865e38SLawrence Tang CPER_GENERIC_ERROR_TYPES_VALUES, 28a0865e38SLawrence Tang CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS, 29a0865e38SLawrence Tang "Unknown (Reserved)")); 30a0865e38SLawrence Tang 31a0865e38SLawrence Tang //Boolean bit fields. 32e407b4c8SLawrence Tang json_object_object_add( 33e407b4c8SLawrence Tang error_status_ir, "addressSignal", 34e407b4c8SLawrence Tang json_object_new_boolean(error_status->AddressSignal)); 35e407b4c8SLawrence Tang json_object_object_add( 36e407b4c8SLawrence Tang error_status_ir, "controlSignal", 37e407b4c8SLawrence Tang json_object_new_boolean(error_status->ControlSignal)); 38e407b4c8SLawrence Tang json_object_object_add( 39e407b4c8SLawrence Tang error_status_ir, "dataSignal", 40e407b4c8SLawrence Tang json_object_new_boolean(error_status->DataSignal)); 41e407b4c8SLawrence Tang json_object_object_add( 42e407b4c8SLawrence Tang error_status_ir, "detectedByResponder", 43e407b4c8SLawrence Tang json_object_new_boolean(error_status->DetectedByResponder)); 44e407b4c8SLawrence Tang json_object_object_add( 45e407b4c8SLawrence Tang error_status_ir, "detectedByRequester", 46e407b4c8SLawrence Tang json_object_new_boolean(error_status->DetectedByRequester)); 47e407b4c8SLawrence Tang json_object_object_add( 48e407b4c8SLawrence Tang error_status_ir, "firstError", 49e407b4c8SLawrence Tang json_object_new_boolean(error_status->FirstError)); 50e407b4c8SLawrence Tang json_object_object_add( 51e407b4c8SLawrence Tang error_status_ir, "overflowDroppedLogs", 52e407b4c8SLawrence Tang json_object_new_boolean(error_status->OverflowNotLogged)); 53a0865e38SLawrence Tang 54a0865e38SLawrence Tang return error_status_ir; 55a0865e38SLawrence Tang } 56a0865e38SLawrence Tang 573b7f45b5SLawrence Tang //Converts the given CPER-JSON generic error status into a CPER structure. 58e407b4c8SLawrence Tang void ir_generic_error_status_to_cper( 59e407b4c8SLawrence Tang json_object *error_status, EFI_GENERIC_ERROR_STATUS *error_status_cper) 603b7f45b5SLawrence Tang { 61e407b4c8SLawrence Tang error_status_cper->Type = readable_pair_to_integer( 62e407b4c8SLawrence Tang json_object_object_get(error_status, "errorType")); 63e407b4c8SLawrence Tang error_status_cper->AddressSignal = json_object_get_boolean( 64e407b4c8SLawrence Tang json_object_object_get(error_status, "addressSignal")); 65e407b4c8SLawrence Tang error_status_cper->ControlSignal = json_object_get_boolean( 66e407b4c8SLawrence Tang json_object_object_get(error_status, "controlSignal")); 67e407b4c8SLawrence Tang error_status_cper->DataSignal = json_object_get_boolean( 68e407b4c8SLawrence Tang json_object_object_get(error_status, "dataSignal")); 69e407b4c8SLawrence Tang error_status_cper->DetectedByResponder = json_object_get_boolean( 70e407b4c8SLawrence Tang json_object_object_get(error_status, "detectedByResponder")); 71e407b4c8SLawrence Tang error_status_cper->DetectedByRequester = json_object_get_boolean( 72e407b4c8SLawrence Tang json_object_object_get(error_status, "detectedByRequester")); 73e407b4c8SLawrence Tang error_status_cper->FirstError = json_object_get_boolean( 74e407b4c8SLawrence Tang json_object_object_get(error_status, "firstError")); 75e407b4c8SLawrence Tang error_status_cper->OverflowNotLogged = json_object_get_boolean( 76e407b4c8SLawrence Tang json_object_object_get(error_status, "overflowDroppedLogs")); 773b7f45b5SLawrence Tang } 783b7f45b5SLawrence Tang 797f21db6cSLawrence Tang //Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order. 807f21db6cSLawrence Tang json_object *uniform_struct64_to_ir(UINT64 *start, int len, const char *names[]) 817f21db6cSLawrence Tang { 827f21db6cSLawrence Tang json_object *result = json_object_new_object(); 837f21db6cSLawrence Tang 847f21db6cSLawrence Tang UINT64 *cur = start; 85e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 86e407b4c8SLawrence Tang json_object_object_add(result, names[i], 87e407b4c8SLawrence Tang json_object_new_uint64(*cur)); 887f21db6cSLawrence Tang cur++; 897f21db6cSLawrence Tang } 907f21db6cSLawrence Tang 917f21db6cSLawrence Tang return result; 927f21db6cSLawrence Tang } 937f21db6cSLawrence Tang 947f21db6cSLawrence Tang //Converts a single uniform struct of UINT32s into intermediate JSON IR format, given names for each field in byte order. 957f21db6cSLawrence Tang json_object *uniform_struct_to_ir(UINT32 *start, int len, const char *names[]) 967f21db6cSLawrence Tang { 977f21db6cSLawrence Tang json_object *result = json_object_new_object(); 987f21db6cSLawrence Tang 997f21db6cSLawrence Tang UINT32 *cur = start; 100e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 101e407b4c8SLawrence Tang json_object_object_add(result, names[i], 102e407b4c8SLawrence Tang json_object_new_uint64(*cur)); 1037f21db6cSLawrence Tang cur++; 1047f21db6cSLawrence Tang } 1057f21db6cSLawrence Tang 1067f21db6cSLawrence Tang return result; 1077f21db6cSLawrence Tang } 1087f21db6cSLawrence Tang 10971570a2aSLawrence Tang //Converts a single object containing UINT32s into a uniform struct. 110e407b4c8SLawrence Tang void ir_to_uniform_struct64(json_object *ir, UINT64 *start, int len, 111e407b4c8SLawrence Tang const char *names[]) 11271570a2aSLawrence Tang { 11371570a2aSLawrence Tang UINT64 *cur = start; 114e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 115e407b4c8SLawrence Tang *cur = json_object_get_uint64( 116e407b4c8SLawrence Tang json_object_object_get(ir, names[i])); 11771570a2aSLawrence Tang cur++; 11871570a2aSLawrence Tang } 11971570a2aSLawrence Tang } 12071570a2aSLawrence Tang 12171570a2aSLawrence Tang //Converts a single object containing UINT32s into a uniform struct. 122e407b4c8SLawrence Tang void ir_to_uniform_struct(json_object *ir, UINT32 *start, int len, 123e407b4c8SLawrence Tang const char *names[]) 12471570a2aSLawrence Tang { 12571570a2aSLawrence Tang UINT32 *cur = start; 126e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 127e407b4c8SLawrence Tang *cur = (UINT32)json_object_get_uint64( 128e407b4c8SLawrence Tang json_object_object_get(ir, names[i])); 12971570a2aSLawrence Tang cur++; 13071570a2aSLawrence Tang } 13171570a2aSLawrence Tang } 13271570a2aSLawrence Tang 1333c43f743SLawrence Tang //Converts a single integer value to an object containing a value, and a readable name if possible. 134e407b4c8SLawrence Tang json_object *integer_to_readable_pair(UINT64 value, int len, int keys[], 135e407b4c8SLawrence Tang const char *values[], 136e407b4c8SLawrence Tang const char *default_value) 1373c43f743SLawrence Tang { 1383c43f743SLawrence Tang json_object *result = json_object_new_object(); 1393c878352SLawrence Tang json_object_object_add(result, "value", json_object_new_uint64(value)); 1403c43f743SLawrence Tang 1413c43f743SLawrence Tang //Search for human readable name, add. 142794312c8SLawrence Tang const char *name = default_value; 143e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 144*f8fc7052SJohn Chung if ((UINT64)keys[i] == value) { 1453c43f743SLawrence Tang name = values[i]; 1463c43f743SLawrence Tang } 147*f8fc7052SJohn Chung } 1483c43f743SLawrence Tang 1493c43f743SLawrence Tang json_object_object_add(result, "name", json_object_new_string(name)); 1503c43f743SLawrence Tang return result; 1513c43f743SLawrence Tang } 1523c43f743SLawrence Tang 1537f21db6cSLawrence Tang //Converts a single integer value to an object containing a value, readable name and description if possible. 154e407b4c8SLawrence Tang json_object *integer_to_readable_pair_with_desc(int value, int len, int keys[], 155e407b4c8SLawrence Tang const char *values[], 156e407b4c8SLawrence Tang const char *descriptions[], 157e407b4c8SLawrence Tang const char *default_value) 1587f21db6cSLawrence Tang { 1597f21db6cSLawrence Tang json_object *result = json_object_new_object(); 1607f21db6cSLawrence Tang json_object_object_add(result, "value", json_object_new_int(value)); 1617f21db6cSLawrence Tang 1627f21db6cSLawrence Tang //Search for human readable name, add. 1637f21db6cSLawrence Tang const char *name = default_value; 164e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 165e407b4c8SLawrence Tang if (keys[i] == value) { 1667f21db6cSLawrence Tang name = values[i]; 167e407b4c8SLawrence Tang json_object_object_add( 168e407b4c8SLawrence Tang result, "description", 169e407b4c8SLawrence Tang json_object_new_string(descriptions[i])); 1707f21db6cSLawrence Tang } 1717f21db6cSLawrence Tang } 1727f21db6cSLawrence Tang 1737f21db6cSLawrence Tang json_object_object_add(result, "name", json_object_new_string(name)); 1747f21db6cSLawrence Tang return result; 1757f21db6cSLawrence Tang } 1767f21db6cSLawrence Tang 177b44314c7SLawrence Tang //Returns a single UINT64 value from the given readable pair object. 178b44314c7SLawrence Tang //Assumes the integer value is held in the "value" field. 179b44314c7SLawrence Tang UINT64 readable_pair_to_integer(json_object *pair) 180b44314c7SLawrence Tang { 181b44314c7SLawrence Tang return json_object_get_uint64(json_object_object_get(pair, "value")); 182b44314c7SLawrence Tang } 183b44314c7SLawrence Tang 184794312c8SLawrence Tang //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left. 185e407b4c8SLawrence Tang json_object *bitfield_to_ir(UINT64 bitfield, int num_fields, 186e407b4c8SLawrence Tang const char *names[]) 187794312c8SLawrence Tang { 188794312c8SLawrence Tang json_object *result = json_object_new_object(); 189e407b4c8SLawrence Tang for (int i = 0; i < num_fields; i++) { 190e407b4c8SLawrence Tang json_object_object_add(result, names[i], 191e407b4c8SLawrence Tang json_object_new_boolean((bitfield >> i) & 192*f8fc7052SJohn Chung 0x1)); 193794312c8SLawrence Tang } 194794312c8SLawrence Tang 195794312c8SLawrence Tang return result; 196794312c8SLawrence Tang } 197794312c8SLawrence Tang 198b44314c7SLawrence Tang //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0. 199b44314c7SLawrence Tang UINT64 ir_to_bitfield(json_object *ir, int num_fields, const char *names[]) 200b44314c7SLawrence Tang { 201b44314c7SLawrence Tang UINT64 result = 0x0; 202e407b4c8SLawrence Tang for (int i = 0; i < num_fields; i++) { 203e407b4c8SLawrence Tang if (json_object_get_boolean( 204*f8fc7052SJohn Chung json_object_object_get(ir, names[i]))) { 205b44314c7SLawrence Tang result |= (0x1 << i); 206b44314c7SLawrence Tang } 207*f8fc7052SJohn Chung } 208b44314c7SLawrence Tang 209b44314c7SLawrence Tang return result; 210b44314c7SLawrence Tang } 211b44314c7SLawrence Tang 212e18aaee9SLawrence Tang //Converts the given UINT64 array into a JSON IR array, given the length. 213e18aaee9SLawrence Tang json_object *uint64_array_to_ir_array(UINT64 *array, int len) 214e18aaee9SLawrence Tang { 215e18aaee9SLawrence Tang json_object *array_ir = json_object_new_array(); 216*f8fc7052SJohn Chung for (int i = 0; i < len; i++) { 217e407b4c8SLawrence Tang json_object_array_add(array_ir, 218e407b4c8SLawrence Tang json_object_new_uint64(array[i])); 219*f8fc7052SJohn Chung } 220e18aaee9SLawrence Tang return array_ir; 221e18aaee9SLawrence Tang } 222794312c8SLawrence Tang 2231b0b00e3SLawrence Tang //Converts a single UINT16 revision number into JSON IR representation. 2241b0b00e3SLawrence Tang json_object *revision_to_ir(UINT16 revision) 2251b0b00e3SLawrence Tang { 2261b0b00e3SLawrence Tang json_object *revision_info = json_object_new_object(); 227e407b4c8SLawrence Tang json_object_object_add(revision_info, "major", 228e407b4c8SLawrence Tang json_object_new_int(revision >> 8)); 229e407b4c8SLawrence Tang json_object_object_add(revision_info, "minor", 230e407b4c8SLawrence Tang json_object_new_int(revision & 0xFF)); 2311b0b00e3SLawrence Tang return revision_info; 2321b0b00e3SLawrence Tang } 2331b0b00e3SLawrence Tang 2341b0b00e3SLawrence Tang //Returns the appropriate string for the given integer severity. 23502c801a5SLawrence Tang const char *severity_to_string(UINT32 severity) 2361b0b00e3SLawrence Tang { 2371b0b00e3SLawrence Tang return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown"; 2381b0b00e3SLawrence Tang } 2391b0b00e3SLawrence Tang 240b44314c7SLawrence Tang //Converts a single EFI timestamp to string, at the given output. 241b44314c7SLawrence Tang //Output must be at least TIMESTAMP_LENGTH bytes long. 242b44314c7SLawrence Tang void timestamp_to_string(char *out, EFI_ERROR_TIME_STAMP *timestamp) 243b44314c7SLawrence Tang { 244aacf0e26SLawrence Tang sprintf(out, "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu.000", 245e407b4c8SLawrence Tang bcd_to_int(timestamp->Century) % 246e407b4c8SLawrence Tang 100, //Cannot go to three digits. 247aacf0e26SLawrence Tang bcd_to_int(timestamp->Year) % 100, //Cannot go to three digits. 248e407b4c8SLawrence Tang bcd_to_int(timestamp->Month), bcd_to_int(timestamp->Day), 249e407b4c8SLawrence Tang bcd_to_int(timestamp->Hours), bcd_to_int(timestamp->Minutes), 250aacf0e26SLawrence Tang bcd_to_int(timestamp->Seconds)); 251b44314c7SLawrence Tang } 252b44314c7SLawrence Tang 253b44314c7SLawrence Tang //Converts a single timestamp string to an EFI timestamp. 254b44314c7SLawrence Tang void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp) 255b44314c7SLawrence Tang { 2560cb33793SLawrence Tang //Ignore invalid timestamps. 257*f8fc7052SJohn Chung if (timestamp == NULL) { 2580cb33793SLawrence Tang return; 259*f8fc7052SJohn Chung } 2600cb33793SLawrence Tang 261aacf0e26SLawrence Tang sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu.000", 262e407b4c8SLawrence Tang &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours, 263e407b4c8SLawrence Tang &out->Minutes, &out->Seconds); 264aacf0e26SLawrence Tang 265aacf0e26SLawrence Tang //Convert back to BCD. 266aacf0e26SLawrence Tang out->Century = int_to_bcd(out->Century); 267aacf0e26SLawrence Tang out->Year = int_to_bcd(out->Year); 268aacf0e26SLawrence Tang out->Month = int_to_bcd(out->Month); 269aacf0e26SLawrence Tang out->Day = int_to_bcd(out->Day); 270aacf0e26SLawrence Tang out->Hours = int_to_bcd(out->Hours); 271aacf0e26SLawrence Tang out->Minutes = int_to_bcd(out->Minutes); 272aacf0e26SLawrence Tang out->Seconds = int_to_bcd(out->Seconds); 273b44314c7SLawrence Tang } 274b44314c7SLawrence Tang 2751b0b00e3SLawrence Tang //Helper function to convert an EDK EFI GUID into a string for intermediate use. 2761b0b00e3SLawrence Tang void guid_to_string(char *out, EFI_GUID *guid) 2771b0b00e3SLawrence Tang { 2781b0b00e3SLawrence Tang sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 279e407b4c8SLawrence Tang guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], 280e407b4c8SLawrence Tang guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], 281e407b4c8SLawrence Tang guid->Data4[5], guid->Data4[6], guid->Data4[7]); 2821b0b00e3SLawrence Tang } 2831b0b00e3SLawrence Tang 284b44314c7SLawrence Tang //Helper function to convert a string into an EDK EFI GUID. 285b44314c7SLawrence Tang void string_to_guid(EFI_GUID *out, const char *guid) 286b44314c7SLawrence Tang { 2870cb33793SLawrence Tang //Ignore invalid GUIDs. 288*f8fc7052SJohn Chung if (guid == NULL) { 2890cb33793SLawrence Tang return; 290*f8fc7052SJohn Chung } 2910cb33793SLawrence Tang 292e407b4c8SLawrence Tang sscanf(guid, 293e407b4c8SLawrence Tang "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 294e407b4c8SLawrence Tang &out->Data1, &out->Data2, &out->Data3, out->Data4, 295e407b4c8SLawrence Tang out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4, 296e407b4c8SLawrence Tang out->Data4 + 5, out->Data4 + 6, out->Data4 + 7); 297b44314c7SLawrence Tang } 298b44314c7SLawrence Tang 2991b0b00e3SLawrence Tang //Returns one if two EFI GUIDs are equal, zero otherwise. 3001b0b00e3SLawrence Tang int guid_equal(EFI_GUID *a, EFI_GUID *b) 3011b0b00e3SLawrence Tang { 3021b0b00e3SLawrence Tang //Check top base 3 components. 303e407b4c8SLawrence Tang if (a->Data1 != b->Data1 || a->Data2 != b->Data2 || 304e407b4c8SLawrence Tang a->Data3 != b->Data3) { 3051b0b00e3SLawrence Tang return 0; 3061b0b00e3SLawrence Tang } 3071b0b00e3SLawrence Tang 3081b0b00e3SLawrence Tang //Check Data4 array for equality. 309e407b4c8SLawrence Tang for (int i = 0; i < 8; i++) { 310*f8fc7052SJohn Chung if (a->Data4[i] != b->Data4[i]) { 3111b0b00e3SLawrence Tang return 0; 3121b0b00e3SLawrence Tang } 313*f8fc7052SJohn Chung } 3141b0b00e3SLawrence Tang 3151b0b00e3SLawrence Tang return 1; 3161b0b00e3SLawrence Tang } 317