blob: 0821a167f04592fcfb42db87430c2c527f324a42 [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
7#include <stdio.h>
Lawrence Tang5202bbb2022-08-12 14:54:36 +01008#include <json.h>
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08009#include <string.h>
Thu Nguyene42fb482024-10-15 14:43:11 +000010#include <libcper/Cper.h>
11#include <libcper/cper-utils.h>
Ed Tanous50b966f2025-03-11 09:06:19 -070012#include <libcper/log.h>
Lawrence Tang1b0b00e2022-07-05 10:33:10 +010013
14//The available severity types for CPER.
Lawrence Tange407b4c2022-07-21 13:54:01 +010015const char *CPER_SEVERITY_TYPES[4] = { "Recoverable", "Fatal", "Corrected",
16 "Informational" };
Lawrence Tang1b0b00e2022-07-05 10:33:10 +010017
Lawrence Tanga0865e32022-07-06 11:59:52 +010018//Converts the given generic CPER error status to JSON IR.
Lawrence Tange407b4c2022-07-21 13:54:01 +010019json_object *
20cper_generic_error_status_to_ir(EFI_GENERIC_ERROR_STATUS *error_status)
Lawrence Tanga0865e32022-07-06 11:59:52 +010021{
Lawrence Tange407b4c2022-07-21 13:54:01 +010022 json_object *error_status_ir = json_object_new_object();
Lawrence Tanga0865e32022-07-06 11:59:52 +010023
Lawrence Tange407b4c2022-07-21 13:54:01 +010024 //Error type.
25 json_object_object_add(error_status_ir, "errorType",
26 integer_to_readable_pair_with_desc(
27 error_status->Type, 18,
28 CPER_GENERIC_ERROR_TYPES_KEYS,
29 CPER_GENERIC_ERROR_TYPES_VALUES,
30 CPER_GENERIC_ERROR_TYPES_DESCRIPTIONS,
31 "Unknown (Reserved)"));
Lawrence Tanga0865e32022-07-06 11:59:52 +010032
Lawrence Tange407b4c2022-07-21 13:54:01 +010033 //Boolean bit fields.
34 json_object_object_add(
35 error_status_ir, "addressSignal",
36 json_object_new_boolean(error_status->AddressSignal));
37 json_object_object_add(
38 error_status_ir, "controlSignal",
39 json_object_new_boolean(error_status->ControlSignal));
40 json_object_object_add(
41 error_status_ir, "dataSignal",
42 json_object_new_boolean(error_status->DataSignal));
43 json_object_object_add(
44 error_status_ir, "detectedByResponder",
45 json_object_new_boolean(error_status->DetectedByResponder));
46 json_object_object_add(
47 error_status_ir, "detectedByRequester",
48 json_object_new_boolean(error_status->DetectedByRequester));
49 json_object_object_add(
50 error_status_ir, "firstError",
51 json_object_new_boolean(error_status->FirstError));
52 json_object_object_add(
53 error_status_ir, "overflowDroppedLogs",
54 json_object_new_boolean(error_status->OverflowNotLogged));
55
56 return error_status_ir;
Lawrence Tanga0865e32022-07-06 11:59:52 +010057}
58
Lawrence Tang3b7f45b2022-07-14 14:14:30 +010059//Converts the given CPER-JSON generic error status into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +010060void ir_generic_error_status_to_cper(
61 json_object *error_status, EFI_GENERIC_ERROR_STATUS *error_status_cper)
Lawrence Tang3b7f45b2022-07-14 14:14:30 +010062{
Lawrence Tange407b4c2022-07-21 13:54:01 +010063 error_status_cper->Type = readable_pair_to_integer(
64 json_object_object_get(error_status, "errorType"));
65 error_status_cper->AddressSignal = json_object_get_boolean(
66 json_object_object_get(error_status, "addressSignal"));
67 error_status_cper->ControlSignal = json_object_get_boolean(
68 json_object_object_get(error_status, "controlSignal"));
69 error_status_cper->DataSignal = json_object_get_boolean(
70 json_object_object_get(error_status, "dataSignal"));
71 error_status_cper->DetectedByResponder = json_object_get_boolean(
72 json_object_object_get(error_status, "detectedByResponder"));
73 error_status_cper->DetectedByRequester = json_object_get_boolean(
74 json_object_object_get(error_status, "detectedByRequester"));
75 error_status_cper->FirstError = json_object_get_boolean(
76 json_object_object_get(error_status, "firstError"));
77 error_status_cper->OverflowNotLogged = json_object_get_boolean(
78 json_object_object_get(error_status, "overflowDroppedLogs"));
Lawrence Tang3b7f45b2022-07-14 14:14:30 +010079}
80
Lawrence Tang7f21db62022-07-06 11:09:39 +010081//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 +010082json_object *uniform_struct64_to_ir(UINT64 *start, int len, const char *names[])
Lawrence Tang7f21db62022-07-06 11:09:39 +010083{
Lawrence Tange407b4c2022-07-21 13:54:01 +010084 json_object *result = json_object_new_object();
Lawrence Tang7f21db62022-07-06 11:09:39 +010085
Lawrence Tange407b4c2022-07-21 13:54:01 +010086 UINT64 *cur = start;
87 for (int i = 0; i < len; i++) {
88 json_object_object_add(result, names[i],
89 json_object_new_uint64(*cur));
90 cur++;
91 }
Lawrence Tang7f21db62022-07-06 11:09:39 +010092
Lawrence Tange407b4c2022-07-21 13:54:01 +010093 return result;
Lawrence Tang7f21db62022-07-06 11:09:39 +010094}
95
96//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 +010097json_object *uniform_struct_to_ir(UINT32 *start, int len, const char *names[])
Lawrence Tang7f21db62022-07-06 11:09:39 +010098{
Lawrence Tange407b4c2022-07-21 13:54:01 +010099 json_object *result = json_object_new_object();
Lawrence Tang7f21db62022-07-06 11:09:39 +0100100
Lawrence Tange407b4c2022-07-21 13:54:01 +0100101 UINT32 *cur = start;
102 for (int i = 0; i < len; i++) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800103 UINT32 value;
104 memcpy(&value, cur, sizeof(UINT32));
Lawrence Tange407b4c2022-07-21 13:54:01 +0100105 json_object_object_add(result, names[i],
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800106 json_object_new_uint64(value));
Lawrence Tange407b4c2022-07-21 13:54:01 +0100107 cur++;
108 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100109
Lawrence Tange407b4c2022-07-21 13:54:01 +0100110 return result;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100111}
112
Lawrence Tang71570a22022-07-14 11:45:28 +0100113//Converts a single object containing UINT32s into a uniform struct.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100114void ir_to_uniform_struct64(json_object *ir, UINT64 *start, int len,
115 const char *names[])
Lawrence Tang71570a22022-07-14 11:45:28 +0100116{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100117 UINT64 *cur = start;
118 for (int i = 0; i < len; i++) {
119 *cur = json_object_get_uint64(
120 json_object_object_get(ir, names[i]));
121 cur++;
122 }
Lawrence Tang71570a22022-07-14 11:45:28 +0100123}
124
125//Converts a single object containing UINT32s into a uniform struct.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100126void ir_to_uniform_struct(json_object *ir, UINT32 *start, int len,
127 const char *names[])
Lawrence Tang71570a22022-07-14 11:45:28 +0100128{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100129 UINT32 *cur = start;
130 for (int i = 0; i < len; i++) {
131 *cur = (UINT32)json_object_get_uint64(
132 json_object_object_get(ir, names[i]));
133 cur++;
134 }
Lawrence Tang71570a22022-07-14 11:45:28 +0100135}
136
Lawrence Tang3c43f742022-07-05 11:37:17 +0100137//Converts a single integer value to an object containing a value, and a readable name if possible.
Ed Tanousb35d9572024-06-18 13:17:22 -0700138json_object *integer_to_readable_pair(UINT64 value, int len, const int keys[],
Lawrence Tange407b4c2022-07-21 13:54:01 +0100139 const char *values[],
140 const char *default_value)
Lawrence Tang3c43f742022-07-05 11:37:17 +0100141{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100142 json_object *result = json_object_new_object();
143 json_object_object_add(result, "value", json_object_new_uint64(value));
Lawrence Tang3c43f742022-07-05 11:37:17 +0100144
Lawrence Tange407b4c2022-07-21 13:54:01 +0100145 //Search for human readable name, add.
146 const char *name = default_value;
147 for (int i = 0; i < len; i++) {
John Chungf8fc7052024-05-03 20:05:29 +0800148 if ((UINT64)keys[i] == value) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100149 name = values[i];
John Chungf8fc7052024-05-03 20:05:29 +0800150 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100151 }
Lawrence Tang3c43f742022-07-05 11:37:17 +0100152
Lawrence Tange407b4c2022-07-21 13:54:01 +0100153 json_object_object_add(result, "name", json_object_new_string(name));
154 return result;
Lawrence Tang3c43f742022-07-05 11:37:17 +0100155}
156
Lawrence Tang7f21db62022-07-06 11:09:39 +0100157//Converts a single integer value to an object containing a value, readable name and description if possible.
Ed Tanousb35d9572024-06-18 13:17:22 -0700158json_object *integer_to_readable_pair_with_desc(int value, int len,
159 const int keys[],
Lawrence Tange407b4c2022-07-21 13:54:01 +0100160 const char *values[],
161 const char *descriptions[],
162 const char *default_value)
Lawrence Tang7f21db62022-07-06 11:09:39 +0100163{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100164 json_object *result = json_object_new_object();
165 json_object_object_add(result, "value", json_object_new_int(value));
Lawrence Tang7f21db62022-07-06 11:09:39 +0100166
Lawrence Tange407b4c2022-07-21 13:54:01 +0100167 //Search for human readable name, add.
168 const char *name = default_value;
169 for (int i = 0; i < len; i++) {
170 if (keys[i] == value) {
171 name = values[i];
172 json_object_object_add(
173 result, "description",
174 json_object_new_string(descriptions[i]));
175 }
176 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100177
Lawrence Tange407b4c2022-07-21 13:54:01 +0100178 json_object_object_add(result, "name", json_object_new_string(name));
179 return result;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100180}
181
Lawrence Tangb44314c2022-07-13 11:45:22 +0100182//Returns a single UINT64 value from the given readable pair object.
183//Assumes the integer value is held in the "value" field.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100184UINT64 readable_pair_to_integer(json_object *pair)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100185{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100186 return json_object_get_uint64(json_object_object_get(pair, "value"));
Lawrence Tangb44314c2022-07-13 11:45:22 +0100187}
188
Lawrence Tang794312c2022-07-05 14:46:10 +0100189//Converts the given 64 bit bitfield to IR, assuming bit 0 starts on the left.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100190json_object *bitfield_to_ir(UINT64 bitfield, int num_fields,
191 const char *names[])
Lawrence Tang794312c2022-07-05 14:46:10 +0100192{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100193 json_object *result = json_object_new_object();
194 for (int i = 0; i < num_fields; i++) {
195 json_object_object_add(result, names[i],
196 json_object_new_boolean((bitfield >> i) &
John Chungf8fc7052024-05-03 20:05:29 +0800197 0x1));
Lawrence Tange407b4c2022-07-21 13:54:01 +0100198 }
Lawrence Tang794312c2022-07-05 14:46:10 +0100199
Lawrence Tange407b4c2022-07-21 13:54:01 +0100200 return result;
Lawrence Tang794312c2022-07-05 14:46:10 +0100201}
202
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800203//Filters properties based on Validation Bits.
204// Refer to CPER spec for vbit_idx to be passed here.
205void add_to_valid_bitfield(ValidationTypes *val, int vbit_idx)
206{
207 switch (val->size) {
208 case UINT_8T:
209 val->value.ui8 |= (0x01 << vbit_idx);
210 break;
211 case UINT_16T:
212 val->value.ui16 |= (0x01 << vbit_idx);
213 break;
214 case UINT_32T:
215 val->value.ui32 |= (0x01 << vbit_idx);
216 break;
217 case UINT_64T:
218 val->value.ui64 |= (0x01 << vbit_idx);
219 break;
220 default:
Ed Tanous50b966f2025-03-11 09:06:19 -0700221 cper_print_log(
222 "IR to CPER: Unknown validation bits size passed, Enum IntType=%d",
223 val->size);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800224 }
225}
226
Lawrence Tangb44314c2022-07-13 11:45:22 +0100227//Converts the given IR bitfield into a standard UINT64 bitfield, with fields beginning from bit 0.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100228UINT64 ir_to_bitfield(json_object *ir, int num_fields, const char *names[])
Lawrence Tangb44314c2022-07-13 11:45:22 +0100229{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100230 UINT64 result = 0x0;
231 for (int i = 0; i < num_fields; i++) {
232 if (json_object_get_boolean(
John Chungf8fc7052024-05-03 20:05:29 +0800233 json_object_object_get(ir, names[i]))) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100234 result |= (0x1 << i);
John Chungf8fc7052024-05-03 20:05:29 +0800235 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100236 }
Lawrence Tangb44314c2022-07-13 11:45:22 +0100237
Lawrence Tange407b4c2022-07-21 13:54:01 +0100238 return result;
Lawrence Tangb44314c2022-07-13 11:45:22 +0100239}
240
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800241// Filters properties based on Validation Bits.
242// Refer to CPER spec for vbit_idx to be passed here.
243// Overload function for 16, 32, 64b
244bool isvalid_prop_to_ir(ValidationTypes *val, int vbit_idx)
245{
Aushim Nagarkattidd9e8d92025-02-28 11:20:45 -0800246// If the option is enabled, output invalid properties
247// as well as valid ones.
248#ifdef OUTPUT_ALL_PROPERTIES
249 return true;
250#endif //OUTPUT_ALL_PROPERTIES
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800251 UINT64 vbit_mask = 0x01 << vbit_idx;
252 switch (val->size) {
253 case UINT_16T:
254 return (vbit_mask & val->value.ui16);
255
256 case UINT_32T:
257 return (vbit_mask & val->value.ui32);
258
259 case UINT_64T:
260 return (vbit_mask & val->value.ui64);
261
262 default:
Ed Tanous50b966f2025-03-11 09:06:19 -0700263 cper_print_log(
264 "CPER to IR:Unknown validation bits size passed. Enum IntType: %d",
265 val->size);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800266 }
267 return 0;
268}
269
270void print_val(ValidationTypes *val)
271{
272 switch (val->size) {
273 case UINT_8T:
Ed Tanous50b966f2025-03-11 09:06:19 -0700274 cper_print_log("Validation bits: %x\n", val->value.ui8);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800275 break;
276 case UINT_16T:
Ed Tanous50b966f2025-03-11 09:06:19 -0700277 cper_print_log("Validation bits: %x\n", val->value.ui16);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800278 break;
279
280 case UINT_32T:
Ed Tanous50b966f2025-03-11 09:06:19 -0700281 cper_print_log("Validation bits: %x\n", val->value.ui32);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800282 break;
283
284 case UINT_64T:
Ed Tanous50b966f2025-03-11 09:06:19 -0700285 cper_print_log("Validation bits: %llx\n", val->value.ui64);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800286 break;
287
288 default:
Ed Tanous50b966f2025-03-11 09:06:19 -0700289 cper_print_log(
290 "CPER to IR:Unknown validation bits size passed. Enum IntType: %d",
291 val->size);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800292 }
293}
294
Lawrence Tange18aaee2022-07-07 09:01:30 +0100295//Converts the given UINT64 array into a JSON IR array, given the length.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100296json_object *uint64_array_to_ir_array(UINT64 *array, int len)
Lawrence Tange18aaee2022-07-07 09:01:30 +0100297{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100298 json_object *array_ir = json_object_new_array();
John Chungf8fc7052024-05-03 20:05:29 +0800299 for (int i = 0; i < len; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100300 json_object_array_add(array_ir,
301 json_object_new_uint64(array[i]));
John Chungf8fc7052024-05-03 20:05:29 +0800302 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100303 return array_ir;
Lawrence Tange18aaee2022-07-07 09:01:30 +0100304}
Lawrence Tang794312c2022-07-05 14:46:10 +0100305
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100306//Converts a single UINT16 revision number into JSON IR representation.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100307json_object *revision_to_ir(UINT16 revision)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100308{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100309 json_object *revision_info = json_object_new_object();
310 json_object_object_add(revision_info, "major",
311 json_object_new_int(revision >> 8));
312 json_object_object_add(revision_info, "minor",
313 json_object_new_int(revision & 0xFF));
314 return revision_info;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100315}
316
317//Returns the appropriate string for the given integer severity.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100318const char *severity_to_string(UINT32 severity)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100319{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100320 return severity < 4 ? CPER_SEVERITY_TYPES[severity] : "Unknown";
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100321}
322
Lawrence Tangb44314c2022-07-13 11:45:22 +0100323//Converts a single EFI timestamp to string, at the given output.
324//Output must be at least TIMESTAMP_LENGTH bytes long.
Ed Tanous596c59e2025-03-10 13:15:58 -0700325int timestamp_to_string(char *out, int out_len, EFI_ERROR_TIME_STAMP *timestamp)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100326{
Ed Tanous596c59e2025-03-10 13:15:58 -0700327 //Cannot go to three digits.
328 int century = bcd_to_int(timestamp->Century) % 100;
329 if (century >= 100) {
330 return -1;
331 }
332 int year = bcd_to_int(timestamp->Year) % 100;
333 if (year >= 100) {
334 return -1;
335 }
336 int month = bcd_to_int(timestamp->Month);
337 if (month > 12) {
338 return -1;
339 }
340 int day = bcd_to_int(timestamp->Day);
341 if (day > 31) {
342 return -1;
343 }
344 int hours = bcd_to_int(timestamp->Hours);
Ed Tanous2d4d3b62025-03-11 10:34:29 -0700345 if (hours > 24) {
Ed Tanous596c59e2025-03-10 13:15:58 -0700346 return -1;
347 }
348 int minutes = bcd_to_int(timestamp->Minutes);
349 if (minutes > 60) {
350 return -1;
351 }
352 int seconds = bcd_to_int(timestamp->Seconds);
353 if (seconds >= 60) {
354 return -1;
355 }
Ed Tanous13f099f2024-11-20 11:10:30 -0800356 int written = snprintf(
357 out, out_len,
358 "%02hhu%02hhu-%02hhu-%02hhuT%02hhu:%02hhu:%02hhu+00:00",
Ed Tanous596c59e2025-03-10 13:15:58 -0700359 century, year, month, day, hours, minutes, seconds);
Ed Tanous13f099f2024-11-20 11:10:30 -0800360
361 if (written < 0 || written >= out_len) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700362 cper_print_log("Timestamp buffer of insufficient size\n");
Ed Tanous596c59e2025-03-10 13:15:58 -0700363 return -1;
Ed Tanous13f099f2024-11-20 11:10:30 -0800364 }
Ed Tanous596c59e2025-03-10 13:15:58 -0700365 return 0;
Lawrence Tangb44314c2022-07-13 11:45:22 +0100366}
367
368//Converts a single timestamp string to an EFI timestamp.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100369void string_to_timestamp(EFI_ERROR_TIME_STAMP *out, const char *timestamp)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100370{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100371 //Ignore invalid timestamps.
John Chungf8fc7052024-05-03 20:05:29 +0800372 if (timestamp == NULL) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100373 return;
John Chungf8fc7052024-05-03 20:05:29 +0800374 }
Lawrence Tang0cb33792022-07-13 13:51:39 +0100375
Aushim Nagarkattide7dd062024-11-04 15:23:39 -0800376 sscanf(timestamp, "%2hhu%2hhu-%hhu-%hhuT%hhu:%hhu:%hhu+00:00",
Lawrence Tange407b4c2022-07-21 13:54:01 +0100377 &out->Century, &out->Year, &out->Month, &out->Day, &out->Hours,
378 &out->Minutes, &out->Seconds);
Lawrence Tangaacf0e22022-07-20 13:28:52 +0100379
Lawrence Tange407b4c2022-07-21 13:54:01 +0100380 //Convert back to BCD.
381 out->Century = int_to_bcd(out->Century);
382 out->Year = int_to_bcd(out->Year);
383 out->Month = int_to_bcd(out->Month);
384 out->Day = int_to_bcd(out->Day);
385 out->Hours = int_to_bcd(out->Hours);
386 out->Minutes = int_to_bcd(out->Minutes);
387 out->Seconds = int_to_bcd(out->Seconds);
Lawrence Tangb44314c2022-07-13 11:45:22 +0100388}
389
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100390//Helper function to convert an EDK EFI GUID into a string for intermediate use.
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700391int guid_to_string(char *out, size_t out_len, EFI_GUID *guid)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100392{
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700393 size_t len = snprintf(
394 out, out_len,
395 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", guid->Data1,
396 guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1],
397 guid->Data4[2], guid->Data4[3], guid->Data4[4], guid->Data4[5],
398 guid->Data4[6], guid->Data4[7]);
399 if (len != out_len) {
400 return -1;
401 }
402 return len;
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100403}
404
Lawrence Tangb44314c2022-07-13 11:45:22 +0100405//Helper function to convert a string into an EDK EFI GUID.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100406void string_to_guid(EFI_GUID *out, const char *guid)
Lawrence Tangb44314c2022-07-13 11:45:22 +0100407{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100408 //Ignore invalid GUIDs.
John Chungf8fc7052024-05-03 20:05:29 +0800409 if (guid == NULL) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100410 return;
John Chungf8fc7052024-05-03 20:05:29 +0800411 }
Lawrence Tang0cb33792022-07-13 13:51:39 +0100412
Lawrence Tange407b4c2022-07-21 13:54:01 +0100413 sscanf(guid,
Karthik Rajagopalan7623a6e2024-09-20 19:24:35 -0700414 "%08x-%04hx-%04hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
Lawrence Tange407b4c2022-07-21 13:54:01 +0100415 &out->Data1, &out->Data2, &out->Data3, out->Data4,
416 out->Data4 + 1, out->Data4 + 2, out->Data4 + 3, out->Data4 + 4,
417 out->Data4 + 5, out->Data4 + 6, out->Data4 + 7);
Lawrence Tangb44314c2022-07-13 11:45:22 +0100418}
419
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100420//Returns one if two EFI GUIDs are equal, zero otherwise.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100421int guid_equal(EFI_GUID *a, EFI_GUID *b)
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100422{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100423 //Check top base 3 components.
424 if (a->Data1 != b->Data1 || a->Data2 != b->Data2 ||
425 a->Data3 != b->Data3) {
426 return 0;
427 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100428
Lawrence Tange407b4c2022-07-21 13:54:01 +0100429 //Check Data4 array for equality.
430 for (int i = 0; i < 8; i++) {
John Chungf8fc7052024-05-03 20:05:29 +0800431 if (a->Data4[i] != b->Data4[i]) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100432 return 0;
John Chungf8fc7052024-05-03 20:05:29 +0800433 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100434 }
Lawrence Tang1b0b00e2022-07-05 10:33:10 +0100435
Lawrence Tange407b4c2022-07-21 13:54:01 +0100436 return 1;
John Chungf8fc7052024-05-03 20:05:29 +0800437}
Ed Tanous5e2164a2025-03-09 09:20:44 -0700438
Ed Tanous1a648562025-03-10 15:23:38 -0700439int select_guid_from_list(EFI_GUID *guid, EFI_GUID *guid_list[], int len)
440{
441 int i = 0;
442 for (; i < len; i++) {
443 if (guid_equal(guid, guid_list[i])) {
444 break;
445 }
446 }
447 // It's unlikely fuzzing can reliably come up with a correct guid, given how
448 // much entropy there is. If we're in fuzzing mode, and if we haven't found
449 // a match, try to force a match so we get some coverage. Note, we still
450 // want coverage of the section failed to convert code, so treat index ==
451 // size as section failed to convert.
452#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
453 if (i == len) {
454 i = guid->Data1 % (len + 1);
455 }
456#endif
457
458 return i;
459}
460
Ed Tanous5e2164a2025-03-09 09:20:44 -0700461void add_untrusted_string(json_object *ir, const char *field_name,
462 const char *str, int len)
463{
464 int fru_text_len = 0;
465 for (; fru_text_len < len; fru_text_len++) {
466 char c = str[fru_text_len];
467 if (c < 0) {
468 fru_text_len = -1;
469 break;
470 }
471 if (c == '\0') {
472 break;
473 }
474 }
475 if (fru_text_len >= 0) {
476 json_object_object_add(
477 ir, field_name,
478 json_object_new_string_len(str, fru_text_len));
479 }
480}
Ed Tanousc2ebddd2025-03-09 10:07:01 -0700481
482void add_guid(json_object *ir, const char *field_name, EFI_GUID *guid)
483{
484 char platform_string[GUID_STRING_LENGTH + 1];
485 if (!guid_to_string(platform_string, sizeof(platform_string), guid)) {
486 return;
487 }
488 json_object_object_add(
489 ir, field_name,
490 json_object_new_string_len(platform_string,
491 sizeof(platform_string) - 1));
492}