1 /** 2 * Describes functions for parsing JSON IR CPER data into binary CPER format. 3 * 4 * Author: Lawrence.Tang@arm.com 5 **/ 6 7 #include <stdio.h> 8 #include <string.h> 9 #include <json.h> 10 #include <libcper/log.h> 11 #include <libcper/base64.h> 12 #include <libcper/Cper.h> 13 #include <libcper/cper-parse.h> 14 #include <libcper/cper-utils.h> 15 #include <libcper/sections/cper-section.h> 16 17 //Private pre-declarations. 18 void ir_header_to_cper(json_object *header_ir, 19 EFI_COMMON_ERROR_RECORD_HEADER *header); 20 void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 21 EFI_ERROR_SECTION_DESCRIPTOR *descriptor); 22 void ir_section_to_cper(json_object *section, 23 EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out); 24 25 //Converts the given JSON IR CPER representation into CPER binary format, piped to the provided file stream. 26 //This function performs no validation of the IR against the CPER-JSON specification. To ensure a safe call, 27 //use validate_schema() from json-schema.h before attempting to call this function. 28 void ir_to_cper(json_object *ir, FILE *out) 29 { 30 //Create the CPER header. 31 EFI_COMMON_ERROR_RECORD_HEADER *header = 32 (EFI_COMMON_ERROR_RECORD_HEADER *)calloc( 33 1, sizeof(EFI_COMMON_ERROR_RECORD_HEADER)); 34 ir_header_to_cper(json_object_object_get(ir, "header"), header); 35 fwrite(header, sizeof(EFI_COMMON_ERROR_RECORD_HEADER), 1, out); 36 fflush(out); 37 38 //Create the CPER section descriptors. 39 json_object *section_descriptors = 40 json_object_object_get(ir, "sectionDescriptors"); 41 if (section_descriptors == NULL) { 42 cper_print_log("Invalid CPER file: No section descriptors.\n"); 43 return; 44 } 45 int amt_descriptors = json_object_array_length(section_descriptors); 46 EFI_ERROR_SECTION_DESCRIPTOR *descriptors[amt_descriptors]; 47 for (int i = 0; i < amt_descriptors; i++) { 48 descriptors[i] = (EFI_ERROR_SECTION_DESCRIPTOR *)calloc( 49 1, sizeof(EFI_ERROR_SECTION_DESCRIPTOR)); 50 ir_section_descriptor_to_cper( 51 json_object_array_get_idx(section_descriptors, i), 52 descriptors[i]); 53 fwrite(descriptors[i], sizeof(EFI_ERROR_SECTION_DESCRIPTOR), 1, 54 out); 55 fflush(out); 56 } 57 58 //Run through each section in turn. 59 json_object *sections = json_object_object_get(ir, "sections"); 60 if (sections == NULL) { 61 cper_print_log("Invalid CPER file: No sections.\n"); 62 return; 63 } 64 int amt_sections = json_object_array_length(sections); 65 if (amt_sections == amt_descriptors) { 66 for (int i = 0; i < amt_sections; i++) { 67 //Get the section itself from the IR. 68 json_object *section = 69 json_object_array_get_idx(sections, i); 70 71 //Convert. 72 ir_section_to_cper(section, descriptors[i], out); 73 } 74 } 75 76 //Free all remaining resources. 77 free(header); 78 for (int i = 0; i < amt_descriptors; i++) { 79 free(descriptors[i]); 80 } 81 } 82 83 //Converts a CPER-JSON IR header to a CPER header structure. 84 void ir_header_to_cper(json_object *header_ir, 85 EFI_COMMON_ERROR_RECORD_HEADER *header) 86 { 87 header->SignatureStart = 0x52455043; //CPER 88 89 //Revision. 90 json_object *revision = json_object_object_get(header_ir, "revision"); 91 int minor = 92 json_object_get_int(json_object_object_get(revision, "minor")); 93 int major = 94 json_object_get_int(json_object_object_get(revision, "major")); 95 header->Revision = minor + (major << 8); 96 97 header->SignatureEnd = 0xFFFFFFFF; 98 99 //Section count. 100 int section_count = json_object_get_int( 101 json_object_object_get(header_ir, "sectionCount")); 102 header->SectionCount = (UINT16)section_count; 103 104 //Error severity. 105 json_object *severity = json_object_object_get(header_ir, "severity"); 106 header->ErrorSeverity = (UINT32)json_object_get_uint64( 107 json_object_object_get(severity, "code")); 108 109 //Validation bits. 110 ValidationTypes ui32Type = { UINT_32T, .value.ui32 = 0 }; 111 struct json_object *obj = NULL; 112 113 //Record length. 114 header->RecordLength = (UINT32)json_object_get_uint64( 115 json_object_object_get(header_ir, "recordLength")); 116 117 //Timestamp, if present. 118 if (json_object_object_get_ex(header_ir, "timestamp", &obj)) { 119 json_object *timestamp = obj; 120 if (timestamp != NULL) { 121 string_to_timestamp(&header->TimeStamp, 122 json_object_get_string(timestamp)); 123 header->TimeStamp.Flag = json_object_get_boolean( 124 json_object_object_get(header_ir, 125 "timestampIsPrecise")); 126 } 127 add_to_valid_bitfield(&ui32Type, 1); 128 } 129 130 //Various GUIDs. 131 json_object *platform_id; 132 json_object_object_get_ex(header_ir, "platformID", &platform_id); 133 json_object *partition_id; 134 json_object_object_get_ex(header_ir, "partitionID", &partition_id); 135 if (platform_id != NULL) { 136 string_to_guid(&header->PlatformID, 137 json_object_get_string(platform_id)); 138 add_to_valid_bitfield(&ui32Type, 0); 139 } 140 if (partition_id != NULL) { 141 string_to_guid(&header->PartitionID, 142 json_object_get_string(partition_id)); 143 add_to_valid_bitfield(&ui32Type, 2); 144 } 145 string_to_guid(&header->CreatorID, 146 json_object_get_string( 147 json_object_object_get(header_ir, "creatorID"))); 148 149 //Notification type. 150 json_object *notification_type = 151 json_object_object_get(header_ir, "notificationType"); 152 string_to_guid(&header->NotificationType, 153 json_object_get_string(json_object_object_get( 154 notification_type, "guid"))); 155 156 //Record ID, persistence info. 157 header->RecordID = json_object_get_uint64( 158 json_object_object_get(header_ir, "recordID")); 159 header->PersistenceInfo = json_object_get_uint64( 160 json_object_object_get(header_ir, "persistenceInfo")); 161 162 //Flags. 163 json_object *flags = json_object_object_get(header_ir, "flags"); 164 header->Flags = (UINT32)json_object_get_uint64( 165 json_object_object_get(flags, "value")); 166 167 header->ValidationBits = ui32Type.value.ui32; 168 } 169 170 //Converts a single given IR section into CPER, outputting to the given stream. 171 void ir_section_to_cper(json_object *section, 172 EFI_ERROR_SECTION_DESCRIPTOR *descriptor, FILE *out) 173 { 174 json_object *ir = NULL; 175 176 //Find the correct section type, and parse. 177 int section_converted = 0; 178 CPER_SECTION_DEFINITION *definition = 179 select_section_by_guid(&descriptor->SectionType); 180 if (definition != NULL) { 181 ir = json_object_object_get(section, definition->ShortName); 182 definition->ToCPER(ir, out); 183 section_converted = 1; 184 } 185 186 //If unknown GUID, so read as a base64 unknown section. 187 if (!section_converted) { 188 ir = json_object_object_get(section, "Unknown"); 189 json_object *encoded = json_object_object_get(ir, "data"); 190 191 int32_t decoded_len = 0; 192 193 UINT8 *decoded = base64_decode( 194 json_object_get_string(encoded), 195 json_object_get_string_len(encoded), &decoded_len); 196 if (decoded == NULL) { 197 cper_print_log( 198 "Failed to allocate decode output buffer. \n"); 199 } else { 200 fwrite(decoded, decoded_len, 1, out); 201 free(decoded); 202 } 203 } 204 } 205 206 //Converts a single CPER-JSON IR section descriptor into a CPER structure. 207 void ir_section_descriptor_to_cper(json_object *section_descriptor_ir, 208 EFI_ERROR_SECTION_DESCRIPTOR *descriptor) 209 { 210 //Section offset, length. 211 descriptor->SectionOffset = (UINT32)json_object_get_uint64( 212 json_object_object_get(section_descriptor_ir, "sectionOffset")); 213 descriptor->SectionLength = (UINT32)json_object_get_uint64( 214 json_object_object_get(section_descriptor_ir, "sectionLength")); 215 216 //Revision. 217 json_object *revision = 218 json_object_object_get(section_descriptor_ir, "revision"); 219 int minor = 220 json_object_get_int(json_object_object_get(revision, "minor")); 221 int major = 222 json_object_get_int(json_object_object_get(revision, "major")); 223 descriptor->Revision = minor + (major << 8); 224 225 //Validation bits, flags. 226 ValidationTypes ui8Type = { UINT_8T, .value.ui8 = 0 }; 227 struct json_object *obj = NULL; 228 229 descriptor->SectionFlags = ir_to_bitfield( 230 json_object_object_get(section_descriptor_ir, "flags"), 8, 231 CPER_SECTION_DESCRIPTOR_FLAGS_BITFIELD_NAMES); 232 233 //Section type. 234 json_object *section_type = 235 json_object_object_get(section_descriptor_ir, "sectionType"); 236 string_to_guid(&descriptor->SectionType, 237 json_object_get_string( 238 json_object_object_get(section_type, "data"))); 239 240 //FRU ID, if present. 241 if (json_object_object_get_ex(section_descriptor_ir, "fruID", &obj)) { 242 json_object *fru_id = obj; 243 if (fru_id != NULL) { 244 string_to_guid(&descriptor->FruId, 245 json_object_get_string(fru_id)); 246 add_to_valid_bitfield(&ui8Type, 0); 247 } 248 } 249 250 //Severity code. 251 json_object *severity = 252 json_object_object_get(section_descriptor_ir, "severity"); 253 descriptor->Severity = (UINT32)json_object_get_uint64( 254 json_object_object_get(severity, "code")); 255 256 //FRU text, if present. 257 if (json_object_object_get_ex(section_descriptor_ir, "fruText", &obj)) { 258 json_object *fru_text = obj; 259 if (fru_text != NULL) { 260 strncpy(descriptor->FruString, 261 json_object_get_string(fru_text), 262 sizeof(descriptor->FruString) - 1); 263 descriptor 264 ->FruString[sizeof(descriptor->FruString) - 1] = 265 '\0'; 266 add_to_valid_bitfield(&ui8Type, 1); 267 } 268 } 269 descriptor->SecValidMask = ui8Type.value.ui8; 270 } 271 272 //Converts IR for a given single section format CPER record into CPER binary. 273 void ir_single_section_to_cper(json_object *ir, FILE *out) 274 { 275 //Create & write a section descriptor to file. 276 EFI_ERROR_SECTION_DESCRIPTOR section_descriptor; 277 memset(§ion_descriptor, 0, sizeof(section_descriptor)); 278 279 ir_section_descriptor_to_cper( 280 json_object_object_get(ir, "sectionDescriptor"), 281 §ion_descriptor); 282 fwrite(§ion_descriptor, sizeof(section_descriptor), 1, out); 283 284 //Write section to file. 285 ir_section_to_cper(json_object_object_get(ir, "section"), 286 §ion_descriptor, out); 287 288 fflush(out); 289 } 290