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