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