1 /** 2 * Describes functions for converting IOMMU specific DMAr CPER sections from binary and JSON format 3 * into an intermediate format. 4 * 5 * Author: Lawrence.Tang@arm.com 6 **/ 7 #include <stdio.h> 8 #include <string.h> 9 #include <json.h> 10 #include <libcper/base64.h> 11 #include <libcper/Cper.h> 12 #include <libcper/cper-utils.h> 13 #include <libcper/sections/cper-section-dmar-iommu.h> 14 #include <libcper/log.h> 15 16 //Converts a single IOMMU specific DMAr CPER section into JSON IR. 17 json_object *cper_section_dmar_iommu_to_ir(const UINT8 *section, UINT32 size) 18 { 19 if (size < sizeof(EFI_IOMMU_DMAR_ERROR_DATA)) { 20 return NULL; 21 } 22 23 EFI_IOMMU_DMAR_ERROR_DATA *iommu_error = 24 (EFI_IOMMU_DMAR_ERROR_DATA *)section; 25 json_object *section_ir = json_object_new_object(); 26 27 //Revision. 28 json_object_object_add(section_ir, "revision", 29 json_object_new_int(iommu_error->Revision)); 30 31 //IOMMU registers. 32 json_object_object_add(section_ir, "controlRegister", 33 json_object_new_uint64(iommu_error->Control)); 34 json_object_object_add(section_ir, "statusRegister", 35 json_object_new_uint64(iommu_error->Status)); 36 37 //IOMMU event log entry. 38 //The format of these entries differ widely by the type of error. 39 int32_t encoded_len = 0; 40 41 char *encoded = base64_encode((UINT8 *)iommu_error->EventLogEntry, 16, 42 &encoded_len); 43 if (encoded == NULL) { 44 cper_print_log("Failed to allocate encode output buffer. \n"); 45 46 return NULL; 47 } 48 json_object_object_add(section_ir, "eventLogEntry", 49 json_object_new_string_len(encoded, 50 encoded_len)); 51 free(encoded); 52 53 //Device table entry (as base64). 54 encoded_len = 0; 55 56 encoded = base64_encode((UINT8 *)iommu_error->DeviceTableEntry, 32, 57 &encoded_len); 58 if (encoded == NULL) { 59 cper_print_log("Failed to allocate encode output buffer. \n"); 60 return NULL; 61 } 62 json_object_object_add(section_ir, "deviceTableEntry", 63 json_object_new_string_len(encoded, 64 encoded_len)); 65 free(encoded); 66 67 //Page table entries. 68 json_object_object_add(section_ir, "pageTableEntry_Level6", 69 json_object_new_uint64(iommu_error->PteL6)); 70 json_object_object_add(section_ir, "pageTableEntry_Level5", 71 json_object_new_uint64(iommu_error->PteL5)); 72 json_object_object_add(section_ir, "pageTableEntry_Level4", 73 json_object_new_uint64(iommu_error->PteL4)); 74 json_object_object_add(section_ir, "pageTableEntry_Level3", 75 json_object_new_uint64(iommu_error->PteL3)); 76 json_object_object_add(section_ir, "pageTableEntry_Level2", 77 json_object_new_uint64(iommu_error->PteL2)); 78 json_object_object_add(section_ir, "pageTableEntry_Level1", 79 json_object_new_uint64(iommu_error->PteL1)); 80 81 return section_ir; 82 } 83 84 //Converts a single DMAR IOMMU CPER-JSON section into CPER binary, outputting to the given stream. 85 void ir_section_dmar_iommu_to_cper(json_object *section, FILE *out) 86 { 87 EFI_IOMMU_DMAR_ERROR_DATA *section_cper = 88 (EFI_IOMMU_DMAR_ERROR_DATA *)calloc( 89 1, sizeof(EFI_IOMMU_DMAR_ERROR_DATA)); 90 91 //Revision, registers. 92 section_cper->Revision = (UINT8)json_object_get_int( 93 json_object_object_get(section, "revision")); 94 section_cper->Control = json_object_get_uint64( 95 json_object_object_get(section, "controlRegister")); 96 section_cper->Status = json_object_get_uint64( 97 json_object_object_get(section, "statusRegister")); 98 99 //IOMMU event log entry. 100 json_object *encoded = json_object_object_get(section, "eventLogEntry"); 101 int32_t decoded_len = 0; 102 103 UINT8 *decoded = base64_decode(json_object_get_string(encoded), 104 json_object_get_string_len(encoded), 105 &decoded_len); 106 if (decoded == NULL) { 107 cper_print_log("Failed to allocate decode output buffer. \n"); 108 } else { 109 memcpy(section_cper->EventLogEntry, decoded, decoded_len); 110 free(decoded); 111 } 112 //Device table entry. 113 encoded = json_object_object_get(section, "deviceTableEntry"); 114 decoded_len = 0; 115 116 decoded = base64_decode(json_object_get_string(encoded), 117 json_object_get_string_len(encoded), 118 &decoded_len); 119 if (decoded == NULL) { 120 cper_print_log("Failed to allocate decode output buffer. \n"); 121 } else { 122 memcpy(section_cper->DeviceTableEntry, decoded, decoded_len); 123 free(decoded); 124 } 125 126 //Page table entries. 127 section_cper->PteL1 = json_object_get_uint64( 128 json_object_object_get(section, "pageTableEntry_Level1")); 129 section_cper->PteL2 = json_object_get_uint64( 130 json_object_object_get(section, "pageTableEntry_Level2")); 131 section_cper->PteL3 = json_object_get_uint64( 132 json_object_object_get(section, "pageTableEntry_Level3")); 133 section_cper->PteL4 = json_object_get_uint64( 134 json_object_object_get(section, "pageTableEntry_Level4")); 135 section_cper->PteL5 = json_object_get_uint64( 136 json_object_object_get(section, "pageTableEntry_Level5")); 137 section_cper->PteL6 = json_object_get_uint64( 138 json_object_object_get(section, "pageTableEntry_Level6")); 139 140 //Write to stream, free resources. 141 fwrite(section_cper, sizeof(EFI_IOMMU_DMAR_ERROR_DATA), 1, out); 142 fflush(out); 143 free(section_cper); 144 } 145