blob: f6adbdb485d97a78d6a6ef4a2df748c1614685c8 [file] [log] [blame]
Lawrence Tang1b0b00e2022-07-05 10:33:10 +01001/**
Ed Tanousfedd4572024-07-12 13:56:00 -07002 * Describes utility functions for parsing CPER into JSON IR.
3 *
Lawrence Tang1b0b00e2022-07-05 10:33:10 +01004 * Author: Lawrence.Tang@arm.com
5 **/
6
Khang D Nguyenbd1814d2025-03-31 13:07:49 +07007#include <ctype.h>
Lawrence Tang1b0b00e2022-07-05 10:33:10 +01008#include <stdio.h>
Lawrence Tang5202bbb2022-08-12 14:54:36 +01009#include <json.h>
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080010#include <string.h>
Thu Nguyene42fb482024-10-15 14:43:11 +000011#include <libcper/Cper.h>
12#include <libcper/cper-utils.h>
Ed Tanous50b966f2025-03-11 09:06:19 -070013#include <libcper/log.h>
Lawrence Tang1b0b00e2022-07-05 10:33:10 +010014
15//The available severity types for CPER.
Lawrence Tange407b4c2022-07-21 13:54:01 +010016const char *CPER_SEVERITY_TYPES[4] = { "Recoverable", "Fatal", "Corrected",
17 "Informational" };
Lawrence Tang1b0b00e2022-07-05 10:33:10 +010018
Lawrence Tanga0865e32022-07-06 11:59:52 +010019//Converts the given generic CPER error status to JSON IR.
Lawrence Tange407b4c2022-07-21 13:54:01 +010020json_object *
21cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS *error_status)
Lawrence Tanga0865e32022-07-06 11:59:52 +010022{
Lawrence Tange407b4c2022-07-21 13:54:01 +010023 json_object *error_status_ir = json_object_new_object();
Lawrence Tanga0865e32022-07-06 11:59:52 +010024
Lawrence Tange407b4c2022-07-21 13:54:01 +010025 //Error type.
26 json_object_object_add(error_status_ir, "errorType",
27 integer_to_readable_pair_with_desc(
28 error_status->Type, 18,
29 CPER_GENERIC_ERROR_TYPES_KEYS,
30 CPER_GENERIC_ERROR_TYPES_VALUES,
31 CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS,
32 "Unknown (Reserved)"));
Lawrence Tanga0865e32022-07-06 11:59:52 +010033
Lawrence Tange407b4c2022-07-21 13:54:01 +010034 //Boolean bit fields.
35 json_object_object_add(
36 error_status_ir, "addressSignal",
37 json_object_new_boolean(error_status->AddressSignal));
38 json_object_object_add(
39 error_status_ir, "controlSignal",
40 json_object_new_boolean(error_status->ControlSignal));
41 json_object_object_add(
42 error_status_ir, "dataSignal",
43 json_object_new_boolean(error_status->DataSignal));
44 json_object_object_add(
45 error_status_ir, "detectedByResponder",
46 json_object_new_boolean(error_status->DetectedByResponder));
47 json_object_object_add(
48 error_status_ir, "detectedByRequester",
49 json_object_new_boolean(error_status->DetectedByRequester));
50 json_object_object_add(
51 error_status_ir, "firstError",
52 json_object_new_boolean(error_status->FirstError));
53 json_object_object_add(
54 error_status_ir, "overflowDroppedLogs",
55 json_object_new_boolean(error_status->OverflowNotLogged));
56
57 return error_status_ir;
Lawrence Tanga0865e32022-07-06 11:59:52 +010058}
59
Lawrence Tang3b7f45b2022-07-14 14:14:30 +010060//Converts the given CPER-JSON generic error status into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +010061void ir_generic_error_status_to_cper(
62 json_object *error_status, EFI_GENERIC_ERROR_STATUS *error_status_cper)
Lawrence Tang3b7f45b2022-07-14 14:14:30 +010063{
Lawrence Tange407b4c2022-07-21 13:54:01 +010064 error_status_cper->Type = readable_pair_to_integer(
65 json_object_object_get(error_status, "errorType"));
66 error_status_cper->AddressSignal = json_object_get_boolean(
67 json_object_object_get(error_status, "addressSignal"));
68 error_status_cper->ControlSignal = json_object_get_boolean(
69 json_object_object_get(error_status, "controlSignal"));
70 error_status_cper->DataSignal = json_object_get_boolean(
71 json_object_object_get(error_status, "dataSignal"));
72 error_status_cper->DetectedByResponder = json_object_get_boolean(
73 json_object_object_get(error_status, "detectedByResponder"));
74 error_status_cper->DetectedByRequester = json_object_get_boolean(
75 json_object_object_get(error_status, "detectedByRequester"));
76 error_status_cper->FirstError = json_object_get_boolean(
77 json_object_object_get(error_status, "firstError"));
78 error_status_cper->OverflowNotLogged = json_object_get_boolean(
79 json_object_object_get(error_status, "overflowDroppedLogs"));
Lawrence Tang3b7f45b2022-07-14 14:14:30 +010080}
81
Lawrence Tang7f21db62022-07-06 11:09:39 +010082//Converts a single uniform struct of UINT64s into intermediate JSON IR format, given names for each field in byte order.
Lawrence Tange407b4c2022-07-21 13:54:01 +010083json_object *uniform_struct64_to_ir(UINT64 *start, int len, const char *names[])
Lawrence Tang7f21db62022-07-06 11:09:39 +010084{
Lawrence Tange407b4c2022-07-21 13:54:01 +010085 json_object *result = json_object_new_object();
Lawrence Tang7f21db62022-07-06 11:09:39 +010086
Lawrence Tange407b4c2022-07-21 13:54:01 +010087 UINT64 *cur = start;
88 for (int i = 0; i < len; i++) {
89 json_object_object_add(result, names[i],
90 json_object_new_uint64(*cur));
91 cur++;
92 }
Lawrence Tang7f21db62022-07-06 11:09:39 +010093
Lawrence Tange407b4c2022-07-21 13:54:01 +010094 return result;
Lawrence Tang7f21db62022-07-06 11:09:39 +010095}
96
97//Converts a single uniform struct of UINT32s into intermediate JSON IR format, given names for each field in byte order.
Lawrence Tange407b4c2022-07-21 13:54:01 +010098json_object *uniform_struct_to_ir(UINT32 *start, int len, const char *names[])
Lawrence Tang7f21db62022-07-06 11:09:39 +010099{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100100 json_object *result = json_object_new_object();
Lawrence Tang7f21db62022-07-06 11:09:39 +0100101
Lawrence Tange407b4c2022-07-21 13:54:01 +0100102 UINT32 *cur = start;
103 for (int i = 0; i < len; i++) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800104 UINT32 value;
105 memcpy(&value, cur, sizeof(UINT32));
Lawrence Tange407b4c2022-07-21 13:54:01 +0100106 json_object_object_add(result, names[i],
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800107 json_object_new_uint64(value));
Lawrence Tange407b4c2022-07-21 13:54:01 +0100108 cur++;
109 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100110
Lawrence Tange407b4c2022-07-21 13:54:01 +0100111 return result;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100112}
113
Lawrence Tang71570a22022-07-14 11:45:28 +0100114//Converts a single object containing UINT32s into a uniform struct.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100115void ir_to_uniform_struct64(json_object *ir, UINT64 *start, int len,
116 const char *names[])
Lawrence Tang71570a22022-07-14 11:45:28 +0100117{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100118 UINT64 *cur = start;
119 for (int i = 0; i < len; i++) {
120 *cur = json_object_get_uint64(
121 json_object_object_get(ir, names[i]));
122 cur++;
123 }
Lawrence Tang71570a22022-07-14 11:45:28 +0100124}
125
126//Converts a single object containing UINT32s into a uniform struct.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100127void ir_to_uniform_struct(json_object *ir, UINT32 *start, int len,
128 const char *names[])
Lawrence Tang71570a22022-07-14 11:45:28 +0100129{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100130 UINT32 *cur = start;
131 for (int i = 0; i < len; i++) {
132 *cur = (UINT32)json_object_get_uint64(
133 json_object_object_get(ir, names[i]));
134 cur++;
135 }
Lawrence Tang71570a22022-07-14 11:45:28 +0100136}
137
Lawrence Tang3c43f742022-07-05 11:37:17 +0100138//Converts a single integer value to an object containing a value, and a readable name if possible.
Ed Tanousb35d9572024-06-18 13:17:22 -0700139json_object *integer_to_readable_pair(UINT64 value, int len, const int keys[],
Lawrence Tange407b4c2022-07-21 13:54:01 +0100140 const char *values[],
141 const char *default_value)
Lawrence Tang3c43f742022-07-05 11:37:17 +0100142{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100143 json_object *result = json_object_new_object();
144 json_object_object_add(result, "value", json_object_new_uint64(value));
Lawrence Tang3c43f742022-07-05 11:37:17 +0100145
Lawrence Tange407b4c2022-07-21 13:54:01 +0100146 //Search for human readable name, add.
147 const char *name = default_value;
148 for (int i = 0; i < len; i++) {
John Chungf8fc7052024-05-03 20:05:29 +0800149 if ((UINT64)keys[i] == value) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100150 name = values[i];
John Chungf8fc7052024-05-03 20:05:29 +0800151 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100152 }
Lawrence Tang3c43f742022-07-05 11:37:17 +0100153
Lawrence Tange407b4c2022-07-21 13:54:01 +0100154 json_object_object_add(result, "name", json_object_new_string(name));
155 return result;
Lawrence Tang3c43f742022-07-05 11:37:17 +0100156}
157
Lawrence Tang7f21db62022-07-06 11:09:39 +0100158//Converts a single integer value to an object containing a value, readable name and description if possible.
Ed Tanousb35d9572024-06-18 13:17:22 -0700159json_object *integer_to_readable_pair_with_desc(int value, int len,
160 const int keys[],
Lawrence Tange407b4c2022-07-21 13:54:01 +0100161 const char *values[],
162 const char *descriptions[],
163 const char *default_value)
Lawrence Tang7f21db62022-07-06 11:09:39 +0100164{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100165 json_object *result = json_object_new_object();
166 json_object_object_add(result, "value", json_object_new_int(value));
Lawrence Tang7f21db62022-07-06 11:09:39 +0100167
Lawrence Tange407b4c2022-07-21 13:54:01 +0100168 //Search for human readable name, add.
169 const char *name = default_value;
170 for (int i = 0; i < len; i++) {
171 if (keys[i] == value) {
172 name = values[i];
173 json_object_object_add(
174 result, "description",
175 json_object_new_string(descriptions[i]));
176 }
177 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100178
Lawrence Tange407b4c2022-07-21 13:54:01 +0100179 json_object_object_add(result, "name", json_object_new_string(name));
180 return result;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100181}
182
Lawrence Tangb44314c2022-07-13 11:45:22 +0100183//Returns a single UINT64 value from the given readable pair object.
184//Assumes the integer value is held in the "value" field.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100185UINT64 readable_pair_to_integer(json_object *pair)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100186{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100187 return json_object_get_uint64(json_object_object_get(pair, "value"));
Lawrence Tangb44314c2022-07-13 11:45:22 +0100188}
189
Lawrence Tang794312c2022-07-05 14:46:10 +0100190//Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100191json_object *bitfield_to_ir(UINT64 bitfield, int num_fields,
192 const char *names[])
Lawrence Tang794312c2022-07-05 14:46:10 +0100193{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100194 json_object *result = json_object_new_object();
195 for (int i = 0; i < num_fields; i++) {
196 json_object_object_add(result, names[i],
197 json_object_new_boolean((bitfield >> i) &
John Chungf8fc7052024-05-03 20:05:29 +0800198 0x1));
Lawrence Tange407b4c2022-07-21 13:54:01 +0100199 }
Lawrence Tang794312c2022-07-05 14:46:10 +0100200
Lawrence Tange407b4c2022-07-21 13:54:01 +0100201 return result;
Lawrence Tang794312c2022-07-05 14:46:10 +0100202}
203
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800204//Filters properties based on Validation Bits.
205// Refer to CPER spec for vbit_idx to be passed here.
206void add_to_valid_bitfield(ValidationTypes *val, int vbit_idx)
207{
208 switch (val->size) {
209 case UINT_8T:
210 val->value.ui8 |= (0x01 << vbit_idx);
211 break;
212 case UINT_16T:
213 val->value.ui16 |= (0x01 << vbit_idx);
214 break;
215 case UINT_32T:
216 val->value.ui32 |= (0x01 << vbit_idx);
217 break;
218 case UINT_64T:
219 val->value.ui64 |= (0x01 << vbit_idx);
220 break;
221 default:
Ed Tanous50b966f2025-03-11 09:06:19 -0700222 cper_print_log(
223 "IR to CPER: Unknown validation bits size passed, Enum IntType=%d",
224 val->size);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800225 }
226}
227
Lawrence Tangb44314c2022-07-13 11:45:22 +0100228//Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100229UINT64 ir_to_bitfield(json_object *ir, int num_fields, const char *names[])
Lawrence Tangb44314c2022-07-13 11:45:22 +0100230{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100231 UINT64 result = 0x0;
232 for (int i = 0; i < num_fields; i++) {
233 if (json_object_get_boolean(
John Chungf8fc7052024-05-03 20:05:29 +0800234 json_object_object_get(ir, names[i]))) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100235 result |= (0x1 << i);
John Chungf8fc7052024-05-03 20:05:29 +0800236 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100237 }
Lawrence Tangb44314c2022-07-13 11:45:22 +0100238
Lawrence Tange407b4c2022-07-21 13:54:01 +0100239 return result;
Lawrence Tangb44314c2022-07-13 11:45:22 +0100240}
241
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800242// Filters properties based on Validation Bits.
243// Refer to CPER spec for vbit_idx to be passed here.
244// Overload function for 16, 32, 64b
245bool isvalid_prop_to_ir(ValidationTypes *val, int vbit_idx)
246{
Aushim Nagarkattidd9e8d92025-02-28 11:20:45 -0800247// If the option is enabled, output invalid properties
248// as well as valid ones.
249#ifdef OUTPUT_ALL_PROPERTIES
250 return true;
251#endif //OUTPUT_ALL_PROPERTIES
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800252 UINT64 vbit_mask = 0x01 << vbit_idx;
253 switch (val->size) {
254 case UINT_16T:
255 return (vbit_mask & val->value.ui16);
256
257 case UINT_32T:
258 return (vbit_mask & val->value.ui32);
259
260 case UINT_64T:
261 return (vbit_mask & val->value.ui64);
262
263 default:
Ed Tanous50b966f2025-03-11 09:06:19 -0700264 cper_print_log(
265 "CPER to IR:Unknown validation bits size passed. Enum IntType: %d",
266 val->size);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800267 }
268 return 0;
269}
270
271void print_val(ValidationTypes *val)
272{
273 switch (val->size) {
274 case UINT_8T:
Ed Tanous50b966f2025-03-11 09:06:19 -0700275 cper_print_log("Validation bits: %x\n", val->value.ui8);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800276 break;
277 case UINT_16T:
Ed Tanous50b966f2025-03-11 09:06:19 -0700278 cper_print_log("Validation bits: %x\n", val->value.ui16);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800279 break;
280
281 case UINT_32T:
Ed Tanous50b966f2025-03-11 09:06:19 -0700282 cper_print_log("Validation bits: %x\n", val->value.ui32);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800283 break;
284
285 case UINT_64T:
Ed Tanous50b966f2025-03-11 09:06:19 -0700286 cper_print_log("Validation bits: %llx\n", val->value.ui64);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800287 break;
288
289 default:
Ed Tanous50b966f2025-03-11 09:06:19 -0700290 cper_print_log(
291 "CPER to IR:Unknown validation bits size passed. Enum IntType: %d",
292 val->size);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800293 }
294}
295
Lawrence Tange18aaee2022-07-07 09:01:30 +0100296//Converts the given UINT64 array into a JSON IR array, given the length.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100297json_object *uint64_array_to_ir_array(UINT64 *array, int len)
Lawrence Tange18aaee2022-07-07 09:01:30 +0100298{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100299 json_object *array_ir = json_object_new_array();
John Chungf8fc7052024-05-03 20:05:29 +0800300 for (int i = 0; i < len; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100301 json_object_array_add(array_ir,
302 json_object_new_uint64(array[i]));
John Chungf8fc7052024-05-03 20:05:29 +0800303 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100304 return array_ir;
Lawrence Tange18aaee2022-07-07 09:01:30 +0100305}
Lawrence Tang794312c2022-07-05 14:46:10 +0100306
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100307//Converts a single UINT16 revision number into JSON IR representation.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100308json_object *revision_to_ir(UINT16 revision)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100309{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100310 json_object *revision_info = json_object_new_object();
311 json_object_object_add(revision_info, "major",
312 json_object_new_int(revision >> 8));
313 json_object_object_add(revision_info, "minor",
314 json_object_new_int(revision & 0xFF));
315 return revision_info;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100316}
317
318//Returns the appropriate string for the given integer severity.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100319const char *severity_to_string(UINT32 severity)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100320{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100321 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown";
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100322}
323
Lawrence Tangb44314c2022-07-13 11:45:22 +0100324//Converts a single EFI timestamp to string, at the given output.
325//Output must be at least TIMESTAMP_LENGTH bytes long.
Ed Tanous596c59e2025-03-10 13:15:58 -0700326int timestamp_to_string(char *out, int out_len, EFI_ERROR_TIME_STAMP *timestamp)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100327{
Ed Tanous596c59e2025-03-10 13:15:58 -0700328 //Cannot go to three digits.
329 int century = bcd_to_int(timestamp->Century) % 100;
330 if (century >= 100) {
331 return -1;
332 }
333 int year = bcd_to_int(timestamp->Year) % 100;
334 if (year >= 100) {
335 return -1;
336 }
337 int month = bcd_to_int(timestamp->Month);
338 if (month > 12) {
339 return -1;
340 }
341 int day = bcd_to_int(timestamp->Day);
342 if (day > 31) {
343 return -1;
344 }
345 int hours = bcd_to_int(timestamp->Hours);
Ed Tanous2d4d3b62025-03-11 10:34:29 -0700346 if (hours > 24) {
Ed Tanous596c59e2025-03-10 13:15:58 -0700347 return -1;
348 }
349 int minutes = bcd_to_int(timestamp->Minutes);
350 if (minutes > 60) {
351 return -1;
352 }
353 int seconds = bcd_to_int(timestamp->Seconds);
354 if (seconds >= 60) {
355 return -1;
356 }
Ed Tanous13f099f2024-11-20 11:10:30 -0800357 int written = snprintf(
358 out, out_len,
359 "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu+00:00",
Ed Tanous596c59e2025-03-10 13:15:58 -0700360 century, year, month, day, hours, minutes, seconds);
Ed Tanous13f099f2024-11-20 11:10:30 -0800361
362 if (written < 0 || written >= out_len) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700363 cper_print_log("Timestamp buffer of insufficient size\n");
Ed Tanous596c59e2025-03-10 13:15:58 -0700364 return -1;
Ed Tanous13f099f2024-11-20 11:10:30 -0800365 }
Ed Tanous596c59e2025-03-10 13:15:58 -0700366 return 0;
Lawrence Tangb44314c2022-07-13 11:45:22 +0100367}
368
369//Converts a single timestamp string to an EFI timestamp.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100370void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100371{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100372 //Ignore invalid timestamps.
John Chungf8fc7052024-05-03 20:05:29 +0800373 if (timestamp == NULL) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100374 return;
John Chungf8fc7052024-05-03 20:05:29 +0800375 }
Lawrence Tang0cb33792022-07-13 13:51:39 +0100376
Aushim Nagarkattide7dd062024-11-04 15:23:39 -0800377 sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu+00:00",
Lawrence Tange407b4c2022-07-21 13:54:01 +0100378 &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours,
379 &out->Minutes, &out->Seconds);
Lawrence Tangaacf0e22022-07-20 13:28:52 +0100380
Lawrence Tange407b4c2022-07-21 13:54:01 +0100381 //Convert back to BCD.
382 out->Century = int_to_bcd(out->Century);
383 out->Year = int_to_bcd(out->Year);
384 out->Month = int_to_bcd(out->Month);
385 out->Day = int_to_bcd(out->Day);
386 out->Hours = int_to_bcd(out->Hours);
387 out->Minutes = int_to_bcd(out->Minutes);
388 out->Seconds = int_to_bcd(out->Seconds);
Lawrence Tangb44314c2022-07-13 11:45:22 +0100389}
390
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100391//Helper function to convert an EDK EFI GUID into a string for intermediate use.
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700392int guid_to_string(char *out, size_t out_len, EFI_GUID *guid)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100393{
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700394 size_t len = snprintf(
395 out, out_len,
396 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->Data1,
397 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
398 guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5],
399 guid->Data4[6], guid->Data4[7]);
400 if (len != out_len) {
401 return -1;
402 }
403 return len;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100404}
405
Lawrence Tangb44314c2022-07-13 11:45:22 +0100406//Helper function to convert a string into an EDK EFI GUID.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100407void string_to_guid(EFI_GUID *out, const char *guid)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100408{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100409 //Ignore invalid GUIDs.
John Chungf8fc7052024-05-03 20:05:29 +0800410 if (guid == NULL) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100411 return;
John Chungf8fc7052024-05-03 20:05:29 +0800412 }
Lawrence Tang0cb33792022-07-13 13:51:39 +0100413
Lawrence Tange407b4c2022-07-21 13:54:01 +0100414 sscanf(guid,
Karthik Rajagopalan7623a6e2024-09-20 19:24:35 -0700415 "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
Lawrence Tange407b4c2022-07-21 13:54:01 +0100416 &out->Data1, &out->Data2, &out->Data3, out->Data4,
417 out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4,
418 out->Data4 + 5, out->Data4 + 6, out->Data4 + 7);
Lawrence Tangb44314c2022-07-13 11:45:22 +0100419}
420
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100421//Returns one if two EFI GUIDs are equal, zero otherwise.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100422int guid_equal(EFI_GUID *a, EFI_GUID *b)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100423{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100424 //Check top base 3 components.
425 if (a->Data1 != b->Data1 || a->Data2 != b->Data2 ||
426 a->Data3 != b->Data3) {
427 return 0;
428 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100429
Lawrence Tange407b4c2022-07-21 13:54:01 +0100430 //Check Data4 array for equality.
431 for (int i = 0; i < 8; i++) {
John Chungf8fc7052024-05-03 20:05:29 +0800432 if (a->Data4[i] != b->Data4[i]) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100433 return 0;
John Chungf8fc7052024-05-03 20:05:29 +0800434 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100435 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100436
Lawrence Tange407b4c2022-07-21 13:54:01 +0100437 return 1;
John Chungf8fc7052024-05-03 20:05:29 +0800438}
Ed Tanous5e2164a2025-03-09 09:20:44 -0700439
Ed Tanous1a648562025-03-10 15:23:38 -0700440int select_guid_from_list(EFI_GUID *guid, EFI_GUID *guid_list[], int len)
441{
442 int i = 0;
443 for (; i < len; i++) {
444 if (guid_equal(guid, guid_list[i])) {
445 break;
446 }
447 }
448 // It's unlikely fuzzing can reliably come up with a correct guid, given how
449 // much entropy there is. If we're in fuzzing mode, and if we haven't found
450 // a match, try to force a match so we get some coverage. Note, we still
451 // want coverage of the section failed to convert code, so treat index ==
452 // size as section failed to convert.
453#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
454 if (i == len) {
455 i = guid->Data1 % (len + 1);
456 }
457#endif
458
459 return i;
460}
461
Ed Tanous5e2164a2025-03-09 09:20:44 -0700462void add_untrusted_string(json_object *ir, const char *field_name,
463 const char *str, int len)
464{
465 int fru_text_len = 0;
466 for (; fru_text_len < len; fru_text_len++) {
467 char c = str[fru_text_len];
Khang D Nguyenbd1814d2025-03-31 13:07:49 +0700468 if (c == '\0') {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700469 break;
470 }
Khang D Nguyenbd1814d2025-03-31 13:07:49 +0700471 if (!isprint(c)) {
472 fru_text_len = -1;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700473 break;
474 }
475 }
476 if (fru_text_len >= 0) {
477 json_object_object_add(
478 ir, field_name,
479 json_object_new_string_len(str, fru_text_len));
480 }
481}
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700482
483void add_guid(json_object *ir, const char *field_name, EFI_GUID *guid)
484{
485 char platform_string[GUID_STRING_LENGTH + 1];
486 if (!guid_to_string(platform_string, sizeof(platform_string), guid)) {
487 return;
488 }
489 json_object_object_add(
490 ir, field_name,
491 json_object_new_string_len(platform_string,
492 sizeof(platform_string) - 1));
493}