blob: d360d18cbb742c81af85b772d3eee0ea3aaf6596 [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>
Thu Nguyene42fb482024-10-15 14:43:11 +000011#include <libcper/base64.h>
12#include <libcper/Cper.h>
13#include <libcper/cper-utils.h>
14#include <libcper/sections/cper-section-arm.h>
Ed Tanous50b966f2025-03-11 09:06:19 -070015#include <libcper/log.h>
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070016#include <string.h>
Lawrence Tang2800cd82022-07-05 16:08:20 +010017
Lawrence Tang3d0e4f22022-07-05 17:17:41 +010018//Private pre-definitions.
Lawrence Tange407b4c2022-07-21 13:54:01 +010019json_object *
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070020cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info,
21 char **err_info_desc_i);
Lawrence Tange407b4c2022-07-21 13:54:01 +010022json_object *
23cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
Ed Tanous5e2164a2025-03-09 09:20:44 -070024 const UINT8 **cur_pos, UINT32 *remaining_size);
Lawrence Tange407b4c2022-07-21 13:54:01 +010025json_object *
26cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
27 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
28json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error);
29json_object *cper_arm_misc_register_array_to_ir(
30 EFI_ARM_MISC_CONTEXT_REGISTER *misc_register);
31void ir_arm_error_info_to_cper(json_object *error_info, FILE *out);
32void ir_arm_context_info_to_cper(json_object *context_info, FILE *out);
33void ir_arm_error_cache_tlb_info_to_cper(
34 json_object *error_information,
35 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
36void ir_arm_error_bus_info_to_cper(json_object *error_information,
37 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper);
38void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out);
39void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out);
40void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out);
41void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out);
42void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out);
43void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out);
44void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out);
45void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out);
46void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out);
John Chungf8fc7052024-05-03 20:05:29 +080047void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out);
Lawrence Tang3d0e4f22022-07-05 17:17:41 +010048
Lawrence Tang2800cd82022-07-05 16:08:20 +010049//Converts the given processor-generic CPER section into JSON IR.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070050json_object *cper_section_arm_to_ir(const UINT8 *section, UINT32 size,
51 char **desc_string)
Lawrence Tang2800cd82022-07-05 16:08:20 +010052{
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070053 *desc_string = malloc(SECTION_DESC_STRING_SIZE);
54 int outstr_len = 0;
55 outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
56 "An ARM Processor Error occurred");
57 if (outstr_len < 0) {
58 cper_print_log(
59 "Error: Could not write to ARM description string\n");
60 } else if (outstr_len > SECTION_DESC_STRING_SIZE) {
61 cper_print_log("Error: ARM description string truncated: %s\n",
62 *desc_string);
63 }
64
Ed Tanous5e2164a2025-03-09 09:20:44 -070065 const UINT8 *cur_pos = section;
66 UINT32 remaining_size = size;
67
68 if (remaining_size < sizeof(EFI_ARM_ERROR_RECORD)) {
Ed Tanous12dbd4f2025-03-08 19:05:01 -080069 return NULL;
70 }
Ed Tanous5e2164a2025-03-09 09:20:44 -070071 EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)cur_pos;
72 cur_pos += sizeof(EFI_ARM_ERROR_RECORD);
73 remaining_size -= sizeof(EFI_ARM_ERROR_RECORD);
Lawrence Tange407b4c2022-07-21 13:54:01 +010074 json_object *section_ir = json_object_new_object();
Lawrence Tang2800cd82022-07-05 16:08:20 +010075
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080076 //Length of ValidationBits from spec
77 ValidationTypes ui64Type = { UINT_64T,
78 .value.ui64 = record->ValidFields };
Lawrence Tang2800cd82022-07-05 16:08:20 +010079
Lawrence Tange407b4c2022-07-21 13:54:01 +010080 //Number of error info and context info structures, and length.
81 json_object_object_add(section_ir, "errorInfoNum",
82 json_object_new_int(record->ErrInfoNum));
83 json_object_object_add(section_ir, "contextInfoNum",
84 json_object_new_int(record->ContextInfoNum));
85 json_object_object_add(section_ir, "sectionLength",
86 json_object_new_uint64(record->SectionLength));
Lawrence Tang2800cd82022-07-05 16:08:20 +010087
Lawrence Tange407b4c2022-07-21 13:54:01 +010088 //Error affinity.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -080089 if (isvalid_prop_to_ir(&ui64Type, 1)) {
90 json_object *error_affinity = json_object_new_object();
91 json_object_object_add(
92 error_affinity, "value",
93 json_object_new_int(record->ErrorAffinityLevel));
94 json_object_object_add(
95 error_affinity, "type",
96 json_object_new_string(record->ErrorAffinityLevel < 4 ?
97 "Vendor Defined" :
98 "Reserved"));
99 json_object_object_add(section_ir, "errorAffinity",
100 error_affinity);
101 }
Lawrence Tang2800cd82022-07-05 16:08:20 +0100102
Lawrence Tange407b4c2022-07-21 13:54:01 +0100103 //Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800104 if (isvalid_prop_to_ir(&ui64Type, 0)) {
105 uint64_t mpidr_eli1 = record->MPIDR_EL1;
106 uint64_t sock;
107 json_object_object_add(section_ir, "mpidrEl1",
108 json_object_new_uint64(mpidr_eli1));
109
110 //Arm Processor socket info dependes on mpidr_eli1
111 sock = (mpidr_eli1 & ARM_SOCK_MASK) >> 32;
112 json_object_object_add(section_ir, "affinity3",
113 json_object_new_uint64(sock));
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700114 char *node_desc_str = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN);
115 outstr_len = snprintf(node_desc_str,
116 EFI_ERROR_DESCRIPTION_STRING_LEN,
117 " on CPU %ld", sock);
118 if (outstr_len < 0) {
119 cper_print_log(
120 "Error: Could not write to node description string\n");
121 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
122 cper_print_log(
123 "Error: Node description string truncated: %s\n",
124 node_desc_str);
125 } else {
126 if (strlen(node_desc_str) + strlen(*desc_string) <
127 SECTION_DESC_STRING_SIZE) {
128 strncat(*desc_string, node_desc_str,
129 outstr_len);
130 } else {
131 cper_print_log(
132 "Error: Node description string too long, not added to description string: %s\n",
133 node_desc_str);
134 }
135 }
136 free(node_desc_str);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800137 }
Aushim Nagarkatti17bc66a2024-11-25 13:47:35 -0800138
Lawrence Tange407b4c2022-07-21 13:54:01 +0100139 json_object_object_add(section_ir, "midrEl1",
140 json_object_new_uint64(record->MIDR_EL1));
Lawrence Tang2800cd82022-07-05 16:08:20 +0100141
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800142 if (isvalid_prop_to_ir(&ui64Type, 2)) {
143 //Whether the processor is running, and the state of it if so.
144 json_object_object_add(
145 section_ir, "running",
146 json_object_new_boolean(record->RunningState & 0x1));
147 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100148 if (!(record->RunningState >> 31)) {
149 //Bit 32 of running state is on, so PSCI state information is included.
150 //This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
151 //or the newer Extended StateID format.
152 json_object_object_add(
153 section_ir, "psciState",
154 json_object_new_uint64(record->PsciState));
155 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100156
Lawrence Tange407b4c2022-07-21 13:54:01 +0100157 //Processor error structures.
158 json_object *error_info_array = json_object_new_array();
159 EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
160 (EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
Ed Tanous5e2164a2025-03-09 09:20:44 -0700161 if (remaining_size <
162 (record->ErrInfoNum * sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY))) {
163 json_object_put(error_info_array);
164 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700165 cper_print_log(
166 "Invalid CPER file: Invalid processor error info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700167 return NULL;
168 }
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700169 strncat(*desc_string, "; Error Type(s): {",
170 EFI_ERROR_DESCRIPTION_STRING_LEN);
171 char *err_info_desc_i =
172 malloc(EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN);
173 size_t err_info_desc_i_len = 0;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100174 for (int i = 0; i < record->ErrInfoNum; i++) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700175 json_object_array_add(
176 error_info_array,
177 cper_arm_error_info_to_ir(cur_error, &err_info_desc_i));
178 err_info_desc_i_len = strlen(err_info_desc_i);
179 if (err_info_desc_i_len > 0 &&
180 strlen(*desc_string) + err_info_desc_i_len <
181 SECTION_DESC_STRING_SIZE) {
182 strncat(*desc_string, err_info_desc_i,
183 err_info_desc_i_len);
184 } else {
185 cper_print_log(
186 "Error: Error info description string too long, not added to description string: %s\n",
187 err_info_desc_i);
188 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100189 cur_error++;
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700190 if (i == record->ErrInfoNum - 1) {
191 if (strlen(*desc_string) + 2 <
192 SECTION_DESC_STRING_SIZE) {
193 strncat(*desc_string, "}", 2);
194 } else {
195 cper_print_log(
196 "Error: Description string too long, not added '}'to description string: %s\n",
197 *desc_string);
198 }
199 break;
200 }
201 if (strlen(*desc_string) + 3 < SECTION_DESC_STRING_SIZE) {
202 strncat(*desc_string, ", ", 3);
203 } else {
204 cper_print_log(
205 "Error: Description string too long, not added ',' to description string: %s\n",
206 *desc_string);
207 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100208 }
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700209 free(err_info_desc_i);
Ed Tanous5e2164a2025-03-09 09:20:44 -0700210
211 cur_pos += (UINT32)(record->ErrInfoNum *
212 sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
213 remaining_size -= (UINT32)(record->ErrInfoNum *
214 sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
215
Lawrence Tange407b4c2022-07-21 13:54:01 +0100216 json_object_object_add(section_ir, "errorInfo", error_info_array);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100217
Lawrence Tange407b4c2022-07-21 13:54:01 +0100218 //Processor context structures.
219 //The current position is moved within the processing, as it is a dynamic size structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100220 json_object *context_info_array = json_object_new_array();
221 for (int i = 0; i < record->ContextInfoNum; i++) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700222 if (remaining_size <
223 sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER)) {
224 json_object_put(context_info_array);
225 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700226 cper_print_log(
227 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700228 return NULL;
229 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100230 EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
231 (EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700232
233 cur_pos += sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
234 remaining_size -= sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100235 json_object *processor_context =
Ed Tanous5e2164a2025-03-09 09:20:44 -0700236 cper_arm_processor_context_to_ir(header, &cur_pos,
237 &remaining_size);
238 if (processor_context == NULL) {
239 json_object_put(context_info_array);
240 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700241 cper_print_log(
242 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700243 return NULL;
244 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100245 json_object_array_add(context_info_array, processor_context);
246 }
247 json_object_object_add(section_ir, "contextInfo", context_info_array);
Lawrence Tangd7e8ca32022-07-07 10:25:53 +0100248
Lawrence Tange407b4c2022-07-21 13:54:01 +0100249 //Is there any vendor-specific information following?
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800250 if (isvalid_prop_to_ir(&ui64Type, 3)) {
251 if (cur_pos < (uint8_t *)section + record->SectionLength) {
252 json_object *vendor_specific = json_object_new_object();
253 size_t input_size = (uint8_t *)section +
254 record->SectionLength - cur_pos;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700255 if (remaining_size < input_size) {
256 json_object_put(vendor_specific);
257 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700258 cper_print_log(
259 "Invalid CPER file: Invalid vendor-specific info length.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700260 return NULL;
261 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800262 int32_t encoded_len = 0;
263 char *encoded = base64_encode(cur_pos, input_size,
264 &encoded_len);
265 if (encoded == NULL) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700266 json_object_put(vendor_specific);
267 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700268 cper_print_log(
269 "base64 encode of vendorSpecificInfo failed\n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800270 return NULL;
271 }
272 json_object_object_add(vendor_specific, "data",
273 json_object_new_string_len(
274 encoded, encoded_len));
275 free(encoded);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700276
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800277 json_object_object_add(section_ir, "vendorSpecificInfo",
278 vendor_specific);
279 } else {
Ed Tanous50b966f2025-03-11 09:06:19 -0700280 cper_print_log(
281 "vendorSpecificInfo is marked valid but not present in binary\n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800282 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100283 }
284
285 return section_ir;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100286}
287
288//Converts a single ARM Process Error Information structure into JSON IR.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100289json_object *
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700290cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info,
291 char **err_info_desc_i)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100292{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100293 json_object *error_info_ir = json_object_new_object();
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700294 int outstr_len = 0;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100295
Lawrence Tange407b4c2022-07-21 13:54:01 +0100296 //Version, length.
297 json_object_object_add(error_info_ir, "version",
298 json_object_new_int(error_info->Version));
299 json_object_object_add(error_info_ir, "length",
300 json_object_new_int(error_info->Length));
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100301
Lawrence Tange407b4c2022-07-21 13:54:01 +0100302 //Validation bitfield.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800303 ValidationTypes ui16Type = { UINT_16T,
304 .value.ui16 = error_info->ValidationBits };
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100305
Lawrence Tange407b4c2022-07-21 13:54:01 +0100306 //The type of error information in this log.
307 json_object *error_type = integer_to_readable_pair(
308 error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
309 ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
310 json_object_object_add(error_info_ir, "errorType", error_type);
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100311
Lawrence Tange407b4c2022-07-21 13:54:01 +0100312 //Multiple error count.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800313 if (isvalid_prop_to_ir(&ui16Type, 0)) {
314 json_object *multiple_error = json_object_new_object();
315 json_object_object_add(
316 multiple_error, "value",
317 json_object_new_int(error_info->MultipleError));
318 json_object_object_add(
319 multiple_error, "type",
320 json_object_new_string(error_info->MultipleError < 1 ?
321 "Single Error" :
322 "Multiple Errors"));
323 json_object_object_add(error_info_ir, "multipleError",
324 multiple_error);
325 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100326
Lawrence Tange407b4c2022-07-21 13:54:01 +0100327 //Flags.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800328 if (isvalid_prop_to_ir(&ui16Type, 1)) {
329 json_object *flags = bitfield_to_ir(
330 error_info->Flags, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
331 json_object_object_add(error_info_ir, "flags", flags);
332 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100333
Lawrence Tange407b4c2022-07-21 13:54:01 +0100334 //Error information, split by type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800335 if (isvalid_prop_to_ir(&ui16Type, 2)) {
336 json_object *error_subinfo = NULL;
337 switch (error_info->Type) {
338 case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800339 error_subinfo = cper_arm_cache_tlb_error_to_ir(
340 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
341 ->ErrorInformation,
342 error_info);
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700343 const char *cache_error_desc = "Cache Error";
344 if (strlen(cache_error_desc) >=
345 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
346 cper_print_log(
347 "Error: Cache Error Description too long %s\n",
348 cache_error_desc);
349 } else {
350 strncpy(*err_info_desc_i, cache_error_desc,
351 strlen(cache_error_desc) + 1);
352 }
353 break;
354 case ARM_ERROR_INFORMATION_TYPE_TLB: //TLB
355 error_subinfo = cper_arm_cache_tlb_error_to_ir(
356 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
357 ->ErrorInformation,
358 error_info);
359 const char *tlb_error_desc = "TLB Error";
360 if (strlen(tlb_error_desc) >=
361 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
362 cper_print_log(
363 "Error: TLB Error Description too long %s\n",
364 tlb_error_desc);
365 } else {
366 strncpy(*err_info_desc_i, tlb_error_desc,
367 strlen(tlb_error_desc) + 1);
368 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800369 break;
370 case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
371 error_subinfo = cper_arm_bus_error_to_ir(
372 (EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
373 ->ErrorInformation);
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700374 const char *bus_error_desc = "Bus Error";
375 if (strlen(bus_error_desc) >=
376 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
377 cper_print_log(
378 "Error: Bus Error Description too long %s\n",
379 bus_error_desc);
380 } else {
381 strncpy(*err_info_desc_i, bus_error_desc,
382 strlen(bus_error_desc) + 1);
383 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800384 break;
Lawrence Tang71570a22022-07-14 11:45:28 +0100385
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800386 default:
387 //Unknown/microarch, will not support.
388 break;
389 }
Ed Tanousd6b62632025-03-14 15:30:07 -0700390 if (error_subinfo != NULL) {
391 json_object_object_add(error_info_ir,
392 "errorInformation",
393 error_subinfo);
394 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100395 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100396
Lawrence Tange407b4c2022-07-21 13:54:01 +0100397 //Virtual fault address, physical fault address.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700398 char *fault_address_desc = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800399 if (isvalid_prop_to_ir(&ui16Type, 3)) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700400 outstr_len = snprintf(fault_address_desc,
401 EFI_ERROR_DESCRIPTION_STRING_LEN,
402 " at Virtual Addr=0x%llX",
403 error_info->VirtualFaultAddress);
404 if (outstr_len < 0) {
405 cper_print_log(
406 "Error: Could not write to fault address description string\n");
407 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
408 cper_print_log(
409 "Error: Virtual fault address description string truncated: %s\n",
410 fault_address_desc);
411 } else {
412 if (strlen(fault_address_desc) +
413 strlen(*err_info_desc_i) <
414 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
415 strncat(*err_info_desc_i, fault_address_desc,
416 outstr_len);
417 } else {
418 cper_print_log(
419 "Error: Virtual fault address description string too long, not added to description string: %s\n",
420 fault_address_desc);
421 }
422 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800423 json_object_object_add(
424 error_info_ir, "virtualFaultAddress",
425 json_object_new_uint64(
426 error_info->VirtualFaultAddress));
427 }
428 if (isvalid_prop_to_ir(&ui16Type, 4)) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700429 outstr_len = snprintf(fault_address_desc,
430 EFI_ERROR_DESCRIPTION_STRING_LEN,
431 " Physical Addr=0x%llX",
432 error_info->PhysicalFaultAddress);
433 if (outstr_len < 0) {
434 cper_print_log(
435 "Error: Could not write to physical fault address description string\n");
436 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
437 cper_print_log(
438 "Error: Physical fault address description string truncated: %s\n",
439 fault_address_desc);
440 } else {
441 if (strlen(fault_address_desc) +
442 strlen(*err_info_desc_i) <
443 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
444 strncat(*err_info_desc_i, fault_address_desc,
445 outstr_len);
446 } else {
447 cper_print_log(
448 "Error:Physical fault address description string too long, not added to description string: %s\n",
449 fault_address_desc);
450 }
451 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800452 json_object_object_add(
453 error_info_ir, "physicalFaultAddress",
454 json_object_new_uint64(
455 error_info->PhysicalFaultAddress));
456 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100457
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700458 free(fault_address_desc);
459
Lawrence Tange407b4c2022-07-21 13:54:01 +0100460 return error_info_ir;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100461}
462
Lawrence Tang7f21db62022-07-06 11:09:39 +0100463//Converts a single ARM cache/TLB error information structure into JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100464json_object *
465cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
466 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100467{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100468 json_object *cache_tlb_error_ir = json_object_new_object();
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700469 json_object *cache_tlb_prop = json_object_new_object();
470 char *cache_tlb_propname;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100471
Lawrence Tange407b4c2022-07-21 13:54:01 +0100472 //Validation bitfield.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800473 ValidationTypes ui64Type = {
474 UINT_64T, .value.ui64 = cache_tlb_error->ValidationBits
475 };
Lawrence Tang7f21db62022-07-06 11:09:39 +0100476
Lawrence Tange407b4c2022-07-21 13:54:01 +0100477 //Transaction type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800478 if (isvalid_prop_to_ir(&ui64Type, 0)) {
479 json_object *transaction_type = integer_to_readable_pair(
480 cache_tlb_error->TransactionType, 3,
481 ARM_ERROR_TRANSACTION_TYPES_KEYS,
482 ARM_ERROR_TRANSACTION_TYPES_VALUES,
483 "Unknown (Reserved)");
484 json_object_object_add(cache_tlb_error_ir, "transactionType",
485 transaction_type);
486 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100487
Lawrence Tange407b4c2022-07-21 13:54:01 +0100488 //Operation.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800489 bool cacheErrorFlag = 1;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100490 if (error_info->Type == 0) {
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700491 cache_tlb_propname = "cacheError";
Lawrence Tange407b4c2022-07-21 13:54:01 +0100492 } else {
493 //TLB operation.
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700494 cache_tlb_propname = "tlbError";
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800495 cacheErrorFlag = 0;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100496 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800497
498 if (isvalid_prop_to_ir(&ui64Type, 1)) {
499 json_object *operation;
500
501 if (cacheErrorFlag) {
502 //Cache operation.
503 operation = integer_to_readable_pair(
504 cache_tlb_error->Operation, 11,
505 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
506 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
507 "Unknown (Reserved)");
508 } else {
509 operation = integer_to_readable_pair(
510 cache_tlb_error->Operation, 9,
511 ARM_TLB_OPERATION_TYPES_KEYS,
512 ARM_TLB_OPERATION_TYPES_VALUES,
513 "Unknown (Reserved)");
514 }
515 json_object_object_add(cache_tlb_error_ir, "operation",
516 operation);
517 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100518
Lawrence Tange407b4c2022-07-21 13:54:01 +0100519 //Miscellaneous remaining fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800520 if (isvalid_prop_to_ir(&ui64Type, 2)) {
521 json_object_object_add(
522 cache_tlb_error_ir, "level",
523 json_object_new_int(cache_tlb_error->Level));
524 }
525 if (isvalid_prop_to_ir(&ui64Type, 3)) {
526 json_object_object_add(
527 cache_tlb_error_ir, "processorContextCorrupt",
528 json_object_new_boolean(
529 cache_tlb_error->ProcessorContextCorrupt));
530 }
531 if (isvalid_prop_to_ir(&ui64Type, 4)) {
532 json_object_object_add(
533 cache_tlb_error_ir, "corrected",
534 json_object_new_boolean(cache_tlb_error->Corrected));
535 }
536 if (isvalid_prop_to_ir(&ui64Type, 5)) {
537 json_object_object_add(
538 cache_tlb_error_ir, "precisePC",
539 json_object_new_boolean(cache_tlb_error->PrecisePC));
540 }
541 if (isvalid_prop_to_ir(&ui64Type, 6)) {
542 json_object_object_add(cache_tlb_error_ir, "restartablePC",
543 json_object_new_boolean(
544 cache_tlb_error->RestartablePC));
545 }
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700546
547 json_object_object_add(cache_tlb_prop, cache_tlb_propname,
548 cache_tlb_error_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800549
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700550 return cache_tlb_prop;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100551}
552
553//Converts a single ARM bus error information structure into JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100554json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100555{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100556 json_object *bus_error_ir = json_object_new_object();
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800557 json_object *bus_prop = json_object_new_object();
558 char *bus_propname = "busError";
Lawrence Tang7f21db62022-07-06 11:09:39 +0100559
Lawrence Tange407b4c2022-07-21 13:54:01 +0100560 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800561 ValidationTypes ui64Type = { UINT_64T,
562 .value.ui64 = bus_error->ValidationBits };
Lawrence Tang7f21db62022-07-06 11:09:39 +0100563
Lawrence Tange407b4c2022-07-21 13:54:01 +0100564 //Transaction type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800565 if (isvalid_prop_to_ir(&ui64Type, 0)) {
566 json_object *transaction_type = integer_to_readable_pair(
567 bus_error->TransactionType, 3,
568 ARM_ERROR_TRANSACTION_TYPES_KEYS,
569 ARM_ERROR_TRANSACTION_TYPES_VALUES,
570 "Unknown (Reserved)");
571 json_object_object_add(bus_error_ir, "transactionType",
572 transaction_type);
573 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100574
Lawrence Tange407b4c2022-07-21 13:54:01 +0100575 //Operation.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800576 if (isvalid_prop_to_ir(&ui64Type, 1)) {
577 json_object *operation = integer_to_readable_pair(
578 bus_error->Operation, 7,
579 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
580 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
581 "Unknown (Reserved)");
582 json_object_object_add(bus_error_ir, "operation", operation);
583 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100584
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800585 if (isvalid_prop_to_ir(&ui64Type, 2)) {
586 //Affinity level of bus error, + miscellaneous fields.
587 json_object_object_add(bus_error_ir, "level",
588 json_object_new_int(bus_error->Level));
589 }
590 if (isvalid_prop_to_ir(&ui64Type, 3)) {
591 json_object_object_add(
592 bus_error_ir, "processorContextCorrupt",
593 json_object_new_boolean(
594 bus_error->ProcessorContextCorrupt));
595 }
596 if (isvalid_prop_to_ir(&ui64Type, 4)) {
597 json_object_object_add(
598 bus_error_ir, "corrected",
599 json_object_new_boolean(bus_error->Corrected));
600 }
601 if (isvalid_prop_to_ir(&ui64Type, 5)) {
602 json_object_object_add(
603 bus_error_ir, "precisePC",
604 json_object_new_boolean(bus_error->PrecisePC));
605 }
606 if (isvalid_prop_to_ir(&ui64Type, 6)) {
607 json_object_object_add(
608 bus_error_ir, "restartablePC",
609 json_object_new_boolean(bus_error->RestartablePC));
610 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100611
Lawrence Tange407b4c2022-07-21 13:54:01 +0100612 //Participation type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800613 if (isvalid_prop_to_ir(&ui64Type, 7)) {
614 json_object *participation_type = integer_to_readable_pair(
615 bus_error->ParticipationType, 4,
616 ARM_BUS_PARTICIPATION_TYPES_KEYS,
617 ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
618 json_object_object_add(bus_error_ir, "participationType",
619 participation_type);
620 }
621 if (isvalid_prop_to_ir(&ui64Type, 8)) {
622 json_object_object_add(
623 bus_error_ir, "timedOut",
624 json_object_new_boolean(bus_error->TimeOut));
625 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100626
Lawrence Tange407b4c2022-07-21 13:54:01 +0100627 //Address space.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800628 if (isvalid_prop_to_ir(&ui64Type, 9)) {
629 json_object *address_space = integer_to_readable_pair(
630 bus_error->AddressSpace, 3,
631 ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
632 ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
633 json_object_object_add(bus_error_ir, "addressSpace",
634 address_space);
635 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100636
Lawrence Tange407b4c2022-07-21 13:54:01 +0100637 //Memory access attributes.
638 //todo: find the specification of these in the ARM ARM
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800639 if (isvalid_prop_to_ir(&ui64Type, 10)) {
640 json_object_object_add(
641 bus_error_ir, "memoryAttributes",
642 json_object_new_int(
643 bus_error->MemoryAddressAttributes));
644 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100645
Lawrence Tange407b4c2022-07-21 13:54:01 +0100646 //Access Mode
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800647 if (isvalid_prop_to_ir(&ui64Type, 8)) {
648 json_object *access_mode = json_object_new_object();
649 json_object_object_add(
650 access_mode, "value",
651 json_object_new_int(bus_error->AccessMode));
652 json_object_object_add(
653 access_mode, "name",
654 json_object_new_string(bus_error->AccessMode == 0 ?
655 "Secure" :
656 "Normal"));
657 json_object_object_add(bus_error_ir, "accessMode", access_mode);
658 }
659 json_object_object_add(bus_prop, bus_propname, bus_error_ir);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100660
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800661 return bus_prop;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100662}
663
664//Converts a single ARM processor context block into JSON IR.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100665json_object *
666cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
Ed Tanous5e2164a2025-03-09 09:20:44 -0700667 const UINT8 **cur_pos, UINT32 *remaining_size)
Lawrence Tang7f21db62022-07-06 11:09:39 +0100668{
Ed Tanous5e2164a2025-03-09 09:20:44 -0700669 if (header->RegisterArraySize > *remaining_size) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700670 cper_print_log(
671 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700672 return NULL;
673 }
674
Lawrence Tange407b4c2022-07-21 13:54:01 +0100675 json_object *context_ir = json_object_new_object();
Lawrence Tang7f21db62022-07-06 11:09:39 +0100676
Lawrence Tange407b4c2022-07-21 13:54:01 +0100677 //Version.
678 json_object_object_add(context_ir, "version",
679 json_object_new_int(header->Version));
Lawrence Tang71570a22022-07-14 11:45:28 +0100680
Lawrence Tange407b4c2022-07-21 13:54:01 +0100681 //Add the context type.
682 json_object *context_type = integer_to_readable_pair(
Ed Tanous5e2164a2025-03-09 09:20:44 -0700683 header->RegisterContextType,
684 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_COUNT,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100685 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
686 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
687 "Unknown (Reserved)");
688 json_object_object_add(context_ir, "registerContextType", context_type);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100689
Lawrence Tange407b4c2022-07-21 13:54:01 +0100690 //Register array size (bytes).
691 json_object_object_add(
692 context_ir, "registerArraySize",
693 json_object_new_uint64(header->RegisterArraySize));
Lawrence Tang7f21db62022-07-06 11:09:39 +0100694
Lawrence Tange407b4c2022-07-21 13:54:01 +0100695 //The register array itself.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100696 json_object *register_array = NULL;
697 switch (header->RegisterContextType) {
698 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700699 if (*remaining_size < sizeof(EFI_ARM_V8_AARCH32_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700700 cper_print_log(
701 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700702 goto fail;
703 }
704 if (header->RegisterArraySize <
705 sizeof(EFI_ARM_V8_AARCH32_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700706 cper_print_log(
707 "Invalid CPER file: Not enough bytes for aarch32 gpr\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700708 goto fail;
709 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100710 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800711 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100712 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
713 ARM_AARCH32_GPR_NAMES);
714 break;
715 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700716 if (*remaining_size <
717 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700718 cper_print_log(
719 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700720 goto fail;
721 }
722 if (header->RegisterArraySize <
723 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700724 cper_print_log(
725 "Invalid CPER file: Not enough bytes for aarch32 el1\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700726 goto fail;
727 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100728 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800729 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100730 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
731 sizeof(UINT32),
732 ARM_AARCH32_EL1_REGISTER_NAMES);
733 break;
734 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700735 if (*remaining_size <
736 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700737 cper_print_log(
738 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700739 goto fail;
740 }
741 if (header->RegisterArraySize <
742 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700743 cper_print_log(
744 "Invalid CPER file: Not enough bytes for aarch32 el2\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700745 goto fail;
746 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100747 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800748 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100749 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
750 sizeof(UINT32),
751 ARM_AARCH32_EL2_REGISTER_NAMES);
Ed Tanous5e2164a2025-03-09 09:20:44 -0700752
Lawrence Tange407b4c2022-07-21 13:54:01 +0100753 break;
754 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700755 if (*remaining_size <
756 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
757 json_object_put(context_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700758 cper_print_log(
759 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700760 return NULL;
761 }
762 if (header->RegisterArraySize <
763 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700764 cper_print_log(
765 "Invalid CPER file: Not enough bytes for aarch32 secure\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700766 goto fail;
767 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100768 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800769 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100770 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
771 sizeof(UINT32),
772 ARM_AARCH32_SECURE_REGISTER_NAMES);
773 break;
774 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700775 if (*remaining_size < sizeof(EFI_ARM_V8_AARCH64_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700776 cper_print_log(
777 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700778 goto fail;
779 }
780 if (header->RegisterArraySize <
781 sizeof(EFI_ARM_V8_AARCH64_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700782 cper_print_log(
783 "Invalid CPER file: Not enough bytes for aarch64 gpr\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700784 goto fail;
785 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100786 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800787 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100788 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
789 ARM_AARCH64_GPR_NAMES);
790 break;
791 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700792 if (*remaining_size <
793 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700794 cper_print_log(
795 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700796 goto fail;
797 }
798 if (header->RegisterArraySize <
799 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700800 cper_print_log(
801 "Invalid CPER file: Not enough bytes for aarch64 el1\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700802 goto fail;
803 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100804 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800805 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100806 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
807 sizeof(UINT64),
808 ARM_AARCH64_EL1_REGISTER_NAMES);
809 break;
810 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700811 if (*remaining_size <
812 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700813 cper_print_log(
814 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700815 goto fail;
816 }
817 if (header->RegisterArraySize <
818 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700819 cper_print_log(
820 "Invalid CPER file: Not enough bytes for aarch64 el2\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700821 goto fail;
822 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100823 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800824 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100825 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
826 sizeof(UINT64),
827 ARM_AARCH64_EL2_REGISTER_NAMES);
828 break;
829 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700830 if (*remaining_size <
831 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700832 cper_print_log(
833 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700834 goto fail;
835 }
836 if (header->RegisterArraySize <
837 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700838 cper_print_log(
839 "Invalid CPER file: Not enough bytes for aarch64 el3\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700840 goto fail;
841 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100842 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800843 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100844 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
845 sizeof(UINT64),
846 ARM_AARCH64_EL3_REGISTER_NAMES);
847 break;
848 case EFI_ARM_CONTEXT_TYPE_MISC:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700849 if (*remaining_size < sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700850 cper_print_log(
851 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700852 goto fail;
853 }
854 if (header->RegisterArraySize <
855 sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700856 cper_print_log(
857 "Invalid CPER file: Not enough bytes for misc\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700858 goto fail;
859 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100860 register_array = cper_arm_misc_register_array_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800861 (EFI_ARM_MISC_CONTEXT_REGISTER *)*cur_pos);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100862 break;
863 default:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700864 if (*remaining_size < header->RegisterArraySize) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700865 cper_print_log(
866 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700867 goto fail;
868 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100869 //Unknown register array type, add as base64 data instead.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700870 int32_t encoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800871 char *encoded = base64_encode((UINT8 *)*cur_pos,
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700872 header->RegisterArraySize,
873 &encoded_len);
874 if (encoded == NULL) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700875 goto fail;
John Chungf8fc7052024-05-03 20:05:29 +0800876 }
Ed Tanous5e2164a2025-03-09 09:20:44 -0700877 register_array = json_object_new_object();
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700878 json_object_object_add(register_array, "data",
879 json_object_new_string_len(encoded,
880 encoded_len));
881 free(encoded);
882
Lawrence Tange407b4c2022-07-21 13:54:01 +0100883 break;
884 }
885 json_object_object_add(context_ir, "registerArray", register_array);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100886
Lawrence Tange407b4c2022-07-21 13:54:01 +0100887 //Set the current position to after the processor context structure.
888 *cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700889 *remaining_size -= header->RegisterArraySize;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100890
Lawrence Tange407b4c2022-07-21 13:54:01 +0100891 return context_ir;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700892
893fail:
894 json_object_put(context_ir);
895 return NULL;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100896}
897
898//Converts a single CPER ARM miscellaneous register array to JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100899json_object *
900cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
Lawrence Tang7f21db62022-07-06 11:09:39 +0100901{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100902 json_object *register_array = json_object_new_object();
903 json_object *mrs_encoding = json_object_new_object();
904 json_object_object_add(mrs_encoding, "op2",
905 json_object_new_uint64(misc_register->MrsOp2));
906 json_object_object_add(mrs_encoding, "crm",
907 json_object_new_uint64(misc_register->MrsCrm));
908 json_object_object_add(mrs_encoding, "crn",
909 json_object_new_uint64(misc_register->MrsCrn));
910 json_object_object_add(mrs_encoding, "op1",
911 json_object_new_uint64(misc_register->MrsOp1));
912 json_object_object_add(mrs_encoding, "o0",
913 json_object_new_uint64(misc_register->MrsO0));
914 json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
915 json_object_object_add(register_array, "value",
916 json_object_new_uint64(misc_register->Value));
Lawrence Tang7f21db62022-07-06 11:09:39 +0100917
Lawrence Tange407b4c2022-07-21 13:54:01 +0100918 return register_array;
Lawrence Tang7cd13902022-07-13 16:59:25 +0100919}
920
921//Converts a single CPER-JSON ARM error section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100922void ir_section_arm_to_cper(json_object *section, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +0100923{
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800924 EFI_ARM_ERROR_RECORD section_cper;
925 memset(&section_cper, 0, sizeof(section_cper));
Lawrence Tang7cd13902022-07-13 16:59:25 +0100926
Lawrence Tange407b4c2022-07-21 13:54:01 +0100927 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800928 struct json_object *obj = NULL;
929 ValidationTypes u32Type = { UINT_32T, .value.ui32 = 0 };
Lawrence Tang7cd13902022-07-13 16:59:25 +0100930
Lawrence Tange407b4c2022-07-21 13:54:01 +0100931 //Count of error/context info structures.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800932 section_cper.ErrInfoNum = json_object_get_int(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100933 json_object_object_get(section, "errorInfoNum"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800934 section_cper.ContextInfoNum = json_object_get_int(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100935 json_object_object_get(section, "contextInfoNum"));
Lawrence Tang7cd13902022-07-13 16:59:25 +0100936
Lawrence Tange407b4c2022-07-21 13:54:01 +0100937 //Miscellaneous raw value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800938 section_cper.SectionLength = json_object_get_uint64(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100939 json_object_object_get(section, "sectionLength"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800940 if (json_object_object_get_ex(section, "mpidrEl1", &obj)) {
941 section_cper.MPIDR_EL1 = json_object_get_uint64(obj);
942 add_to_valid_bitfield(&u32Type, 0);
943 }
944 if (json_object_object_get_ex(section, "errorAffinity", &obj)) {
945 section_cper.ErrorAffinityLevel = readable_pair_to_integer(obj);
946 add_to_valid_bitfield(&u32Type, 1);
947 }
948 section_cper.MIDR_EL1 = json_object_get_uint64(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100949 json_object_object_get(section, "midrEl1"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800950 if (json_object_object_get_ex(section, "running", &obj)) {
951 section_cper.RunningState = json_object_get_boolean(obj);
952 add_to_valid_bitfield(&u32Type, 2);
953 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100954
Lawrence Tange407b4c2022-07-21 13:54:01 +0100955 //Optional PSCI state.
956 json_object *psci_state = json_object_object_get(section, "psciState");
John Chungf8fc7052024-05-03 20:05:29 +0800957 if (psci_state != NULL) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800958 section_cper.PsciState = json_object_get_uint64(psci_state);
John Chungf8fc7052024-05-03 20:05:29 +0800959 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100960
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800961 //Validationbits for EFI_ARM_ERROR_RECORD should also consider vendorSpecificInfo
962 bool vendorSpecificPresent =
963 json_object_object_get_ex(section, "vendorSpecificInfo", &obj);
964 json_object *vendor_specific_info = obj;
965 if (vendorSpecificPresent) {
966 add_to_valid_bitfield(&u32Type, 3);
967 }
968
969 section_cper.ValidFields = u32Type.value.ui32;
970
Lawrence Tange407b4c2022-07-21 13:54:01 +0100971 //Flush header to stream.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800972 fwrite(&section_cper, sizeof(section_cper), 1, out);
Lawrence Tang7cd13902022-07-13 16:59:25 +0100973
Lawrence Tange407b4c2022-07-21 13:54:01 +0100974 //Error info structure array.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800975
Lawrence Tange407b4c2022-07-21 13:54:01 +0100976 json_object *error_info = json_object_object_get(section, "errorInfo");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800977 for (int i = 0; i < section_cper.ErrInfoNum; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100978 ir_arm_error_info_to_cper(
979 json_object_array_get_idx(error_info, i), out);
John Chungf8fc7052024-05-03 20:05:29 +0800980 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100981
Lawrence Tange407b4c2022-07-21 13:54:01 +0100982 //Context info structure array.
983 json_object *context_info =
984 json_object_object_get(section, "contextInfo");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800985 for (int i = 0; i < section_cper.ContextInfoNum; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100986 ir_arm_context_info_to_cper(
987 json_object_array_get_idx(context_info, i), out);
John Chungf8fc7052024-05-03 20:05:29 +0800988 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100989
Lawrence Tange407b4c2022-07-21 13:54:01 +0100990 //Vendor specific error info.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800991 if (vendorSpecificPresent) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100992 json_object *vendor_info_string =
993 json_object_object_get(vendor_specific_info, "data");
994 int vendor_specific_len =
995 json_object_get_string_len(vendor_info_string);
Lawrence Tang01e3a442022-07-20 15:14:50 +0100996
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700997 int32_t decoded_len = 0;
998
999 UINT8 *decoded = base64_decode(
1000 json_object_get_string(vendor_info_string),
1001 vendor_specific_len, &decoded_len);
1002
1003 //Write out to file.
1004 fwrite(decoded, decoded_len, 1, out);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -07001005 free(decoded);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001006 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001007
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001008 fflush(out);
Lawrence Tang7cd13902022-07-13 16:59:25 +01001009}
1010
1011//Converts a single ARM error information structure into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001012void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +01001013{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001014 EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001015 memset(&error_info_cper, 0, sizeof(error_info_cper));
1016 struct json_object *obj = NULL;
1017 ValidationTypes ui16Type = { UINT_16T, .value.ui16 = 0 };
Lawrence Tang7cd13902022-07-13 16:59:25 +01001018
Lawrence Tange407b4c2022-07-21 13:54:01 +01001019 //Version, length.
1020 error_info_cper.Version = json_object_get_int(
1021 json_object_object_get(error_info, "version"));
1022 error_info_cper.Length = json_object_get_int(
1023 json_object_object_get(error_info, "length"));
Lawrence Tang7cd13902022-07-13 16:59:25 +01001024
Lawrence Tange407b4c2022-07-21 13:54:01 +01001025 //Type, multiple error.
1026 error_info_cper.Type = (UINT8)readable_pair_to_integer(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001027 json_object_object_get(error_info, "errorType"));
1028
1029 if (json_object_object_get_ex(error_info, "multipleError", &obj)) {
1030 error_info_cper.MultipleError =
1031 (UINT16)readable_pair_to_integer(obj);
1032 add_to_valid_bitfield(&ui16Type, 0);
1033 } else {
1034 error_info_cper.MultipleError = 0;
1035 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001036
Lawrence Tange407b4c2022-07-21 13:54:01 +01001037 //Flags object.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001038 if (json_object_object_get_ex(error_info, "flags", &obj)) {
1039 error_info_cper.Flags = (UINT8)ir_to_bitfield(
1040 obj, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
1041 add_to_valid_bitfield(&ui16Type, 1);
1042 } else {
1043 error_info_cper.Flags = 0;
1044 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001045
Lawrence Tange407b4c2022-07-21 13:54:01 +01001046 //Error information.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001047 if (json_object_object_get_ex(error_info, "errorInformation", &obj)) {
1048 json_object *error_info_information = obj;
1049 json_object *error_info_prop = NULL;
1050 switch (error_info_cper.Type) {
1051 case ARM_ERROR_INFORMATION_TYPE_CACHE:
1052 error_info_cper.ErrorInformation.Value = 0;
1053 error_info_prop = json_object_object_get(
1054 error_info_information, "cacheError");
1055 ir_arm_error_cache_tlb_info_to_cper(
1056 error_info_prop,
1057 &error_info_cper.ErrorInformation.CacheError);
1058 break;
1059 case ARM_ERROR_INFORMATION_TYPE_TLB:
1060 error_info_cper.ErrorInformation.Value = 0;
1061 error_info_prop = json_object_object_get(
1062 error_info_information, "tlbError");
1063 ir_arm_error_cache_tlb_info_to_cper(
1064 error_info_prop,
1065 &error_info_cper.ErrorInformation.CacheError);
1066 break;
Aushim Nagarkatti5b793002024-09-26 17:07:30 -07001067
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001068 case ARM_ERROR_INFORMATION_TYPE_BUS:
1069 error_info_cper.ErrorInformation.Value = 0;
1070 error_info_prop = json_object_object_get(
1071 error_info_information, "busError");
1072 ir_arm_error_bus_info_to_cper(
1073 error_info_prop,
1074 &error_info_cper.ErrorInformation.BusError);
1075 break;
Lawrence Tang71570a22022-07-14 11:45:28 +01001076
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001077 default:
1078 //Unknown error information type.
1079 break;
1080 }
1081 add_to_valid_bitfield(&ui16Type, 2);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001082 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001083
Lawrence Tange407b4c2022-07-21 13:54:01 +01001084 //Virtual/physical fault address.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001085 if (json_object_object_get_ex(error_info, "virtualFaultAddress",
1086 &obj)) {
1087 error_info_cper.VirtualFaultAddress =
1088 json_object_get_uint64(obj);
1089 add_to_valid_bitfield(&ui16Type, 3);
1090 } else {
1091 error_info_cper.VirtualFaultAddress = 0;
1092 }
1093
1094 if (json_object_object_get_ex(error_info, "physicalFaultAddress",
1095 &obj)) {
1096 error_info_cper.PhysicalFaultAddress =
1097 json_object_get_uint64(obj);
1098 add_to_valid_bitfield(&ui16Type, 4);
1099 } else {
1100 error_info_cper.PhysicalFaultAddress = 0;
1101 }
1102 error_info_cper.ValidationBits = ui16Type.value.ui16;
Lawrence Tang7cd13902022-07-13 16:59:25 +01001103
Lawrence Tange407b4c2022-07-21 13:54:01 +01001104 //Write out to stream.
1105 fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
1106 out);
Lawrence Tang7cd13902022-07-13 16:59:25 +01001107}
1108
Lawrence Tang71570a22022-07-14 11:45:28 +01001109//Converts a single ARM cache/TLB error information structure into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001110void ir_arm_error_cache_tlb_info_to_cper(
1111 json_object *error_information,
1112 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
Lawrence Tang71570a22022-07-14 11:45:28 +01001113{
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001114 // //Validation bits.
1115 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1116 struct json_object *obj = NULL;
Lawrence Tang71570a22022-07-14 11:45:28 +01001117
Lawrence Tange407b4c2022-07-21 13:54:01 +01001118 //Miscellaneous value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001119 if (json_object_object_get_ex(error_information, "transactionType",
1120 &obj)) {
1121 error_info_cper->TransactionType =
1122 readable_pair_to_integer(obj);
1123 add_to_valid_bitfield(&ui64Type, 0);
1124 }
1125 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1126 error_info_cper->Operation = readable_pair_to_integer(obj);
1127 add_to_valid_bitfield(&ui64Type, 1);
1128 }
1129 if (json_object_object_get_ex(error_information, "level", &obj)) {
1130 error_info_cper->Level = json_object_get_uint64(obj);
1131 add_to_valid_bitfield(&ui64Type, 2);
1132 }
1133 if (json_object_object_get_ex(error_information,
1134 "processorContextCorrupt", &obj)) {
1135 error_info_cper->ProcessorContextCorrupt =
1136 json_object_get_boolean(obj);
1137 add_to_valid_bitfield(&ui64Type, 3);
1138 }
1139 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1140 error_info_cper->Corrected = json_object_get_boolean(obj);
1141 add_to_valid_bitfield(&ui64Type, 4);
1142 }
1143 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1144 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1145 add_to_valid_bitfield(&ui64Type, 5);
1146 }
1147 if (json_object_object_get_ex(error_information, "restartablePC",
1148 &obj)) {
1149 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1150 add_to_valid_bitfield(&ui64Type, 6);
1151 }
Lawrence Tange407b4c2022-07-21 13:54:01 +01001152 error_info_cper->Reserved = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001153 error_info_cper->ValidationBits = ui64Type.value.ui64;
Lawrence Tang71570a22022-07-14 11:45:28 +01001154}
1155
1156//Converts a single ARM bus error information structure into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001157void ir_arm_error_bus_info_to_cper(json_object *error_information,
1158 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
Lawrence Tang71570a22022-07-14 11:45:28 +01001159{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001160 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001161 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1162 struct json_object *obj = NULL;
1163
1164 memset(error_info_cper, 0, sizeof(EFI_ARM_BUS_ERROR_STRUCTURE));
Lawrence Tang71570a22022-07-14 11:45:28 +01001165
Lawrence Tange407b4c2022-07-21 13:54:01 +01001166 //Miscellaneous value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001167 if (json_object_object_get_ex(error_information, "transactionType",
1168 &obj)) {
1169 error_info_cper->TransactionType =
1170 readable_pair_to_integer(obj);
1171 add_to_valid_bitfield(&ui64Type, 0);
1172 } else {
1173 error_info_cper->TransactionType = 0;
1174 }
1175 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1176 error_info_cper->Operation = readable_pair_to_integer(obj);
1177 add_to_valid_bitfield(&ui64Type, 1);
1178 } else {
1179 error_info_cper->Operation = 0;
1180 }
1181 if (json_object_object_get_ex(error_information, "level", &obj)) {
1182 error_info_cper->Level = json_object_get_uint64(obj);
1183 add_to_valid_bitfield(&ui64Type, 2);
1184 } else {
1185 error_info_cper->Level = 0;
1186 }
1187 if (json_object_object_get_ex(error_information,
1188 "processorContextCorrupt", &obj)) {
1189 error_info_cper->ProcessorContextCorrupt =
1190 json_object_get_boolean(obj);
1191 add_to_valid_bitfield(&ui64Type, 3);
1192 } else {
1193 error_info_cper->ProcessorContextCorrupt = 0;
1194 }
1195 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1196 error_info_cper->Corrected = json_object_get_boolean(obj);
1197 add_to_valid_bitfield(&ui64Type, 4);
1198 } else {
1199 error_info_cper->Corrected = 0;
1200 }
1201 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1202 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1203 add_to_valid_bitfield(&ui64Type, 5);
1204 } else {
1205 error_info_cper->PrecisePC = 0;
1206 }
1207 if (json_object_object_get_ex(error_information, "restartablePC",
1208 &obj)) {
1209 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1210 add_to_valid_bitfield(&ui64Type, 6);
1211 } else {
1212 error_info_cper->RestartablePC = 0;
1213 }
1214 if (json_object_object_get_ex(error_information, "participationType",
1215 &obj)) {
1216 error_info_cper->ParticipationType =
1217 readable_pair_to_integer(obj);
1218 add_to_valid_bitfield(&ui64Type, 7);
1219 } else {
1220 error_info_cper->ParticipationType = 0;
1221 }
1222 if (json_object_object_get_ex(error_information, "timedOut", &obj)) {
1223 error_info_cper->TimeOut = json_object_get_boolean(obj);
1224 add_to_valid_bitfield(&ui64Type, 8);
1225 } else {
1226 error_info_cper->TimeOut = 0;
1227 }
1228 if (json_object_object_get_ex(error_information, "addressSpace",
1229 &obj)) {
1230 error_info_cper->AddressSpace = readable_pair_to_integer(obj);
1231 add_to_valid_bitfield(&ui64Type, 9);
1232 } else {
1233 error_info_cper->AddressSpace = 0;
1234 }
1235 if (json_object_object_get_ex(error_information, "accessMode", &obj)) {
1236 error_info_cper->AccessMode = readable_pair_to_integer(obj);
1237 add_to_valid_bitfield(&ui64Type, 11);
1238 } else {
1239 error_info_cper->AccessMode = 0;
1240 }
1241 if (json_object_object_get_ex(error_information, "memoryAttributes",
1242 &obj)) {
1243 error_info_cper->MemoryAddressAttributes =
1244 json_object_get_uint64(obj);
1245 add_to_valid_bitfield(&ui64Type, 10);
1246 } else {
1247 error_info_cper->MemoryAddressAttributes = 0;
1248 }
Lawrence Tange407b4c2022-07-21 13:54:01 +01001249 error_info_cper->Reserved = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001250 error_info_cper->ValidationBits = ui64Type.value.ui64;
Lawrence Tang71570a22022-07-14 11:45:28 +01001251}
1252
Lawrence Tang7cd13902022-07-13 16:59:25 +01001253//Converts a single ARM context information structure into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001254void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +01001255{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001256 EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
Lawrence Tang7cd13902022-07-13 16:59:25 +01001257
Lawrence Tange407b4c2022-07-21 13:54:01 +01001258 //Version, array size, context type.
1259 info_header.Version = json_object_get_int(
1260 json_object_object_get(context_info, "version"));
1261 info_header.RegisterArraySize = json_object_get_int(
1262 json_object_object_get(context_info, "registerArraySize"));
1263 info_header.RegisterContextType = readable_pair_to_integer(
1264 json_object_object_get(context_info, "registerContextType"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001265
Lawrence Tange407b4c2022-07-21 13:54:01 +01001266 //Flush to stream, write the register array itself.
1267 fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
1268 out);
1269 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001270
Lawrence Tange407b4c2022-07-21 13:54:01 +01001271 json_object *register_array =
1272 json_object_object_get(context_info, "registerArray");
1273 switch (info_header.RegisterContextType) {
1274 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
1275 ir_arm_aarch32_gpr_to_cper(register_array, out);
1276 break;
1277 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
1278 ir_arm_aarch32_el1_to_cper(register_array, out);
1279 break;
1280 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
1281 ir_arm_aarch32_el2_to_cper(register_array, out);
1282 break;
1283 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
1284 ir_arm_aarch32_secure_to_cper(register_array, out);
1285 break;
1286 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
1287 ir_arm_aarch64_gpr_to_cper(register_array, out);
1288 break;
1289 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
1290 ir_arm_aarch64_el1_to_cper(register_array, out);
1291 break;
1292 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
1293 ir_arm_aarch64_el2_to_cper(register_array, out);
1294 break;
1295 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
1296 ir_arm_aarch64_el3_to_cper(register_array, out);
1297 break;
1298 case EFI_ARM_CONTEXT_TYPE_MISC:
1299 ir_arm_misc_registers_to_cper(register_array, out);
1300 break;
1301 default:
1302 //Unknown register structure.
John Chungf8fc7052024-05-03 20:05:29 +08001303 ir_arm_unknown_register_to_cper(register_array, out);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001304 break;
1305 }
Lawrence Tang71570a22022-07-14 11:45:28 +01001306}
1307
1308//Converts a single AARCH32 GPR CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001309void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001310{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001311 //Get uniform register array.
1312 EFI_ARM_V8_AARCH32_GPR reg_array;
1313 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1314 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
1315 ARM_AARCH32_GPR_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001316
Lawrence Tange407b4c2022-07-21 13:54:01 +01001317 //Flush to stream.
1318 fwrite(&reg_array, sizeof(reg_array), 1, out);
1319 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001320}
1321
1322//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 +01001323void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001324{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001325 //Get uniform register array.
1326 EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
1327 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1328 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
1329 sizeof(UINT32),
1330 ARM_AARCH32_EL1_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001331
Lawrence Tange407b4c2022-07-21 13:54:01 +01001332 //Flush to stream.
1333 fwrite(&reg_array, sizeof(reg_array), 1, out);
1334 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001335}
1336
1337//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 +01001338void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001339{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001340 //Get uniform register array.
1341 EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
1342 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1343 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
1344 sizeof(UINT32),
1345 ARM_AARCH32_EL2_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001346
Lawrence Tange407b4c2022-07-21 13:54:01 +01001347 //Flush to stream.
1348 fwrite(&reg_array, sizeof(reg_array), 1, out);
1349 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001350}
1351
1352//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 +01001353void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001354{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001355 //Get uniform register array.
1356 EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
1357 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1358 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
1359 sizeof(UINT32),
1360 ARM_AARCH32_SECURE_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001361
Lawrence Tange407b4c2022-07-21 13:54:01 +01001362 //Flush to stream.
1363 fwrite(&reg_array, sizeof(reg_array), 1, out);
1364 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001365}
1366
1367//Converts a single AARCH64 GPR CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001368void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001369{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001370 //Get uniform register array.
1371 EFI_ARM_V8_AARCH64_GPR reg_array;
1372 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1373 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
1374 ARM_AARCH64_GPR_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001375
Lawrence Tange407b4c2022-07-21 13:54:01 +01001376 //Flush to stream.
1377 fwrite(&reg_array, sizeof(reg_array), 1, out);
1378 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001379}
1380
1381//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 +01001382void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001383{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001384 //Get uniform register array.
1385 EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
1386 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1387 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
1388 sizeof(UINT64),
1389 ARM_AARCH64_EL1_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001390
Lawrence Tange407b4c2022-07-21 13:54:01 +01001391 //Flush to stream.
1392 fwrite(&reg_array, sizeof(reg_array), 1, out);
1393 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001394}
1395
1396//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 +01001397void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001398{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001399 //Get uniform register array.
1400 EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
1401 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1402 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
1403 sizeof(UINT64),
1404 ARM_AARCH64_EL2_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001405
Lawrence Tange407b4c2022-07-21 13:54:01 +01001406 //Flush to stream.
1407 fwrite(&reg_array, sizeof(reg_array), 1, out);
1408 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001409}
1410
1411//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 +01001412void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001413{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001414 //Get uniform register array.
1415 EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
1416 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1417 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
1418 sizeof(UINT64),
1419 ARM_AARCH64_EL3_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001420
Lawrence Tange407b4c2022-07-21 13:54:01 +01001421 //Flush to stream.
1422 fwrite(&reg_array, sizeof(reg_array), 1, out);
1423 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001424}
1425
1426//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 +01001427void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001428{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001429 EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
Lawrence Tang71570a22022-07-14 11:45:28 +01001430
Lawrence Tange407b4c2022-07-21 13:54:01 +01001431 //MRS encoding information.
1432 json_object *mrs_encoding =
1433 json_object_object_get(registers, "mrsEncoding");
1434 reg_array.MrsOp2 = json_object_get_uint64(
1435 json_object_object_get(mrs_encoding, "op2"));
1436 reg_array.MrsCrm = json_object_get_uint64(
1437 json_object_object_get(mrs_encoding, "crm"));
1438 reg_array.MrsCrn = json_object_get_uint64(
1439 json_object_object_get(mrs_encoding, "crn"));
1440 reg_array.MrsOp1 = json_object_get_uint64(
1441 json_object_object_get(mrs_encoding, "op1"));
1442 reg_array.MrsO0 = json_object_get_uint64(
1443 json_object_object_get(mrs_encoding, "o0"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001444
Lawrence Tange407b4c2022-07-21 13:54:01 +01001445 //Actual register value.
1446 reg_array.Value = json_object_get_uint64(
1447 json_object_object_get(registers, "value"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001448
Lawrence Tange407b4c2022-07-21 13:54:01 +01001449 //Flush to stream.
1450 fwrite(&reg_array, sizeof(reg_array), 1, out);
1451 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001452}
1453
1454//Converts a single ARM unknown register CPER-JSON object to CPER binary, outputting to the given stream.
John Chungf8fc7052024-05-03 20:05:29 +08001455void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001456{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001457 //Get base64 represented data.
1458 json_object *encoded = json_object_object_get(registers, "data");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -07001459
1460 int32_t decoded_len = 0;
1461
1462 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
1463 json_object_get_string_len(encoded),
1464 &decoded_len);
1465
1466 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -07001467 cper_print_log("Failed to allocate decode output buffer. \n");
John Chungf8fc7052024-05-03 20:05:29 +08001468 } else {
John Chungf8fc7052024-05-03 20:05:29 +08001469 //Flush out to stream.
1470 fwrite(&decoded, decoded_len, 1, out);
1471 fflush(out);
1472 free(decoded);
1473 }
1474}