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" 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); 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. 154580423feSLawrence Tang int section_converted = 0; 155*f1f3b839SLawrence Tang for (int i = 0; i < section_definitions_len; i++) { 156*f1f3b839SLawrence Tang if (guid_equal(section_definitions[i].Guid, 157*f1f3b839SLawrence Tang &descriptor->SectionType) && 158*f1f3b839SLawrence Tang section_definitions[i].ToCPER != NULL) { 159580423feSLawrence Tang section_definitions[i].ToCPER(section, out); 160580423feSLawrence Tang section_converted = 1; 161580423feSLawrence Tang break; 162580423feSLawrence Tang } 163580423feSLawrence Tang } 164580423feSLawrence Tang 165580423feSLawrence Tang //If unknown GUID, so read as a base64 unknown section. 166580423feSLawrence Tang if (!section_converted) { 167617949e4SLawrence Tang json_object *encoded = json_object_object_get(section, "data"); 168617949e4SLawrence Tang UINT8 *decoded = 169617949e4SLawrence Tang b64_decode(json_object_get_string(encoded), 170617949e4SLawrence Tang json_object_get_string_len(encoded)); 171617949e4SLawrence Tang fwrite(decoded, descriptor->SectionLength, 1, out); 172617949e4SLawrence Tang fflush(out); 173617949e4SLawrence Tang free(decoded); 174617949e4SLawrence Tang } 175617949e4SLawrence Tang } 176617949e4SLawrence Tang 1770cb33793SLawrence Tang //Converts a single CPER-JSON IR section descriptor into a CPER structure. 178e407b4c8SLawrence Tang void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 179e407b4c8SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *descriptor) 1800cb33793SLawrence Tang { 1810cb33793SLawrence Tang //Section offset, length. 182e407b4c8SLawrence Tang descriptor->SectionOffset = (UINT32)json_object_get_uint64( 183e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionOffset")); 184e407b4c8SLawrence Tang descriptor->SectionLength = (UINT32)json_object_get_uint64( 185e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionLength")); 1860cb33793SLawrence Tang 1870cb33793SLawrence Tang //Revision. 188e407b4c8SLawrence Tang json_object *revision = 189e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "revision"); 190e407b4c8SLawrence Tang int minor = 191e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "minor")); 192e407b4c8SLawrence Tang int major = 193e407b4c8SLawrence Tang json_object_get_int(json_object_object_get(revision, "major")); 1940cb33793SLawrence Tang descriptor->Revision = minor + (major << 8); 1950cb33793SLawrence Tang 1960cb33793SLawrence Tang //Validation bits, flags. 197e407b4c8SLawrence Tang descriptor->SecValidMask = ir_to_bitfield( 198e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "validationBits"), 1990cb33793SLawrence Tang 2, CPER_SECTION_DESCRIPTOR_VALID_BITFIELD_NAMES); 200e407b4c8SLawrence Tang descriptor->SectionFlags = ir_to_bitfield( 201e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "flags"), 8, 202e407b4c8SLawrence Tang CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 2030cb33793SLawrence Tang 2040cb33793SLawrence Tang //Section type. 205e407b4c8SLawrence Tang json_object *section_type = 206e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "sectionType"); 207e407b4c8SLawrence Tang string_to_guid(&descriptor->SectionType, 208e407b4c8SLawrence Tang json_object_get_string( 209e407b4c8SLawrence Tang json_object_object_get(section_type, "data"))); 2100cb33793SLawrence Tang 2110cb33793SLawrence Tang //FRU ID, if present. 212e407b4c8SLawrence Tang json_object *fru_id = 213e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruID"); 2140cb33793SLawrence Tang if (fru_id != NULL) 215e407b4c8SLawrence Tang string_to_guid(&descriptor->FruId, 216e407b4c8SLawrence Tang json_object_get_string(fru_id)); 2170cb33793SLawrence Tang 2180cb33793SLawrence Tang //Severity code. 219e407b4c8SLawrence Tang json_object *severity = 220e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "severity"); 221e407b4c8SLawrence Tang descriptor->Severity = (UINT32)json_object_get_uint64( 222e407b4c8SLawrence Tang json_object_object_get(severity, "code")); 2230cb33793SLawrence Tang 2240cb33793SLawrence Tang //FRU text, if present. 225e407b4c8SLawrence Tang json_object *fru_text = 226e407b4c8SLawrence Tang json_object_object_get(section_descriptor_ir, "fruText"); 2270cb33793SLawrence Tang if (fru_text != NULL) 228e407b4c8SLawrence Tang strncpy(descriptor->FruString, json_object_get_string(fru_text), 229e407b4c8SLawrence Tang 20); 2300cb33793SLawrence Tang } 231617949e4SLawrence Tang 232617949e4SLawrence Tang //Converts IR for a given single section format CPER record into CPER binary. 233617949e4SLawrence Tang void ir_single_section_to_cper(json_object *ir, FILE *out) 234617949e4SLawrence Tang { 235617949e4SLawrence Tang //Create & write a section descriptor to file. 236617949e4SLawrence Tang EFI_ERROR_SECTION_DESCRIPTOR *section_descriptor = 237617949e4SLawrence Tang (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 238617949e4SLawrence Tang 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 239617949e4SLawrence Tang ir_section_descriptor_to_cper( 240617949e4SLawrence Tang json_object_object_get(ir, "sectionDescriptor"), 241617949e4SLawrence Tang section_descriptor); 242617949e4SLawrence Tang fwrite(section_descriptor, sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 243617949e4SLawrence Tang out); 244617949e4SLawrence Tang fflush(out); 245617949e4SLawrence Tang 246617949e4SLawrence Tang //Write section to file. 247617949e4SLawrence Tang ir_section_to_cper(json_object_object_get(ir, "section"), 248617949e4SLawrence Tang section_descriptor, out); 249617949e4SLawrence Tang 250617949e4SLawrence Tang //Free remaining resources. 251617949e4SLawrence Tang free(section_descriptor); 252617949e4SLawrence Tang }