blob: b07c829823e7f0f68129c350dd7d7662c1511d6b [file] [log] [blame]
/**
* Describes functions for converting ARM CPER sections from binary and JSON format
* into an intermediate format.
*
* Author: Lawrence.Tang@arm.com
**/
#include <stdio.h>
#include <json.h>
#include <libcper/base64.h>
#include <libcper/Cper.h>
#include <libcper/cper-utils.h>
#include <libcper/sections/cper-section-arm.h>
//Private pre-definitions.
json_object *
cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
void **cur_pos);
json_object *
cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
EFI_ARM_ERROR_INFORMATION_ENTRY *error_info);
json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error);
json_object *cper_arm_misc_register_array_to_ir(
EFI_ARM_MISC_CONTEXT_REGISTER *misc_register);
void ir_arm_error_info_to_cper(json_object *error_info, FILE *out);
void ir_arm_context_info_to_cper(json_object *context_info, FILE *out);
void ir_arm_error_cache_tlb_info_to_cper(
json_object *error_information,
EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper);
void ir_arm_error_bus_info_to_cper(json_object *error_information,
EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper);
void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out);
void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out);
void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out);
void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out);
void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out);
void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out);
void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out);
void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out);
void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out);
void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out);
//Converts the given processor-generic CPER section into JSON IR.
json_object *cper_section_arm_to_ir(void *section)
{
EFI_ARM_ERROR_RECORD *record = (EFI_ARM_ERROR_RECORD *)section;
json_object *section_ir = json_object_new_object();
//Validation bits.
json_object *validation = bitfield_to_ir(
record->ValidFields, 4, ARM_ERROR_VALID_BITFIELD_NAMES);
json_object_object_add(section_ir, "validationBits", validation);
//Number of error info and context info structures, and length.
json_object_object_add(section_ir, "errorInfoNum",
json_object_new_int(record->ErrInfoNum));
json_object_object_add(section_ir, "contextInfoNum",
json_object_new_int(record->ContextInfoNum));
json_object_object_add(section_ir, "sectionLength",
json_object_new_uint64(record->SectionLength));
//Error affinity.
json_object *error_affinity = json_object_new_object();
json_object_object_add(error_affinity, "value",
json_object_new_int(record->ErrorAffinityLevel));
json_object_object_add(
error_affinity, "type",
json_object_new_string(record->ErrorAffinityLevel < 4 ?
"Vendor Defined" :
"Reserved"));
json_object_object_add(section_ir, "errorAffinity", error_affinity);
//Processor ID (MPIDR_EL1) and chip ID (MIDR_EL1).
uint64_t sock;
uint64_t mpidr_eli1 = record->MPIDR_EL1;
json_object_object_add(section_ir, "mpidrEl1",
json_object_new_uint64(mpidr_eli1));
//Arm Processor socket info
sock = (mpidr_eli1 & ARM_SOCK_MASK) >> 32;
json_object_object_add(section_ir, "affinity3",
json_object_new_uint64(sock));
json_object_object_add(section_ir, "midrEl1",
json_object_new_uint64(record->MIDR_EL1));
//Whether the processor is running, and the state of it if so.
json_object_object_add(section_ir, "running",
json_object_new_boolean(record->RunningState &
0x1));
if (!(record->RunningState >> 31)) {
//Bit 32 of running state is on, so PSCI state information is included.
//This can't be made human readable, as it is unknown whether this will be the pre-PSCI 1.0 format
//or the newer Extended StateID format.
json_object_object_add(
section_ir, "psciState",
json_object_new_uint64(record->PsciState));
}
//Processor error structures.
json_object *error_info_array = json_object_new_array();
EFI_ARM_ERROR_INFORMATION_ENTRY *cur_error =
(EFI_ARM_ERROR_INFORMATION_ENTRY *)(record + 1);
for (int i = 0; i < record->ErrInfoNum; i++) {
json_object_array_add(error_info_array,
cper_arm_error_info_to_ir(cur_error));
cur_error++;
}
json_object_object_add(section_ir, "errorInfo", error_info_array);
//Processor context structures.
//The current position is moved within the processing, as it is a dynamic size structure.
uint8_t *cur_pos = (uint8_t *)cur_error;
json_object *context_info_array = json_object_new_array();
for (int i = 0; i < record->ContextInfoNum; i++) {
EFI_ARM_CONTEXT_INFORMATION_HEADER *header =
(EFI_ARM_CONTEXT_INFORMATION_HEADER *)cur_pos;
json_object *processor_context =
cper_arm_processor_context_to_ir(header,
(void **)&cur_pos);
json_object_array_add(context_info_array, processor_context);
}
json_object_object_add(section_ir, "contextInfo", context_info_array);
//Is there any vendor-specific information following?
if (cur_pos < (uint8_t *)section + record->SectionLength) {
json_object *vendor_specific = json_object_new_object();
size_t input_size =
(uint8_t *)section + record->SectionLength - cur_pos;
int32_t encoded_len = 0;
char *encoded =
base64_encode(cur_pos, input_size, &encoded_len);
if (encoded == NULL) {
return NULL;
}
json_object_object_add(vendor_specific, "data",
json_object_new_string_len(encoded,
encoded_len));
free(encoded);
json_object_object_add(section_ir, "vendorSpecificInfo",
vendor_specific);
}
return section_ir;
}
//Converts a single ARM Process Error Information structure into JSON IR.
json_object *
cper_arm_error_info_to_ir(EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
{
json_object *error_info_ir = json_object_new_object();
//Version, length.
json_object_object_add(error_info_ir, "version",
json_object_new_int(error_info->Version));
json_object_object_add(error_info_ir, "length",
json_object_new_int(error_info->Length));
//Validation bitfield.
json_object *validation =
bitfield_to_ir(error_info->ValidationBits, 5,
ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
json_object_object_add(error_info_ir, "validationBits", validation);
//The type of error information in this log.
json_object *error_type = integer_to_readable_pair(
error_info->Type, 4, ARM_ERROR_INFO_ENTRY_INFO_TYPES_KEYS,
ARM_ERROR_INFO_ENTRY_INFO_TYPES_VALUES, "Unknown (Reserved)");
json_object_object_add(error_info_ir, "errorType", error_type);
//Multiple error count.
json_object *multiple_error = json_object_new_object();
json_object_object_add(multiple_error, "value",
json_object_new_int(error_info->MultipleError));
json_object_object_add(
multiple_error, "type",
json_object_new_string(error_info->MultipleError < 1 ?
"Single Error" :
"Multiple Errors"));
json_object_object_add(error_info_ir, "multipleError", multiple_error);
//Flags.
json_object *flags = bitfield_to_ir(error_info->Flags, 4,
ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
json_object_object_add(error_info_ir, "flags", flags);
//Error information, split by type.
json_object *error_subinfo = NULL;
switch (error_info->Type) {
case ARM_ERROR_INFORMATION_TYPE_CACHE: //Cache
case ARM_ERROR_INFORMATION_TYPE_TLB: //TLB
error_subinfo = cper_arm_cache_tlb_error_to_ir(
(EFI_ARM_CACHE_ERROR_STRUCTURE *)&error_info
->ErrorInformation,
error_info);
break;
case ARM_ERROR_INFORMATION_TYPE_BUS: //Bus
error_subinfo = cper_arm_bus_error_to_ir(
(EFI_ARM_BUS_ERROR_STRUCTURE *)&error_info
->ErrorInformation);
break;
default:
//Unknown/microarch, will not support.
break;
}
json_object_object_add(error_info_ir, "errorInformation",
error_subinfo);
//Virtual fault address, physical fault address.
json_object_object_add(
error_info_ir, "virtualFaultAddress",
json_object_new_uint64(error_info->VirtualFaultAddress));
json_object_object_add(
error_info_ir, "physicalFaultAddress",
json_object_new_uint64(error_info->PhysicalFaultAddress));
return error_info_ir;
}
//Converts a single ARM cache/TLB error information structure into JSON IR format.
json_object *
cper_arm_cache_tlb_error_to_ir(EFI_ARM_CACHE_ERROR_STRUCTURE *cache_tlb_error,
EFI_ARM_ERROR_INFORMATION_ENTRY *error_info)
{
json_object *cache_tlb_error_ir = json_object_new_object();
json_object *cache_tlb_prop = json_object_new_object();
char *cache_tlb_propname;
//Validation bitfield.
json_object *validation =
bitfield_to_ir(cache_tlb_error->ValidationBits, 7,
ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
json_object_object_add(cache_tlb_error_ir, "validationBits",
validation);
//Transaction type.
json_object *transaction_type = integer_to_readable_pair(
cache_tlb_error->TransactionType, 3,
ARM_ERROR_TRANSACTION_TYPES_KEYS,
ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
json_object_object_add(cache_tlb_error_ir, "transactionType",
transaction_type);
//Operation.
json_object *operation;
if (error_info->Type == 0) {
//Cache operation.
operation = integer_to_readable_pair(
cache_tlb_error->Operation, 11,
ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
ARM_CACHE_BUS_OPERATION_TYPES_VALUES,
"Unknown (Reserved)");
cache_tlb_propname = "cacheError";
} else {
//TLB operation.
operation = integer_to_readable_pair(
cache_tlb_error->Operation, 9,
ARM_TLB_OPERATION_TYPES_KEYS,
ARM_TLB_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
cache_tlb_propname = "tlbError";
}
json_object_object_add(cache_tlb_error_ir, "operation", operation);
//Miscellaneous remaining fields.
json_object_object_add(cache_tlb_error_ir, "level",
json_object_new_int(cache_tlb_error->Level));
json_object_object_add(
cache_tlb_error_ir, "processorContextCorrupt",
json_object_new_boolean(
cache_tlb_error->ProcessorContextCorrupt));
json_object_object_add(
cache_tlb_error_ir, "corrected",
json_object_new_boolean(cache_tlb_error->Corrected));
json_object_object_add(
cache_tlb_error_ir, "precisePC",
json_object_new_boolean(cache_tlb_error->PrecisePC));
json_object_object_add(
cache_tlb_error_ir, "restartablePC",
json_object_new_boolean(cache_tlb_error->RestartablePC));
json_object_object_add(cache_tlb_prop, cache_tlb_propname,
cache_tlb_error_ir);
return cache_tlb_prop;
}
//Converts a single ARM bus error information structure into JSON IR format.
json_object *cper_arm_bus_error_to_ir(EFI_ARM_BUS_ERROR_STRUCTURE *bus_error)
{
json_object *bus_error_ir = json_object_new_object();
//Validation bits.
json_object *validation =
bitfield_to_ir(bus_error->ValidationBits, 12,
ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
json_object_object_add(bus_error_ir, "validationBits", validation);
//Transaction type.
json_object *transaction_type = integer_to_readable_pair(
bus_error->TransactionType, 3, ARM_ERROR_TRANSACTION_TYPES_KEYS,
ARM_ERROR_TRANSACTION_TYPES_VALUES, "Unknown (Reserved)");
json_object_object_add(bus_error_ir, "transactionType",
transaction_type);
//Operation.
json_object *operation = integer_to_readable_pair(
bus_error->Operation, 7, ARM_CACHE_BUS_OPERATION_TYPES_KEYS,
ARM_CACHE_BUS_OPERATION_TYPES_VALUES, "Unknown (Reserved)");
json_object_object_add(bus_error_ir, "operation", operation);
//Affinity level of bus error, + miscellaneous fields.
json_object_object_add(bus_error_ir, "level",
json_object_new_int(bus_error->Level));
json_object_object_add(
bus_error_ir, "processorContextCorrupt",
json_object_new_boolean(bus_error->ProcessorContextCorrupt));
json_object_object_add(bus_error_ir, "corrected",
json_object_new_boolean(bus_error->Corrected));
json_object_object_add(bus_error_ir, "precisePC",
json_object_new_boolean(bus_error->PrecisePC));
json_object_object_add(
bus_error_ir, "restartablePC",
json_object_new_boolean(bus_error->RestartablePC));
json_object_object_add(bus_error_ir, "timedOut",
json_object_new_boolean(bus_error->TimeOut));
//Participation type.
json_object *participation_type = integer_to_readable_pair(
bus_error->ParticipationType, 4,
ARM_BUS_PARTICIPATION_TYPES_KEYS,
ARM_BUS_PARTICIPATION_TYPES_VALUES, "Unknown");
json_object_object_add(bus_error_ir, "participationType",
participation_type);
//Address space.
json_object *address_space = integer_to_readable_pair(
bus_error->AddressSpace, 3, ARM_BUS_ADDRESS_SPACE_TYPES_KEYS,
ARM_BUS_ADDRESS_SPACE_TYPES_VALUES, "Unknown");
json_object_object_add(bus_error_ir, "addressSpace", address_space);
//Memory access attributes.
//todo: find the specification of these in the ARM ARM
json_object_object_add(
bus_error_ir, "memoryAttributes",
json_object_new_int(bus_error->MemoryAddressAttributes));
//Access Mode
json_object *access_mode = json_object_new_object();
json_object_object_add(access_mode, "value",
json_object_new_int(bus_error->AccessMode));
json_object_object_add(
access_mode, "name",
json_object_new_string(bus_error->AccessMode == 0 ? "Secure" :
"Normal"));
json_object_object_add(bus_error_ir, "accessMode", access_mode);
return bus_error_ir;
}
//Converts a single ARM processor context block into JSON IR.
json_object *
cper_arm_processor_context_to_ir(EFI_ARM_CONTEXT_INFORMATION_HEADER *header,
void **cur_pos)
{
json_object *context_ir = json_object_new_object();
//Version.
json_object_object_add(context_ir, "version",
json_object_new_int(header->Version));
//Add the context type.
json_object *context_type = integer_to_readable_pair(
header->RegisterContextType, 9,
ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_KEYS,
ARM_PROCESSOR_INFO_REGISTER_CONTEXT_TYPES_VALUES,
"Unknown (Reserved)");
json_object_object_add(context_ir, "registerContextType", context_type);
//Register array size (bytes).
json_object_object_add(
context_ir, "registerArraySize",
json_object_new_uint64(header->RegisterArraySize));
//The register array itself.
*cur_pos = (void *)(header + 1);
json_object *register_array = NULL;
switch (header->RegisterContextType) {
case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
register_array = uniform_struct_to_ir(
(UINT32 *)cur_pos,
sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
ARM_AARCH32_GPR_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
register_array = uniform_struct_to_ir(
(UINT32 *)cur_pos,
sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
sizeof(UINT32),
ARM_AARCH32_EL1_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
register_array = uniform_struct_to_ir(
(UINT32 *)cur_pos,
sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
sizeof(UINT32),
ARM_AARCH32_EL2_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
register_array = uniform_struct_to_ir(
(UINT32 *)cur_pos,
sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
sizeof(UINT32),
ARM_AARCH32_SECURE_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
register_array = uniform_struct64_to_ir(
(UINT64 *)cur_pos,
sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
ARM_AARCH64_GPR_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
register_array = uniform_struct64_to_ir(
(UINT64 *)cur_pos,
sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
sizeof(UINT64),
ARM_AARCH64_EL1_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
register_array = uniform_struct64_to_ir(
(UINT64 *)cur_pos,
sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
sizeof(UINT64),
ARM_AARCH64_EL2_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
register_array = uniform_struct64_to_ir(
(UINT64 *)cur_pos,
sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
sizeof(UINT64),
ARM_AARCH64_EL3_REGISTER_NAMES);
break;
case EFI_ARM_CONTEXT_TYPE_MISC:
register_array = cper_arm_misc_register_array_to_ir(
(EFI_ARM_MISC_CONTEXT_REGISTER *)cur_pos);
break;
default:
//Unknown register array type, add as base64 data instead.
register_array = json_object_new_object();
int32_t encoded_len = 0;
char *encoded = base64_encode((UINT8 *)cur_pos,
header->RegisterArraySize,
&encoded_len);
if (encoded == NULL) {
printf("Failed to allocate encode output buffer. \n");
return NULL;
}
json_object_object_add(register_array, "data",
json_object_new_string_len(encoded,
encoded_len));
free(encoded);
break;
}
json_object_object_add(context_ir, "registerArray", register_array);
//Set the current position to after the processor context structure.
*cur_pos = (UINT8 *)(*cur_pos) + header->RegisterArraySize;
return context_ir;
}
//Converts a single CPER ARM miscellaneous register array to JSON IR format.
json_object *
cper_arm_misc_register_array_to_ir(EFI_ARM_MISC_CONTEXT_REGISTER *misc_register)
{
json_object *register_array = json_object_new_object();
json_object *mrs_encoding = json_object_new_object();
json_object_object_add(mrs_encoding, "op2",
json_object_new_uint64(misc_register->MrsOp2));
json_object_object_add(mrs_encoding, "crm",
json_object_new_uint64(misc_register->MrsCrm));
json_object_object_add(mrs_encoding, "crn",
json_object_new_uint64(misc_register->MrsCrn));
json_object_object_add(mrs_encoding, "op1",
json_object_new_uint64(misc_register->MrsOp1));
json_object_object_add(mrs_encoding, "o0",
json_object_new_uint64(misc_register->MrsO0));
json_object_object_add(register_array, "mrsEncoding", mrs_encoding);
json_object_object_add(register_array, "value",
json_object_new_uint64(misc_register->Value));
return register_array;
}
//Converts a single CPER-JSON ARM error section into CPER binary, outputting to the given stream.
void ir_section_arm_to_cper(json_object *section, FILE *out)
{
EFI_ARM_ERROR_RECORD *section_cper =
(EFI_ARM_ERROR_RECORD *)calloc(1, sizeof(EFI_ARM_ERROR_RECORD));
//Validation bits.
section_cper->ValidFields = ir_to_bitfield(
json_object_object_get(section, "validationBits"), 4,
ARM_ERROR_VALID_BITFIELD_NAMES);
//Count of error/context info structures.
section_cper->ErrInfoNum = json_object_get_int(
json_object_object_get(section, "errorInfoNum"));
section_cper->ContextInfoNum = json_object_get_int(
json_object_object_get(section, "contextInfoNum"));
//Miscellaneous raw value fields.
section_cper->SectionLength = json_object_get_uint64(
json_object_object_get(section, "sectionLength"));
section_cper->ErrorAffinityLevel = readable_pair_to_integer(
json_object_object_get(section, "errorAffinity"));
section_cper->MPIDR_EL1 = json_object_get_uint64(
json_object_object_get(section, "mpidrEl1"));
section_cper->MIDR_EL1 = json_object_get_uint64(
json_object_object_get(section, "midrEl1"));
section_cper->RunningState = json_object_get_boolean(
json_object_object_get(section, "running"));
//Optional PSCI state.
json_object *psci_state = json_object_object_get(section, "psciState");
if (psci_state != NULL) {
section_cper->PsciState = json_object_get_uint64(psci_state);
}
//Flush header to stream.
fwrite(section_cper, sizeof(EFI_ARM_ERROR_RECORD), 1, out);
fflush(out);
//Error info structure array.
json_object *error_info = json_object_object_get(section, "errorInfo");
for (int i = 0; i < section_cper->ErrInfoNum; i++) {
ir_arm_error_info_to_cper(
json_object_array_get_idx(error_info, i), out);
}
//Context info structure array.
json_object *context_info =
json_object_object_get(section, "contextInfo");
for (int i = 0; i < section_cper->ContextInfoNum; i++) {
ir_arm_context_info_to_cper(
json_object_array_get_idx(context_info, i), out);
}
//Vendor specific error info.
json_object *vendor_specific_info =
json_object_object_get(section, "vendorSpecificInfo");
if (vendor_specific_info != NULL) {
json_object *vendor_info_string =
json_object_object_get(vendor_specific_info, "data");
int vendor_specific_len =
json_object_get_string_len(vendor_info_string);
int32_t decoded_len = 0;
UINT8 *decoded = base64_decode(
json_object_get_string(vendor_info_string),
vendor_specific_len, &decoded_len);
//Write out to file.
fwrite(decoded, decoded_len, 1, out);
fflush(out);
free(decoded);
}
//Free remaining resources.
free(section_cper);
}
//Converts a single ARM error information structure into CPER binary, outputting to the given stream.
void ir_arm_error_info_to_cper(json_object *error_info, FILE *out)
{
EFI_ARM_ERROR_INFORMATION_ENTRY error_info_cper;
//Version, length.
error_info_cper.Version = json_object_get_int(
json_object_object_get(error_info, "version"));
error_info_cper.Length = json_object_get_int(
json_object_object_get(error_info, "length"));
//Validation bits.
error_info_cper.ValidationBits = ir_to_bitfield(
json_object_object_get(error_info, "validationBits"), 5,
ARM_ERROR_INFO_ENTRY_VALID_BITFIELD_NAMES);
//Type, multiple error.
error_info_cper.Type = (UINT8)readable_pair_to_integer(
json_object_object_get(error_info, "type"));
error_info_cper.MultipleError = (UINT16)readable_pair_to_integer(
json_object_object_get(error_info, "multipleError"));
//Flags object.
error_info_cper.Flags = (UINT8)ir_to_bitfield(
json_object_object_get(error_info, "flags"), 4,
ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
//Error information.
json_object *error_info_information =
json_object_object_get(error_info, "errorInformation");
json_object *error_info_prop = NULL;
switch (error_info_cper.Type) {
case ARM_ERROR_INFORMATION_TYPE_CACHE:
error_info_prop = json_object_object_get(error_info_information,
"cacheError");
ir_arm_error_cache_tlb_info_to_cper(
error_info_prop,
&error_info_cper.ErrorInformation.CacheError);
break;
case ARM_ERROR_INFORMATION_TYPE_TLB:
error_info_prop = json_object_object_get(error_info_information,
"tlbError");
ir_arm_error_cache_tlb_info_to_cper(
error_info_prop,
&error_info_cper.ErrorInformation.CacheError);
break;
case ARM_ERROR_INFORMATION_TYPE_BUS:
ir_arm_error_bus_info_to_cper(
error_info_information,
&error_info_cper.ErrorInformation.BusError);
break;
default:
//Unknown error information type.
break;
}
//Virtual/physical fault address.
error_info_cper.VirtualFaultAddress = json_object_get_uint64(
json_object_object_get(error_info, "virtualFaultAddress"));
error_info_cper.PhysicalFaultAddress = json_object_get_uint64(
json_object_object_get(error_info, "physicalFaultAddress"));
//Write out to stream.
fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
out);
fflush(out);
}
//Converts a single ARM cache/TLB error information structure into a CPER structure.
void ir_arm_error_cache_tlb_info_to_cper(
json_object *error_information,
EFI_ARM_CACHE_ERROR_STRUCTURE *error_info_cper)
{
//Validation bits.
error_info_cper->ValidationBits = ir_to_bitfield(
json_object_object_get(error_information, "validationBits"), 7,
ARM_CACHE_TLB_ERROR_VALID_BITFIELD_NAMES);
//Miscellaneous value fields.
error_info_cper->TransactionType = readable_pair_to_integer(
json_object_object_get(error_information, "transactionType"));
error_info_cper->Operation = readable_pair_to_integer(
json_object_object_get(error_information, "operation"));
error_info_cper->Level = json_object_get_uint64(
json_object_object_get(error_information, "level"));
error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
json_object_object_get(error_information,
"processorContextCorrupt"));
error_info_cper->Corrected = json_object_get_boolean(
json_object_object_get(error_information, "corrected"));
error_info_cper->PrecisePC = json_object_get_boolean(
json_object_object_get(error_information, "precisePC"));
error_info_cper->RestartablePC = json_object_get_boolean(
json_object_object_get(error_information, "restartablePC"));
error_info_cper->Reserved = 0;
}
//Converts a single ARM bus error information structure into a CPER structure.
void ir_arm_error_bus_info_to_cper(json_object *error_information,
EFI_ARM_BUS_ERROR_STRUCTURE *error_info_cper)
{
//Validation bits.
error_info_cper->ValidationBits = ir_to_bitfield(
json_object_object_get(error_information, "validationBits"), 7,
ARM_BUS_ERROR_VALID_BITFIELD_NAMES);
//Miscellaneous value fields.
error_info_cper->TransactionType = readable_pair_to_integer(
json_object_object_get(error_information, "transactionType"));
error_info_cper->Operation = readable_pair_to_integer(
json_object_object_get(error_information, "operation"));
error_info_cper->Level = json_object_get_uint64(
json_object_object_get(error_information, "level"));
error_info_cper->ProcessorContextCorrupt = json_object_get_boolean(
json_object_object_get(error_information,
"processorContextCorrupt"));
error_info_cper->Corrected = json_object_get_boolean(
json_object_object_get(error_information, "corrected"));
error_info_cper->PrecisePC = json_object_get_boolean(
json_object_object_get(error_information, "precisePC"));
error_info_cper->RestartablePC = json_object_get_boolean(
json_object_object_get(error_information, "restartablePC"));
error_info_cper->ParticipationType = readable_pair_to_integer(
json_object_object_get(error_information, "participationType"));
error_info_cper->AddressSpace = readable_pair_to_integer(
json_object_object_get(error_information, "addressSpace"));
error_info_cper->AccessMode = readable_pair_to_integer(
json_object_object_get(error_information, "accessMode"));
error_info_cper->MemoryAddressAttributes = json_object_get_uint64(
json_object_object_get(error_information, "memoryAttributes"));
error_info_cper->Reserved = 0;
}
//Converts a single ARM context information structure into CPER binary, outputting to the given stream.
void ir_arm_context_info_to_cper(json_object *context_info, FILE *out)
{
EFI_ARM_CONTEXT_INFORMATION_HEADER info_header;
//Version, array size, context type.
info_header.Version = json_object_get_int(
json_object_object_get(context_info, "version"));
info_header.RegisterArraySize = json_object_get_int(
json_object_object_get(context_info, "registerArraySize"));
info_header.RegisterContextType = readable_pair_to_integer(
json_object_object_get(context_info, "registerContextType"));
//Flush to stream, write the register array itself.
fwrite(&info_header, sizeof(EFI_ARM_CONTEXT_INFORMATION_HEADER), 1,
out);
fflush(out);
json_object *register_array =
json_object_object_get(context_info, "registerArray");
switch (info_header.RegisterContextType) {
case EFI_ARM_CONTEXT_TYPE_AARCH32_GPR:
ir_arm_aarch32_gpr_to_cper(register_array, out);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_EL1:
ir_arm_aarch32_el1_to_cper(register_array, out);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_EL2:
ir_arm_aarch32_el2_to_cper(register_array, out);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH32_SECURE:
ir_arm_aarch32_secure_to_cper(register_array, out);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_GPR:
ir_arm_aarch64_gpr_to_cper(register_array, out);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL1:
ir_arm_aarch64_el1_to_cper(register_array, out);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL2:
ir_arm_aarch64_el2_to_cper(register_array, out);
break;
case EFI_ARM_CONTEXT_TYPE_AARCH64_EL3:
ir_arm_aarch64_el3_to_cper(register_array, out);
break;
case EFI_ARM_CONTEXT_TYPE_MISC:
ir_arm_misc_registers_to_cper(register_array, out);
break;
default:
//Unknown register structure.
ir_arm_unknown_register_to_cper(register_array, out);
break;
}
}
//Converts a single AARCH32 GPR CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_aarch32_gpr_to_cper(json_object *registers, FILE *out)
{
//Get uniform register array.
EFI_ARM_V8_AARCH32_GPR reg_array;
ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
sizeof(EFI_ARM_V8_AARCH32_GPR) / sizeof(UINT32),
ARM_AARCH32_GPR_NAMES);
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single AARCH32 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_aarch32_el1_to_cper(json_object *registers, FILE *out)
{
//Get uniform register array.
EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS reg_array;
ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
sizeof(EFI_ARM_AARCH32_EL1_CONTEXT_REGISTERS) /
sizeof(UINT32),
ARM_AARCH32_EL1_REGISTER_NAMES);
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single AARCH32 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_aarch32_el2_to_cper(json_object *registers, FILE *out)
{
//Get uniform register array.
EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS reg_array;
ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
sizeof(EFI_ARM_AARCH32_EL2_CONTEXT_REGISTERS) /
sizeof(UINT32),
ARM_AARCH32_EL2_REGISTER_NAMES);
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single AARCH32 secure register set CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_aarch32_secure_to_cper(json_object *registers, FILE *out)
{
//Get uniform register array.
EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS reg_array;
ir_to_uniform_struct(registers, (UINT32 *)&reg_array,
sizeof(EFI_ARM_AARCH32_SECURE_CONTEXT_REGISTERS) /
sizeof(UINT32),
ARM_AARCH32_SECURE_REGISTER_NAMES);
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single AARCH64 GPR CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_aarch64_gpr_to_cper(json_object *registers, FILE *out)
{
//Get uniform register array.
EFI_ARM_V8_AARCH64_GPR reg_array;
ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
sizeof(EFI_ARM_V8_AARCH64_GPR) / sizeof(UINT64),
ARM_AARCH64_GPR_NAMES);
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single AARCH64 EL1 register set CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_aarch64_el1_to_cper(json_object *registers, FILE *out)
{
//Get uniform register array.
EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS reg_array;
ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
sizeof(EFI_ARM_AARCH64_EL1_CONTEXT_REGISTERS) /
sizeof(UINT64),
ARM_AARCH64_EL1_REGISTER_NAMES);
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single AARCH64 EL2 register set CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_aarch64_el2_to_cper(json_object *registers, FILE *out)
{
//Get uniform register array.
EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS reg_array;
ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
sizeof(EFI_ARM_AARCH64_EL2_CONTEXT_REGISTERS) /
sizeof(UINT64),
ARM_AARCH64_EL2_REGISTER_NAMES);
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single AARCH64 EL3 register set CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_aarch64_el3_to_cper(json_object *registers, FILE *out)
{
//Get uniform register array.
EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS reg_array;
ir_to_uniform_struct64(registers, (UINT64 *)&reg_array,
sizeof(EFI_ARM_AARCH64_EL3_CONTEXT_REGISTERS) /
sizeof(UINT64),
ARM_AARCH64_EL3_REGISTER_NAMES);
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single ARM miscellaneous register set CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_misc_registers_to_cper(json_object *registers, FILE *out)
{
EFI_ARM_MISC_CONTEXT_REGISTER reg_array;
//MRS encoding information.
json_object *mrs_encoding =
json_object_object_get(registers, "mrsEncoding");
reg_array.MrsOp2 = json_object_get_uint64(
json_object_object_get(mrs_encoding, "op2"));
reg_array.MrsCrm = json_object_get_uint64(
json_object_object_get(mrs_encoding, "crm"));
reg_array.MrsCrn = json_object_get_uint64(
json_object_object_get(mrs_encoding, "crn"));
reg_array.MrsOp1 = json_object_get_uint64(
json_object_object_get(mrs_encoding, "op1"));
reg_array.MrsO0 = json_object_get_uint64(
json_object_object_get(mrs_encoding, "o0"));
//Actual register value.
reg_array.Value = json_object_get_uint64(
json_object_object_get(registers, "value"));
//Flush to stream.
fwrite(&reg_array, sizeof(reg_array), 1, out);
fflush(out);
}
//Converts a single ARM unknown register CPER-JSON object to CPER binary, outputting to the given stream.
void ir_arm_unknown_register_to_cper(json_object *registers, FILE *out)
{
//Get base64 represented data.
json_object *encoded = json_object_object_get(registers, "data");
int32_t decoded_len = 0;
UINT8 *decoded = base64_decode(json_object_get_string(encoded),
json_object_get_string_len(encoded),
&decoded_len);
if (decoded == NULL) {
printf("Failed to allocate decode output buffer. \n");
} else {
//Flush out to stream.
fwrite(&decoded, decoded_len, 1, out);
fflush(out);
free(decoded);
}
}