1f0f95574SLawrence Tang /** 2f0f95574SLawrence Tang * Describes functions for parsing JSON IR CPER data into binary CPER format. 3f0f95574SLawrence Tang * 4f0f95574SLawrence Tang * Author: Lawrence.Tang@arm.com 5f0f95574SLawrence Tang **/ 6f0f95574SLawrence Tang 7f0f95574SLawrence Tang #include <stdio.h> 80cb33793SLawrence Tang #include <string.h> 95202bbb4SLawrence Tang #include <json.h> 100cb33793SLawrence Tang #include "b64.h" 11b44314c7SLawrence Tang #include "edk/Cper.h" 12f0f95574SLawrence Tang #include "cper-parse.h" 13b44314c7SLawrence Tang #include "cper-utils.h" 14*580423feSLawrence Tang #include "sections/cper-section.h" 15b44314c7SLawrence Tang 16b44314c7SLawrence Tang //Private pre-declarations. 17e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir, 18e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header); 19e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 20e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor); 21617949e4SLawrence Tang void ir_section_to_cper(json_object *section, 22617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out); 23f0f95574SLawrence Tang 24f0f95574SLawrence Tang //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream. 250cb33793SLawrence Tang //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call, 260cb33793SLawrence Tang //use validate_schema() from json-schema.h before attempting to call this function. 27f0f95574SLawrence Tang void ir_to_cper(json_object *ir, FILE *out) 28f0f95574SLawrence Tang { 29b44314c7SLawrence Tang //Create the CPER header. 30e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header = 31e407b4c8SLawrence Tang (EFI_COMMON_ERROR_RECORD_HEADER *)calloc( 32e407b4c8SLawrence Tang 1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 33b44314c7SLawrence Tang ir_header_to_cper(json_object_object_get(ir, "header"), header); 34b44314c7SLawrence Tang fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out); 35b44314c7SLawrence Tang fflush(out); 360cb33793SLawrence Tang 370cb33793SLawrence Tang //Create the CPER section descriptors. 38e407b4c8SLawrence Tang json_object *section_descriptors = 39e407b4c8SLawrence Tang json_object_object_get(ir, "sectionDescriptors"); 400cb33793SLawrence Tang int amt_descriptors = json_object_array_length(section_descriptors); 410cb33793SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors]; 42e407b4c8SLawrence Tang for (int i = 0; i < amt_descriptors; i++) { 43e407b4c8SLawrence Tang descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 44e407b4c8SLawrence Tang 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 45e407b4c8SLawrence Tang ir_section_descriptor_to_cper( 46e407b4c8SLawrence Tang json_object_array_get_idx(section_descriptors, i), 47e407b4c8SLawrence Tang descriptors[i]); 48e407b4c8SLawrence Tang fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 49e407b4c8SLawrence Tang out); 500cb33793SLawrence Tang fflush(out); 510cb33793SLawrence Tang } 520cb33793SLawrence Tang 530cb33793SLawrence Tang //Run through each section in turn. 540cb33793SLawrence Tang json_object *sections = json_object_object_get(ir, "sections"); 550cb33793SLawrence Tang int amt_sections = json_object_array_length(sections); 56e407b4c8SLawrence Tang for (int i = 0; i < amt_sections; i++) { 570cb33793SLawrence Tang //Get the section itself from the IR. 580cb33793SLawrence Tang json_object *section = json_object_array_get_idx(sections, i); 590cb33793SLawrence Tang 60617949e4SLawrence Tang //Convert. 61617949e4SLawrence Tang ir_section_to_cper(section, descriptors[i], out); 620cb33793SLawrence Tang } 630cb33793SLawrence Tang 640cb33793SLawrence Tang //Free all remaining resources. 65b44314c7SLawrence Tang free(header); 660cb33793SLawrence Tang for (int i = 0; i < amt_descriptors; i++) 670cb33793SLawrence Tang free(descriptors[i]); 68b44314c7SLawrence Tang } 69b44314c7SLawrence Tang 70b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure. 71e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir, 72e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header) 73b44314c7SLawrence Tang { 74b44314c7SLawrence Tang header->SignatureStart = 0x52455043; //CPER 75b44314c7SLawrence Tang 76b44314c7SLawrence Tang //Revision. 77b44314c7SLawrence Tang json_object *revision = json_object_object_get(header_ir, "revision"); 78e407b4c8SLawrence Tang int minor = 79e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 80e407b4c8SLawrence Tang int major = 81e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 82b44314c7SLawrence Tang header->Revision = minor + (major << 8); 83b44314c7SLawrence Tang 84b44314c7SLawrence Tang header->SignatureEnd = 0xFFFFFFFF; 85b44314c7SLawrence Tang 86b44314c7SLawrence Tang //Section count. 87e407b4c8SLawrence Tang int section_count = json_object_get_int( 88e407b4c8SLawrence Tang json_object_object_get(header_ir, "sectionCount")); 89b44314c7SLawrence Tang header->SectionCount = (UINT16)section_count; 90b44314c7SLawrence Tang 91b44314c7SLawrence Tang //Error severity. 92b44314c7SLawrence Tang json_object *severity = json_object_object_get(header_ir, "severity"); 93e407b4c8SLawrence Tang header->ErrorSeverity = (UINT32)json_object_get_uint64( 94e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 95b44314c7SLawrence Tang 96b44314c7SLawrence Tang //Validation bits. 97e407b4c8SLawrence Tang header->ValidationBits = ir_to_bitfield( 98e407b4c8SLawrence Tang json_object_object_get(header_ir, "validationBits"), 3, 99e407b4c8SLawrence Tang CPER_HEADER_VALID_BITFIELD_NAMES); 100b44314c7SLawrence Tang 101b44314c7SLawrence Tang //Record length. 102e407b4c8SLawrence Tang header->RecordLength = (UINT32)json_object_get_uint64( 103e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordLength")); 104b44314c7SLawrence Tang 105b44314c7SLawrence Tang //Timestamp, if present. 106b44314c7SLawrence Tang json_object *timestamp = json_object_object_get(header_ir, "timestamp"); 107e407b4c8SLawrence Tang if (timestamp != NULL) { 108e407b4c8SLawrence Tang string_to_timestamp(&header->TimeStamp, 109e407b4c8SLawrence Tang json_object_get_string(timestamp)); 110e407b4c8SLawrence Tang header->TimeStamp.Flag = json_object_get_boolean( 111e407b4c8SLawrence Tang json_object_object_get(header_ir, 112e407b4c8SLawrence Tang "timestampIsPrecise")); 113b44314c7SLawrence Tang } 114b44314c7SLawrence Tang 115b44314c7SLawrence Tang //Various GUIDs. 116e407b4c8SLawrence Tang json_object *platform_id = 117e407b4c8SLawrence Tang json_object_object_get(header_ir, "platformID"); 118e407b4c8SLawrence Tang json_object *partition_id = 119e407b4c8SLawrence Tang json_object_object_get(header_ir, "partitionID"); 120b44314c7SLawrence Tang if (platform_id != NULL) 121e407b4c8SLawrence Tang string_to_guid(&header->PlatformID, 122e407b4c8SLawrence Tang json_object_get_string(platform_id)); 123b44314c7SLawrence Tang if (partition_id != NULL) 124e407b4c8SLawrence Tang string_to_guid(&header->PartitionID, 125e407b4c8SLawrence Tang json_object_get_string(partition_id)); 126e407b4c8SLawrence Tang string_to_guid(&header->CreatorID, 127e407b4c8SLawrence Tang json_object_get_string( 128e407b4c8SLawrence Tang json_object_object_get(header_ir, "creatorID"))); 129b44314c7SLawrence Tang 130b44314c7SLawrence Tang //Notification type. 131e407b4c8SLawrence Tang json_object *notification_type = 132e407b4c8SLawrence Tang json_object_object_get(header_ir, "notificationType"); 133e407b4c8SLawrence Tang string_to_guid(&header->NotificationType, 134e407b4c8SLawrence Tang json_object_get_string(json_object_object_get( 135e407b4c8SLawrence Tang notification_type, "guid"))); 136b44314c7SLawrence Tang 137b44314c7SLawrence Tang //Record ID, persistence info. 138e407b4c8SLawrence Tang header->RecordID = json_object_get_uint64( 139e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordID")); 140e407b4c8SLawrence Tang header->PersistenceInfo = json_object_get_uint64( 141e407b4c8SLawrence Tang json_object_object_get(header_ir, "persistenceInfo")); 142b44314c7SLawrence Tang 143b44314c7SLawrence Tang //Flags. 144b44314c7SLawrence Tang json_object *flags = json_object_object_get(header_ir, "flags"); 145e407b4c8SLawrence Tang header->Flags = (UINT32)json_object_get_uint64( 146e407b4c8SLawrence Tang json_object_object_get(flags, "value")); 147f0f95574SLawrence Tang } 1480cb33793SLawrence Tang 149617949e4SLawrence Tang //Converts a single given IR section into CPER, outputting to the given stream. 150617949e4SLawrence Tang void ir_section_to_cper(json_object *section, 151617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out) 152617949e4SLawrence Tang { 153617949e4SLawrence Tang //Find the correct section type, and parse. 154*580423feSLawrence Tang int section_converted = 0; 155*580423feSLawrence Tang for (int i=0; i<section_definitions_len; i++) 156*580423feSLawrence Tang { 157*580423feSLawrence Tang if (guid_equal(section_definitions[i].Guid, &descriptor->SectionType) && section_definitions[i].ToCPER != NULL) { 158*580423feSLawrence Tang section_definitions[i].ToCPER(section, out); 159*580423feSLawrence Tang section_converted = 1; 160*580423feSLawrence Tang break; 161*580423feSLawrence Tang } 162*580423feSLawrence Tang } 163*580423feSLawrence Tang 164*580423feSLawrence Tang //If unknown GUID, so read as a base64 unknown section. 165*580423feSLawrence Tang if (!section_converted) { 166617949e4SLawrence Tang json_object *encoded = json_object_object_get(section, "data"); 167617949e4SLawrence Tang UINT8 *decoded = 168617949e4SLawrence Tang b64_decode(json_object_get_string(encoded), 169617949e4SLawrence Tang json_object_get_string_len(encoded)); 170617949e4SLawrence Tang fwrite(decoded, descriptor->SectionLength, 1, out); 171617949e4SLawrence Tang fflush(out); 172617949e4SLawrence Tang free(decoded); 173617949e4SLawrence Tang } 174617949e4SLawrence Tang } 175617949e4SLawrence Tang 1760cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure. 177e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 178e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor) 1790cb33793SLawrence Tang { 1800cb33793SLawrence Tang //Section offset, length. 181e407b4c8SLawrence Tang descriptor->SectionOffset = (UINT32)json_object_get_uint64( 182e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionOffset")); 183e407b4c8SLawrence Tang descriptor->SectionLength = (UINT32)json_object_get_uint64( 184e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionLength")); 1850cb33793SLawrence Tang 1860cb33793SLawrence Tang //Revision. 187e407b4c8SLawrence Tang json_object *revision = 188e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "revision"); 189e407b4c8SLawrence Tang int minor = 190e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 191e407b4c8SLawrence Tang int major = 192e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 1930cb33793SLawrence Tang descriptor->Revision = minor + (major << 8); 1940cb33793SLawrence Tang 1950cb33793SLawrence Tang //Validation bits, flags. 196e407b4c8SLawrence Tang descriptor->SecValidMask = ir_to_bitfield( 197e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "validationBits"), 1980cb33793SLawrence Tang 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 199e407b4c8SLawrence Tang descriptor->SectionFlags = ir_to_bitfield( 200e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "flags"), 8, 201e407b4c8SLawrence Tang CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 2020cb33793SLawrence Tang 2030cb33793SLawrence Tang //Section type. 204e407b4c8SLawrence Tang json_object *section_type = 205e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionType"); 206e407b4c8SLawrence Tang string_to_guid(&descriptor->SectionType, 207e407b4c8SLawrence Tang json_object_get_string( 208e407b4c8SLawrence Tang json_object_object_get(section_type, "data"))); 2090cb33793SLawrence Tang 2100cb33793SLawrence Tang //FRU ID, if present. 211e407b4c8SLawrence Tang json_object *fru_id = 212e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruID"); 2130cb33793SLawrence Tang if (fru_id != NULL) 214e407b4c8SLawrence Tang string_to_guid(&descriptor->FruId, 215e407b4c8SLawrence Tang json_object_get_string(fru_id)); 2160cb33793SLawrence Tang 2170cb33793SLawrence Tang //Severity code. 218e407b4c8SLawrence Tang json_object *severity = 219e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "severity"); 220e407b4c8SLawrence Tang descriptor->Severity = (UINT32)json_object_get_uint64( 221e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 2220cb33793SLawrence Tang 2230cb33793SLawrence Tang //FRU text, if present. 224e407b4c8SLawrence Tang json_object *fru_text = 225e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruText"); 2260cb33793SLawrence Tang if (fru_text != NULL) 227e407b4c8SLawrence Tang strncpy(descriptor->FruString, json_object_get_string(fru_text), 228e407b4c8SLawrence Tang 20); 2290cb33793SLawrence Tang } 230617949e4SLawrence Tang 231617949e4SLawrence Tang //Converts IR for a given single section format CPER record into CPER binary. 232617949e4SLawrence Tang void ir_single_section_to_cper(json_object *ir, FILE *out) 233617949e4SLawrence Tang { 234617949e4SLawrence Tang //Create & write a section descriptor to file. 235617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor = 236617949e4SLawrence Tang (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 237617949e4SLawrence Tang 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 238617949e4SLawrence Tang ir_section_descriptor_to_cper( 239617949e4SLawrence Tang json_object_object_get(ir, "sectionDescriptor"), 240617949e4SLawrence Tang section_descriptor); 241617949e4SLawrence Tang fwrite(section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 242617949e4SLawrence Tang out); 243617949e4SLawrence Tang fflush(out); 244617949e4SLawrence Tang 245617949e4SLawrence Tang //Write section to file. 246617949e4SLawrence Tang ir_section_to_cper(json_object_object_get(ir, "section"), 247617949e4SLawrence Tang section_descriptor, out); 248617949e4SLawrence Tang 249617949e4SLawrence Tang //Free remaining resources. 250617949e4SLawrence Tang free(section_descriptor); 251617949e4SLawrence Tang }