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> 10*f8fc7052SJohn Chung #include "libbase64.h" 11b44314c7SLawrence Tang #include "edk/Cper.h" 12f0f95574SLawrence Tang #include "cper-parse.h" 13b44314c7SLawrence Tang #include "cper-utils.h" 14580423feSLawrence 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); 56*f8fc7052SJohn Chung if (amt_sections == amt_descriptors) { 57e407b4c8SLawrence Tang for (int i = 0; i < amt_sections; i++) { 580cb33793SLawrence Tang //Get the section itself from the IR. 59*f8fc7052SJohn Chung json_object *section = 60*f8fc7052SJohn Chung json_object_array_get_idx(sections, i); 610cb33793SLawrence Tang 62617949e4SLawrence Tang //Convert. 63617949e4SLawrence Tang ir_section_to_cper(section, descriptors[i], out); 640cb33793SLawrence Tang } 65*f8fc7052SJohn Chung } 660cb33793SLawrence Tang 670cb33793SLawrence Tang //Free all remaining resources. 68b44314c7SLawrence Tang free(header); 69*f8fc7052SJohn Chung for (int i = 0; i < amt_descriptors; i++) { 700cb33793SLawrence Tang free(descriptors[i]); 71b44314c7SLawrence Tang } 72*f8fc7052SJohn Chung } 73b44314c7SLawrence Tang 74b44314c7SLawrence Tang //Converts a CPER-JSON IR header to a CPER header structure. 75e407b4c8SLawrence Tang void ir_header_to_cper(json_object *header_ir, 76e407b4c8SLawrence Tang EFI_COMMON_ERROR_RECORD_HEADER *header) 77b44314c7SLawrence Tang { 78b44314c7SLawrence Tang header->SignatureStart = 0x52455043; //CPER 79b44314c7SLawrence Tang 80b44314c7SLawrence Tang //Revision. 81b44314c7SLawrence Tang json_object *revision = json_object_object_get(header_ir, "revision"); 82e407b4c8SLawrence Tang int minor = 83e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 84e407b4c8SLawrence Tang int major = 85e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 86b44314c7SLawrence Tang header->Revision = minor + (major << 8); 87b44314c7SLawrence Tang 88b44314c7SLawrence Tang header->SignatureEnd = 0xFFFFFFFF; 89b44314c7SLawrence Tang 90b44314c7SLawrence Tang //Section count. 91e407b4c8SLawrence Tang int section_count = json_object_get_int( 92e407b4c8SLawrence Tang json_object_object_get(header_ir, "sectionCount")); 93b44314c7SLawrence Tang header->SectionCount = (UINT16)section_count; 94b44314c7SLawrence Tang 95b44314c7SLawrence Tang //Error severity. 96b44314c7SLawrence Tang json_object *severity = json_object_object_get(header_ir, "severity"); 97e407b4c8SLawrence Tang header->ErrorSeverity = (UINT32)json_object_get_uint64( 98e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 99b44314c7SLawrence Tang 100b44314c7SLawrence Tang //Validation bits. 101e407b4c8SLawrence Tang header->ValidationBits = ir_to_bitfield( 102e407b4c8SLawrence Tang json_object_object_get(header_ir, "validationBits"), 3, 103e407b4c8SLawrence Tang CPER_HEADER_VALID_BITFIELD_NAMES); 104b44314c7SLawrence Tang 105b44314c7SLawrence Tang //Record length. 106e407b4c8SLawrence Tang header->RecordLength = (UINT32)json_object_get_uint64( 107e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordLength")); 108b44314c7SLawrence Tang 109b44314c7SLawrence Tang //Timestamp, if present. 110b44314c7SLawrence Tang json_object *timestamp = json_object_object_get(header_ir, "timestamp"); 111e407b4c8SLawrence Tang if (timestamp != NULL) { 112e407b4c8SLawrence Tang string_to_timestamp(&header->TimeStamp, 113e407b4c8SLawrence Tang json_object_get_string(timestamp)); 114e407b4c8SLawrence Tang header->TimeStamp.Flag = json_object_get_boolean( 115e407b4c8SLawrence Tang json_object_object_get(header_ir, 116e407b4c8SLawrence Tang "timestampIsPrecise")); 117b44314c7SLawrence Tang } 118b44314c7SLawrence Tang 119b44314c7SLawrence Tang //Various GUIDs. 120e407b4c8SLawrence Tang json_object *platform_id = 121e407b4c8SLawrence Tang json_object_object_get(header_ir, "platformID"); 122e407b4c8SLawrence Tang json_object *partition_id = 123e407b4c8SLawrence Tang json_object_object_get(header_ir, "partitionID"); 124*f8fc7052SJohn Chung if (platform_id != NULL) { 125e407b4c8SLawrence Tang string_to_guid(&header->PlatformID, 126e407b4c8SLawrence Tang json_object_get_string(platform_id)); 127*f8fc7052SJohn Chung } 128*f8fc7052SJohn Chung if (partition_id != NULL) { 129e407b4c8SLawrence Tang string_to_guid(&header->PartitionID, 130e407b4c8SLawrence Tang json_object_get_string(partition_id)); 131*f8fc7052SJohn Chung } 132e407b4c8SLawrence Tang string_to_guid(&header->CreatorID, 133e407b4c8SLawrence Tang json_object_get_string( 134e407b4c8SLawrence Tang json_object_object_get(header_ir, "creatorID"))); 135b44314c7SLawrence Tang 136b44314c7SLawrence Tang //Notification type. 137e407b4c8SLawrence Tang json_object *notification_type = 138e407b4c8SLawrence Tang json_object_object_get(header_ir, "notificationType"); 139e407b4c8SLawrence Tang string_to_guid(&header->NotificationType, 140e407b4c8SLawrence Tang json_object_get_string(json_object_object_get( 141e407b4c8SLawrence Tang notification_type, "guid"))); 142b44314c7SLawrence Tang 143b44314c7SLawrence Tang //Record ID, persistence info. 144e407b4c8SLawrence Tang header->RecordID = json_object_get_uint64( 145e407b4c8SLawrence Tang json_object_object_get(header_ir, "recordID")); 146e407b4c8SLawrence Tang header->PersistenceInfo = json_object_get_uint64( 147e407b4c8SLawrence Tang json_object_object_get(header_ir, "persistenceInfo")); 148b44314c7SLawrence Tang 149b44314c7SLawrence Tang //Flags. 150b44314c7SLawrence Tang json_object *flags = json_object_object_get(header_ir, "flags"); 151e407b4c8SLawrence Tang header->Flags = (UINT32)json_object_get_uint64( 152e407b4c8SLawrence Tang json_object_object_get(flags, "value")); 153f0f95574SLawrence Tang } 1540cb33793SLawrence Tang 155617949e4SLawrence Tang //Converts a single given IR section into CPER, outputting to the given stream. 156617949e4SLawrence Tang void ir_section_to_cper(json_object *section, 157617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out) 158617949e4SLawrence Tang { 159617949e4SLawrence Tang //Find the correct section type, and parse. 160580423feSLawrence Tang int section_converted = 0; 161*f8fc7052SJohn Chung for (size_t i = 0; i < section_definitions_len; i++) { 162f1f3b839SLawrence Tang if (guid_equal(section_definitions[i].Guid, 163f1f3b839SLawrence Tang &descriptor->SectionType) && 164f1f3b839SLawrence Tang section_definitions[i].ToCPER != NULL) { 165580423feSLawrence Tang section_definitions[i].ToCPER(section, out); 166580423feSLawrence Tang section_converted = 1; 167580423feSLawrence Tang break; 168580423feSLawrence Tang } 169580423feSLawrence Tang } 170580423feSLawrence Tang 171580423feSLawrence Tang //If unknown GUID, so read as a base64 unknown section. 172580423feSLawrence Tang if (!section_converted) { 173617949e4SLawrence Tang json_object *encoded = json_object_object_get(section, "data"); 174*f8fc7052SJohn Chung char *decoded = malloc(json_object_get_string_len(encoded)); 175*f8fc7052SJohn Chung size_t decoded_len = 0; 176*f8fc7052SJohn Chung if (!decoded) { 177*f8fc7052SJohn Chung printf("Failed to allocate decode output buffer. \n"); 178*f8fc7052SJohn Chung } else { 179*f8fc7052SJohn Chung base64_decode(json_object_get_string(encoded), 180*f8fc7052SJohn Chung json_object_get_string_len(encoded), 181*f8fc7052SJohn Chung decoded, &decoded_len, 0); 182*f8fc7052SJohn Chung fwrite(decoded, decoded_len, 1, out); 183617949e4SLawrence Tang fflush(out); 184617949e4SLawrence Tang free(decoded); 185617949e4SLawrence Tang } 186617949e4SLawrence Tang } 187*f8fc7052SJohn Chung } 188617949e4SLawrence Tang 1890cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure. 190e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 191e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor) 1920cb33793SLawrence Tang { 1930cb33793SLawrence Tang //Section offset, length. 194e407b4c8SLawrence Tang descriptor->SectionOffset = (UINT32)json_object_get_uint64( 195e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionOffset")); 196e407b4c8SLawrence Tang descriptor->SectionLength = (UINT32)json_object_get_uint64( 197e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionLength")); 1980cb33793SLawrence Tang 1990cb33793SLawrence Tang //Revision. 200e407b4c8SLawrence Tang json_object *revision = 201e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "revision"); 202e407b4c8SLawrence Tang int minor = 203e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 204e407b4c8SLawrence Tang int major = 205e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 2060cb33793SLawrence Tang descriptor->Revision = minor + (major << 8); 2070cb33793SLawrence Tang 2080cb33793SLawrence Tang //Validation bits, flags. 209e407b4c8SLawrence Tang descriptor->SecValidMask = ir_to_bitfield( 210e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "validationBits"), 2110cb33793SLawrence Tang 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 212e407b4c8SLawrence Tang descriptor->SectionFlags = ir_to_bitfield( 213e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "flags"), 8, 214e407b4c8SLawrence Tang CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 2150cb33793SLawrence Tang 2160cb33793SLawrence Tang //Section type. 217e407b4c8SLawrence Tang json_object *section_type = 218e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionType"); 219e407b4c8SLawrence Tang string_to_guid(&descriptor->SectionType, 220e407b4c8SLawrence Tang json_object_get_string( 221e407b4c8SLawrence Tang json_object_object_get(section_type, "data"))); 2220cb33793SLawrence Tang 2230cb33793SLawrence Tang //FRU ID, if present. 224e407b4c8SLawrence Tang json_object *fru_id = 225e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruID"); 226*f8fc7052SJohn Chung if (fru_id != NULL) { 227e407b4c8SLawrence Tang string_to_guid(&descriptor->FruId, 228e407b4c8SLawrence Tang json_object_get_string(fru_id)); 229*f8fc7052SJohn Chung } 2300cb33793SLawrence Tang 2310cb33793SLawrence Tang //Severity code. 232e407b4c8SLawrence Tang json_object *severity = 233e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "severity"); 234e407b4c8SLawrence Tang descriptor->Severity = (UINT32)json_object_get_uint64( 235e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 2360cb33793SLawrence Tang 2370cb33793SLawrence Tang //FRU text, if present. 238e407b4c8SLawrence Tang json_object *fru_text = 239e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruText"); 240*f8fc7052SJohn Chung if (fru_text != NULL) { 241e407b4c8SLawrence Tang strncpy(descriptor->FruString, json_object_get_string(fru_text), 242e407b4c8SLawrence Tang 20); 2430cb33793SLawrence Tang } 244*f8fc7052SJohn Chung } 245617949e4SLawrence Tang 246617949e4SLawrence Tang //Converts IR for a given single section format CPER record into CPER binary. 247617949e4SLawrence Tang void ir_single_section_to_cper(json_object *ir, FILE *out) 248617949e4SLawrence Tang { 249617949e4SLawrence Tang //Create & write a section descriptor to file. 250617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor = 251617949e4SLawrence Tang (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 252617949e4SLawrence Tang 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 253617949e4SLawrence Tang ir_section_descriptor_to_cper( 254617949e4SLawrence Tang json_object_object_get(ir, "sectionDescriptor"), 255617949e4SLawrence Tang section_descriptor); 256617949e4SLawrence Tang fwrite(section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 257617949e4SLawrence Tang out); 258617949e4SLawrence Tang fflush(out); 259617949e4SLawrence Tang 260617949e4SLawrence Tang //Write section to file. 261617949e4SLawrence Tang ir_section_to_cper(json_object_object_get(ir, "section"), 262617949e4SLawrence Tang section_descriptor, out); 263617949e4SLawrence Tang 264617949e4SLawrence Tang //Free remaining resources. 265617949e4SLawrence Tang free(section_descriptor); 266617949e4SLawrence Tang } 267