blob: db41381f40d8d18fe13cf0ecedb76210d4ba636c [file] [log] [blame]
Lawrence Tang1b0b00e2022-07-05 10:33:10 +01001/**
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.
13const char* CPER_SEVERITY_TYPES[4] = {"Recoverable", "Fatal", "Corrected", "Informational"};
14
Lawrence Tanga0865e32022-07-06 11:59:52 +010015//Converts the given generic CPER error status to JSON IR.
16json_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));
Lawrence Tang583cdee2022-07-11 14:31:11 +010034 json_object_object_add(error_status_ir, "overflowDroppedLogs", json_object_new_boolean(error_status->OverflowNotLogged));
Lawrence Tanga0865e32022-07-06 11:59:52 +010035
36 return error_status_ir;
37}
38
Lawrence Tang7f21db62022-07-06 11:09:39 +010039//Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order.
40json_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.
55json_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
Lawrence Tang3c43f742022-07-05 11:37:17 +010069//Converts a single integer value to an object containing a value, and a readable name if possible.
Lawrence Tang3c878352022-07-08 14:04:50 +010070json_object* integer_to_readable_pair(UINT64 value, int len, int keys[], const char* values[], const char* default_value)
Lawrence Tang3c43f742022-07-05 11:37:17 +010071{
72 json_object* result = json_object_new_object();
Lawrence Tang3c878352022-07-08 14:04:50 +010073 json_object_object_add(result, "value", json_object_new_uint64(value));
Lawrence Tang3c43f742022-07-05 11:37:17 +010074
75 //Search for human readable name, add.
Lawrence Tang794312c2022-07-05 14:46:10 +010076 const char* name = default_value;
Lawrence Tang3c43f742022-07-05 11:37:17 +010077 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
Lawrence Tang7f21db62022-07-06 11:09:39 +010087//Converts a single integer value to an object containing a value, readable name and description if possible.
88json_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
Lawrence Tangb44314c2022-07-13 11:45:22 +0100109//Returns a single UINT64 value from the given readable pair object.
110//Assumes the integer value is held in the "value" field.
111UINT64 readable_pair_to_integer(json_object* pair)
112{
113 return json_object_get_uint64(json_object_object_get(pair, "value"));
114}
115
Lawrence Tang794312c2022-07-05 14:46:10 +0100116//Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left.
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100117json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[])
Lawrence Tang794312c2022-07-05 14:46:10 +0100118{
119 json_object* result = json_object_new_object();
120 for (int i=0; i<num_fields; i++)
121 {
Lawrence Tang2800cd82022-07-05 16:08:20 +0100122 json_object_object_add(result, names[i], json_object_new_boolean((bitfield >> i) & 0b1));
Lawrence Tang794312c2022-07-05 14:46:10 +0100123 }
124
125 return result;
126}
127
Lawrence Tangb44314c2022-07-13 11:45:22 +0100128//Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0.
129UINT64 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
Lawrence Tange18aaee2022-07-07 09:01:30 +0100141//Converts the given UINT64 array into a JSON IR array, given the length.
142json_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}
Lawrence Tang794312c2022-07-05 14:46:10 +0100149
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100150//Converts a single UINT16 revision number into JSON IR representation.
151json_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.
160const char* severity_to_string(UINT8 severity)
161{
162 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown";
163}
164
Lawrence Tangb44314c2022-07-13 11:45:22 +0100165//Converts a single EFI timestamp to string, at the given output.
166//Output must be at least TIMESTAMP_LENGTH bytes long.
167void 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.
180void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp)
181{
Lawrence Tang0cb33792022-07-13 13:51:39 +0100182 //Ignore invalid timestamps.
183 if (timestamp == NULL)
184 return;
185
186 sscanf(timestamp, "%02hhd%02hhd-%02hhd-%02hhdT%02hhd:%02hhd:%02hhd.000",
Lawrence Tangb44314c2022-07-13 11:45:22 +0100187 &out->Century,
188 &out->Year,
189 &out->Month,
190 &out->Day,
191 &out->Hours,
192 &out->Minutes,
193 &out->Seconds);
194}
195
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100196//Helper function to convert an EDK EFI GUID into a string for intermediate use.
197void 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
Lawrence Tangb44314c2022-07-13 11:45:22 +0100213//Helper function to convert a string into an EDK EFI GUID.
214void string_to_guid(EFI_GUID* out, const char* guid)
215{
Lawrence Tang0cb33792022-07-13 13:51:39 +0100216 //Ignore invalid GUIDs.
217 if (guid == NULL)
218 return;
219
220 sscanf(guid, "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
Lawrence Tangb44314c2022-07-13 11:45:22 +0100221 &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
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100234//Returns one if two EFI GUIDs are equal, zero otherwise.
235int 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;
Lawrence Tang4dbe3d72022-07-06 13:51:01 +0100253}
254
255//Converts the given BCD byte to a standard integer.
256int bcd_to_int(UINT8 bcd)
257{
258 return ((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100259}