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