blob: 28d94d4e234a25ba70cc3380f79adf7899a3bdf5 [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.
195const char* severity_to_string(UINT8 severity)
196{
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{
204 sprintf(out, "%02d%02d-%02d-%02dT%02d:%02d:%02d.000",
205 timestamp->Century,
206 timestamp->Year,
207 timestamp->Month,
208 timestamp->Day,
209 timestamp->Hours,
210 timestamp->Minutes,
211 timestamp->Seconds);
212}
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
221 sscanf(timestamp, "%02hhd%02hhd-%02hhd-%02hhdT%02hhd:%02hhd:%02hhd.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);
229}
230
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100231//Helper function to convert an EDK EFI GUID into a string for intermediate use.
232void guid_to_string(char* out, EFI_GUID* guid)
233{
234 sprintf(out, "%08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x",
235 guid->Data1,
236 guid->Data2,
237 guid->Data3,
238 guid->Data4[0],
239 guid->Data4[1],
240 guid->Data4[2],
241 guid->Data4[3],
242 guid->Data4[4],
243 guid->Data4[5],
244 guid->Data4[6],
245 guid->Data4[7]);
246}
247
Lawrence Tangb44314c2022-07-13 11:45:22 +0100248//Helper function to convert a string into an EDK EFI GUID.
249void string_to_guid(EFI_GUID* out, const char* guid)
250{
Lawrence Tang0cb33792022-07-13 13:51:39 +0100251 //Ignore invalid GUIDs.
252 if (guid == NULL)
253 return;
254
255 sscanf(guid, "%08x-%04hx-%04hx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
Lawrence Tangb44314c2022-07-13 11:45:22 +0100256 &out->Data1,
257 &out->Data2,
258 &out->Data3,
259 out->Data4,
260 out->Data4 + 1,
261 out->Data4 + 2,
262 out->Data4 + 3,
263 out->Data4 + 4,
264 out->Data4 + 5,
265 out->Data4 + 6,
266 out->Data4 + 7);
267}
268
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100269//Returns one if two EFI GUIDs are equal, zero otherwise.
270int guid_equal(EFI_GUID* a, EFI_GUID* b)
271{
272 //Check top base 3 components.
273 if (a->Data1 != b->Data1
274 || a->Data2 != b->Data2
275 || a->Data3 != b->Data3)
276 {
277 return 0;
278 }
279
280 //Check Data4 array for equality.
281 for (int i=0; i<8; i++)
282 {
283 if (a->Data4[i] != b->Data4[i])
284 return 0;
285 }
286
287 return 1;
Lawrence Tang4dbe3d72022-07-06 13:51:01 +0100288}
289
290//Converts the given BCD byte to a standard integer.
291int bcd_to_int(UINT8 bcd)
292{
293 return ((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F);
Lawrence Tang3b7f45b2022-07-14 14:14:30 +0100294}
295
296//Converts the given integer to a single byte BCD.
297UINT8 int_to_bcd(int value)
298{
299 UINT8 result = 0;
300 int shift = 0;
301 while (value > 0) {
302 result |= (value % 10) << (shift++ << 2);
303 value /= 10;
304 }
305
306 return result;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100307}