blob: a1e9a2d8cfe5c97aadc6034cb37206cd415be5e5 [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,
Aushim Nagarkatti9147b632025-07-09 09:38:23 -0700184 SECTION_DESC_STRING_SIZE -
185 strlen(*desc_string) - 1);
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700186 } else {
187 cper_print_log(
188 "Error: Error info description string too long, not added to description string: %s\n",
189 err_info_desc_i);
190 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100191 cur_error++;
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700192 if (i == record->ErrInfoNum - 1) {
193 if (strlen(*desc_string) + 2 <
194 SECTION_DESC_STRING_SIZE) {
195 strncat(*desc_string, "}", 2);
196 } else {
197 cper_print_log(
198 "Error: Description string too long, not added '}'to description string: %s\n",
199 *desc_string);
200 }
201 break;
202 }
203 if (strlen(*desc_string) + 3 < SECTION_DESC_STRING_SIZE) {
204 strncat(*desc_string, ", ", 3);
205 } else {
206 cper_print_log(
207 "Error: Description string too long, not added ',' to description string: %s\n",
208 *desc_string);
209 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100210 }
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700211 free(err_info_desc_i);
Ed Tanous5e2164a2025-03-09 09:20:44 -0700212
213 cur_pos += (UINT32)(record->ErrInfoNum *
214 sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
215 remaining_size -= (UINT32)(record->ErrInfoNum *
216 sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY));
217
Lawrence Tange407b4c2022-07-21 13:54:01 +0100218 json_object_object_add(section_ir, "errorInfo", error_info_array);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100219
Lawrence Tange407b4c2022-07-21 13:54:01 +0100220 //Processor context structures.
221 //The current position is moved within the processing, as it is a dynamic size structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100222 json_object *context_info_array = json_object_new_array();
223 for (int i = 0; i < record->ContextInfoNum; i++) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700224 if (remaining_size <
225 sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER)) {
226 json_object_put(context_info_array);
227 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700228 cper_print_log(
229 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700230 return NULL;
231 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100232 EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
233 (EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700234
235 cur_pos += sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
236 remaining_size -= sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100237 json_object *processor_context =
Ed Tanous5e2164a2025-03-09 09:20:44 -0700238 cper_arm_processor_context_to_ir(header, &cur_pos,
239 &remaining_size);
240 if (processor_context == NULL) {
241 json_object_put(context_info_array);
242 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700243 cper_print_log(
244 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700245 return NULL;
246 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100247 json_object_array_add(context_info_array, processor_context);
248 }
249 json_object_object_add(section_ir, "contextInfo", context_info_array);
Lawrence Tangd7e8ca32022-07-07 10:25:53 +0100250
Lawrence Tange407b4c2022-07-21 13:54:01 +0100251 //Is there any vendor-specific information following?
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800252 if (isvalid_prop_to_ir(&ui64Type, 3)) {
253 if (cur_pos < (uint8_t *)section + record->SectionLength) {
254 json_object *vendor_specific = json_object_new_object();
255 size_t input_size = (uint8_t *)section +
256 record->SectionLength - cur_pos;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700257 if (remaining_size < input_size) {
258 json_object_put(vendor_specific);
259 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700260 cper_print_log(
261 "Invalid CPER file: Invalid vendor-specific info length.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700262 return NULL;
263 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800264 int32_t encoded_len = 0;
265 char *encoded = base64_encode(cur_pos, input_size,
266 &encoded_len);
267 if (encoded == NULL) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700268 json_object_put(vendor_specific);
269 json_object_put(section_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700270 cper_print_log(
271 "base64 encode of vendorSpecificInfo failed\n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800272 return NULL;
273 }
274 json_object_object_add(vendor_specific, "data",
275 json_object_new_string_len(
276 encoded, encoded_len));
277 free(encoded);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700278
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800279 json_object_object_add(section_ir, "vendorSpecificInfo",
280 vendor_specific);
281 } else {
Ed Tanous50b966f2025-03-11 09:06:19 -0700282 cper_print_log(
283 "vendorSpecificInfo is marked valid but not present in binary\n");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800284 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100285 }
286
287 return section_ir;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100288}
289
290//Converts a single ARM Process Error Information structure into JSON IR.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100291json_object *
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700292cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info,
293 char **err_info_desc_i)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100294{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100295 json_object *error_info_ir = json_object_new_object();
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700296 int outstr_len = 0;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100297
Lawrence Tange407b4c2022-07-21 13:54:01 +0100298 //Version, length.
299 json_object_object_add(error_info_ir, "version",
300 json_object_new_int(error_info->Version));
301 json_object_object_add(error_info_ir, "length",
302 json_object_new_int(error_info->Length));
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100303
Lawrence Tange407b4c2022-07-21 13:54:01 +0100304 //Validation bitfield.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800305 ValidationTypes ui16Type = { UINT_16T,
306 .value.ui16 = error_info->ValidationBits };
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100307
Lawrence Tange407b4c2022-07-21 13:54:01 +0100308 //The type of error information in this log.
309 json_object *error_type = integer_to_readable_pair(
310 error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
311 ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
312 json_object_object_add(error_info_ir, "errorType", error_type);
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100313
Lawrence Tange407b4c2022-07-21 13:54:01 +0100314 //Multiple error count.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800315 if (isvalid_prop_to_ir(&ui16Type, 0)) {
316 json_object *multiple_error = json_object_new_object();
317 json_object_object_add(
318 multiple_error, "value",
319 json_object_new_int(error_info->MultipleError));
320 json_object_object_add(
321 multiple_error, "type",
322 json_object_new_string(error_info->MultipleError < 1 ?
323 "Single Error" :
324 "Multiple Errors"));
325 json_object_object_add(error_info_ir, "multipleError",
326 multiple_error);
327 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100328
Lawrence Tange407b4c2022-07-21 13:54:01 +0100329 //Flags.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800330 if (isvalid_prop_to_ir(&ui16Type, 1)) {
331 json_object *flags = bitfield_to_ir(
332 error_info->Flags, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
333 json_object_object_add(error_info_ir, "flags", flags);
334 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100335
Lawrence Tange407b4c2022-07-21 13:54:01 +0100336 //Error information, split by type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800337 if (isvalid_prop_to_ir(&ui16Type, 2)) {
338 json_object *error_subinfo = NULL;
339 switch (error_info->Type) {
340 case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800341 error_subinfo = cper_arm_cache_tlb_error_to_ir(
342 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
343 ->ErrorInformation,
344 error_info);
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700345 const char *cache_error_desc = "Cache Error";
346 if (strlen(cache_error_desc) >=
347 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
348 cper_print_log(
349 "Error: Cache Error Description too long %s\n",
350 cache_error_desc);
351 } else {
352 strncpy(*err_info_desc_i, cache_error_desc,
353 strlen(cache_error_desc) + 1);
354 }
355 break;
356 case ARM_ERROR_INFORMATION_TYPE_TLB: //TLB
357 error_subinfo = cper_arm_cache_tlb_error_to_ir(
358 (EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
359 ->ErrorInformation,
360 error_info);
361 const char *tlb_error_desc = "TLB Error";
362 if (strlen(tlb_error_desc) >=
363 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
364 cper_print_log(
365 "Error: TLB Error Description too long %s\n",
366 tlb_error_desc);
367 } else {
368 strncpy(*err_info_desc_i, tlb_error_desc,
369 strlen(tlb_error_desc) + 1);
370 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800371 break;
372 case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
373 error_subinfo = cper_arm_bus_error_to_ir(
374 (EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
375 ->ErrorInformation);
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700376 const char *bus_error_desc = "Bus Error";
377 if (strlen(bus_error_desc) >=
378 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
379 cper_print_log(
380 "Error: Bus Error Description too long %s\n",
381 bus_error_desc);
382 } else {
383 strncpy(*err_info_desc_i, bus_error_desc,
384 strlen(bus_error_desc) + 1);
385 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800386 break;
Lawrence Tang71570a22022-07-14 11:45:28 +0100387
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800388 default:
389 //Unknown/microarch, will not support.
390 break;
391 }
Ed Tanousd6b62632025-03-14 15:30:07 -0700392 if (error_subinfo != NULL) {
393 json_object_object_add(error_info_ir,
394 "errorInformation",
395 error_subinfo);
396 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100397 }
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100398
Lawrence Tange407b4c2022-07-21 13:54:01 +0100399 //Virtual fault address, physical fault address.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700400 char *fault_address_desc = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800401 if (isvalid_prop_to_ir(&ui16Type, 3)) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700402 outstr_len = snprintf(fault_address_desc,
403 EFI_ERROR_DESCRIPTION_STRING_LEN,
404 " at Virtual Addr=0x%llX",
405 error_info->VirtualFaultAddress);
406 if (outstr_len < 0) {
407 cper_print_log(
408 "Error: Could not write to fault address description string\n");
409 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
410 cper_print_log(
411 "Error: Virtual fault address description string truncated: %s\n",
412 fault_address_desc);
413 } else {
414 if (strlen(fault_address_desc) +
415 strlen(*err_info_desc_i) <
416 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
417 strncat(*err_info_desc_i, fault_address_desc,
418 outstr_len);
419 } else {
420 cper_print_log(
421 "Error: Virtual fault address description string too long, not added to description string: %s\n",
422 fault_address_desc);
423 }
424 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800425 json_object_object_add(
426 error_info_ir, "virtualFaultAddress",
427 json_object_new_uint64(
428 error_info->VirtualFaultAddress));
429 }
430 if (isvalid_prop_to_ir(&ui16Type, 4)) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700431 outstr_len = snprintf(fault_address_desc,
432 EFI_ERROR_DESCRIPTION_STRING_LEN,
433 " Physical Addr=0x%llX",
434 error_info->PhysicalFaultAddress);
435 if (outstr_len < 0) {
436 cper_print_log(
437 "Error: Could not write to physical fault address description string\n");
438 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) {
439 cper_print_log(
440 "Error: Physical fault address description string truncated: %s\n",
441 fault_address_desc);
442 } else {
443 if (strlen(fault_address_desc) +
444 strlen(*err_info_desc_i) <
445 EFI_ERROR_INFORMATION_DESCRIPTION_STRING_LEN) {
446 strncat(*err_info_desc_i, fault_address_desc,
447 outstr_len);
448 } else {
449 cper_print_log(
450 "Error:Physical fault address description string too long, not added to description string: %s\n",
451 fault_address_desc);
452 }
453 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800454 json_object_object_add(
455 error_info_ir, "physicalFaultAddress",
456 json_object_new_uint64(
457 error_info->PhysicalFaultAddress));
458 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100459
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700460 free(fault_address_desc);
461
Lawrence Tange407b4c2022-07-21 13:54:01 +0100462 return error_info_ir;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100463}
464
Lawrence Tang7f21db62022-07-06 11:09:39 +0100465//Converts a single ARM cache/TLB error information structure into JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100466json_object *
467cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
468 EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100469{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100470 json_object *cache_tlb_error_ir = json_object_new_object();
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700471 json_object *cache_tlb_prop = json_object_new_object();
472 char *cache_tlb_propname;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100473
Lawrence Tange407b4c2022-07-21 13:54:01 +0100474 //Validation bitfield.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800475 ValidationTypes ui64Type = {
476 UINT_64T, .value.ui64 = cache_tlb_error->ValidationBits
477 };
Lawrence Tang7f21db62022-07-06 11:09:39 +0100478
Lawrence Tange407b4c2022-07-21 13:54:01 +0100479 //Transaction type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800480 if (isvalid_prop_to_ir(&ui64Type, 0)) {
481 json_object *transaction_type = integer_to_readable_pair(
482 cache_tlb_error->TransactionType, 3,
483 ARM_ERROR_TRANSACTION_TYPES_KEYS,
484 ARM_ERROR_TRANSACTION_TYPES_VALUES,
485 "Unknown (Reserved)");
486 json_object_object_add(cache_tlb_error_ir, "transactionType",
487 transaction_type);
488 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100489
Lawrence Tange407b4c2022-07-21 13:54:01 +0100490 //Operation.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800491 bool cacheErrorFlag = 1;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100492 if (error_info->Type == 0) {
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700493 cache_tlb_propname = "cacheError";
Lawrence Tange407b4c2022-07-21 13:54:01 +0100494 } else {
495 //TLB operation.
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700496 cache_tlb_propname = "tlbError";
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800497 cacheErrorFlag = 0;
Lawrence Tange407b4c2022-07-21 13:54:01 +0100498 }
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800499
500 if (isvalid_prop_to_ir(&ui64Type, 1)) {
501 json_object *operation;
502
503 if (cacheErrorFlag) {
504 //Cache operation.
505 operation = integer_to_readable_pair(
506 cache_tlb_error->Operation, 11,
507 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
508 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
509 "Unknown (Reserved)");
510 } else {
511 operation = integer_to_readable_pair(
512 cache_tlb_error->Operation, 9,
513 ARM_TLB_OPERATION_TYPES_KEYS,
514 ARM_TLB_OPERATION_TYPES_VALUES,
515 "Unknown (Reserved)");
516 }
517 json_object_object_add(cache_tlb_error_ir, "operation",
518 operation);
519 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100520
Lawrence Tange407b4c2022-07-21 13:54:01 +0100521 //Miscellaneous remaining fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800522 if (isvalid_prop_to_ir(&ui64Type, 2)) {
523 json_object_object_add(
524 cache_tlb_error_ir, "level",
525 json_object_new_int(cache_tlb_error->Level));
526 }
527 if (isvalid_prop_to_ir(&ui64Type, 3)) {
528 json_object_object_add(
529 cache_tlb_error_ir, "processorContextCorrupt",
530 json_object_new_boolean(
531 cache_tlb_error->ProcessorContextCorrupt));
532 }
533 if (isvalid_prop_to_ir(&ui64Type, 4)) {
534 json_object_object_add(
535 cache_tlb_error_ir, "corrected",
536 json_object_new_boolean(cache_tlb_error->Corrected));
537 }
538 if (isvalid_prop_to_ir(&ui64Type, 5)) {
539 json_object_object_add(
540 cache_tlb_error_ir, "precisePC",
541 json_object_new_boolean(cache_tlb_error->PrecisePC));
542 }
543 if (isvalid_prop_to_ir(&ui64Type, 6)) {
544 json_object_object_add(cache_tlb_error_ir, "restartablePC",
545 json_object_new_boolean(
546 cache_tlb_error->RestartablePC));
547 }
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700548
549 json_object_object_add(cache_tlb_prop, cache_tlb_propname,
550 cache_tlb_error_ir);
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800551
Aushim Nagarkatti5b793002024-09-26 17:07:30 -0700552 return cache_tlb_prop;
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100553}
554
555//Converts a single ARM bus error information structure into JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100556json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
Lawrence Tang3d0e4f22022-07-05 17:17:41 +0100557{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100558 json_object *bus_error_ir = json_object_new_object();
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800559 json_object *bus_prop = json_object_new_object();
560 char *bus_propname = "busError";
Lawrence Tang7f21db62022-07-06 11:09:39 +0100561
Lawrence Tange407b4c2022-07-21 13:54:01 +0100562 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800563 ValidationTypes ui64Type = { UINT_64T,
564 .value.ui64 = bus_error->ValidationBits };
Lawrence Tang7f21db62022-07-06 11:09:39 +0100565
Lawrence Tange407b4c2022-07-21 13:54:01 +0100566 //Transaction type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800567 if (isvalid_prop_to_ir(&ui64Type, 0)) {
568 json_object *transaction_type = integer_to_readable_pair(
569 bus_error->TransactionType, 3,
570 ARM_ERROR_TRANSACTION_TYPES_KEYS,
571 ARM_ERROR_TRANSACTION_TYPES_VALUES,
572 "Unknown (Reserved)");
573 json_object_object_add(bus_error_ir, "transactionType",
574 transaction_type);
575 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100576
Lawrence Tange407b4c2022-07-21 13:54:01 +0100577 //Operation.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800578 if (isvalid_prop_to_ir(&ui64Type, 1)) {
579 json_object *operation = integer_to_readable_pair(
580 bus_error->Operation, 7,
581 ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
582 ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
583 "Unknown (Reserved)");
584 json_object_object_add(bus_error_ir, "operation", operation);
585 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100586
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800587 if (isvalid_prop_to_ir(&ui64Type, 2)) {
588 //Affinity level of bus error, + miscellaneous fields.
589 json_object_object_add(bus_error_ir, "level",
590 json_object_new_int(bus_error->Level));
591 }
592 if (isvalid_prop_to_ir(&ui64Type, 3)) {
593 json_object_object_add(
594 bus_error_ir, "processorContextCorrupt",
595 json_object_new_boolean(
596 bus_error->ProcessorContextCorrupt));
597 }
598 if (isvalid_prop_to_ir(&ui64Type, 4)) {
599 json_object_object_add(
600 bus_error_ir, "corrected",
601 json_object_new_boolean(bus_error->Corrected));
602 }
603 if (isvalid_prop_to_ir(&ui64Type, 5)) {
604 json_object_object_add(
605 bus_error_ir, "precisePC",
606 json_object_new_boolean(bus_error->PrecisePC));
607 }
608 if (isvalid_prop_to_ir(&ui64Type, 6)) {
609 json_object_object_add(
610 bus_error_ir, "restartablePC",
611 json_object_new_boolean(bus_error->RestartablePC));
612 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100613
Lawrence Tange407b4c2022-07-21 13:54:01 +0100614 //Participation type.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800615 if (isvalid_prop_to_ir(&ui64Type, 7)) {
616 json_object *participation_type = integer_to_readable_pair(
617 bus_error->ParticipationType, 4,
618 ARM_BUS_PARTICIPATION_TYPES_KEYS,
619 ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
620 json_object_object_add(bus_error_ir, "participationType",
621 participation_type);
622 }
623 if (isvalid_prop_to_ir(&ui64Type, 8)) {
624 json_object_object_add(
625 bus_error_ir, "timedOut",
626 json_object_new_boolean(bus_error->TimeOut));
627 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100628
Lawrence Tange407b4c2022-07-21 13:54:01 +0100629 //Address space.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800630 if (isvalid_prop_to_ir(&ui64Type, 9)) {
631 json_object *address_space = integer_to_readable_pair(
632 bus_error->AddressSpace, 3,
633 ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
634 ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
635 json_object_object_add(bus_error_ir, "addressSpace",
636 address_space);
637 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100638
Lawrence Tange407b4c2022-07-21 13:54:01 +0100639 //Memory access attributes.
640 //todo: find the specification of these in the ARM ARM
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800641 if (isvalid_prop_to_ir(&ui64Type, 10)) {
642 json_object_object_add(
643 bus_error_ir, "memoryAttributes",
644 json_object_new_int(
645 bus_error->MemoryAddressAttributes));
646 }
Lawrence Tang7f21db62022-07-06 11:09:39 +0100647
Lawrence Tange407b4c2022-07-21 13:54:01 +0100648 //Access Mode
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800649 if (isvalid_prop_to_ir(&ui64Type, 8)) {
650 json_object *access_mode = json_object_new_object();
651 json_object_object_add(
652 access_mode, "value",
653 json_object_new_int(bus_error->AccessMode));
654 json_object_object_add(
655 access_mode, "name",
656 json_object_new_string(bus_error->AccessMode == 0 ?
657 "Secure" :
658 "Normal"));
659 json_object_object_add(bus_error_ir, "accessMode", access_mode);
660 }
661 json_object_object_add(bus_prop, bus_propname, bus_error_ir);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100662
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800663 return bus_prop;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100664}
665
666//Converts a single ARM processor context block into JSON IR.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100667json_object *
668cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
Ed Tanous5e2164a2025-03-09 09:20:44 -0700669 const UINT8 **cur_pos, UINT32 *remaining_size)
Lawrence Tang7f21db62022-07-06 11:09:39 +0100670{
Ed Tanous5e2164a2025-03-09 09:20:44 -0700671 if (header->RegisterArraySize > *remaining_size) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700672 cper_print_log(
673 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700674 return NULL;
675 }
676
Lawrence Tange407b4c2022-07-21 13:54:01 +0100677 json_object *context_ir = json_object_new_object();
Lawrence Tang7f21db62022-07-06 11:09:39 +0100678
Lawrence Tange407b4c2022-07-21 13:54:01 +0100679 //Version.
680 json_object_object_add(context_ir, "version",
681 json_object_new_int(header->Version));
Lawrence Tang71570a22022-07-14 11:45:28 +0100682
Lawrence Tange407b4c2022-07-21 13:54:01 +0100683 //Add the context type.
684 json_object *context_type = integer_to_readable_pair(
Ed Tanous5e2164a2025-03-09 09:20:44 -0700685 header->RegisterContextType,
686 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_COUNT,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100687 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
688 ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
689 "Unknown (Reserved)");
690 json_object_object_add(context_ir, "registerContextType", context_type);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100691
Lawrence Tange407b4c2022-07-21 13:54:01 +0100692 //Register array size (bytes).
693 json_object_object_add(
694 context_ir, "registerArraySize",
695 json_object_new_uint64(header->RegisterArraySize));
Lawrence Tang7f21db62022-07-06 11:09:39 +0100696
Lawrence Tange407b4c2022-07-21 13:54:01 +0100697 //The register array itself.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100698 json_object *register_array = NULL;
699 switch (header->RegisterContextType) {
700 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700701 if (*remaining_size < sizeof(EFI_ARM_V8_AARCH32_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700702 cper_print_log(
703 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700704 goto fail;
705 }
706 if (header->RegisterArraySize <
707 sizeof(EFI_ARM_V8_AARCH32_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700708 cper_print_log(
709 "Invalid CPER file: Not enough bytes for aarch32 gpr\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700710 goto fail;
711 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100712 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800713 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100714 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
715 ARM_AARCH32_GPR_NAMES);
716 break;
717 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700718 if (*remaining_size <
719 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700720 cper_print_log(
721 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700722 goto fail;
723 }
724 if (header->RegisterArraySize <
725 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700726 cper_print_log(
727 "Invalid CPER file: Not enough bytes for aarch32 el1\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700728 goto fail;
729 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100730 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800731 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100732 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
733 sizeof(UINT32),
734 ARM_AARCH32_EL1_REGISTER_NAMES);
735 break;
736 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700737 if (*remaining_size <
738 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700739 cper_print_log(
740 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700741 goto fail;
742 }
743 if (header->RegisterArraySize <
744 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700745 cper_print_log(
746 "Invalid CPER file: Not enough bytes for aarch32 el2\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700747 goto fail;
748 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100749 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800750 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100751 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
752 sizeof(UINT32),
753 ARM_AARCH32_EL2_REGISTER_NAMES);
Ed Tanous5e2164a2025-03-09 09:20:44 -0700754
Lawrence Tange407b4c2022-07-21 13:54:01 +0100755 break;
756 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700757 if (*remaining_size <
758 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
759 json_object_put(context_ir);
Ed Tanous50b966f2025-03-11 09:06:19 -0700760 cper_print_log(
761 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700762 return NULL;
763 }
764 if (header->RegisterArraySize <
765 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700766 cper_print_log(
767 "Invalid CPER file: Not enough bytes for aarch32 secure\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700768 goto fail;
769 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100770 register_array = uniform_struct_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800771 (UINT32 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100772 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
773 sizeof(UINT32),
774 ARM_AARCH32_SECURE_REGISTER_NAMES);
775 break;
776 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700777 if (*remaining_size < sizeof(EFI_ARM_V8_AARCH64_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700778 cper_print_log(
779 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700780 goto fail;
781 }
782 if (header->RegisterArraySize <
783 sizeof(EFI_ARM_V8_AARCH64_GPR)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700784 cper_print_log(
785 "Invalid CPER file: Not enough bytes for aarch64 gpr\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700786 goto fail;
787 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100788 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800789 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100790 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
791 ARM_AARCH64_GPR_NAMES);
792 break;
793 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700794 if (*remaining_size <
795 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700796 cper_print_log(
797 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700798 goto fail;
799 }
800 if (header->RegisterArraySize <
801 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700802 cper_print_log(
803 "Invalid CPER file: Not enough bytes for aarch64 el1\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700804 goto fail;
805 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100806 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800807 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100808 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
809 sizeof(UINT64),
810 ARM_AARCH64_EL1_REGISTER_NAMES);
811 break;
812 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700813 if (*remaining_size <
814 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700815 cper_print_log(
816 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700817 goto fail;
818 }
819 if (header->RegisterArraySize <
820 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700821 cper_print_log(
822 "Invalid CPER file: Not enough bytes for aarch64 el2\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700823 goto fail;
824 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100825 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800826 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100827 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
828 sizeof(UINT64),
829 ARM_AARCH64_EL2_REGISTER_NAMES);
830 break;
831 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700832 if (*remaining_size <
833 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700834 cper_print_log(
835 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700836 goto fail;
837 }
838 if (header->RegisterArraySize <
839 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700840 cper_print_log(
841 "Invalid CPER file: Not enough bytes for aarch64 el3\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700842 goto fail;
843 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100844 register_array = uniform_struct64_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800845 (UINT64 *)*cur_pos,
Lawrence Tange407b4c2022-07-21 13:54:01 +0100846 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
847 sizeof(UINT64),
848 ARM_AARCH64_EL3_REGISTER_NAMES);
849 break;
850 case EFI_ARM_CONTEXT_TYPE_MISC:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700851 if (*remaining_size < sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700852 cper_print_log(
853 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700854 goto fail;
855 }
856 if (header->RegisterArraySize <
857 sizeof(EFI_ARM_MISC_CONTEXT_REGISTER)) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700858 cper_print_log(
859 "Invalid CPER file: Not enough bytes for misc\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700860 goto fail;
861 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100862 register_array = cper_arm_misc_register_array_to_ir(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800863 (EFI_ARM_MISC_CONTEXT_REGISTER *)*cur_pos);
Lawrence Tange407b4c2022-07-21 13:54:01 +0100864 break;
865 default:
Ed Tanous5e2164a2025-03-09 09:20:44 -0700866 if (*remaining_size < header->RegisterArraySize) {
Ed Tanous50b966f2025-03-11 09:06:19 -0700867 cper_print_log(
868 "Invalid CPER file: Invalid processor context info num.\n");
Ed Tanous5e2164a2025-03-09 09:20:44 -0700869 goto fail;
870 }
Lawrence Tange407b4c2022-07-21 13:54:01 +0100871 //Unknown register array type, add as base64 data instead.
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700872 int32_t encoded_len = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800873 char *encoded = base64_encode((UINT8 *)*cur_pos,
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700874 header->RegisterArraySize,
875 &encoded_len);
876 if (encoded == NULL) {
Ed Tanous5e2164a2025-03-09 09:20:44 -0700877 goto fail;
John Chungf8fc7052024-05-03 20:05:29 +0800878 }
Ed Tanous5e2164a2025-03-09 09:20:44 -0700879 register_array = json_object_new_object();
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700880 json_object_object_add(register_array, "data",
881 json_object_new_string_len(encoded,
882 encoded_len));
883 free(encoded);
884
Lawrence Tange407b4c2022-07-21 13:54:01 +0100885 break;
886 }
887 json_object_object_add(context_ir, "registerArray", register_array);
Lawrence Tang7f21db62022-07-06 11:09:39 +0100888
Lawrence Tange407b4c2022-07-21 13:54:01 +0100889 //Set the current position to after the processor context structure.
890 *cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700891 *remaining_size -= header->RegisterArraySize;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100892
Lawrence Tange407b4c2022-07-21 13:54:01 +0100893 return context_ir;
Ed Tanous5e2164a2025-03-09 09:20:44 -0700894
895fail:
896 json_object_put(context_ir);
897 return NULL;
Lawrence Tang7f21db62022-07-06 11:09:39 +0100898}
899
900//Converts a single CPER ARM miscellaneous register array to JSON IR format.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100901json_object *
902cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
Lawrence Tang7f21db62022-07-06 11:09:39 +0100903{
Lawrence Tange407b4c2022-07-21 13:54:01 +0100904 json_object *register_array = json_object_new_object();
905 json_object *mrs_encoding = json_object_new_object();
906 json_object_object_add(mrs_encoding, "op2",
907 json_object_new_uint64(misc_register->MrsOp2));
908 json_object_object_add(mrs_encoding, "crm",
909 json_object_new_uint64(misc_register->MrsCrm));
910 json_object_object_add(mrs_encoding, "crn",
911 json_object_new_uint64(misc_register->MrsCrn));
912 json_object_object_add(mrs_encoding, "op1",
913 json_object_new_uint64(misc_register->MrsOp1));
914 json_object_object_add(mrs_encoding, "o0",
915 json_object_new_uint64(misc_register->MrsO0));
916 json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
917 json_object_object_add(register_array, "value",
918 json_object_new_uint64(misc_register->Value));
Lawrence Tang7f21db62022-07-06 11:09:39 +0100919
Lawrence Tange407b4c2022-07-21 13:54:01 +0100920 return register_array;
Lawrence Tang7cd13902022-07-13 16:59:25 +0100921}
922
923//Converts a single CPER-JSON ARM error section into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +0100924void ir_section_arm_to_cper(json_object *section, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +0100925{
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800926 EFI_ARM_ERROR_RECORD section_cper;
927 memset(&section_cper, 0, sizeof(section_cper));
Lawrence Tang7cd13902022-07-13 16:59:25 +0100928
Lawrence Tange407b4c2022-07-21 13:54:01 +0100929 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800930 struct json_object *obj = NULL;
931 ValidationTypes u32Type = { UINT_32T, .value.ui32 = 0 };
Lawrence Tang7cd13902022-07-13 16:59:25 +0100932
Lawrence Tange407b4c2022-07-21 13:54:01 +0100933 //Count of error/context info structures.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800934 section_cper.ErrInfoNum = json_object_get_int(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100935 json_object_object_get(section, "errorInfoNum"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800936 section_cper.ContextInfoNum = json_object_get_int(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100937 json_object_object_get(section, "contextInfoNum"));
Lawrence Tang7cd13902022-07-13 16:59:25 +0100938
Lawrence Tange407b4c2022-07-21 13:54:01 +0100939 //Miscellaneous raw value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800940 section_cper.SectionLength = json_object_get_uint64(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100941 json_object_object_get(section, "sectionLength"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800942 if (json_object_object_get_ex(section, "mpidrEl1", &obj)) {
943 section_cper.MPIDR_EL1 = json_object_get_uint64(obj);
944 add_to_valid_bitfield(&u32Type, 0);
945 }
946 if (json_object_object_get_ex(section, "errorAffinity", &obj)) {
947 section_cper.ErrorAffinityLevel = readable_pair_to_integer(obj);
948 add_to_valid_bitfield(&u32Type, 1);
949 }
950 section_cper.MIDR_EL1 = json_object_get_uint64(
Lawrence Tange407b4c2022-07-21 13:54:01 +0100951 json_object_object_get(section, "midrEl1"));
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800952 if (json_object_object_get_ex(section, "running", &obj)) {
953 section_cper.RunningState = json_object_get_boolean(obj);
954 add_to_valid_bitfield(&u32Type, 2);
955 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100956
Lawrence Tange407b4c2022-07-21 13:54:01 +0100957 //Optional PSCI state.
958 json_object *psci_state = json_object_object_get(section, "psciState");
John Chungf8fc7052024-05-03 20:05:29 +0800959 if (psci_state != NULL) {
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800960 section_cper.PsciState = json_object_get_uint64(psci_state);
John Chungf8fc7052024-05-03 20:05:29 +0800961 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100962
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800963 //Validationbits for EFI_ARM_ERROR_RECORD should also consider vendorSpecificInfo
964 bool vendorSpecificPresent =
965 json_object_object_get_ex(section, "vendorSpecificInfo", &obj);
966 json_object *vendor_specific_info = obj;
967 if (vendorSpecificPresent) {
968 add_to_valid_bitfield(&u32Type, 3);
969 }
970
971 section_cper.ValidFields = u32Type.value.ui32;
972
Lawrence Tange407b4c2022-07-21 13:54:01 +0100973 //Flush header to stream.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800974 fwrite(&section_cper, sizeof(section_cper), 1, out);
Lawrence Tang7cd13902022-07-13 16:59:25 +0100975
Lawrence Tange407b4c2022-07-21 13:54:01 +0100976 //Error info structure array.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800977
Lawrence Tange407b4c2022-07-21 13:54:01 +0100978 json_object *error_info = json_object_object_get(section, "errorInfo");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800979 for (int i = 0; i < section_cper.ErrInfoNum; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100980 ir_arm_error_info_to_cper(
981 json_object_array_get_idx(error_info, i), out);
John Chungf8fc7052024-05-03 20:05:29 +0800982 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100983
Lawrence Tange407b4c2022-07-21 13:54:01 +0100984 //Context info structure array.
985 json_object *context_info =
986 json_object_object_get(section, "contextInfo");
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800987 for (int i = 0; i < section_cper.ContextInfoNum; i++) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100988 ir_arm_context_info_to_cper(
989 json_object_array_get_idx(context_info, i), out);
John Chungf8fc7052024-05-03 20:05:29 +0800990 }
Lawrence Tang7cd13902022-07-13 16:59:25 +0100991
Lawrence Tange407b4c2022-07-21 13:54:01 +0100992 //Vendor specific error info.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -0800993 if (vendorSpecificPresent) {
Lawrence Tange407b4c2022-07-21 13:54:01 +0100994 json_object *vendor_info_string =
995 json_object_object_get(vendor_specific_info, "data");
996 int vendor_specific_len =
997 json_object_get_string_len(vendor_info_string);
Lawrence Tang01e3a442022-07-20 15:14:50 +0100998
Ed Tanousa7d2cdd2024-07-15 11:07:27 -0700999 int32_t decoded_len = 0;
1000
1001 UINT8 *decoded = base64_decode(
1002 json_object_get_string(vendor_info_string),
1003 vendor_specific_len, &decoded_len);
1004
1005 //Write out to file.
1006 fwrite(decoded, decoded_len, 1, out);
Ed Tanousa7d2cdd2024-07-15 11:07:27 -07001007 free(decoded);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001008 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001009
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001010 fflush(out);
Lawrence Tang7cd13902022-07-13 16:59:25 +01001011}
1012
1013//Converts a single ARM error information structure into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001014void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +01001015{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001016 EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001017 memset(&error_info_cper, 0, sizeof(error_info_cper));
1018 struct json_object *obj = NULL;
1019 ValidationTypes ui16Type = { UINT_16T, .value.ui16 = 0 };
Lawrence Tang7cd13902022-07-13 16:59:25 +01001020
Lawrence Tange407b4c2022-07-21 13:54:01 +01001021 //Version, length.
1022 error_info_cper.Version = json_object_get_int(
1023 json_object_object_get(error_info, "version"));
1024 error_info_cper.Length = json_object_get_int(
1025 json_object_object_get(error_info, "length"));
Lawrence Tang7cd13902022-07-13 16:59:25 +01001026
Lawrence Tange407b4c2022-07-21 13:54:01 +01001027 //Type, multiple error.
1028 error_info_cper.Type = (UINT8)readable_pair_to_integer(
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001029 json_object_object_get(error_info, "errorType"));
1030
1031 if (json_object_object_get_ex(error_info, "multipleError", &obj)) {
1032 error_info_cper.MultipleError =
1033 (UINT16)readable_pair_to_integer(obj);
1034 add_to_valid_bitfield(&ui16Type, 0);
1035 } else {
1036 error_info_cper.MultipleError = 0;
1037 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001038
Lawrence Tange407b4c2022-07-21 13:54:01 +01001039 //Flags object.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001040 if (json_object_object_get_ex(error_info, "flags", &obj)) {
1041 error_info_cper.Flags = (UINT8)ir_to_bitfield(
1042 obj, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
1043 add_to_valid_bitfield(&ui16Type, 1);
1044 } else {
1045 error_info_cper.Flags = 0;
1046 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001047
Lawrence Tange407b4c2022-07-21 13:54:01 +01001048 //Error information.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001049 if (json_object_object_get_ex(error_info, "errorInformation", &obj)) {
1050 json_object *error_info_information = obj;
1051 json_object *error_info_prop = NULL;
1052 switch (error_info_cper.Type) {
1053 case ARM_ERROR_INFORMATION_TYPE_CACHE:
1054 error_info_cper.ErrorInformation.Value = 0;
1055 error_info_prop = json_object_object_get(
1056 error_info_information, "cacheError");
1057 ir_arm_error_cache_tlb_info_to_cper(
1058 error_info_prop,
1059 &error_info_cper.ErrorInformation.CacheError);
1060 break;
1061 case ARM_ERROR_INFORMATION_TYPE_TLB:
1062 error_info_cper.ErrorInformation.Value = 0;
1063 error_info_prop = json_object_object_get(
1064 error_info_information, "tlbError");
1065 ir_arm_error_cache_tlb_info_to_cper(
1066 error_info_prop,
1067 &error_info_cper.ErrorInformation.CacheError);
1068 break;
Aushim Nagarkatti5b793002024-09-26 17:07:30 -07001069
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001070 case ARM_ERROR_INFORMATION_TYPE_BUS:
1071 error_info_cper.ErrorInformation.Value = 0;
1072 error_info_prop = json_object_object_get(
1073 error_info_information, "busError");
1074 ir_arm_error_bus_info_to_cper(
1075 error_info_prop,
1076 &error_info_cper.ErrorInformation.BusError);
1077 break;
Lawrence Tang71570a22022-07-14 11:45:28 +01001078
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001079 default:
1080 //Unknown error information type.
1081 break;
1082 }
1083 add_to_valid_bitfield(&ui16Type, 2);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001084 }
Lawrence Tang7cd13902022-07-13 16:59:25 +01001085
Lawrence Tange407b4c2022-07-21 13:54:01 +01001086 //Virtual/physical fault address.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001087 if (json_object_object_get_ex(error_info, "virtualFaultAddress",
1088 &obj)) {
1089 error_info_cper.VirtualFaultAddress =
1090 json_object_get_uint64(obj);
1091 add_to_valid_bitfield(&ui16Type, 3);
1092 } else {
1093 error_info_cper.VirtualFaultAddress = 0;
1094 }
1095
1096 if (json_object_object_get_ex(error_info, "physicalFaultAddress",
1097 &obj)) {
1098 error_info_cper.PhysicalFaultAddress =
1099 json_object_get_uint64(obj);
1100 add_to_valid_bitfield(&ui16Type, 4);
1101 } else {
1102 error_info_cper.PhysicalFaultAddress = 0;
1103 }
1104 error_info_cper.ValidationBits = ui16Type.value.ui16;
Lawrence Tang7cd13902022-07-13 16:59:25 +01001105
Lawrence Tange407b4c2022-07-21 13:54:01 +01001106 //Write out to stream.
1107 fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
1108 out);
Lawrence Tang7cd13902022-07-13 16:59:25 +01001109}
1110
Lawrence Tang71570a22022-07-14 11:45:28 +01001111//Converts a single ARM cache/TLB error information structure into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001112void ir_arm_error_cache_tlb_info_to_cper(
1113 json_object *error_information,
1114 EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
Lawrence Tang71570a22022-07-14 11:45:28 +01001115{
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001116 // //Validation bits.
1117 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1118 struct json_object *obj = NULL;
Lawrence Tang71570a22022-07-14 11:45:28 +01001119
Lawrence Tange407b4c2022-07-21 13:54:01 +01001120 //Miscellaneous value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001121 if (json_object_object_get_ex(error_information, "transactionType",
1122 &obj)) {
1123 error_info_cper->TransactionType =
1124 readable_pair_to_integer(obj);
1125 add_to_valid_bitfield(&ui64Type, 0);
1126 }
1127 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1128 error_info_cper->Operation = readable_pair_to_integer(obj);
1129 add_to_valid_bitfield(&ui64Type, 1);
1130 }
1131 if (json_object_object_get_ex(error_information, "level", &obj)) {
1132 error_info_cper->Level = json_object_get_uint64(obj);
1133 add_to_valid_bitfield(&ui64Type, 2);
1134 }
1135 if (json_object_object_get_ex(error_information,
1136 "processorContextCorrupt", &obj)) {
1137 error_info_cper->ProcessorContextCorrupt =
1138 json_object_get_boolean(obj);
1139 add_to_valid_bitfield(&ui64Type, 3);
1140 }
1141 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1142 error_info_cper->Corrected = json_object_get_boolean(obj);
1143 add_to_valid_bitfield(&ui64Type, 4);
1144 }
1145 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1146 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1147 add_to_valid_bitfield(&ui64Type, 5);
1148 }
1149 if (json_object_object_get_ex(error_information, "restartablePC",
1150 &obj)) {
1151 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1152 add_to_valid_bitfield(&ui64Type, 6);
1153 }
Lawrence Tange407b4c2022-07-21 13:54:01 +01001154 error_info_cper->Reserved = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001155 error_info_cper->ValidationBits = ui64Type.value.ui64;
Lawrence Tang71570a22022-07-14 11:45:28 +01001156}
1157
1158//Converts a single ARM bus error information structure into a CPER structure.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001159void ir_arm_error_bus_info_to_cper(json_object *error_information,
1160 EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
Lawrence Tang71570a22022-07-14 11:45:28 +01001161{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001162 //Validation bits.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001163 ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
1164 struct json_object *obj = NULL;
1165
1166 memset(error_info_cper, 0, sizeof(EFI_ARM_BUS_ERROR_STRUCTURE));
Lawrence Tang71570a22022-07-14 11:45:28 +01001167
Lawrence Tange407b4c2022-07-21 13:54:01 +01001168 //Miscellaneous value fields.
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001169 if (json_object_object_get_ex(error_information, "transactionType",
1170 &obj)) {
1171 error_info_cper->TransactionType =
1172 readable_pair_to_integer(obj);
1173 add_to_valid_bitfield(&ui64Type, 0);
1174 } else {
1175 error_info_cper->TransactionType = 0;
1176 }
1177 if (json_object_object_get_ex(error_information, "operation", &obj)) {
1178 error_info_cper->Operation = readable_pair_to_integer(obj);
1179 add_to_valid_bitfield(&ui64Type, 1);
1180 } else {
1181 error_info_cper->Operation = 0;
1182 }
1183 if (json_object_object_get_ex(error_information, "level", &obj)) {
1184 error_info_cper->Level = json_object_get_uint64(obj);
1185 add_to_valid_bitfield(&ui64Type, 2);
1186 } else {
1187 error_info_cper->Level = 0;
1188 }
1189 if (json_object_object_get_ex(error_information,
1190 "processorContextCorrupt", &obj)) {
1191 error_info_cper->ProcessorContextCorrupt =
1192 json_object_get_boolean(obj);
1193 add_to_valid_bitfield(&ui64Type, 3);
1194 } else {
1195 error_info_cper->ProcessorContextCorrupt = 0;
1196 }
1197 if (json_object_object_get_ex(error_information, "corrected", &obj)) {
1198 error_info_cper->Corrected = json_object_get_boolean(obj);
1199 add_to_valid_bitfield(&ui64Type, 4);
1200 } else {
1201 error_info_cper->Corrected = 0;
1202 }
1203 if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
1204 error_info_cper->PrecisePC = json_object_get_boolean(obj);
1205 add_to_valid_bitfield(&ui64Type, 5);
1206 } else {
1207 error_info_cper->PrecisePC = 0;
1208 }
1209 if (json_object_object_get_ex(error_information, "restartablePC",
1210 &obj)) {
1211 error_info_cper->RestartablePC = json_object_get_boolean(obj);
1212 add_to_valid_bitfield(&ui64Type, 6);
1213 } else {
1214 error_info_cper->RestartablePC = 0;
1215 }
1216 if (json_object_object_get_ex(error_information, "participationType",
1217 &obj)) {
1218 error_info_cper->ParticipationType =
1219 readable_pair_to_integer(obj);
1220 add_to_valid_bitfield(&ui64Type, 7);
1221 } else {
1222 error_info_cper->ParticipationType = 0;
1223 }
1224 if (json_object_object_get_ex(error_information, "timedOut", &obj)) {
1225 error_info_cper->TimeOut = json_object_get_boolean(obj);
1226 add_to_valid_bitfield(&ui64Type, 8);
1227 } else {
1228 error_info_cper->TimeOut = 0;
1229 }
1230 if (json_object_object_get_ex(error_information, "addressSpace",
1231 &obj)) {
1232 error_info_cper->AddressSpace = readable_pair_to_integer(obj);
1233 add_to_valid_bitfield(&ui64Type, 9);
1234 } else {
1235 error_info_cper->AddressSpace = 0;
1236 }
1237 if (json_object_object_get_ex(error_information, "accessMode", &obj)) {
1238 error_info_cper->AccessMode = readable_pair_to_integer(obj);
1239 add_to_valid_bitfield(&ui64Type, 11);
1240 } else {
1241 error_info_cper->AccessMode = 0;
1242 }
1243 if (json_object_object_get_ex(error_information, "memoryAttributes",
1244 &obj)) {
1245 error_info_cper->MemoryAddressAttributes =
1246 json_object_get_uint64(obj);
1247 add_to_valid_bitfield(&ui64Type, 10);
1248 } else {
1249 error_info_cper->MemoryAddressAttributes = 0;
1250 }
Lawrence Tange407b4c2022-07-21 13:54:01 +01001251 error_info_cper->Reserved = 0;
Aushim Nagarkattiae8f6d92025-01-29 17:34:44 -08001252 error_info_cper->ValidationBits = ui64Type.value.ui64;
Lawrence Tang71570a22022-07-14 11:45:28 +01001253}
1254
Lawrence Tang7cd13902022-07-13 16:59:25 +01001255//Converts a single ARM context information structure into CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001256void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
Lawrence Tang7cd13902022-07-13 16:59:25 +01001257{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001258 EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
Lawrence Tang7cd13902022-07-13 16:59:25 +01001259
Lawrence Tange407b4c2022-07-21 13:54:01 +01001260 //Version, array size, context type.
1261 info_header.Version = json_object_get_int(
1262 json_object_object_get(context_info, "version"));
1263 info_header.RegisterArraySize = json_object_get_int(
1264 json_object_object_get(context_info, "registerArraySize"));
1265 info_header.RegisterContextType = readable_pair_to_integer(
1266 json_object_object_get(context_info, "registerContextType"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001267
Lawrence Tange407b4c2022-07-21 13:54:01 +01001268 //Flush to stream, write the register array itself.
1269 fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
1270 out);
1271 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001272
Lawrence Tange407b4c2022-07-21 13:54:01 +01001273 json_object *register_array =
1274 json_object_object_get(context_info, "registerArray");
1275 switch (info_header.RegisterContextType) {
1276 case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
1277 ir_arm_aarch32_gpr_to_cper(register_array, out);
1278 break;
1279 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
1280 ir_arm_aarch32_el1_to_cper(register_array, out);
1281 break;
1282 case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
1283 ir_arm_aarch32_el2_to_cper(register_array, out);
1284 break;
1285 case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
1286 ir_arm_aarch32_secure_to_cper(register_array, out);
1287 break;
1288 case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
1289 ir_arm_aarch64_gpr_to_cper(register_array, out);
1290 break;
1291 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
1292 ir_arm_aarch64_el1_to_cper(register_array, out);
1293 break;
1294 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
1295 ir_arm_aarch64_el2_to_cper(register_array, out);
1296 break;
1297 case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
1298 ir_arm_aarch64_el3_to_cper(register_array, out);
1299 break;
1300 case EFI_ARM_CONTEXT_TYPE_MISC:
1301 ir_arm_misc_registers_to_cper(register_array, out);
1302 break;
1303 default:
1304 //Unknown register structure.
John Chungf8fc7052024-05-03 20:05:29 +08001305 ir_arm_unknown_register_to_cper(register_array, out);
Lawrence Tange407b4c2022-07-21 13:54:01 +01001306 break;
1307 }
Lawrence Tang71570a22022-07-14 11:45:28 +01001308}
1309
1310//Converts a single AARCH32 GPR CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001311void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001312{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001313 //Get uniform register array.
1314 EFI_ARM_V8_AARCH32_GPR reg_array;
1315 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1316 sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
1317 ARM_AARCH32_GPR_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001318
Lawrence Tange407b4c2022-07-21 13:54:01 +01001319 //Flush to stream.
1320 fwrite(&reg_array, sizeof(reg_array), 1, out);
1321 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001322}
1323
1324//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 +01001325void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001326{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001327 //Get uniform register array.
1328 EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
1329 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1330 sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
1331 sizeof(UINT32),
1332 ARM_AARCH32_EL1_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001333
Lawrence Tange407b4c2022-07-21 13:54:01 +01001334 //Flush to stream.
1335 fwrite(&reg_array, sizeof(reg_array), 1, out);
1336 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001337}
1338
1339//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 +01001340void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001341{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001342 //Get uniform register array.
1343 EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
1344 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1345 sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
1346 sizeof(UINT32),
1347 ARM_AARCH32_EL2_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001348
Lawrence Tange407b4c2022-07-21 13:54:01 +01001349 //Flush to stream.
1350 fwrite(&reg_array, sizeof(reg_array), 1, out);
1351 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001352}
1353
1354//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 +01001355void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001356{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001357 //Get uniform register array.
1358 EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
1359 ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
1360 sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
1361 sizeof(UINT32),
1362 ARM_AARCH32_SECURE_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001363
Lawrence Tange407b4c2022-07-21 13:54:01 +01001364 //Flush to stream.
1365 fwrite(&reg_array, sizeof(reg_array), 1, out);
1366 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001367}
1368
1369//Converts a single AARCH64 GPR CPER-JSON object to CPER binary, outputting to the given stream.
Lawrence Tange407b4c2022-07-21 13:54:01 +01001370void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001371{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001372 //Get uniform register array.
1373 EFI_ARM_V8_AARCH64_GPR reg_array;
1374 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1375 sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
1376 ARM_AARCH64_GPR_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001377
Lawrence Tange407b4c2022-07-21 13:54:01 +01001378 //Flush to stream.
1379 fwrite(&reg_array, sizeof(reg_array), 1, out);
1380 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001381}
1382
1383//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 +01001384void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001385{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001386 //Get uniform register array.
1387 EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
1388 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1389 sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
1390 sizeof(UINT64),
1391 ARM_AARCH64_EL1_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001392
Lawrence Tange407b4c2022-07-21 13:54:01 +01001393 //Flush to stream.
1394 fwrite(&reg_array, sizeof(reg_array), 1, out);
1395 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001396}
1397
1398//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 +01001399void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001400{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001401 //Get uniform register array.
1402 EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
1403 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1404 sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
1405 sizeof(UINT64),
1406 ARM_AARCH64_EL2_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001407
Lawrence Tange407b4c2022-07-21 13:54:01 +01001408 //Flush to stream.
1409 fwrite(&reg_array, sizeof(reg_array), 1, out);
1410 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001411}
1412
1413//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 +01001414void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001415{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001416 //Get uniform register array.
1417 EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
1418 ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
1419 sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
1420 sizeof(UINT64),
1421 ARM_AARCH64_EL3_REGISTER_NAMES);
Lawrence Tang71570a22022-07-14 11:45:28 +01001422
Lawrence Tange407b4c2022-07-21 13:54:01 +01001423 //Flush to stream.
1424 fwrite(&reg_array, sizeof(reg_array), 1, out);
1425 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001426}
1427
1428//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 +01001429void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001430{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001431 EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
Lawrence Tang71570a22022-07-14 11:45:28 +01001432
Lawrence Tange407b4c2022-07-21 13:54:01 +01001433 //MRS encoding information.
1434 json_object *mrs_encoding =
1435 json_object_object_get(registers, "mrsEncoding");
1436 reg_array.MrsOp2 = json_object_get_uint64(
1437 json_object_object_get(mrs_encoding, "op2"));
1438 reg_array.MrsCrm = json_object_get_uint64(
1439 json_object_object_get(mrs_encoding, "crm"));
1440 reg_array.MrsCrn = json_object_get_uint64(
1441 json_object_object_get(mrs_encoding, "crn"));
1442 reg_array.MrsOp1 = json_object_get_uint64(
1443 json_object_object_get(mrs_encoding, "op1"));
1444 reg_array.MrsO0 = json_object_get_uint64(
1445 json_object_object_get(mrs_encoding, "o0"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001446
Lawrence Tange407b4c2022-07-21 13:54:01 +01001447 //Actual register value.
1448 reg_array.Value = json_object_get_uint64(
1449 json_object_object_get(registers, "value"));
Lawrence Tang71570a22022-07-14 11:45:28 +01001450
Lawrence Tange407b4c2022-07-21 13:54:01 +01001451 //Flush to stream.
1452 fwrite(&reg_array, sizeof(reg_array), 1, out);
1453 fflush(out);
Lawrence Tang71570a22022-07-14 11:45:28 +01001454}
1455
1456//Converts a single ARM unknown register CPER-JSON object to CPER binary, outputting to the given stream.
John Chungf8fc7052024-05-03 20:05:29 +08001457void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
Lawrence Tang71570a22022-07-14 11:45:28 +01001458{
Lawrence Tange407b4c2022-07-21 13:54:01 +01001459 //Get base64 represented data.
1460 json_object *encoded = json_object_object_get(registers, "data");
Ed Tanousa7d2cdd2024-07-15 11:07:27 -07001461
1462 int32_t decoded_len = 0;
1463
1464 UINT8 *decoded = base64_decode(json_object_get_string(encoded),
1465 json_object_get_string_len(encoded),
1466 &decoded_len);
1467
1468 if (decoded == NULL) {
Ed Tanous50b966f2025-03-11 09:06:19 -07001469 cper_print_log("Failed to allocate decode output buffer. \n");
John Chungf8fc7052024-05-03 20:05:29 +08001470 } else {
John Chungf8fc7052024-05-03 20:05:29 +08001471 //Flush out to stream.
1472 fwrite(&decoded, decoded_len, 1, out);
1473 fflush(out);
1474 free(decoded);
1475 }
1476}