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> 81b0b00e3SLawrence 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. 13*e407b4c8SLawrence Tang const char *CPER_SEVERITY_TYPES[4] = { "Recoverable", "Fatal", "Corrected", 14*e407b4c8SLawrence Tang "Informational" }; 151b0b00e3SLawrence Tang 16a0865e38SLawrence Tang //Converts the given generic CPER error status to JSON IR. 17*e407b4c8SLawrence Tang json_object * 18*e407b4c8SLawrence 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. 23*e407b4c8SLawrence Tang json_object_object_add(error_status_ir, "errorType", 24*e407b4c8SLawrence Tang integer_to_readable_pair_with_desc( 25*e407b4c8SLawrence 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. 32*e407b4c8SLawrence Tang json_object_object_add( 33*e407b4c8SLawrence Tang error_status_ir, "addressSignal", 34*e407b4c8SLawrence Tang json_object_new_boolean(error_status->AddressSignal)); 35*e407b4c8SLawrence Tang json_object_object_add( 36*e407b4c8SLawrence Tang error_status_ir, "controlSignal", 37*e407b4c8SLawrence Tang json_object_new_boolean(error_status->ControlSignal)); 38*e407b4c8SLawrence Tang json_object_object_add( 39*e407b4c8SLawrence Tang error_status_ir, "dataSignal", 40*e407b4c8SLawrence Tang json_object_new_boolean(error_status->DataSignal)); 41*e407b4c8SLawrence Tang json_object_object_add( 42*e407b4c8SLawrence Tang error_status_ir, "detectedByResponder", 43*e407b4c8SLawrence Tang json_object_new_boolean(error_status->DetectedByResponder)); 44*e407b4c8SLawrence Tang json_object_object_add( 45*e407b4c8SLawrence Tang error_status_ir, "detectedByRequester", 46*e407b4c8SLawrence Tang json_object_new_boolean(error_status->DetectedByRequester)); 47*e407b4c8SLawrence Tang json_object_object_add( 48*e407b4c8SLawrence Tang error_status_ir, "firstError", 49*e407b4c8SLawrence Tang json_object_new_boolean(error_status->FirstError)); 50*e407b4c8SLawrence Tang json_object_object_add( 51*e407b4c8SLawrence Tang error_status_ir, "overflowDroppedLogs", 52*e407b4c8SLawrence 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. 58*e407b4c8SLawrence Tang void ir_generic_error_status_to_cper( 59*e407b4c8SLawrence Tang json_object *error_status, EFI_GENERIC_ERROR_STATUS *error_status_cper) 603b7f45b5SLawrence Tang { 61*e407b4c8SLawrence Tang error_status_cper->Type = readable_pair_to_integer( 62*e407b4c8SLawrence Tang json_object_object_get(error_status, "errorType")); 63*e407b4c8SLawrence Tang error_status_cper->AddressSignal = json_object_get_boolean( 64*e407b4c8SLawrence Tang json_object_object_get(error_status, "addressSignal")); 65*e407b4c8SLawrence Tang error_status_cper->ControlSignal = json_object_get_boolean( 66*e407b4c8SLawrence Tang json_object_object_get(error_status, "controlSignal")); 67*e407b4c8SLawrence Tang error_status_cper->DataSignal = json_object_get_boolean( 68*e407b4c8SLawrence Tang json_object_object_get(error_status, "dataSignal")); 69*e407b4c8SLawrence Tang error_status_cper->DetectedByResponder = json_object_get_boolean( 70*e407b4c8SLawrence Tang json_object_object_get(error_status, "detectedByResponder")); 71*e407b4c8SLawrence Tang error_status_cper->DetectedByRequester = json_object_get_boolean( 72*e407b4c8SLawrence Tang json_object_object_get(error_status, "detectedByRequester")); 73*e407b4c8SLawrence Tang error_status_cper->FirstError = json_object_get_boolean( 74*e407b4c8SLawrence Tang json_object_object_get(error_status, "firstError")); 75*e407b4c8SLawrence Tang error_status_cper->OverflowNotLogged = json_object_get_boolean( 76*e407b4c8SLawrence 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; 85*e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 86*e407b4c8SLawrence Tang json_object_object_add(result, names[i], 87*e407b4c8SLawrence 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; 100*e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 101*e407b4c8SLawrence Tang json_object_object_add(result, names[i], 102*e407b4c8SLawrence 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. 110*e407b4c8SLawrence Tang void ir_to_uniform_struct64(json_object *ir, UINT64 *start, int len, 111*e407b4c8SLawrence Tang const char *names[]) 11271570a2aSLawrence Tang { 11371570a2aSLawrence Tang UINT64 *cur = start; 114*e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 115*e407b4c8SLawrence Tang *cur = json_object_get_uint64( 116*e407b4c8SLawrence 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. 122*e407b4c8SLawrence Tang void ir_to_uniform_struct(json_object *ir, UINT32 *start, int len, 123*e407b4c8SLawrence Tang const char *names[]) 12471570a2aSLawrence Tang { 12571570a2aSLawrence Tang UINT32 *cur = start; 126*e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 127*e407b4c8SLawrence Tang *cur = (UINT32)json_object_get_uint64( 128*e407b4c8SLawrence 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. 134*e407b4c8SLawrence Tang json_object *integer_to_readable_pair(UINT64 value, int len, int keys[], 135*e407b4c8SLawrence Tang const char *values[], 136*e407b4c8SLawrence 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; 143*e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 1443c43f743SLawrence Tang if (keys[i] == value) 1453c43f743SLawrence Tang name = values[i]; 1463c43f743SLawrence Tang } 1473c43f743SLawrence Tang 1483c43f743SLawrence Tang json_object_object_add(result, "name", json_object_new_string(name)); 1493c43f743SLawrence Tang return result; 1503c43f743SLawrence Tang } 1513c43f743SLawrence Tang 1527f21db6cSLawrence Tang //Converts a single integer value to an object containing a value, readable name and description if possible. 153*e407b4c8SLawrence Tang json_object *integer_to_readable_pair_with_desc(int value, int len, int keys[], 154*e407b4c8SLawrence Tang const char *values[], 155*e407b4c8SLawrence Tang const char *descriptions[], 156*e407b4c8SLawrence Tang const char *default_value) 1577f21db6cSLawrence Tang { 1587f21db6cSLawrence Tang json_object *result = json_object_new_object(); 1597f21db6cSLawrence Tang json_object_object_add(result, "value", json_object_new_int(value)); 1607f21db6cSLawrence Tang 1617f21db6cSLawrence Tang //Search for human readable name, add. 1627f21db6cSLawrence Tang const char *name = default_value; 163*e407b4c8SLawrence Tang for (int i = 0; i < len; i++) { 164*e407b4c8SLawrence Tang if (keys[i] == value) { 1657f21db6cSLawrence Tang name = values[i]; 166*e407b4c8SLawrence Tang json_object_object_add( 167*e407b4c8SLawrence Tang result, "description", 168*e407b4c8SLawrence Tang json_object_new_string(descriptions[i])); 1697f21db6cSLawrence Tang } 1707f21db6cSLawrence Tang } 1717f21db6cSLawrence Tang 1727f21db6cSLawrence Tang json_object_object_add(result, "name", json_object_new_string(name)); 1737f21db6cSLawrence Tang return result; 1747f21db6cSLawrence Tang } 1757f21db6cSLawrence Tang 176b44314c7SLawrence Tang //Returns a single UINT64 value from the given readable pair object. 177b44314c7SLawrence Tang //Assumes the integer value is held in the "value" field. 178b44314c7SLawrence Tang UINT64 readable_pair_to_integer(json_object *pair) 179b44314c7SLawrence Tang { 180b44314c7SLawrence Tang return json_object_get_uint64(json_object_object_get(pair, "value")); 181b44314c7SLawrence Tang } 182b44314c7SLawrence Tang 183794312c8SLawrence Tang //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left. 184*e407b4c8SLawrence Tang json_object *bitfield_to_ir(UINT64 bitfield, int num_fields, 185*e407b4c8SLawrence Tang const char *names[]) 186794312c8SLawrence Tang { 187794312c8SLawrence Tang json_object *result = json_object_new_object(); 188*e407b4c8SLawrence Tang for (int i = 0; i < num_fields; i++) { 189*e407b4c8SLawrence Tang json_object_object_add(result, names[i], 190*e407b4c8SLawrence Tang json_object_new_boolean((bitfield >> i) & 191*e407b4c8SLawrence Tang 0b1)); 192794312c8SLawrence Tang } 193794312c8SLawrence Tang 194794312c8SLawrence Tang return result; 195794312c8SLawrence Tang } 196794312c8SLawrence Tang 197b44314c7SLawrence Tang //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0. 198b44314c7SLawrence Tang UINT64 ir_to_bitfield(json_object *ir, int num_fields, const char *names[]) 199b44314c7SLawrence Tang { 200b44314c7SLawrence Tang UINT64 result = 0x0; 201*e407b4c8SLawrence Tang for (int i = 0; i < num_fields; i++) { 202*e407b4c8SLawrence Tang if (json_object_get_boolean( 203*e407b4c8SLawrence Tang json_object_object_get(ir, names[i]))) 204b44314c7SLawrence Tang result |= (0x1 << i); 205b44314c7SLawrence Tang } 206b44314c7SLawrence Tang 207b44314c7SLawrence Tang return result; 208b44314c7SLawrence Tang } 209b44314c7SLawrence Tang 210e18aaee9SLawrence Tang //Converts the given UINT64 array into a JSON IR array, given the length. 211e18aaee9SLawrence Tang json_object *uint64_array_to_ir_array(UINT64 *array, int len) 212e18aaee9SLawrence Tang { 213e18aaee9SLawrence Tang json_object *array_ir = json_object_new_array(); 214e18aaee9SLawrence Tang for (int i = 0; i < len; i++) 215*e407b4c8SLawrence Tang json_object_array_add(array_ir, 216*e407b4c8SLawrence Tang json_object_new_uint64(array[i])); 217e18aaee9SLawrence Tang return array_ir; 218e18aaee9SLawrence Tang } 219794312c8SLawrence Tang 2201b0b00e3SLawrence Tang //Converts a single UINT16 revision number into JSON IR representation. 2211b0b00e3SLawrence Tang json_object *revision_to_ir(UINT16 revision) 2221b0b00e3SLawrence Tang { 2231b0b00e3SLawrence Tang json_object *revision_info = json_object_new_object(); 224*e407b4c8SLawrence Tang json_object_object_add(revision_info, "major", 225*e407b4c8SLawrence Tang json_object_new_int(revision >> 8)); 226*e407b4c8SLawrence Tang json_object_object_add(revision_info, "minor", 227*e407b4c8SLawrence Tang json_object_new_int(revision & 0xFF)); 2281b0b00e3SLawrence Tang return revision_info; 2291b0b00e3SLawrence Tang } 2301b0b00e3SLawrence Tang 2311b0b00e3SLawrence Tang //Returns the appropriate string for the given integer severity. 23202c801a5SLawrence Tang const char *severity_to_string(UINT32 severity) 2331b0b00e3SLawrence Tang { 2341b0b00e3SLawrence Tang return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown"; 2351b0b00e3SLawrence Tang } 2361b0b00e3SLawrence Tang 237b44314c7SLawrence Tang //Converts a single EFI timestamp to string, at the given output. 238b44314c7SLawrence Tang //Output must be at least TIMESTAMP_LENGTH bytes long. 239b44314c7SLawrence Tang void timestamp_to_string(char *out, EFI_ERROR_TIME_STAMP *timestamp) 240b44314c7SLawrence Tang { 241aacf0e26SLawrence Tang sprintf(out, "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu.000", 242*e407b4c8SLawrence Tang bcd_to_int(timestamp->Century) % 243*e407b4c8SLawrence Tang 100, //Cannot go to three digits. 244aacf0e26SLawrence Tang bcd_to_int(timestamp->Year) % 100, //Cannot go to three digits. 245*e407b4c8SLawrence Tang bcd_to_int(timestamp->Month), bcd_to_int(timestamp->Day), 246*e407b4c8SLawrence Tang bcd_to_int(timestamp->Hours), bcd_to_int(timestamp->Minutes), 247aacf0e26SLawrence Tang bcd_to_int(timestamp->Seconds)); 248b44314c7SLawrence Tang } 249b44314c7SLawrence Tang 250b44314c7SLawrence Tang //Converts a single timestamp string to an EFI timestamp. 251b44314c7SLawrence Tang void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp) 252b44314c7SLawrence Tang { 2530cb33793SLawrence Tang //Ignore invalid timestamps. 2540cb33793SLawrence Tang if (timestamp == NULL) 2550cb33793SLawrence Tang return; 2560cb33793SLawrence Tang 257aacf0e26SLawrence Tang sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu.000", 258*e407b4c8SLawrence Tang &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours, 259*e407b4c8SLawrence Tang &out->Minutes, &out->Seconds); 260aacf0e26SLawrence Tang 261aacf0e26SLawrence Tang //Convert back to BCD. 262aacf0e26SLawrence Tang out->Century = int_to_bcd(out->Century); 263aacf0e26SLawrence Tang out->Year = int_to_bcd(out->Year); 264aacf0e26SLawrence Tang out->Month = int_to_bcd(out->Month); 265aacf0e26SLawrence Tang out->Day = int_to_bcd(out->Day); 266aacf0e26SLawrence Tang out->Hours = int_to_bcd(out->Hours); 267aacf0e26SLawrence Tang out->Minutes = int_to_bcd(out->Minutes); 268aacf0e26SLawrence Tang out->Seconds = int_to_bcd(out->Seconds); 269b44314c7SLawrence Tang } 270b44314c7SLawrence Tang 2711b0b00e3SLawrence Tang //Helper function to convert an EDK EFI GUID into a string for intermediate use. 2721b0b00e3SLawrence Tang void guid_to_string(char *out, EFI_GUID *guid) 2731b0b00e3SLawrence Tang { 2741b0b00e3SLawrence Tang sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 275*e407b4c8SLawrence Tang guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], 276*e407b4c8SLawrence Tang guid->Data4[1], guid->Data4[2], guid->Data4[3], guid->Data4[4], 277*e407b4c8SLawrence Tang guid->Data4[5], guid->Data4[6], guid->Data4[7]); 2781b0b00e3SLawrence Tang } 2791b0b00e3SLawrence Tang 280b44314c7SLawrence Tang //Helper function to convert a string into an EDK EFI GUID. 281b44314c7SLawrence Tang void string_to_guid(EFI_GUID *out, const char *guid) 282b44314c7SLawrence Tang { 2830cb33793SLawrence Tang //Ignore invalid GUIDs. 2840cb33793SLawrence Tang if (guid == NULL) 2850cb33793SLawrence Tang return; 2860cb33793SLawrence Tang 287*e407b4c8SLawrence Tang sscanf(guid, 288*e407b4c8SLawrence Tang "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 289*e407b4c8SLawrence Tang &out->Data1, &out->Data2, &out->Data3, out->Data4, 290*e407b4c8SLawrence Tang out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4, 291*e407b4c8SLawrence Tang out->Data4 + 5, out->Data4 + 6, out->Data4 + 7); 292b44314c7SLawrence Tang } 293b44314c7SLawrence Tang 2941b0b00e3SLawrence Tang //Returns one if two EFI GUIDs are equal, zero otherwise. 2951b0b00e3SLawrence Tang int guid_equal(EFI_GUID *a, EFI_GUID *b) 2961b0b00e3SLawrence Tang { 2971b0b00e3SLawrence Tang //Check top base 3 components. 298*e407b4c8SLawrence Tang if (a->Data1 != b->Data1 || a->Data2 != b->Data2 || 299*e407b4c8SLawrence Tang a->Data3 != b->Data3) { 3001b0b00e3SLawrence Tang return 0; 3011b0b00e3SLawrence Tang } 3021b0b00e3SLawrence Tang 3031b0b00e3SLawrence Tang //Check Data4 array for equality. 304*e407b4c8SLawrence Tang for (int i = 0; i < 8; i++) { 3051b0b00e3SLawrence Tang if (a->Data4[i] != b->Data4[i]) 3061b0b00e3SLawrence Tang return 0; 3071b0b00e3SLawrence Tang } 3081b0b00e3SLawrence Tang 3091b0b00e3SLawrence Tang return 1; 3101b0b00e3SLawrence Tang }