xref: /openbmc/libcper/cper-utils.c (revision 3ab351fe)
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, "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu.000",
205             bcd_to_int(timestamp->Century) % 100, //Cannot go to three digits.
206             bcd_to_int(timestamp->Year) % 100, //Cannot go to three digits.
207             bcd_to_int(timestamp->Month),
208             bcd_to_int(timestamp->Day),
209             bcd_to_int(timestamp->Hours),
210             bcd_to_int(timestamp->Minutes),
211             bcd_to_int(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, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu.000",
222             &out->Century,
223             &out->Year,
224             &out->Month,
225             &out->Day,
226             &out->Hours,
227             &out->Minutes,
228             &out->Seconds);
229 
230     //Convert back to BCD.
231     out->Century = int_to_bcd(out->Century);
232     out->Year = int_to_bcd(out->Year);
233     out->Month = int_to_bcd(out->Month);
234     out->Day = int_to_bcd(out->Day);
235     out->Hours = int_to_bcd(out->Hours);
236     out->Minutes = int_to_bcd(out->Minutes);
237     out->Seconds = int_to_bcd(out->Seconds);
238 }
239 
240 //Helper function to convert an EDK EFI GUID into a string for intermediate use.
241 void guid_to_string(char* out, EFI_GUID* guid)
242 {
243     sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
244         guid->Data1,
245         guid->Data2,
246         guid->Data3,
247         guid->Data4[0],
248         guid->Data4[1],
249         guid->Data4[2],
250         guid->Data4[3],
251         guid->Data4[4],
252         guid->Data4[5],
253         guid->Data4[6],
254         guid->Data4[7]);
255 }
256 
257 //Helper function to convert a string into an EDK EFI GUID.
258 void string_to_guid(EFI_GUID* out, const char* guid)
259 {
260     //Ignore invalid GUIDs.
261     if (guid == NULL)
262         return;
263 
264     sscanf(guid, "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
265         &out->Data1,
266         &out->Data2,
267         &out->Data3,
268         out->Data4,
269         out->Data4 + 1,
270         out->Data4 + 2,
271         out->Data4 + 3,
272         out->Data4 + 4,
273         out->Data4 + 5,
274         out->Data4 + 6,
275         out->Data4 + 7);
276 }
277 
278 //Returns one if two EFI GUIDs are equal, zero otherwise.
279 int guid_equal(EFI_GUID* a, EFI_GUID* b)
280 {
281     //Check top base 3 components.
282     if (a->Data1 != b->Data1
283         || a->Data2 != b->Data2
284         || a->Data3 != b->Data3)
285     {
286         return 0;
287     }
288 
289     //Check Data4 array for equality.
290     for (int i=0; i<8; i++)
291     {
292         if (a->Data4[i] != b->Data4[i])
293             return 0;
294     }
295 
296     return 1;
297 }