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