blob: 067c4f8daec2bb4eab684ab3a8bf97400af8043a [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 <string.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();
//Length of ValidationBits from spec
ValidationTypes ui64Type = { UINT_64T,
.value.ui64 = record->ValidFields };
//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.
if (isvalid_prop_to_ir(&ui64Type, 1)) {
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).
if (isvalid_prop_to_ir(&ui64Type, 0)) {
uint64_t mpidr_eli1 = record->MPIDR_EL1;
uint64_t sock;
json_object_object_add(section_ir, "mpidrEl1",
json_object_new_uint64(mpidr_eli1));
//Arm Processor socket info dependes on mpidr_eli1
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));
if (isvalid_prop_to_ir(&ui64Type, 2)) {
//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 (isvalid_prop_to_ir(&ui64Type, 3)) {
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) {
printf("base64 encode of vendorSpecificInfo failed\n");
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);
} else {
printf("vendorSpecificInfo is marked valid but not present in binary\n");
}
}
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.
ValidationTypes ui16Type = { UINT_16T,
.value.ui16 = error_info->ValidationBits };
//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.
if (isvalid_prop_to_ir(&ui16Type, 0)) {
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.
if (isvalid_prop_to_ir(&ui16Type, 1)) {
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.
if (isvalid_prop_to_ir(&ui16Type, 2)) {
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.
if (isvalid_prop_to_ir(&ui16Type, 3)) {
json_object_object_add(
error_info_ir, "virtualFaultAddress",
json_object_new_uint64(
error_info->VirtualFaultAddress));
}
if (isvalid_prop_to_ir(&ui16Type, 4)) {
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.
ValidationTypes ui64Type = {
UINT_64T, .value.ui64 = cache_tlb_error->ValidationBits
};
//Transaction type.
if (isvalid_prop_to_ir(&ui64Type, 0)) {
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.
bool cacheErrorFlag = 1;
if (error_info->Type == 0) {
cache_tlb_propname = "cacheError";
} else {
//TLB operation.
cache_tlb_propname = "tlbError";
cacheErrorFlag = 0;
}
if (isvalid_prop_to_ir(&ui64Type, 1)) {
json_object *operation;
if (cacheErrorFlag) {
//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)");
} else {
operation = integer_to_readable_pair(
cache_tlb_error->Operation, 9,
ARM_TLB_OPERATION_TYPES_KEYS,
ARM_TLB_OPERATION_TYPES_VALUES,
"Unknown (Reserved)");
}
json_object_object_add(cache_tlb_error_ir, "operation",
operation);
}
//Miscellaneous remaining fields.
if (isvalid_prop_to_ir(&ui64Type, 2)) {
json_object_object_add(
cache_tlb_error_ir, "level",
json_object_new_int(cache_tlb_error->Level));
}
if (isvalid_prop_to_ir(&ui64Type, 3)) {
json_object_object_add(
cache_tlb_error_ir, "processorContextCorrupt",
json_object_new_boolean(
cache_tlb_error->ProcessorContextCorrupt));
}
if (isvalid_prop_to_ir(&ui64Type, 4)) {
json_object_object_add(
cache_tlb_error_ir, "corrected",
json_object_new_boolean(cache_tlb_error->Corrected));
}
if (isvalid_prop_to_ir(&ui64Type, 5)) {
json_object_object_add(
cache_tlb_error_ir, "precisePC",
json_object_new_boolean(cache_tlb_error->PrecisePC));
}
if (isvalid_prop_to_ir(&ui64Type, 6)) {
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();
json_object *bus_prop = json_object_new_object();
char *bus_propname = "busError";
//Validation bits.
ValidationTypes ui64Type = { UINT_64T,
.value.ui64 = bus_error->ValidationBits };
//Transaction type.
if (isvalid_prop_to_ir(&ui64Type, 0)) {
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.
if (isvalid_prop_to_ir(&ui64Type, 1)) {
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);
}
if (isvalid_prop_to_ir(&ui64Type, 2)) {
//Affinity level of bus error, + miscellaneous fields.
json_object_object_add(bus_error_ir, "level",
json_object_new_int(bus_error->Level));
}
if (isvalid_prop_to_ir(&ui64Type, 3)) {
json_object_object_add(
bus_error_ir, "processorContextCorrupt",
json_object_new_boolean(
bus_error->ProcessorContextCorrupt));
}
if (isvalid_prop_to_ir(&ui64Type, 4)) {
json_object_object_add(
bus_error_ir, "corrected",
json_object_new_boolean(bus_error->Corrected));
}
if (isvalid_prop_to_ir(&ui64Type, 5)) {
json_object_object_add(
bus_error_ir, "precisePC",
json_object_new_boolean(bus_error->PrecisePC));
}
if (isvalid_prop_to_ir(&ui64Type, 6)) {
json_object_object_add(
bus_error_ir, "restartablePC",
json_object_new_boolean(bus_error->RestartablePC));
}
//Participation type.
if (isvalid_prop_to_ir(&ui64Type, 7)) {
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);
}
if (isvalid_prop_to_ir(&ui64Type, 8)) {
json_object_object_add(
bus_error_ir, "timedOut",
json_object_new_boolean(bus_error->TimeOut));
}
//Address space.
if (isvalid_prop_to_ir(&ui64Type, 9)) {
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
if (isvalid_prop_to_ir(&ui64Type, 10)) {
json_object_object_add(
bus_error_ir, "memoryAttributes",
json_object_new_int(
bus_error->MemoryAddressAttributes));
}
//Access Mode
if (isvalid_prop_to_ir(&ui64Type, 8)) {
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);
}
json_object_object_add(bus_prop, bus_propname, bus_error_ir);
return bus_prop;
}
//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;
memset(&section_cper, 0, sizeof(section_cper));
//Validation bits.
struct json_object *obj = NULL;
ValidationTypes u32Type = { UINT_32T, .value.ui32 = 0 };
//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"));
if (json_object_object_get_ex(section, "mpidrEl1", &obj)) {
section_cper.MPIDR_EL1 = json_object_get_uint64(obj);
add_to_valid_bitfield(&u32Type, 0);
}
if (json_object_object_get_ex(section, "errorAffinity", &obj)) {
section_cper.ErrorAffinityLevel = readable_pair_to_integer(obj);
add_to_valid_bitfield(&u32Type, 1);
}
section_cper.MIDR_EL1 = json_object_get_uint64(
json_object_object_get(section, "midrEl1"));
if (json_object_object_get_ex(section, "running", &obj)) {
section_cper.RunningState = json_object_get_boolean(obj);
add_to_valid_bitfield(&u32Type, 2);
}
//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);
}
//Validationbits for EFI_ARM_ERROR_RECORD should also consider vendorSpecificInfo
bool vendorSpecificPresent =
json_object_object_get_ex(section, "vendorSpecificInfo", &obj);
json_object *vendor_specific_info = obj;
if (vendorSpecificPresent) {
add_to_valid_bitfield(&u32Type, 3);
}
section_cper.ValidFields = u32Type.value.ui32;
//Flush header to stream.
fwrite(&section_cper, sizeof(section_cper), 1, 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.
if (vendorSpecificPresent) {
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);
free(decoded);
}
fflush(out);
}
//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;
memset(&error_info_cper, 0, sizeof(error_info_cper));
struct json_object *obj = NULL;
ValidationTypes ui16Type = { UINT_16T, .value.ui16 = 0 };
//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"));
//Type, multiple error.
error_info_cper.Type = (UINT8)readable_pair_to_integer(
json_object_object_get(error_info, "errorType"));
if (json_object_object_get_ex(error_info, "multipleError", &obj)) {
error_info_cper.MultipleError =
(UINT16)readable_pair_to_integer(obj);
add_to_valid_bitfield(&ui16Type, 0);
} else {
error_info_cper.MultipleError = 0;
}
//Flags object.
if (json_object_object_get_ex(error_info, "flags", &obj)) {
error_info_cper.Flags = (UINT8)ir_to_bitfield(
obj, 4, ARM_ERROR_INFO_ENTRY_FLAGS_NAMES);
add_to_valid_bitfield(&ui16Type, 1);
} else {
error_info_cper.Flags = 0;
}
//Error information.
if (json_object_object_get_ex(error_info, "errorInformation", &obj)) {
json_object *error_info_information = obj;
json_object *error_info_prop = NULL;
switch (error_info_cper.Type) {
case ARM_ERROR_INFORMATION_TYPE_CACHE:
error_info_cper.ErrorInformation.Value = 0;
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_cper.ErrorInformation.Value = 0;
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:
error_info_cper.ErrorInformation.Value = 0;
error_info_prop = json_object_object_get(
error_info_information, "busError");
ir_arm_error_bus_info_to_cper(
error_info_prop,
&error_info_cper.ErrorInformation.BusError);
break;
default:
//Unknown error information type.
break;
}
add_to_valid_bitfield(&ui16Type, 2);
}
//Virtual/physical fault address.
if (json_object_object_get_ex(error_info, "virtualFaultAddress",
&obj)) {
error_info_cper.VirtualFaultAddress =
json_object_get_uint64(obj);
add_to_valid_bitfield(&ui16Type, 3);
} else {
error_info_cper.VirtualFaultAddress = 0;
}
if (json_object_object_get_ex(error_info, "physicalFaultAddress",
&obj)) {
error_info_cper.PhysicalFaultAddress =
json_object_get_uint64(obj);
add_to_valid_bitfield(&ui16Type, 4);
} else {
error_info_cper.PhysicalFaultAddress = 0;
}
error_info_cper.ValidationBits = ui16Type.value.ui16;
//Write out to stream.
fwrite(&error_info_cper, sizeof(EFI_ARM_ERROR_INFORMATION_ENTRY), 1,
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.
ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
struct json_object *obj = NULL;
//Miscellaneous value fields.
if (json_object_object_get_ex(error_information, "transactionType",
&obj)) {
error_info_cper->TransactionType =
readable_pair_to_integer(obj);
add_to_valid_bitfield(&ui64Type, 0);
}
if (json_object_object_get_ex(error_information, "operation", &obj)) {
error_info_cper->Operation = readable_pair_to_integer(obj);
add_to_valid_bitfield(&ui64Type, 1);
}
if (json_object_object_get_ex(error_information, "level", &obj)) {
error_info_cper->Level = json_object_get_uint64(obj);
add_to_valid_bitfield(&ui64Type, 2);
}
if (json_object_object_get_ex(error_information,
"processorContextCorrupt", &obj)) {
error_info_cper->ProcessorContextCorrupt =
json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 3);
}
if (json_object_object_get_ex(error_information, "corrected", &obj)) {
error_info_cper->Corrected = json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 4);
}
if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
error_info_cper->PrecisePC = json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 5);
}
if (json_object_object_get_ex(error_information, "restartablePC",
&obj)) {
error_info_cper->RestartablePC = json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 6);
}
error_info_cper->Reserved = 0;
error_info_cper->ValidationBits = ui64Type.value.ui64;
}
//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.
ValidationTypes ui64Type = { UINT_64T, .value.ui64 = 0 };
struct json_object *obj = NULL;
memset(error_info_cper, 0, sizeof(EFI_ARM_BUS_ERROR_STRUCTURE));
//Miscellaneous value fields.
if (json_object_object_get_ex(error_information, "transactionType",
&obj)) {
error_info_cper->TransactionType =
readable_pair_to_integer(obj);
add_to_valid_bitfield(&ui64Type, 0);
} else {
error_info_cper->TransactionType = 0;
}
if (json_object_object_get_ex(error_information, "operation", &obj)) {
error_info_cper->Operation = readable_pair_to_integer(obj);
add_to_valid_bitfield(&ui64Type, 1);
} else {
error_info_cper->Operation = 0;
}
if (json_object_object_get_ex(error_information, "level", &obj)) {
error_info_cper->Level = json_object_get_uint64(obj);
add_to_valid_bitfield(&ui64Type, 2);
} else {
error_info_cper->Level = 0;
}
if (json_object_object_get_ex(error_information,
"processorContextCorrupt", &obj)) {
error_info_cper->ProcessorContextCorrupt =
json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 3);
} else {
error_info_cper->ProcessorContextCorrupt = 0;
}
if (json_object_object_get_ex(error_information, "corrected", &obj)) {
error_info_cper->Corrected = json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 4);
} else {
error_info_cper->Corrected = 0;
}
if (json_object_object_get_ex(error_information, "precisePC", &obj)) {
error_info_cper->PrecisePC = json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 5);
} else {
error_info_cper->PrecisePC = 0;
}
if (json_object_object_get_ex(error_information, "restartablePC",
&obj)) {
error_info_cper->RestartablePC = json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 6);
} else {
error_info_cper->RestartablePC = 0;
}
if (json_object_object_get_ex(error_information, "participationType",
&obj)) {
error_info_cper->ParticipationType =
readable_pair_to_integer(obj);
add_to_valid_bitfield(&ui64Type, 7);
} else {
error_info_cper->ParticipationType = 0;
}
if (json_object_object_get_ex(error_information, "timedOut", &obj)) {
error_info_cper->TimeOut = json_object_get_boolean(obj);
add_to_valid_bitfield(&ui64Type, 8);
} else {
error_info_cper->TimeOut = 0;
}
if (json_object_object_get_ex(error_information, "addressSpace",
&obj)) {
error_info_cper->AddressSpace = readable_pair_to_integer(obj);
add_to_valid_bitfield(&ui64Type, 9);
} else {
error_info_cper->AddressSpace = 0;
}
if (json_object_object_get_ex(error_information, "accessMode", &obj)) {
error_info_cper->AccessMode = readable_pair_to_integer(obj);
add_to_valid_bitfield(&ui64Type, 11);
} else {
error_info_cper->AccessMode = 0;
}
if (json_object_object_get_ex(error_information, "memoryAttributes",
&obj)) {
error_info_cper->MemoryAddressAttributes =
json_object_get_uint64(obj);
add_to_valid_bitfield(&ui64Type, 10);
} else {
error_info_cper->MemoryAddressAttributes = 0;
}
error_info_cper->Reserved = 0;
error_info_cper->ValidationBits = ui64Type.value.ui64;
}
//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);
}
}