blob: 0eadf10cecde8bcf41b15c302fc83128aad5b214 [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 Tang3b7f45b2022-07-14 14:14:30 +010039//Converts the given CPER-JSON generic error status into a CPER structure.
40void 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
Lawrence Tang7f21db62022-07-06 11:09:39 +010052//Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order.
53json_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.
68json_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
Lawrence Tang71570a22022-07-14 11:45:28 +010082//Converts a single object containing UINT32s into a uniform struct.
83void 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.
94void 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
Lawrence Tang3c43f742022-07-05 11:37:17 +0100104//Converts a single integer value to an object containing a value, and a readable name if possible.
Lawrence Tang3c878352022-07-08 14:04:50 +0100105json_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 +0100106{
107 json_object* result = json_object_new_object();
Lawrence Tang3c878352022-07-08 14:04:50 +0100108 json_object_object_add(result, "value", json_object_new_uint64(value));
Lawrence Tang3c43f742022-07-05 11:37:17 +0100109
110 //Search for human readable name, add.
Lawrence Tang794312c2022-07-05 14:46:10 +0100111 const char* name = default_value;
Lawrence Tang3c43f742022-07-05 11:37:17 +0100112 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
Lawrence Tang7f21db62022-07-06 11:09:39 +0100122//Converts a single integer value to an object containing a value, readable name and description if possible.
123json_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
Lawrence Tangb44314c2022-07-13 11:45:22 +0100144//Returns a single UINT64 value from the given readable pair object.
145//Assumes the integer value is held in the "value" field.
146UINT64 readable_pair_to_integer(json_object* pair)
147{
148 return json_object_get_uint64(json_object_object_get(pair, "value"));
149}
150
Lawrence Tang794312c2022-07-05 14:46:10 +0100151//Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left.
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100152json_object* bitfield_to_ir(UINT64 bitfield, int num_fields, const char* names[])
Lawrence Tang794312c2022-07-05 14:46:10 +0100153{
154 json_object* result = json_object_new_object();
155 for (int i=0; i<num_fields; i++)
156 {
Lawrence Tang2800cd82022-07-05 16:08:20 +0100157 json_object_object_add(result, names[i], json_object_new_boolean((bitfield >> i) & 0b1));
Lawrence Tang794312c2022-07-05 14:46:10 +0100158 }
159
160 return result;
161}
162
Lawrence Tangb44314c2022-07-13 11:45:22 +0100163//Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0.
164UINT64 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
Lawrence Tange18aaee2022-07-07 09:01:30 +0100176//Converts the given UINT64 array into a JSON IR array, given the length.
177json_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}
Lawrence Tang794312c2022-07-05 14:46:10 +0100184
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100185//Converts a single UINT16 revision number into JSON IR representation.
186json_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.
Lawrence Tang02c801a2022-07-18 14:43:52 +0100195const char* severity_to_string(UINT32 severity)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100196{
197 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown";
198}
199
Lawrence Tangb44314c2022-07-13 11:45:22 +0100200//Converts a single EFI timestamp to string, at the given output.
201//Output must be at least TIMESTAMP_LENGTH bytes long.
202void timestamp_to_string(char* out, EFI_ERROR_TIME_STAMP* timestamp)
203{
Lawrence Tangaacf0e22022-07-20 13:28:52 +0100204 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));
Lawrence Tangb44314c2022-07-13 11:45:22 +0100212}
213
214//Converts a single timestamp string to an EFI timestamp.
215void string_to_timestamp(EFI_ERROR_TIME_STAMP* out, const char* timestamp)
216{
Lawrence Tang0cb33792022-07-13 13:51:39 +0100217 //Ignore invalid timestamps.
218 if (timestamp == NULL)
219 return;
220
Lawrence Tangaacf0e22022-07-20 13:28:52 +0100221 sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu.000",
Lawrence Tangb44314c2022-07-13 11:45:22 +0100222 &out->Century,
223 &out->Year,
224 &out->Month,
225 &out->Day,
226 &out->Hours,
227 &out->Minutes,
228 &out->Seconds);
Lawrence Tangaacf0e22022-07-20 13:28:52 +0100229
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);
Lawrence Tangb44314c2022-07-13 11:45:22 +0100238}
239
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100240//Helper function to convert an EDK EFI GUID into a string for intermediate use.
241void 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
Lawrence Tangb44314c2022-07-13 11:45:22 +0100257//Helper function to convert a string into an EDK EFI GUID.
258void string_to_guid(EFI_GUID* out, const char* guid)
259{
Lawrence Tang0cb33792022-07-13 13:51:39 +0100260 //Ignore invalid GUIDs.
261 if (guid == NULL)
262 return;
263
264 sscanf(guid, "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
Lawrence Tangb44314c2022-07-13 11:45:22 +0100265 &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
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100278//Returns one if two EFI GUIDs are equal, zero otherwise.
279int 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;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100297}