blob: b56dc50cd5d97e1d4e797013f4c868a3d2855d8f [file] [log] [blame]
Lawrence Tang2800cd82022-07-05 16:08:20 +01001/**
2 * Describes functions for converting ARM CPER sections from binary and JSON format
3 * into an intermediate format.
Ed Tanousfedd4572024-07-12 13:56:00 -07004 *
Lawrence Tang2800cd82022-07-05 16:08:20 +01005 * Author: Lawrence.Tang@arm.com
6 **/
7
8#include <stdio.h>
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08009#include <string.h>
Lawrence Tang5202bbb2022-08-12 14:54:36 +010010#include <json.h>
Aushim Nagarkatti89833fe2025-07-08 11:33:20 -070011#include <inttypes.h>
Thu Nguyene42fb482024-10-15 14:43:11 +000012#include <libcper/base64.h>
13#include <libcper/Cper.h>
14#include <libcper/cper-utils.h>
15#include <libcper/sections/cper-section-arm.h>
Ed Tanous50b966f2025-03-11 09:06:19 -070016#include <libcper/log.h>
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070017#include <string.h>
Lawrence Tang2800cd82022-07-05 16:08:20 +010018
Lawrence Tang3d0e4f22022-07-05 17:17:41 +010019//Private pre-definitions.
Lawrence Tange407b4c2022-07-21 13:54:01 +010020json_object *
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070021cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info,
22 char **err_info_desc_i);
Lawrence Tange407b4c2022-07-21 13:54:01 +010023json_object *
24cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
Ed Tanous5e2164a2025-03-09 09:20:44 -070025 const UINT8 **cur_pos, UINT32 *remaining_size);
Lawrence Tange407b4c2022-07-21 13:54:01 +010026json_object *
27cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
28 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
29json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error);
30json_object *cper_arm_misc_register_array_to_ir(
31 EFI_ARM_MISC_CONTEXT_REGISTER *misc_register);
32void ir_arm_error_info_to_cper(json_object *error_info, FILE *out);
33void ir_arm_context_info_to_cper(json_object *context_info, FILE *out);
34void ir_arm_error_cache_tlb_info_to_cper(
35 json_object *error_information,
36 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
37void ir_arm_error_bus_info_to_cper(json_object *error_information,
38 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper);
39void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out);
40void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out);
41void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out);
42void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out);
43void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out);
44void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out);
45void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out);
46void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out);
47void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out);
John Chungf8fc7052024-05-03 20:05:29 +080048void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out);
Lawrence Tang3d0e4f22022-07-05 17:17:41 +010049
Lawrence Tang2800cd82022-07-05 16:08:20 +010050//Converts the given processor-generic CPER section into JSON IR.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070051json_object *cper_section_arm_to_ir(const UINT8 *section, UINT32 size,
52 char **desc_string)
Lawrence Tang2800cd82022-07-05 16:08:20 +010053{
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070054 *desc_string = malloc(SECTION_DESC_STRING_SIZE);
55 int outstr_len = 0;
56 outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
57 "An ARM Processor Error occurred");
58 if (outstr_len < 0) {
59 cper_print_log(
60 "Error: Could not write to ARM description string\n");
61 } else if (outstr_len > SECTION_DESC_STRING_SIZE) {
62 cper_print_log("Error: ARM description string truncated: %s\n",
63 *desc_string);
64 }
65
Ed Tanous5e2164a2025-03-09 09:20:44 -070066 const UINT8 *cur_pos = section;
67 UINT32 remaining_size = size;
68
69 if (remaining_size < sizeof(EFI_ARM_ERROR_RECORD)) {
Ed Tanous12dbd4f2025-03-08 19:05:01 -080070 return NULL;
71 }
Ed Tanous5e2164a2025-03-09 09:20:44 -070072 EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)cur_pos;
73 cur_pos += sizeof(EFI_ARM_ERROR_RECORD);
74 remaining_size -= sizeof(EFI_ARM_ERROR_RECORD);
Lawrence Tange407b4c2022-07-21 13:54:01 +010075 json_object *section_ir = json_object_new_object();
Lawrence Tang2800cd82022-07-05 16:08:20 +010076
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080077 //Length of ValidationBits from spec
78 ValidationTypes ui64Type = { UINT_64T,
79 .value.ui64 = record->ValidFields };
Lawrence Tang2800cd82022-07-05 16:08:20 +010080
Lawrence Tange407b4c2022-07-21 13:54:01 +010081 //Number of error info and context info structures, and length.
82 json_object_object_add(section_ir, "errorInfoNum",
83 json_object_new_int(record->ErrInfoNum));
84 json_object_object_add(section_ir, "contextInfoNum",
85 json_object_new_int(record->ContextInfoNum));
86 json_object_object_add(section_ir, "sectionLength",
87 json_object_new_uint64(record->SectionLength));
Lawrence Tang2800cd82022-07-05 16:08:20 +010088
Lawrence Tange407b4c2022-07-21 13:54:01 +010089 //Error affinity.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080090 if (isvalid_prop_to_ir(&ui64Type, 1)) {
91 json_object *error_affinity = json_object_new_object();
92 json_object_object_add(
93 error_affinity, "value",
94 json_object_new_int(record->ErrorAffinityLevel));
95 json_object_object_add(
96 error_affinity, "type",
97 json_object_new_string(record->ErrorAffinityLevel < 4 ?
98 "Vendor Defined" :
99 "Reserved"));
100 json_object_object_add(section_ir, "errorAffinity",
101 error_affinity);
102 }
Lawrence Tang2800cd82022-07-05 16:08:20 +0100103
Lawrence Tange407b4c2022-07-21 13:54:01 +0100104 //Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800105 if (isvalid_prop_to_ir(&ui64Type, 0)) {
106 uint64_t mpidr_eli1 = record->MPIDR_EL1;
107 uint64_t sock;
108 json_object_object_add(section_ir, "mpidrEl1",
109 json_object_new_uint64(mpidr_eli1));
110
111 //Arm Processor socket info dependes on mpidr_eli1
112 sock = (mpidr_eli1 & ARM_SOCK_MASK) >> 32;
113 json_object_object_add(section_ir, "affinity3",
114 json_object_new_uint64(sock));
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700115 char *node_desc_str = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN);
116 outstr_len = snprintf(node_desc_str,
117 EFI_ERROR_DESCRIPTION_STRING_LEN,
Aushim Nagarkatti89833fe2025-07-08 11:33:20 -0700118 " on CPU %" PRIu64, sock);
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700119 if (outstr_len < 0) {
120 cper_print_log(
121 "Error: Could not write to node description string\n");
122 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
123 cper_print_log(
124 "Error: Node description string truncated: %s\n",
125 node_desc_str);
126 } else {
127 if (strlen(node_desc_str) + strlen(*desc_string) <
128 SECTION_DESC_STRING_SIZE) {
129 strncat(*desc_string, node_desc_str,
130 outstr_len);
131 } else {
132 cper_print_log(
133 "Error: Node description string too long, not added to description string: %s\n",
134 node_desc_str);
135 }
136 }
137 free(node_desc_str);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800138 }
Aushim Nagarkatti17bc66a2024-11-25 13:47:35 -0800139
Lawrence Tange407b4c2022-07-21 13:54:01 +0100140 json_object_object_add(section_ir, "midrEl1",
141 json_object_new_uint64(record->MIDR_EL1));
Lawrence Tang2800cd82022-07-05 16:08:20 +0100142
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800143 if (isvalid_prop_to_ir(&ui64Type, 2)) {
144 //Whether the processor is running, and the state of it if so.
145 json_object_object_add(
146 section_ir, "running",
147 json_object_new_boolean(record->RunningState & 0x1));
148 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100149 if (!(record->RunningState >> 31)) {
150 //Bit 32 of running state is on, so PSCI state information is included.
151 //This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
152 //or the newer Extended StateID format.
153 json_object_object_add(
154 section_ir, "psciState",
155 json_object_new_uint64(record->PsciState));
156 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100157
Lawrence Tange407b4c2022-07-21 13:54:01 +0100158 //Processor error structures.
159 json_object *error_info_array = json_object_new_array();
160 EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
161 (EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
Ed Tanous5e2164a2025-03-09 09:20:44 -0700162 if (remaining_size <
163 (record->ErrInfoNum * sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY))) {
164 json_object_put(error_info_array);
165 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700166 cper_print_log(
167 "Invalid CPER file: Invalid processor error info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700168 return NULL;
169 }
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700170 strncat(*desc_string, "; Error Type(s): {",
171 EFI_ERROR_DESCRIPTION_STRING_LEN);
172 char *err_info_desc_i =
173 malloc(EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN);
174 size_t err_info_desc_i_len = 0;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100175 for (int i = 0; i < record->ErrInfoNum; i++) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700176 json_object_array_add(
177 error_info_array,
178 cper_arm_error_info_to_ir(cur_error, &err_info_desc_i));
179 err_info_desc_i_len = strlen(err_info_desc_i);
180 if (err_info_desc_i_len > 0 &&
181 strlen(*desc_string) + err_info_desc_i_len <
182 SECTION_DESC_STRING_SIZE) {
183 strncat(*desc_string, err_info_desc_i,
184 err_info_desc_i_len);
185 } else {
186 cper_print_log(
187 "Error: Error info description string too long, not added to description string: %s\n",
188 err_info_desc_i);
189 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100190 cur_error++;
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700191 if (i == record->ErrInfoNum - 1) {
192 if (strlen(*desc_string) + 2 <
193 SECTION_DESC_STRING_SIZE) {
194 strncat(*desc_string, "}", 2);
195 } else {
196 cper_print_log(
197 "Error: Description string too long, not added '}'to description string: %s\n",
198 *desc_string);
199 }
200 break;
201 }
202 if (strlen(*desc_string) + 3 < SECTION_DESC_STRING_SIZE) {
203 strncat(*desc_string, ", ", 3);
204 } else {
205 cper_print_log(
206 "Error: Description string too long, not added ',' to description string: %s\n",
207 *desc_string);
208 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100209 }
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700210 free(err_info_desc_i);
Ed Tanous5e2164a2025-03-09 09:20:44 -0700211
212 cur_pos += (UINT32)(record->ErrInfoNum *
213 sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
214 remaining_size -= (UINT32)(record->ErrInfoNum *
215 sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
216
Lawrence Tange407b4c2022-07-21 13:54:01 +0100217 json_object_object_add(section_ir, "errorInfo", error_info_array);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100218
Lawrence Tange407b4c2022-07-21 13:54:01 +0100219 //Processor context structures.
220 //The current position is moved within the processing, as it is a dynamic size structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100221 json_object *context_info_array = json_object_new_array();
222 for (int i = 0; i < record->ContextInfoNum; i++) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700223 if (remaining_size <
224 sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER)) {
225 json_object_put(context_info_array);
226 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700227 cper_print_log(
228 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700229 return NULL;
230 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100231 EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
232 (EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700233
234 cur_pos += sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
235 remaining_size -= sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100236 json_object *processor_context =
Ed Tanous5e2164a2025-03-09 09:20:44 -0700237 cper_arm_processor_context_to_ir(header, &cur_pos,
238 &remaining_size);
239 if (processor_context == NULL) {
240 json_object_put(context_info_array);
241 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700242 cper_print_log(
243 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700244 return NULL;
245 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100246 json_object_array_add(context_info_array, processor_context);
247 }
248 json_object_object_add(section_ir, "contextInfo", context_info_array);
Lawrence Tangd7e8ca32022-07-07 10:25:53 +0100249
Lawrence Tange407b4c2022-07-21 13:54:01 +0100250 //Is there any vendor-specific information following?
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800251 if (isvalid_prop_to_ir(&ui64Type, 3)) {
252 if (cur_pos < (uint8_t *)section + record->SectionLength) {
253 json_object *vendor_specific = json_object_new_object();
254 size_t input_size = (uint8_t *)section +
255 record->SectionLength - cur_pos;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700256 if (remaining_size < input_size) {
257 json_object_put(vendor_specific);
258 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700259 cper_print_log(
260 "Invalid CPER file: Invalid vendor-specific info length.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700261 return NULL;
262 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800263 int32_t encoded_len = 0;
264 char *encoded = base64_encode(cur_pos, input_size,
265 &encoded_len);
266 if (encoded == NULL) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700267 json_object_put(vendor_specific);
268 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700269 cper_print_log(
270 "base64 encode of vendorSpecificInfo failed\n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800271 return NULL;
272 }
273 json_object_object_add(vendor_specific, "data",
274 json_object_new_string_len(
275 encoded, encoded_len));
276 free(encoded);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700277
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800278 json_object_object_add(section_ir, "vendorSpecificInfo",
279 vendor_specific);
280 } else {
Ed Tanous50b966f2025-03-11 09:06:19 -0700281 cper_print_log(
282 "vendorSpecificInfo is marked valid but not present in binary\n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800283 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100284 }
285
286 return section_ir;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100287}
288
289//Converts a single ARM Process Error Information structure into JSON IR.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100290json_object *
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700291cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info,
292 char **err_info_desc_i)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100293{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100294 json_object *error_info_ir = json_object_new_object();
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700295 int outstr_len = 0;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100296
Lawrence Tange407b4c2022-07-21 13:54:01 +0100297 //Version, length.
298 json_object_object_add(error_info_ir, "version",
299 json_object_new_int(error_info->Version));
300 json_object_object_add(error_info_ir, "length",
301 json_object_new_int(error_info->Length));
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100302
Lawrence Tange407b4c2022-07-21 13:54:01 +0100303 //Validation bitfield.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800304 ValidationTypes ui16Type = { UINT_16T,
305 .value.ui16 = error_info->ValidationBits };
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100306
Lawrence Tange407b4c2022-07-21 13:54:01 +0100307 //The type of error information in this log.
308 json_object *error_type = integer_to_readable_pair(
309 error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
310 ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
311 json_object_object_add(error_info_ir, "errorType", error_type);
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100312
Lawrence Tange407b4c2022-07-21 13:54:01 +0100313 //Multiple error count.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800314 if (isvalid_prop_to_ir(&ui16Type, 0)) {
315 json_object *multiple_error = json_object_new_object();
316 json_object_object_add(
317 multiple_error, "value",
318 json_object_new_int(error_info->MultipleError));
319 json_object_object_add(
320 multiple_error, "type",
321 json_object_new_string(error_info->MultipleError < 1 ?
322 "Single Error" :
323 "Multiple Errors"));
324 json_object_object_add(error_info_ir, "multipleError",
325 multiple_error);
326 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100327
Lawrence Tange407b4c2022-07-21 13:54:01 +0100328 //Flags.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800329 if (isvalid_prop_to_ir(&ui16Type, 1)) {
330 json_object *flags = bitfield_to_ir(
331 error_info->Flags, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
332 json_object_object_add(error_info_ir, "flags", flags);
333 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100334
Lawrence Tange407b4c2022-07-21 13:54:01 +0100335 //Error information, split by type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800336 if (isvalid_prop_to_ir(&ui16Type, 2)) {
337 json_object *error_subinfo = NULL;
338 switch (error_info->Type) {
339 case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800340 error_subinfo = cper_arm_cache_tlb_error_to_ir(
341 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
342 ->ErrorInformation,
343 error_info);
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700344 const char *cache_error_desc = "Cache Error";
345 if (strlen(cache_error_desc) >=
346 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
347 cper_print_log(
348 "Error: Cache Error Description too long %s\n",
349 cache_error_desc);
350 } else {
351 strncpy(*err_info_desc_i, cache_error_desc,
352 strlen(cache_error_desc) + 1);
353 }
354 break;
355 case ARM_ERROR_INFORMATION_TYPE_TLB: //TLB
356 error_subinfo = cper_arm_cache_tlb_error_to_ir(
357 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
358 ->ErrorInformation,
359 error_info);
360 const char *tlb_error_desc = "TLB Error";
361 if (strlen(tlb_error_desc) >=
362 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
363 cper_print_log(
364 "Error: TLB Error Description too long %s\n",
365 tlb_error_desc);
366 } else {
367 strncpy(*err_info_desc_i, tlb_error_desc,
368 strlen(tlb_error_desc) + 1);
369 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800370 break;
371 case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
372 error_subinfo = cper_arm_bus_error_to_ir(
373 (EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
374 ->ErrorInformation);
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700375 const char *bus_error_desc = "Bus Error";
376 if (strlen(bus_error_desc) >=
377 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
378 cper_print_log(
379 "Error: Bus Error Description too long %s\n",
380 bus_error_desc);
381 } else {
382 strncpy(*err_info_desc_i, bus_error_desc,
383 strlen(bus_error_desc) + 1);
384 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800385 break;
Lawrence Tang71570a22022-07-14 11:45:28 +0100386
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800387 default:
388 //Unknown/microarch, will not support.
389 break;
390 }
Ed Tanousd6b62632025-03-14 15:30:07 -0700391 if (error_subinfo != NULL) {
392 json_object_object_add(error_info_ir,
393 "errorInformation",
394 error_subinfo);
395 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100396 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100397
Lawrence Tange407b4c2022-07-21 13:54:01 +0100398 //Virtual fault address, physical fault address.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700399 char *fault_address_desc = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800400 if (isvalid_prop_to_ir(&ui16Type, 3)) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700401 outstr_len = snprintf(fault_address_desc,
402 EFI_ERROR_DESCRIPTION_STRING_LEN,
403 " at Virtual Addr=0x%llX",
404 error_info->VirtualFaultAddress);
405 if (outstr_len < 0) {
406 cper_print_log(
407 "Error: Could not write to fault address description string\n");
408 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
409 cper_print_log(
410 "Error: Virtual fault address description string truncated: %s\n",
411 fault_address_desc);
412 } else {
413 if (strlen(fault_address_desc) +
414 strlen(*err_info_desc_i) <
415 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
416 strncat(*err_info_desc_i, fault_address_desc,
417 outstr_len);
418 } else {
419 cper_print_log(
420 "Error: Virtual fault address description string too long, not added to description string: %s\n",
421 fault_address_desc);
422 }
423 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800424 json_object_object_add(
425 error_info_ir, "virtualFaultAddress",
426 json_object_new_uint64(
427 error_info->VirtualFaultAddress));
428 }
429 if (isvalid_prop_to_ir(&ui16Type, 4)) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700430 outstr_len = snprintf(fault_address_desc,
431 EFI_ERROR_DESCRIPTION_STRING_LEN,
432 " Physical Addr=0x%llX",
433 error_info->PhysicalFaultAddress);
434 if (outstr_len < 0) {
435 cper_print_log(
436 "Error: Could not write to physical fault address description string\n");
437 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
438 cper_print_log(
439 "Error: Physical fault address description string truncated: %s\n",
440 fault_address_desc);
441 } else {
442 if (strlen(fault_address_desc) +
443 strlen(*err_info_desc_i) <
444 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
445 strncat(*err_info_desc_i, fault_address_desc,
446 outstr_len);
447 } else {
448 cper_print_log(
449 "Error:Physical fault address description string too long, not added to description string: %s\n",
450 fault_address_desc);
451 }
452 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800453 json_object_object_add(
454 error_info_ir, "physicalFaultAddress",
455 json_object_new_uint64(
456 error_info->PhysicalFaultAddress));
457 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100458
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700459 free(fault_address_desc);
460
Lawrence Tange407b4c2022-07-21 13:54:01 +0100461 return error_info_ir;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100462}
463
Lawrence Tang7f21db62022-07-06 11:09:39 +0100464//Converts a single ARM cache/TLB error information structure into JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100465json_object *
466cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
467 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100468{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100469 json_object *cache_tlb_error_ir = json_object_new_object();
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700470 json_object *cache_tlb_prop = json_object_new_object();
471 char *cache_tlb_propname;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100472
Lawrence Tange407b4c2022-07-21 13:54:01 +0100473 //Validation bitfield.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800474 ValidationTypes ui64Type = {
475 UINT_64T, .value.ui64 = cache_tlb_error->ValidationBits
476 };
Lawrence Tang7f21db62022-07-06 11:09:39 +0100477
Lawrence Tange407b4c2022-07-21 13:54:01 +0100478 //Transaction type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800479 if (isvalid_prop_to_ir(&ui64Type, 0)) {
480 json_object *transaction_type = integer_to_readable_pair(
481 cache_tlb_error->TransactionType, 3,
482 ARM_ERROR_TRANSACTION_TYPES_KEYS,
483 ARM_ERROR_TRANSACTION_TYPES_VALUES,
484 "Unknown (Reserved)");
485 json_object_object_add(cache_tlb_error_ir, "transactionType",
486 transaction_type);
487 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100488
Lawrence Tange407b4c2022-07-21 13:54:01 +0100489 //Operation.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800490 bool cacheErrorFlag = 1;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100491 if (error_info->Type == 0) {
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700492 cache_tlb_propname = "cacheError";
Lawrence Tange407b4c2022-07-21 13:54:01 +0100493 } else {
494 //TLB operation.
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700495 cache_tlb_propname = "tlbError";
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800496 cacheErrorFlag = 0;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100497 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800498
499 if (isvalid_prop_to_ir(&ui64Type, 1)) {
500 json_object *operation;
501
502 if (cacheErrorFlag) {
503 //Cache operation.
504 operation = integer_to_readable_pair(
505 cache_tlb_error->Operation, 11,
506 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
507 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
508 "Unknown (Reserved)");
509 } else {
510 operation = integer_to_readable_pair(
511 cache_tlb_error->Operation, 9,
512 ARM_TLB_OPERATION_TYPES_KEYS,
513 ARM_TLB_OPERATION_TYPES_VALUES,
514 "Unknown (Reserved)");
515 }
516 json_object_object_add(cache_tlb_error_ir, "operation",
517 operation);
518 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100519
Lawrence Tange407b4c2022-07-21 13:54:01 +0100520 //Miscellaneous remaining fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800521 if (isvalid_prop_to_ir(&ui64Type, 2)) {
522 json_object_object_add(
523 cache_tlb_error_ir, "level",
524 json_object_new_int(cache_tlb_error->Level));
525 }
526 if (isvalid_prop_to_ir(&ui64Type, 3)) {
527 json_object_object_add(
528 cache_tlb_error_ir, "processorContextCorrupt",
529 json_object_new_boolean(
530 cache_tlb_error->ProcessorContextCorrupt));
531 }
532 if (isvalid_prop_to_ir(&ui64Type, 4)) {
533 json_object_object_add(
534 cache_tlb_error_ir, "corrected",
535 json_object_new_boolean(cache_tlb_error->Corrected));
536 }
537 if (isvalid_prop_to_ir(&ui64Type, 5)) {
538 json_object_object_add(
539 cache_tlb_error_ir, "precisePC",
540 json_object_new_boolean(cache_tlb_error->PrecisePC));
541 }
542 if (isvalid_prop_to_ir(&ui64Type, 6)) {
543 json_object_object_add(cache_tlb_error_ir, "restartablePC",
544 json_object_new_boolean(
545 cache_tlb_error->RestartablePC));
546 }
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700547
548 json_object_object_add(cache_tlb_prop, cache_tlb_propname,
549 cache_tlb_error_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800550
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700551 return cache_tlb_prop;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100552}
553
554//Converts a single ARM bus error information structure into JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100555json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100556{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100557 json_object *bus_error_ir = json_object_new_object();
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800558 json_object *bus_prop = json_object_new_object();
559 char *bus_propname = "busError";
Lawrence Tang7f21db62022-07-06 11:09:39 +0100560
Lawrence Tange407b4c2022-07-21 13:54:01 +0100561 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800562 ValidationTypes ui64Type = { UINT_64T,
563 .value.ui64 = bus_error->ValidationBits };
Lawrence Tang7f21db62022-07-06 11:09:39 +0100564
Lawrence Tange407b4c2022-07-21 13:54:01 +0100565 //Transaction type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800566 if (isvalid_prop_to_ir(&ui64Type, 0)) {
567 json_object *transaction_type = integer_to_readable_pair(
568 bus_error->TransactionType, 3,
569 ARM_ERROR_TRANSACTION_TYPES_KEYS,
570 ARM_ERROR_TRANSACTION_TYPES_VALUES,
571 "Unknown (Reserved)");
572 json_object_object_add(bus_error_ir, "transactionType",
573 transaction_type);
574 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100575
Lawrence Tange407b4c2022-07-21 13:54:01 +0100576 //Operation.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800577 if (isvalid_prop_to_ir(&ui64Type, 1)) {
578 json_object *operation = integer_to_readable_pair(
579 bus_error->Operation, 7,
580 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
581 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
582 "Unknown (Reserved)");
583 json_object_object_add(bus_error_ir, "operation", operation);
584 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100585
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800586 if (isvalid_prop_to_ir(&ui64Type, 2)) {
587 //Affinity level of bus error, + miscellaneous fields.
588 json_object_object_add(bus_error_ir, "level",
589 json_object_new_int(bus_error->Level));
590 }
591 if (isvalid_prop_to_ir(&ui64Type, 3)) {
592 json_object_object_add(
593 bus_error_ir, "processorContextCorrupt",
594 json_object_new_boolean(
595 bus_error->ProcessorContextCorrupt));
596 }
597 if (isvalid_prop_to_ir(&ui64Type, 4)) {
598 json_object_object_add(
599 bus_error_ir, "corrected",
600 json_object_new_boolean(bus_error->Corrected));
601 }
602 if (isvalid_prop_to_ir(&ui64Type, 5)) {
603 json_object_object_add(
604 bus_error_ir, "precisePC",
605 json_object_new_boolean(bus_error->PrecisePC));
606 }
607 if (isvalid_prop_to_ir(&ui64Type, 6)) {
608 json_object_object_add(
609 bus_error_ir, "restartablePC",
610 json_object_new_boolean(bus_error->RestartablePC));
611 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100612
Lawrence Tange407b4c2022-07-21 13:54:01 +0100613 //Participation type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800614 if (isvalid_prop_to_ir(&ui64Type, 7)) {
615 json_object *participation_type = integer_to_readable_pair(
616 bus_error->ParticipationType, 4,
617 ARM_BUS_PARTICIPATION_TYPES_KEYS,
618 ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
619 json_object_object_add(bus_error_ir, "participationType",
620 participation_type);
621 }
622 if (isvalid_prop_to_ir(&ui64Type, 8)) {
623 json_object_object_add(
624 bus_error_ir, "timedOut",
625 json_object_new_boolean(bus_error->TimeOut));
626 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100627
Lawrence Tange407b4c2022-07-21 13:54:01 +0100628 //Address space.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800629 if (isvalid_prop_to_ir(&ui64Type, 9)) {
630 json_object *address_space = integer_to_readable_pair(
631 bus_error->AddressSpace, 3,
632 ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
633 ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
634 json_object_object_add(bus_error_ir, "addressSpace",
635 address_space);
636 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100637
Lawrence Tange407b4c2022-07-21 13:54:01 +0100638 //Memory access attributes.
639 //todo: find the specification of these in the ARM ARM
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800640 if (isvalid_prop_to_ir(&ui64Type, 10)) {
641 json_object_object_add(
642 bus_error_ir, "memoryAttributes",
643 json_object_new_int(
644 bus_error->MemoryAddressAttributes));
645 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100646
Lawrence Tange407b4c2022-07-21 13:54:01 +0100647 //Access Mode
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800648 if (isvalid_prop_to_ir(&ui64Type, 8)) {
649 json_object *access_mode = json_object_new_object();
650 json_object_object_add(
651 access_mode, "value",
652 json_object_new_int(bus_error->AccessMode));
653 json_object_object_add(
654 access_mode, "name",
655 json_object_new_string(bus_error->AccessMode == 0 ?
656 "Secure" :
657 "Normal"));
658 json_object_object_add(bus_error_ir, "accessMode", access_mode);
659 }
660 json_object_object_add(bus_prop, bus_propname, bus_error_ir);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100661
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800662 return bus_prop;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100663}
664
665//Converts a single ARM processor context block into JSON IR.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100666json_object *
667cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
Ed Tanous5e2164a2025-03-09 09:20:44 -0700668 const UINT8 **cur_pos, UINT32 *remaining_size)
Lawrence Tang7f21db62022-07-06 11:09:39 +0100669{
Ed Tanous5e2164a2025-03-09 09:20:44 -0700670 if (header->RegisterArraySize > *remaining_size) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700671 cper_print_log(
672 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700673 return NULL;
674 }
675
Lawrence Tange407b4c2022-07-21 13:54:01 +0100676 json_object *context_ir = json_object_new_object();
Lawrence Tang7f21db62022-07-06 11:09:39 +0100677
Lawrence Tange407b4c2022-07-21 13:54:01 +0100678 //Version.
679 json_object_object_add(context_ir, "version",
680 json_object_new_int(header->Version));
Lawrence Tang71570a22022-07-14 11:45:28 +0100681
Lawrence Tange407b4c2022-07-21 13:54:01 +0100682 //Add the context type.
683 json_object *context_type = integer_to_readable_pair(
Ed Tanous5e2164a2025-03-09 09:20:44 -0700684 header->RegisterContextType,
685 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_COUNT,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100686 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
687 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
688 "Unknown (Reserved)");
689 json_object_object_add(context_ir, "registerContextType", context_type);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100690
Lawrence Tange407b4c2022-07-21 13:54:01 +0100691 //Register array size (bytes).
692 json_object_object_add(
693 context_ir, "registerArraySize",
694 json_object_new_uint64(header->RegisterArraySize));
Lawrence Tang7f21db62022-07-06 11:09:39 +0100695
Lawrence Tange407b4c2022-07-21 13:54:01 +0100696 //The register array itself.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100697 json_object *register_array = NULL;
698 switch (header->RegisterContextType) {
699 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700700 if (*remaining_size < sizeof(EFI_ARM_V8_AARCH32_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700701 cper_print_log(
702 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700703 goto fail;
704 }
705 if (header->RegisterArraySize <
706 sizeof(EFI_ARM_V8_AARCH32_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700707 cper_print_log(
708 "Invalid CPER file: Not enough bytes for aarch32 gpr\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700709 goto fail;
710 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100711 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800712 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100713 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
714 ARM_AARCH32_GPR_NAMES);
715 break;
716 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700717 if (*remaining_size <
718 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700719 cper_print_log(
720 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700721 goto fail;
722 }
723 if (header->RegisterArraySize <
724 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700725 cper_print_log(
726 "Invalid CPER file: Not enough bytes for aarch32 el1\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700727 goto fail;
728 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100729 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800730 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100731 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
732 sizeof(UINT32),
733 ARM_AARCH32_EL1_REGISTER_NAMES);
734 break;
735 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700736 if (*remaining_size <
737 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700738 cper_print_log(
739 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700740 goto fail;
741 }
742 if (header->RegisterArraySize <
743 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700744 cper_print_log(
745 "Invalid CPER file: Not enough bytes for aarch32 el2\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700746 goto fail;
747 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100748 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800749 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100750 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
751 sizeof(UINT32),
752 ARM_AARCH32_EL2_REGISTER_NAMES);
Ed Tanous5e2164a2025-03-09 09:20:44 -0700753
Lawrence Tange407b4c2022-07-21 13:54:01 +0100754 break;
755 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700756 if (*remaining_size <
757 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
758 json_object_put(context_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700759 cper_print_log(
760 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700761 return NULL;
762 }
763 if (header->RegisterArraySize <
764 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700765 cper_print_log(
766 "Invalid CPER file: Not enough bytes for aarch32 secure\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700767 goto fail;
768 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100769 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800770 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100771 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
772 sizeof(UINT32),
773 ARM_AARCH32_SECURE_REGISTER_NAMES);
774 break;
775 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700776 if (*remaining_size < sizeof(EFI_ARM_V8_AARCH64_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700777 cper_print_log(
778 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700779 goto fail;
780 }
781 if (header->RegisterArraySize <
782 sizeof(EFI_ARM_V8_AARCH64_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700783 cper_print_log(
784 "Invalid CPER file: Not enough bytes for aarch64 gpr\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700785 goto fail;
786 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100787 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800788 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100789 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
790 ARM_AARCH64_GPR_NAMES);
791 break;
792 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700793 if (*remaining_size <
794 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700795 cper_print_log(
796 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700797 goto fail;
798 }
799 if (header->RegisterArraySize <
800 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700801 cper_print_log(
802 "Invalid CPER file: Not enough bytes for aarch64 el1\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700803 goto fail;
804 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100805 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800806 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100807 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
808 sizeof(UINT64),
809 ARM_AARCH64_EL1_REGISTER_NAMES);
810 break;
811 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700812 if (*remaining_size <
813 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700814 cper_print_log(
815 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700816 goto fail;
817 }
818 if (header->RegisterArraySize <
819 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700820 cper_print_log(
821 "Invalid CPER file: Not enough bytes for aarch64 el2\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700822 goto fail;
823 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100824 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800825 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100826 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
827 sizeof(UINT64),
828 ARM_AARCH64_EL2_REGISTER_NAMES);
829 break;
830 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700831 if (*remaining_size <
832 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700833 cper_print_log(
834 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700835 goto fail;
836 }
837 if (header->RegisterArraySize <
838 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700839 cper_print_log(
840 "Invalid CPER file: Not enough bytes for aarch64 el3\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700841 goto fail;
842 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100843 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800844 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100845 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
846 sizeof(UINT64),
847 ARM_AARCH64_EL3_REGISTER_NAMES);
848 break;
849 case EFI_ARM_CONTEXT_TYPE_MISC:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700850 if (*remaining_size < sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700851 cper_print_log(
852 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700853 goto fail;
854 }
855 if (header->RegisterArraySize <
856 sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700857 cper_print_log(
858 "Invalid CPER file: Not enough bytes for misc\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700859 goto fail;
860 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100861 register_array = cper_arm_misc_register_array_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800862 (EFI_ARM_MISC_CONTEXT_REGISTER *)*cur_pos);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100863 break;
864 default:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700865 if (*remaining_size < header->RegisterArraySize) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700866 cper_print_log(
867 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700868 goto fail;
869 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100870 //Unknown register array type, add as base64 data instead.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700871 int32_t encoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800872 char *encoded = base64_encode((UINT8 *)*cur_pos,
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700873 header->RegisterArraySize,
874 &encoded_len);
875 if (encoded == NULL) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700876 goto fail;
John Chungf8fc7052024-05-03 20:05:29 +0800877 }
Ed Tanous5e2164a2025-03-09 09:20:44 -0700878 register_array = json_object_new_object();
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700879 json_object_object_add(register_array, "data",
880 json_object_new_string_len(encoded,
881 encoded_len));
882 free(encoded);
883
Lawrence Tange407b4c2022-07-21 13:54:01 +0100884 break;
885 }
886 json_object_object_add(context_ir, "registerArray", register_array);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100887
Lawrence Tange407b4c2022-07-21 13:54:01 +0100888 //Set the current position to after the processor context structure.
889 *cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700890 *remaining_size -= header->RegisterArraySize;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100891
Lawrence Tange407b4c2022-07-21 13:54:01 +0100892 return context_ir;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700893
894fail:
895 json_object_put(context_ir);
896 return NULL;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100897}
898
899//Converts a single CPER ARM miscellaneous register array to JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100900json_object *
901cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
Lawrence Tang7f21db62022-07-06 11:09:39 +0100902{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100903 json_object *register_array = json_object_new_object();
904 json_object *mrs_encoding = json_object_new_object();
905 json_object_object_add(mrs_encoding, "op2",
906 json_object_new_uint64(misc_register->MrsOp2));
907 json_object_object_add(mrs_encoding, "crm",
908 json_object_new_uint64(misc_register->MrsCrm));
909 json_object_object_add(mrs_encoding, "crn",
910 json_object_new_uint64(misc_register->MrsCrn));
911 json_object_object_add(mrs_encoding, "op1",
912 json_object_new_uint64(misc_register->MrsOp1));
913 json_object_object_add(mrs_encoding, "o0",
914 json_object_new_uint64(misc_register->MrsO0));
915 json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
916 json_object_object_add(register_array, "value",
917 json_object_new_uint64(misc_register->Value));
Lawrence Tang7f21db62022-07-06 11:09:39 +0100918
Lawrence Tange407b4c2022-07-21 13:54:01 +0100919 return register_array;
Lawrence Tang7cd13902022-07-13 16:59:25 +0100920}
921
922//Converts a single CPER-JSON ARM error section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100923void ir_section_arm_to_cper(json_object *section, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +0100924{
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800925 EFI_ARM_ERROR_RECORD section_cper;
926 memset(&section_cper, 0, sizeof(section_cper));
Lawrence Tang7cd13902022-07-13 16:59:25 +0100927
Lawrence Tange407b4c2022-07-21 13:54:01 +0100928 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800929 struct json_object *obj = NULL;
930 ValidationTypes u32Type = { UINT_32T, .value.ui32 = 0 };
Lawrence Tang7cd13902022-07-13 16:59:25 +0100931
Lawrence Tange407b4c2022-07-21 13:54:01 +0100932 //Count of error/context info structures.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800933 section_cper.ErrInfoNum = json_object_get_int(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100934 json_object_object_get(section, "errorInfoNum"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800935 section_cper.ContextInfoNum = json_object_get_int(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100936 json_object_object_get(section, "contextInfoNum"));
Lawrence Tang7cd13902022-07-13 16:59:25 +0100937
Lawrence Tange407b4c2022-07-21 13:54:01 +0100938 //Miscellaneous raw value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800939 section_cper.SectionLength = json_object_get_uint64(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100940 json_object_object_get(section, "sectionLength"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800941 if (json_object_object_get_ex(section, "mpidrEl1", &obj)) {
942 section_cper.MPIDR_EL1 = json_object_get_uint64(obj);
943 add_to_valid_bitfield(&u32Type, 0);
944 }
945 if (json_object_object_get_ex(section, "errorAffinity", &obj)) {
946 section_cper.ErrorAffinityLevel = readable_pair_to_integer(obj);
947 add_to_valid_bitfield(&u32Type, 1);
948 }
949 section_cper.MIDR_EL1 = json_object_get_uint64(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100950 json_object_object_get(section, "midrEl1"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800951 if (json_object_object_get_ex(section, "running", &obj)) {
952 section_cper.RunningState = json_object_get_boolean(obj);
953 add_to_valid_bitfield(&u32Type, 2);
954 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100955
Lawrence Tange407b4c2022-07-21 13:54:01 +0100956 //Optional PSCI state.
957 json_object *psci_state = json_object_object_get(section, "psciState");
John Chungf8fc7052024-05-03 20:05:29 +0800958 if (psci_state != NULL) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800959 section_cper.PsciState = json_object_get_uint64(psci_state);
John Chungf8fc7052024-05-03 20:05:29 +0800960 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100961
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800962 //Validationbits for EFI_ARM_ERROR_RECORD should also consider vendorSpecificInfo
963 bool vendorSpecificPresent =
964 json_object_object_get_ex(section, "vendorSpecificInfo", &obj);
965 json_object *vendor_specific_info = obj;
966 if (vendorSpecificPresent) {
967 add_to_valid_bitfield(&u32Type, 3);
968 }
969
970 section_cper.ValidFields = u32Type.value.ui32;
971
Lawrence Tange407b4c2022-07-21 13:54:01 +0100972 //Flush header to stream.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800973 fwrite(&section_cper, sizeof(section_cper), 1, out);
Lawrence Tang7cd13902022-07-13 16:59:25 +0100974
Lawrence Tange407b4c2022-07-21 13:54:01 +0100975 //Error info structure array.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800976
Lawrence Tange407b4c2022-07-21 13:54:01 +0100977 json_object *error_info = json_object_object_get(section, "errorInfo");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800978 for (int i = 0; i < section_cper.ErrInfoNum; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100979 ir_arm_error_info_to_cper(
980 json_object_array_get_idx(error_info, i), out);
John Chungf8fc7052024-05-03 20:05:29 +0800981 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100982
Lawrence Tange407b4c2022-07-21 13:54:01 +0100983 //Context info structure array.
984 json_object *context_info =
985 json_object_object_get(section, "contextInfo");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800986 for (int i = 0; i < section_cper.ContextInfoNum; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100987 ir_arm_context_info_to_cper(
988 json_object_array_get_idx(context_info, i), out);
John Chungf8fc7052024-05-03 20:05:29 +0800989 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100990
Lawrence Tange407b4c2022-07-21 13:54:01 +0100991 //Vendor specific error info.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800992 if (vendorSpecificPresent) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100993 json_object *vendor_info_string =
994 json_object_object_get(vendor_specific_info, "data");
995 int vendor_specific_len =
996 json_object_get_string_len(vendor_info_string);
Lawrence Tang01e3a442022-07-20 15:14:50 +0100997
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700998 int32_t decoded_len = 0;
999
1000 UINT8 *decoded = base64_decode(
1001 json_object_get_string(vendor_info_string),
1002 vendor_specific_len, &decoded_len);
1003
1004 //Write out to file.
1005 fwrite(decoded, decoded_len, 1, out);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -07001006 free(decoded);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001007 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001008
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001009 fflush(out);
Lawrence Tang7cd13902022-07-13 16:59:25 +01001010}
1011
1012//Converts a single ARM error information structure into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001013void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +01001014{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001015 EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001016 memset(&error_info_cper, 0, sizeof(error_info_cper));
1017 struct json_object *obj = NULL;
1018 ValidationTypes ui16Type = { UINT_16T, .value.ui16 = 0 };
Lawrence Tang7cd13902022-07-13 16:59:25 +01001019
Lawrence Tange407b4c2022-07-21 13:54:01 +01001020 //Version, length.
1021 error_info_cper.Version = json_object_get_int(
1022 json_object_object_get(error_info, "version"));
1023 error_info_cper.Length = json_object_get_int(
1024 json_object_object_get(error_info, "length"));
Lawrence Tang7cd13902022-07-13 16:59:25 +01001025
Lawrence Tange407b4c2022-07-21 13:54:01 +01001026 //Type, multiple error.
1027 error_info_cper.Type = (UINT8)readable_pair_to_integer(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001028 json_object_object_get(error_info, "errorType"));
1029
1030 if (json_object_object_get_ex(error_info, "multipleError", &obj)) {
1031 error_info_cper.MultipleError =
1032 (UINT16)readable_pair_to_integer(obj);
1033 add_to_valid_bitfield(&ui16Type, 0);
1034 } else {
1035 error_info_cper.MultipleError = 0;
1036 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001037
Lawrence Tange407b4c2022-07-21 13:54:01 +01001038 //Flags object.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001039 if (json_object_object_get_ex(error_info, "flags", &obj)) {
1040 error_info_cper.Flags = (UINT8)ir_to_bitfield(
1041 obj, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
1042 add_to_valid_bitfield(&ui16Type, 1);
1043 } else {
1044 error_info_cper.Flags = 0;
1045 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001046
Lawrence Tange407b4c2022-07-21 13:54:01 +01001047 //Error information.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001048 if (json_object_object_get_ex(error_info, "errorInformation", &obj)) {
1049 json_object *error_info_information = obj;
1050 json_object *error_info_prop = NULL;
1051 switch (error_info_cper.Type) {
1052 case ARM_ERROR_INFORMATION_TYPE_CACHE:
1053 error_info_cper.ErrorInformation.Value = 0;
1054 error_info_prop = json_object_object_get(
1055 error_info_information, "cacheError");
1056 ir_arm_error_cache_tlb_info_to_cper(
1057 error_info_prop,
1058 &error_info_cper.ErrorInformation.CacheError);
1059 break;
1060 case ARM_ERROR_INFORMATION_TYPE_TLB:
1061 error_info_cper.ErrorInformation.Value = 0;
1062 error_info_prop = json_object_object_get(
1063 error_info_information, "tlbError");
1064 ir_arm_error_cache_tlb_info_to_cper(
1065 error_info_prop,
1066 &error_info_cper.ErrorInformation.CacheError);
1067 break;
Aushim Nagarkatti5b793002024-09-26 17:07:30 -07001068
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001069 case ARM_ERROR_INFORMATION_TYPE_BUS:
1070 error_info_cper.ErrorInformation.Value = 0;
1071 error_info_prop = json_object_object_get(
1072 error_info_information, "busError");
1073 ir_arm_error_bus_info_to_cper(
1074 error_info_prop,
1075 &error_info_cper.ErrorInformation.BusError);
1076 break;
Lawrence Tang71570a22022-07-14 11:45:28 +01001077
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001078 default:
1079 //Unknown error information type.
1080 break;
1081 }
1082 add_to_valid_bitfield(&ui16Type, 2);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001083 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001084
Lawrence Tange407b4c2022-07-21 13:54:01 +01001085 //Virtual/physical fault address.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001086 if (json_object_object_get_ex(error_info, "virtualFaultAddress",
1087 &obj)) {
1088 error_info_cper.VirtualFaultAddress =
1089 json_object_get_uint64(obj);
1090 add_to_valid_bitfield(&ui16Type, 3);
1091 } else {
1092 error_info_cper.VirtualFaultAddress = 0;
1093 }
1094
1095 if (json_object_object_get_ex(error_info, "physicalFaultAddress",
1096 &obj)) {
1097 error_info_cper.PhysicalFaultAddress =
1098 json_object_get_uint64(obj);
1099 add_to_valid_bitfield(&ui16Type, 4);
1100 } else {
1101 error_info_cper.PhysicalFaultAddress = 0;
1102 }
1103 error_info_cper.ValidationBits = ui16Type.value.ui16;
Lawrence Tang7cd13902022-07-13 16:59:25 +01001104
Lawrence Tange407b4c2022-07-21 13:54:01 +01001105 //Write out to stream.
1106 fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
1107 out);
Lawrence Tang7cd13902022-07-13 16:59:25 +01001108}
1109
Lawrence Tang71570a22022-07-14 11:45:28 +01001110//Converts a single ARM cache/TLB error information structure into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001111void ir_arm_error_cache_tlb_info_to_cper(
1112 json_object *error_information,
1113 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
Lawrence Tang71570a22022-07-14 11:45:28 +01001114{
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001115 // //Validation bits.
1116 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1117 struct json_object *obj = NULL;
Lawrence Tang71570a22022-07-14 11:45:28 +01001118
Lawrence Tange407b4c2022-07-21 13:54:01 +01001119 //Miscellaneous value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001120 if (json_object_object_get_ex(error_information, "transactionType",
1121 &obj)) {
1122 error_info_cper->TransactionType =
1123 readable_pair_to_integer(obj);
1124 add_to_valid_bitfield(&ui64Type, 0);
1125 }
1126 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1127 error_info_cper->Operation = readable_pair_to_integer(obj);
1128 add_to_valid_bitfield(&ui64Type, 1);
1129 }
1130 if (json_object_object_get_ex(error_information, "level", &obj)) {
1131 error_info_cper->Level = json_object_get_uint64(obj);
1132 add_to_valid_bitfield(&ui64Type, 2);
1133 }
1134 if (json_object_object_get_ex(error_information,
1135 "processorContextCorrupt", &obj)) {
1136 error_info_cper->ProcessorContextCorrupt =
1137 json_object_get_boolean(obj);
1138 add_to_valid_bitfield(&ui64Type, 3);
1139 }
1140 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1141 error_info_cper->Corrected = json_object_get_boolean(obj);
1142 add_to_valid_bitfield(&ui64Type, 4);
1143 }
1144 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1145 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1146 add_to_valid_bitfield(&ui64Type, 5);
1147 }
1148 if (json_object_object_get_ex(error_information, "restartablePC",
1149 &obj)) {
1150 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1151 add_to_valid_bitfield(&ui64Type, 6);
1152 }
Lawrence Tange407b4c2022-07-21 13:54:01 +01001153 error_info_cper->Reserved = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001154 error_info_cper->ValidationBits = ui64Type.value.ui64;
Lawrence Tang71570a22022-07-14 11:45:28 +01001155}
1156
1157//Converts a single ARM bus error information structure into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001158void ir_arm_error_bus_info_to_cper(json_object *error_information,
1159 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
Lawrence Tang71570a22022-07-14 11:45:28 +01001160{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001161 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001162 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1163 struct json_object *obj = NULL;
1164
1165 memset(error_info_cper, 0, sizeof(EFI_ARM_BUS_ERROR_STRUCTURE));
Lawrence Tang71570a22022-07-14 11:45:28 +01001166
Lawrence Tange407b4c2022-07-21 13:54:01 +01001167 //Miscellaneous value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001168 if (json_object_object_get_ex(error_information, "transactionType",
1169 &obj)) {
1170 error_info_cper->TransactionType =
1171 readable_pair_to_integer(obj);
1172 add_to_valid_bitfield(&ui64Type, 0);
1173 } else {
1174 error_info_cper->TransactionType = 0;
1175 }
1176 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1177 error_info_cper->Operation = readable_pair_to_integer(obj);
1178 add_to_valid_bitfield(&ui64Type, 1);
1179 } else {
1180 error_info_cper->Operation = 0;
1181 }
1182 if (json_object_object_get_ex(error_information, "level", &obj)) {
1183 error_info_cper->Level = json_object_get_uint64(obj);
1184 add_to_valid_bitfield(&ui64Type, 2);
1185 } else {
1186 error_info_cper->Level = 0;
1187 }
1188 if (json_object_object_get_ex(error_information,
1189 "processorContextCorrupt", &obj)) {
1190 error_info_cper->ProcessorContextCorrupt =
1191 json_object_get_boolean(obj);
1192 add_to_valid_bitfield(&ui64Type, 3);
1193 } else {
1194 error_info_cper->ProcessorContextCorrupt = 0;
1195 }
1196 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1197 error_info_cper->Corrected = json_object_get_boolean(obj);
1198 add_to_valid_bitfield(&ui64Type, 4);
1199 } else {
1200 error_info_cper->Corrected = 0;
1201 }
1202 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1203 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1204 add_to_valid_bitfield(&ui64Type, 5);
1205 } else {
1206 error_info_cper->PrecisePC = 0;
1207 }
1208 if (json_object_object_get_ex(error_information, "restartablePC",
1209 &obj)) {
1210 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1211 add_to_valid_bitfield(&ui64Type, 6);
1212 } else {
1213 error_info_cper->RestartablePC = 0;
1214 }
1215 if (json_object_object_get_ex(error_information, "participationType",
1216 &obj)) {
1217 error_info_cper->ParticipationType =
1218 readable_pair_to_integer(obj);
1219 add_to_valid_bitfield(&ui64Type, 7);
1220 } else {
1221 error_info_cper->ParticipationType = 0;
1222 }
1223 if (json_object_object_get_ex(error_information, "timedOut", &obj)) {
1224 error_info_cper->TimeOut = json_object_get_boolean(obj);
1225 add_to_valid_bitfield(&ui64Type, 8);
1226 } else {
1227 error_info_cper->TimeOut = 0;
1228 }
1229 if (json_object_object_get_ex(error_information, "addressSpace",
1230 &obj)) {
1231 error_info_cper->AddressSpace = readable_pair_to_integer(obj);
1232 add_to_valid_bitfield(&ui64Type, 9);
1233 } else {
1234 error_info_cper->AddressSpace = 0;
1235 }
1236 if (json_object_object_get_ex(error_information, "accessMode", &obj)) {
1237 error_info_cper->AccessMode = readable_pair_to_integer(obj);
1238 add_to_valid_bitfield(&ui64Type, 11);
1239 } else {
1240 error_info_cper->AccessMode = 0;
1241 }
1242 if (json_object_object_get_ex(error_information, "memoryAttributes",
1243 &obj)) {
1244 error_info_cper->MemoryAddressAttributes =
1245 json_object_get_uint64(obj);
1246 add_to_valid_bitfield(&ui64Type, 10);
1247 } else {
1248 error_info_cper->MemoryAddressAttributes = 0;
1249 }
Lawrence Tange407b4c2022-07-21 13:54:01 +01001250 error_info_cper->Reserved = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001251 error_info_cper->ValidationBits = ui64Type.value.ui64;
Lawrence Tang71570a22022-07-14 11:45:28 +01001252}
1253
Lawrence Tang7cd13902022-07-13 16:59:25 +01001254//Converts a single ARM context information structure into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001255void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +01001256{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001257 EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
Lawrence Tang7cd13902022-07-13 16:59:25 +01001258
Lawrence Tange407b4c2022-07-21 13:54:01 +01001259 //Version, array size, context type.
1260 info_header.Version = json_object_get_int(
1261 json_object_object_get(context_info, "version"));
1262 info_header.RegisterArraySize = json_object_get_int(
1263 json_object_object_get(context_info, "registerArraySize"));
1264 info_header.RegisterContextType = readable_pair_to_integer(
1265 json_object_object_get(context_info, "registerContextType"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001266
Lawrence Tange407b4c2022-07-21 13:54:01 +01001267 //Flush to stream, write the register array itself.
1268 fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
1269 out);
1270 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001271
Lawrence Tange407b4c2022-07-21 13:54:01 +01001272 json_object *register_array =
1273 json_object_object_get(context_info, "registerArray");
1274 switch (info_header.RegisterContextType) {
1275 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
1276 ir_arm_aarch32_gpr_to_cper(register_array, out);
1277 break;
1278 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
1279 ir_arm_aarch32_el1_to_cper(register_array, out);
1280 break;
1281 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
1282 ir_arm_aarch32_el2_to_cper(register_array, out);
1283 break;
1284 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
1285 ir_arm_aarch32_secure_to_cper(register_array, out);
1286 break;
1287 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
1288 ir_arm_aarch64_gpr_to_cper(register_array, out);
1289 break;
1290 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
1291 ir_arm_aarch64_el1_to_cper(register_array, out);
1292 break;
1293 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
1294 ir_arm_aarch64_el2_to_cper(register_array, out);
1295 break;
1296 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
1297 ir_arm_aarch64_el3_to_cper(register_array, out);
1298 break;
1299 case EFI_ARM_CONTEXT_TYPE_MISC:
1300 ir_arm_misc_registers_to_cper(register_array, out);
1301 break;
1302 default:
1303 //Unknown register structure.
John Chungf8fc7052024-05-03 20:05:29 +08001304 ir_arm_unknown_register_to_cper(register_array, out);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001305 break;
1306 }
Lawrence Tang71570a22022-07-14 11:45:28 +01001307}
1308
1309//Converts a single AARCH32 GPR CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001310void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001311{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001312 //Get uniform register array.
1313 EFI_ARM_V8_AARCH32_GPR reg_array;
1314 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1315 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
1316 ARM_AARCH32_GPR_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001317
Lawrence Tange407b4c2022-07-21 13:54:01 +01001318 //Flush to stream.
1319 fwrite(&reg_array, sizeof(reg_array), 1, out);
1320 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001321}
1322
1323//Converts a single AARCH32 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001324void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001325{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001326 //Get uniform register array.
1327 EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
1328 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1329 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
1330 sizeof(UINT32),
1331 ARM_AARCH32_EL1_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001332
Lawrence Tange407b4c2022-07-21 13:54:01 +01001333 //Flush to stream.
1334 fwrite(&reg_array, sizeof(reg_array), 1, out);
1335 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001336}
1337
1338//Converts a single AARCH32 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001339void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001340{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001341 //Get uniform register array.
1342 EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
1343 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1344 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
1345 sizeof(UINT32),
1346 ARM_AARCH32_EL2_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001347
Lawrence Tange407b4c2022-07-21 13:54:01 +01001348 //Flush to stream.
1349 fwrite(&reg_array, sizeof(reg_array), 1, out);
1350 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001351}
1352
1353//Converts a single AARCH32 secure register set CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001354void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001355{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001356 //Get uniform register array.
1357 EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
1358 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1359 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
1360 sizeof(UINT32),
1361 ARM_AARCH32_SECURE_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001362
Lawrence Tange407b4c2022-07-21 13:54:01 +01001363 //Flush to stream.
1364 fwrite(&reg_array, sizeof(reg_array), 1, out);
1365 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001366}
1367
1368//Converts a single AARCH64 GPR CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001369void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001370{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001371 //Get uniform register array.
1372 EFI_ARM_V8_AARCH64_GPR reg_array;
1373 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1374 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
1375 ARM_AARCH64_GPR_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001376
Lawrence Tange407b4c2022-07-21 13:54:01 +01001377 //Flush to stream.
1378 fwrite(&reg_array, sizeof(reg_array), 1, out);
1379 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001380}
1381
1382//Converts a single AARCH64 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001383void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001384{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001385 //Get uniform register array.
1386 EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
1387 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1388 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
1389 sizeof(UINT64),
1390 ARM_AARCH64_EL1_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001391
Lawrence Tange407b4c2022-07-21 13:54:01 +01001392 //Flush to stream.
1393 fwrite(&reg_array, sizeof(reg_array), 1, out);
1394 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001395}
1396
1397//Converts a single AARCH64 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001398void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001399{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001400 //Get uniform register array.
1401 EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
1402 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1403 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
1404 sizeof(UINT64),
1405 ARM_AARCH64_EL2_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001406
Lawrence Tange407b4c2022-07-21 13:54:01 +01001407 //Flush to stream.
1408 fwrite(&reg_array, sizeof(reg_array), 1, out);
1409 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001410}
1411
1412//Converts a single AARCH64 EL3 register set CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001413void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001414{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001415 //Get uniform register array.
1416 EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
1417 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1418 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
1419 sizeof(UINT64),
1420 ARM_AARCH64_EL3_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001421
Lawrence Tange407b4c2022-07-21 13:54:01 +01001422 //Flush to stream.
1423 fwrite(&reg_array, sizeof(reg_array), 1, out);
1424 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001425}
1426
1427//Converts a single ARM miscellaneous register set CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001428void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001429{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001430 EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
Lawrence Tang71570a22022-07-14 11:45:28 +01001431
Lawrence Tange407b4c2022-07-21 13:54:01 +01001432 //MRS encoding information.
1433 json_object *mrs_encoding =
1434 json_object_object_get(registers, "mrsEncoding");
1435 reg_array.MrsOp2 = json_object_get_uint64(
1436 json_object_object_get(mrs_encoding, "op2"));
1437 reg_array.MrsCrm = json_object_get_uint64(
1438 json_object_object_get(mrs_encoding, "crm"));
1439 reg_array.MrsCrn = json_object_get_uint64(
1440 json_object_object_get(mrs_encoding, "crn"));
1441 reg_array.MrsOp1 = json_object_get_uint64(
1442 json_object_object_get(mrs_encoding, "op1"));
1443 reg_array.MrsO0 = json_object_get_uint64(
1444 json_object_object_get(mrs_encoding, "o0"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001445
Lawrence Tange407b4c2022-07-21 13:54:01 +01001446 //Actual register value.
1447 reg_array.Value = json_object_get_uint64(
1448 json_object_object_get(registers, "value"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001449
Lawrence Tange407b4c2022-07-21 13:54:01 +01001450 //Flush to stream.
1451 fwrite(&reg_array, sizeof(reg_array), 1, out);
1452 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001453}
1454
1455//Converts a single ARM unknown register CPER-JSON object to CPER binary, outputting to the given stream.
John Chungf8fc7052024-05-03 20:05:29 +08001456void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001457{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001458 //Get base64 represented data.
1459 json_object *encoded = json_object_object_get(registers, "data");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -07001460
1461 int32_t decoded_len = 0;
1462
1463 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
1464 json_object_get_string_len(encoded),
1465 &decoded_len);
1466
1467 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -07001468 cper_print_log("Failed to allocate decode output buffer. \n");
John Chungf8fc7052024-05-03 20:05:29 +08001469 } else {
John Chungf8fc7052024-05-03 20:05:29 +08001470 //Flush out to stream.
1471 fwrite(&decoded, decoded_len, 1, out);
1472 fflush(out);
1473 free(decoded);
1474 }
1475}