xref: /openbmc/libcper/cper-utils.c (revision 02c801a5)
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 
393b7f45b5SLawrence Tang //Converts the given CPER-JSON generic error status into a CPER structure.
403b7f45b5SLawrence Tang void ir_generic_error_status_to_cper(json_object* error_status, EFI_GENERIC_ERROR_STATUS* error_status_cper)
413b7f45b5SLawrence Tang {
423b7f45b5SLawrence Tang     error_status_cper->Type = readable_pair_to_integer(json_object_object_get(error_status, "errorType"));
433b7f45b5SLawrence Tang     error_status_cper->AddressSignal = json_object_get_boolean(json_object_object_get(error_status, "addressSignal"));
443b7f45b5SLawrence Tang     error_status_cper->ControlSignal = json_object_get_boolean(json_object_object_get(error_status, "controlSignal"));
453b7f45b5SLawrence Tang     error_status_cper->DataSignal = json_object_get_boolean(json_object_object_get(error_status, "dataSignal"));
463b7f45b5SLawrence Tang     error_status_cper->DetectedByResponder = json_object_get_boolean(json_object_object_get(error_status, "detectedByResponder"));
473b7f45b5SLawrence Tang     error_status_cper->DetectedByRequester = json_object_get_boolean(json_object_object_get(error_status, "detectedByRequester"));
483b7f45b5SLawrence Tang     error_status_cper->FirstError = json_object_get_boolean(json_object_object_get(error_status, "firstError"));
493b7f45b5SLawrence Tang     error_status_cper->OverflowNotLogged = json_object_get_boolean(json_object_object_get(error_status, "overflowDroppedLogs"));
503b7f45b5SLawrence Tang }
513b7f45b5SLawrence 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.
195*02c801a5SLawrence Tang const char* severity_to_string(UINT32 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 }
2953b7f45b5SLawrence Tang 
2963b7f45b5SLawrence Tang //Converts the given integer to a single byte BCD.
2973b7f45b5SLawrence Tang UINT8 int_to_bcd(int value)
2983b7f45b5SLawrence Tang {
2993b7f45b5SLawrence Tang     UINT8 result = 0;
3003b7f45b5SLawrence Tang     int shift = 0;
3013b7f45b5SLawrence Tang     while (value > 0) {
3023b7f45b5SLawrence Tang         result |= (value % 10) << (shift++ << 2);
3033b7f45b5SLawrence Tang         value /= 10;
3043b7f45b5SLawrence Tang     }
3053b7f45b5SLawrence Tang 
3063b7f45b5SLawrence Tang     return result;
3073b7f45b5SLawrence Tang }