blob: ba8cd63eeed8a84c86288187d898ffbdde4d7a05 [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 Tang71570a22022-07-14 11:45:28 +010069//Converts a single object containing UINT32s into a uniform struct.
70void 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.
81void 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
Lawrence Tang3c43f742022-07-05 11:37:17 +010091//Converts a single integer value to an object containing a value, and a readable name if possible.
Lawrence Tang3c878352022-07-08 14:04:50 +010092json_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 +010093{
94 json_object* result = json_object_new_object();
Lawrence Tang3c878352022-07-08 14:04:50 +010095 json_object_object_add(result, "value", json_object_new_uint64(value));
Lawrence Tang3c43f742022-07-05 11:37:17 +010096
97 //Search for human readable name, add.
Lawrence Tang794312c2022-07-05 14:46:10 +010098 const char* name = default_value;
Lawrence Tang3c43f742022-07-05 11:37:17 +010099 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
Lawrence Tang7f21db62022-07-06 11:09:39 +0100109//Converts a single integer value to an object containing a value, readable name and description if possible.
110json_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
Lawrence Tangb44314c2022-07-13 11:45:22 +0100131//Returns a single UINT64 value from the given readable pair object.
132//Assumes the integer value is held in the "value" field.
133UINT64 readable_pair_to_integer(json_object* pair)
134{
135 return json_object_get_uint64(json_object_object_get(pair, "value"));
136}
137
Lawrence Tang794312c2022-07-05 14:46:10 +0100138//Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left.
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100139json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[])
Lawrence Tang794312c2022-07-05 14:46:10 +0100140{
141 json_object* result = json_object_new_object();
142 for (int i=0; i<num_fields; i++)
143 {
Lawrence Tang2800cd82022-07-05 16:08:20 +0100144 json_object_object_add(result, names[i], json_object_new_boolean((bitfield >> i) & 0b1));
Lawrence Tang794312c2022-07-05 14:46:10 +0100145 }
146
147 return result;
148}
149
Lawrence Tangb44314c2022-07-13 11:45:22 +0100150//Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0.
151UINT64 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
Lawrence Tange18aaee2022-07-07 09:01:30 +0100163//Converts the given UINT64 array into a JSON IR array, given the length.
164json_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}
Lawrence Tang794312c2022-07-05 14:46:10 +0100171
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100172//Converts a single UINT16 revision number into JSON IR representation.
173json_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.
182const char* severity_to_string(UINT8 severity)
183{
184 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown";
185}
186
Lawrence Tangb44314c2022-07-13 11:45:22 +0100187//Converts a single EFI timestamp to string, at the given output.
188//Output must be at least TIMESTAMP_LENGTH bytes long.
189void 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.
202void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp)
203{
Lawrence Tang0cb33792022-07-13 13:51:39 +0100204 //Ignore invalid timestamps.
205 if (timestamp == NULL)
206 return;
207
208 sscanf(timestamp, "%02hhd%02hhd-%02hhd-%02hhdT%02hhd:%02hhd:%02hhd.000",
Lawrence Tangb44314c2022-07-13 11:45:22 +0100209 &out->Century,
210 &out->Year,
211 &out->Month,
212 &out->Day,
213 &out->Hours,
214 &out->Minutes,
215 &out->Seconds);
216}
217
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100218//Helper function to convert an EDK EFI GUID into a string for intermediate use.
219void 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
Lawrence Tangb44314c2022-07-13 11:45:22 +0100235//Helper function to convert a string into an EDK EFI GUID.
236void string_to_guid(EFI_GUID* out, const char* guid)
237{
Lawrence Tang0cb33792022-07-13 13:51:39 +0100238 //Ignore invalid GUIDs.
239 if (guid == NULL)
240 return;
241
242 sscanf(guid, "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
Lawrence Tangb44314c2022-07-13 11:45:22 +0100243 &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
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100256//Returns one if two EFI GUIDs are equal, zero otherwise.
257int 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;
Lawrence Tang4dbe3d72022-07-06 13:51:01 +0100275}
276
277//Converts the given BCD byte to a standard integer.
278int bcd_to_int(UINT8 bcd)
279{
280 return ((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F);
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100281}