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. 131b0b00e3SLawrence Tang const char* CPER_SEVERITY_TYPES[4] = {"Recoverable", "Fatal", "Corrected", "Informational"}; 141b0b00e3SLawrence Tang 15a0865e38SLawrence Tang //Converts the given generic CPER error status to JSON IR. 16a0865e38SLawrence Tang json_object* cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS* error_status) 17a0865e38SLawrence Tang { 18a0865e38SLawrence Tang json_object* error_status_ir = json_object_new_object(); 19a0865e38SLawrence Tang 20a0865e38SLawrence Tang //Error type. 21a0865e38SLawrence Tang json_object_object_add(error_status_ir, "errorType", integer_to_readable_pair_with_desc(error_status->Type, 18, 22a0865e38SLawrence Tang CPER_GENERIC_ERROR_TYPES_KEYS, 23a0865e38SLawrence Tang CPER_GENERIC_ERROR_TYPES_VALUES, 24a0865e38SLawrence Tang CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS, 25a0865e38SLawrence Tang "Unknown (Reserved)")); 26a0865e38SLawrence Tang 27a0865e38SLawrence Tang //Boolean bit fields. 28a0865e38SLawrence Tang json_object_object_add(error_status_ir, "addressSignal", json_object_new_boolean(error_status->AddressSignal)); 29a0865e38SLawrence Tang json_object_object_add(error_status_ir, "controlSignal", json_object_new_boolean(error_status->ControlSignal)); 30a0865e38SLawrence Tang json_object_object_add(error_status_ir, "dataSignal", json_object_new_boolean(error_status->DataSignal)); 31a0865e38SLawrence Tang json_object_object_add(error_status_ir, "detectedByResponder", json_object_new_boolean(error_status->DetectedByResponder)); 32a0865e38SLawrence Tang json_object_object_add(error_status_ir, "detectedByRequester", json_object_new_boolean(error_status->DetectedByRequester)); 33a0865e38SLawrence Tang json_object_object_add(error_status_ir, "firstError", json_object_new_boolean(error_status->FirstError)); 34583cdeeeSLawrence Tang json_object_object_add(error_status_ir, "overflowDroppedLogs", json_object_new_boolean(error_status->OverflowNotLogged)); 35a0865e38SLawrence Tang 36a0865e38SLawrence Tang return error_status_ir; 37a0865e38SLawrence Tang } 38a0865e38SLawrence Tang 39*3b7f45b5SLawrence Tang //Converts the given CPER-JSON generic error status into a CPER structure. 40*3b7f45b5SLawrence Tang void ir_generic_error_status_to_cper(json_object* error_status, EFI_GENERIC_ERROR_STATUS* error_status_cper) 41*3b7f45b5SLawrence Tang { 42*3b7f45b5SLawrence Tang error_status_cper->Type = readable_pair_to_integer(json_object_object_get(error_status, "errorType")); 43*3b7f45b5SLawrence Tang error_status_cper->AddressSignal = json_object_get_boolean(json_object_object_get(error_status, "addressSignal")); 44*3b7f45b5SLawrence Tang error_status_cper->ControlSignal = json_object_get_boolean(json_object_object_get(error_status, "controlSignal")); 45*3b7f45b5SLawrence Tang error_status_cper->DataSignal = json_object_get_boolean(json_object_object_get(error_status, "dataSignal")); 46*3b7f45b5SLawrence Tang error_status_cper->DetectedByResponder = json_object_get_boolean(json_object_object_get(error_status, "detectedByResponder")); 47*3b7f45b5SLawrence Tang error_status_cper->DetectedByRequester = json_object_get_boolean(json_object_object_get(error_status, "detectedByRequester")); 48*3b7f45b5SLawrence Tang error_status_cper->FirstError = json_object_get_boolean(json_object_object_get(error_status, "firstError")); 49*3b7f45b5SLawrence Tang error_status_cper->OverflowNotLogged = json_object_get_boolean(json_object_object_get(error_status, "overflowDroppedLogs")); 50*3b7f45b5SLawrence Tang } 51*3b7f45b5SLawrence Tang 527f21db6cSLawrence Tang //Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order. 537f21db6cSLawrence Tang json_object* uniform_struct64_to_ir(UINT64* start, int len, const char* names[]) 547f21db6cSLawrence Tang { 557f21db6cSLawrence Tang json_object* result = json_object_new_object(); 567f21db6cSLawrence Tang 577f21db6cSLawrence Tang UINT64* cur = start; 587f21db6cSLawrence Tang for (int i=0; i<len; i++) 597f21db6cSLawrence Tang { 607f21db6cSLawrence Tang json_object_object_add(result, names[i], json_object_new_uint64(*cur)); 617f21db6cSLawrence Tang cur++; 627f21db6cSLawrence Tang } 637f21db6cSLawrence Tang 647f21db6cSLawrence Tang return result; 657f21db6cSLawrence Tang } 667f21db6cSLawrence Tang 677f21db6cSLawrence Tang //Converts a single uniform struct of UINT32s into intermediate JSON IR format, given names for each field in byte order. 687f21db6cSLawrence Tang json_object* uniform_struct_to_ir(UINT32* start, int len, const char* names[]) 697f21db6cSLawrence Tang { 707f21db6cSLawrence Tang json_object* result = json_object_new_object(); 717f21db6cSLawrence Tang 727f21db6cSLawrence Tang UINT32* cur = start; 737f21db6cSLawrence Tang for (int i=0; i<len; i++) 747f21db6cSLawrence Tang { 757f21db6cSLawrence Tang json_object_object_add(result, names[i], json_object_new_uint64(*cur)); 767f21db6cSLawrence Tang cur++; 777f21db6cSLawrence Tang } 787f21db6cSLawrence Tang 797f21db6cSLawrence Tang return result; 807f21db6cSLawrence Tang } 817f21db6cSLawrence Tang 8271570a2aSLawrence Tang //Converts a single object containing UINT32s into a uniform struct. 8371570a2aSLawrence Tang void ir_to_uniform_struct64(json_object* ir, UINT64* start, int len, const char* names[]) 8471570a2aSLawrence Tang { 8571570a2aSLawrence Tang UINT64* cur = start; 8671570a2aSLawrence Tang for (int i=0; i<len; i++) 8771570a2aSLawrence Tang { 8871570a2aSLawrence Tang *cur = json_object_get_uint64(json_object_object_get(ir, names[i])); 8971570a2aSLawrence Tang cur++; 9071570a2aSLawrence Tang } 9171570a2aSLawrence Tang } 9271570a2aSLawrence Tang 9371570a2aSLawrence Tang //Converts a single object containing UINT32s into a uniform struct. 9471570a2aSLawrence Tang void ir_to_uniform_struct(json_object* ir, UINT32* start, int len, const char* names[]) 9571570a2aSLawrence Tang { 9671570a2aSLawrence Tang UINT32* cur = start; 9771570a2aSLawrence Tang for (int i=0; i<len; i++) 9871570a2aSLawrence Tang { 9971570a2aSLawrence Tang *cur = (UINT32)json_object_get_uint64(json_object_object_get(ir, names[i])); 10071570a2aSLawrence Tang cur++; 10171570a2aSLawrence Tang } 10271570a2aSLawrence Tang } 10371570a2aSLawrence Tang 1043c43f743SLawrence Tang //Converts a single integer value to an object containing a value, and a readable name if possible. 1053c878352SLawrence Tang json_object* integer_to_readable_pair(UINT64 value, int len, int keys[], const char* values[], const char* default_value) 1063c43f743SLawrence Tang { 1073c43f743SLawrence Tang json_object* result = json_object_new_object(); 1083c878352SLawrence Tang json_object_object_add(result, "value", json_object_new_uint64(value)); 1093c43f743SLawrence Tang 1103c43f743SLawrence Tang //Search for human readable name, add. 111794312c8SLawrence Tang const char* name = default_value; 1123c43f743SLawrence Tang for (int i=0; i<len; i++) 1133c43f743SLawrence Tang { 1143c43f743SLawrence Tang if (keys[i] == value) 1153c43f743SLawrence Tang name = values[i]; 1163c43f743SLawrence Tang } 1173c43f743SLawrence Tang 1183c43f743SLawrence Tang json_object_object_add(result, "name", json_object_new_string(name)); 1193c43f743SLawrence Tang return result; 1203c43f743SLawrence Tang } 1213c43f743SLawrence Tang 1227f21db6cSLawrence Tang //Converts a single integer value to an object containing a value, readable name and description if possible. 1237f21db6cSLawrence Tang json_object* integer_to_readable_pair_with_desc(int value, int len, int keys[], const char* values[], 1247f21db6cSLawrence Tang const char* descriptions[], const char* default_value) 1257f21db6cSLawrence Tang { 1267f21db6cSLawrence Tang json_object* result = json_object_new_object(); 1277f21db6cSLawrence Tang json_object_object_add(result, "value", json_object_new_int(value)); 1287f21db6cSLawrence Tang 1297f21db6cSLawrence Tang //Search for human readable name, add. 1307f21db6cSLawrence Tang const char* name = default_value; 1317f21db6cSLawrence Tang for (int i=0; i<len; i++) 1327f21db6cSLawrence Tang { 1337f21db6cSLawrence Tang if (keys[i] == value) 1347f21db6cSLawrence Tang { 1357f21db6cSLawrence Tang name = values[i]; 1367f21db6cSLawrence Tang json_object_object_add(result, "description", json_object_new_string(descriptions[i])); 1377f21db6cSLawrence Tang } 1387f21db6cSLawrence Tang } 1397f21db6cSLawrence Tang 1407f21db6cSLawrence Tang json_object_object_add(result, "name", json_object_new_string(name)); 1417f21db6cSLawrence Tang return result; 1427f21db6cSLawrence Tang } 1437f21db6cSLawrence Tang 144b44314c7SLawrence Tang //Returns a single UINT64 value from the given readable pair object. 145b44314c7SLawrence Tang //Assumes the integer value is held in the "value" field. 146b44314c7SLawrence Tang UINT64 readable_pair_to_integer(json_object* pair) 147b44314c7SLawrence Tang { 148b44314c7SLawrence Tang return json_object_get_uint64(json_object_object_get(pair, "value")); 149b44314c7SLawrence Tang } 150b44314c7SLawrence Tang 151794312c8SLawrence Tang //Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left. 1523d0e4f24SLawrence Tang json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[]) 153794312c8SLawrence Tang { 154794312c8SLawrence Tang json_object* result = json_object_new_object(); 155794312c8SLawrence Tang for (int i=0; i<num_fields; i++) 156794312c8SLawrence Tang { 1572800cd8eSLawrence Tang json_object_object_add(result, names[i], json_object_new_boolean((bitfield >> i) & 0b1)); 158794312c8SLawrence Tang } 159794312c8SLawrence Tang 160794312c8SLawrence Tang return result; 161794312c8SLawrence Tang } 162794312c8SLawrence Tang 163b44314c7SLawrence Tang //Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0. 164b44314c7SLawrence Tang UINT64 ir_to_bitfield(json_object* ir, int num_fields, const char* names[]) 165b44314c7SLawrence Tang { 166b44314c7SLawrence Tang UINT64 result = 0x0; 167b44314c7SLawrence Tang for (int i=0; i<num_fields; i++) 168b44314c7SLawrence Tang { 169b44314c7SLawrence Tang if (json_object_get_boolean(json_object_object_get(ir, names[i]))) 170b44314c7SLawrence Tang result |= (0x1 << i); 171b44314c7SLawrence Tang } 172b44314c7SLawrence Tang 173b44314c7SLawrence Tang return result; 174b44314c7SLawrence Tang } 175b44314c7SLawrence Tang 176e18aaee9SLawrence Tang //Converts the given UINT64 array into a JSON IR array, given the length. 177e18aaee9SLawrence Tang json_object* uint64_array_to_ir_array(UINT64* array, int len) 178e18aaee9SLawrence Tang { 179e18aaee9SLawrence Tang json_object* array_ir = json_object_new_array(); 180e18aaee9SLawrence Tang for (int i=0; i<len; i++) 181e18aaee9SLawrence Tang json_object_array_add(array_ir, json_object_new_uint64(array[i])); 182e18aaee9SLawrence Tang return array_ir; 183e18aaee9SLawrence Tang } 184794312c8SLawrence Tang 1851b0b00e3SLawrence Tang //Converts a single UINT16 revision number into JSON IR representation. 1861b0b00e3SLawrence Tang json_object* revision_to_ir(UINT16 revision) 1871b0b00e3SLawrence Tang { 1881b0b00e3SLawrence Tang json_object* revision_info = json_object_new_object(); 1891b0b00e3SLawrence Tang json_object_object_add(revision_info, "major", json_object_new_int(revision >> 8)); 1901b0b00e3SLawrence Tang json_object_object_add(revision_info, "minor", json_object_new_int(revision & 0xFF)); 1911b0b00e3SLawrence Tang return revision_info; 1921b0b00e3SLawrence Tang } 1931b0b00e3SLawrence Tang 1941b0b00e3SLawrence Tang //Returns the appropriate string for the given integer severity. 1951b0b00e3SLawrence Tang const char* severity_to_string(UINT8 severity) 1961b0b00e3SLawrence Tang { 1971b0b00e3SLawrence Tang return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown"; 1981b0b00e3SLawrence Tang } 1991b0b00e3SLawrence Tang 200b44314c7SLawrence Tang //Converts a single EFI timestamp to string, at the given output. 201b44314c7SLawrence Tang //Output must be at least TIMESTAMP_LENGTH bytes long. 202b44314c7SLawrence Tang void timestamp_to_string(char* out, EFI_ERROR_TIME_STAMP* timestamp) 203b44314c7SLawrence Tang { 204b44314c7SLawrence Tang sprintf(out, "%02d%02d-%02d-%02dT%02d:%02d:%02d.000", 205b44314c7SLawrence Tang timestamp->Century, 206b44314c7SLawrence Tang timestamp->Year, 207b44314c7SLawrence Tang timestamp->Month, 208b44314c7SLawrence Tang timestamp->Day, 209b44314c7SLawrence Tang timestamp->Hours, 210b44314c7SLawrence Tang timestamp->Minutes, 211b44314c7SLawrence Tang timestamp->Seconds); 212b44314c7SLawrence Tang } 213b44314c7SLawrence Tang 214b44314c7SLawrence Tang //Converts a single timestamp string to an EFI timestamp. 215b44314c7SLawrence Tang void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp) 216b44314c7SLawrence Tang { 2170cb33793SLawrence Tang //Ignore invalid timestamps. 2180cb33793SLawrence Tang if (timestamp == NULL) 2190cb33793SLawrence Tang return; 2200cb33793SLawrence Tang 2210cb33793SLawrence Tang sscanf(timestamp, "%02hhd%02hhd-%02hhd-%02hhdT%02hhd:%02hhd:%02hhd.000", 222b44314c7SLawrence Tang &out->Century, 223b44314c7SLawrence Tang &out->Year, 224b44314c7SLawrence Tang &out->Month, 225b44314c7SLawrence Tang &out->Day, 226b44314c7SLawrence Tang &out->Hours, 227b44314c7SLawrence Tang &out->Minutes, 228b44314c7SLawrence Tang &out->Seconds); 229b44314c7SLawrence Tang } 230b44314c7SLawrence Tang 2311b0b00e3SLawrence Tang //Helper function to convert an EDK EFI GUID into a string for intermediate use. 2321b0b00e3SLawrence Tang void guid_to_string(char* out, EFI_GUID* guid) 2331b0b00e3SLawrence Tang { 2341b0b00e3SLawrence Tang sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x", 2351b0b00e3SLawrence Tang guid->Data1, 2361b0b00e3SLawrence Tang guid->Data2, 2371b0b00e3SLawrence Tang guid->Data3, 2381b0b00e3SLawrence Tang guid->Data4[0], 2391b0b00e3SLawrence Tang guid->Data4[1], 2401b0b00e3SLawrence Tang guid->Data4[2], 2411b0b00e3SLawrence Tang guid->Data4[3], 2421b0b00e3SLawrence Tang guid->Data4[4], 2431b0b00e3SLawrence Tang guid->Data4[5], 2441b0b00e3SLawrence Tang guid->Data4[6], 2451b0b00e3SLawrence Tang guid->Data4[7]); 2461b0b00e3SLawrence Tang } 2471b0b00e3SLawrence Tang 248b44314c7SLawrence Tang //Helper function to convert a string into an EDK EFI GUID. 249b44314c7SLawrence Tang void string_to_guid(EFI_GUID* out, const char* guid) 250b44314c7SLawrence Tang { 2510cb33793SLawrence Tang //Ignore invalid GUIDs. 2520cb33793SLawrence Tang if (guid == NULL) 2530cb33793SLawrence Tang return; 2540cb33793SLawrence Tang 2550cb33793SLawrence Tang sscanf(guid, "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx", 256b44314c7SLawrence Tang &out->Data1, 257b44314c7SLawrence Tang &out->Data2, 258b44314c7SLawrence Tang &out->Data3, 259b44314c7SLawrence Tang out->Data4, 260b44314c7SLawrence Tang out->Data4 + 1, 261b44314c7SLawrence Tang out->Data4 + 2, 262b44314c7SLawrence Tang out->Data4 + 3, 263b44314c7SLawrence Tang out->Data4 + 4, 264b44314c7SLawrence Tang out->Data4 + 5, 265b44314c7SLawrence Tang out->Data4 + 6, 266b44314c7SLawrence Tang out->Data4 + 7); 267b44314c7SLawrence Tang } 268b44314c7SLawrence Tang 2691b0b00e3SLawrence Tang //Returns one if two EFI GUIDs are equal, zero otherwise. 2701b0b00e3SLawrence Tang int guid_equal(EFI_GUID* a, EFI_GUID* b) 2711b0b00e3SLawrence Tang { 2721b0b00e3SLawrence Tang //Check top base 3 components. 2731b0b00e3SLawrence Tang if (a->Data1 != b->Data1 2741b0b00e3SLawrence Tang || a->Data2 != b->Data2 2751b0b00e3SLawrence Tang || a->Data3 != b->Data3) 2761b0b00e3SLawrence Tang { 2771b0b00e3SLawrence Tang return 0; 2781b0b00e3SLawrence Tang } 2791b0b00e3SLawrence Tang 2801b0b00e3SLawrence Tang //Check Data4 array for equality. 2811b0b00e3SLawrence Tang for (int i=0; i<8; i++) 2821b0b00e3SLawrence Tang { 2831b0b00e3SLawrence Tang if (a->Data4[i] != b->Data4[i]) 2841b0b00e3SLawrence Tang return 0; 2851b0b00e3SLawrence Tang } 2861b0b00e3SLawrence Tang 2871b0b00e3SLawrence Tang return 1; 2881b0b00e3SLawrence Tang } 2894dbe3d72SLawrence Tang 2904dbe3d72SLawrence Tang //Converts the given BCD byte to a standard integer. 2914dbe3d72SLawrence Tang int bcd_to_int(UINT8 bcd) 2924dbe3d72SLawrence Tang { 2934dbe3d72SLawrence Tang return ((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F); 2944dbe3d72SLawrence Tang } 295*3b7f45b5SLawrence Tang 296*3b7f45b5SLawrence Tang //Converts the given integer to a single byte BCD. 297*3b7f45b5SLawrence Tang UINT8 int_to_bcd(int value) 298*3b7f45b5SLawrence Tang { 299*3b7f45b5SLawrence Tang UINT8 result = 0; 300*3b7f45b5SLawrence Tang int shift = 0; 301*3b7f45b5SLawrence Tang while (value > 0) { 302*3b7f45b5SLawrence Tang result |= (value % 10) << (shift++ << 2); 303*3b7f45b5SLawrence Tang value /= 10; 304*3b7f45b5SLawrence Tang } 305*3b7f45b5SLawrence Tang 306*3b7f45b5SLawrence Tang return result; 307*3b7f45b5SLawrence Tang }