1db1b7ce2SLawrence Tang /** 2db1b7ce2SLawrence Tang * Describes functions for converting VT-d specific DMAr CPER sections from binary and JSON format 3db1b7ce2SLawrence Tang * into an intermediate format. 4db1b7ce2SLawrence Tang * 5db1b7ce2SLawrence Tang * Author: Lawrence.Tang@arm.com 6db1b7ce2SLawrence Tang **/ 7db1b7ce2SLawrence Tang #include <stdio.h> 8205dd1d7SLawrence Tang #include <string.h> 95202bbb4SLawrence Tang #include <json.h> 10*f8fc7052SJohn Chung #include "libbase64.h" 11db1b7ce2SLawrence Tang #include "../edk/Cper.h" 12db1b7ce2SLawrence Tang #include "../cper-utils.h" 13db1b7ce2SLawrence Tang #include "cper-section-dmar-vtd.h" 14db1b7ce2SLawrence Tang 15db1b7ce2SLawrence Tang //Converts a single VT-d specific DMAr CPER section into JSON IR. 16*f8fc7052SJohn Chung json_object *cper_section_dmar_vtd_to_ir(void *section) 17db1b7ce2SLawrence Tang { 18e407b4c8SLawrence Tang EFI_DIRECTED_IO_DMAR_ERROR_DATA *vtd_error = 19e407b4c8SLawrence Tang (EFI_DIRECTED_IO_DMAR_ERROR_DATA *)section; 20db1b7ce2SLawrence Tang json_object *section_ir = json_object_new_object(); 21db1b7ce2SLawrence Tang 22db1b7ce2SLawrence Tang //Version, revision and OEM ID, as defined in the VT-d architecture. 230a4b3f2dSLawrence Tang UINT64 oem_id = 0; 24*f8fc7052SJohn Chung for (int i = 0; i < 6; i++) { 250a4b3f2dSLawrence Tang oem_id |= (UINT64)vtd_error->OemId[i] << (i * 8); 26*f8fc7052SJohn Chung } 27e407b4c8SLawrence Tang json_object_object_add(section_ir, "version", 28e407b4c8SLawrence Tang json_object_new_int(vtd_error->Version)); 29e407b4c8SLawrence Tang json_object_object_add(section_ir, "revision", 30e407b4c8SLawrence Tang json_object_new_int(vtd_error->Revision)); 31e407b4c8SLawrence Tang json_object_object_add(section_ir, "oemID", 32e407b4c8SLawrence Tang json_object_new_uint64(oem_id)); 33db1b7ce2SLawrence Tang 34db1b7ce2SLawrence Tang //Registers. 35e407b4c8SLawrence Tang json_object_object_add(section_ir, "capabilityRegister", 36e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->Capability)); 37e407b4c8SLawrence Tang json_object_object_add(section_ir, "extendedCapabilityRegister", 38e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->CapabilityEx)); 39e407b4c8SLawrence Tang json_object_object_add( 40e407b4c8SLawrence Tang section_ir, "globalCommandRegister", 41e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->GlobalCommand)); 42e407b4c8SLawrence Tang json_object_object_add(section_ir, "globalStatusRegister", 43e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->GlobalStatus)); 44e407b4c8SLawrence Tang json_object_object_add(section_ir, "faultStatusRegister", 45e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->FaultStatus)); 46db1b7ce2SLawrence Tang 47ce0f82bfSLawrence Tang //Fault record basic fields. 48ce0f82bfSLawrence Tang json_object *fault_record_ir = json_object_new_object(); 49e407b4c8SLawrence Tang EFI_VTD_FAULT_RECORD *fault_record = 50e407b4c8SLawrence Tang (EFI_VTD_FAULT_RECORD *)vtd_error->FaultRecord; 51e407b4c8SLawrence Tang json_object_object_add( 52e407b4c8SLawrence Tang fault_record_ir, "faultInformation", 53e407b4c8SLawrence Tang json_object_new_uint64(fault_record->FaultInformation)); 54e407b4c8SLawrence Tang json_object_object_add( 55e407b4c8SLawrence Tang fault_record_ir, "sourceIdentifier", 56e407b4c8SLawrence Tang json_object_new_uint64(fault_record->SourceIdentifier)); 57e407b4c8SLawrence Tang json_object_object_add( 58e407b4c8SLawrence Tang fault_record_ir, "privelegeModeRequested", 59ce0f82bfSLawrence Tang json_object_new_boolean(fault_record->PrivelegeModeRequested)); 60e407b4c8SLawrence Tang json_object_object_add( 61e407b4c8SLawrence Tang fault_record_ir, "executePermissionRequested", 62e407b4c8SLawrence Tang json_object_new_boolean( 63e407b4c8SLawrence Tang fault_record->ExecutePermissionRequested)); 64e407b4c8SLawrence Tang json_object_object_add( 65e407b4c8SLawrence Tang fault_record_ir, "pasidPresent", 66e407b4c8SLawrence Tang json_object_new_boolean(fault_record->PasidPresent)); 67e407b4c8SLawrence Tang json_object_object_add( 68e407b4c8SLawrence Tang fault_record_ir, "faultReason", 69e407b4c8SLawrence Tang json_object_new_uint64(fault_record->FaultReason)); 70e407b4c8SLawrence Tang json_object_object_add( 71e407b4c8SLawrence Tang fault_record_ir, "pasidValue", 72e407b4c8SLawrence Tang json_object_new_uint64(fault_record->PasidValue)); 73e407b4c8SLawrence Tang json_object_object_add( 74e407b4c8SLawrence Tang fault_record_ir, "addressType", 75e407b4c8SLawrence Tang json_object_new_uint64(fault_record->AddressType)); 76ce0f82bfSLawrence Tang 77205dd1d7SLawrence Tang //Fault record type. 78e407b4c8SLawrence Tang json_object *fault_record_type = integer_to_readable_pair( 79e407b4c8SLawrence Tang fault_record->Type, 2, VTD_FAULT_RECORD_TYPES_KEYS, 80e407b4c8SLawrence Tang VTD_FAULT_RECORD_TYPES_VALUES, "Unknown"); 81ce0f82bfSLawrence Tang json_object_object_add(fault_record_ir, "type", fault_record_type); 82ce0f82bfSLawrence Tang json_object_object_add(section_ir, "faultRecord", fault_record_ir); 83ce0f82bfSLawrence Tang 84ce0f82bfSLawrence Tang //Root entry. 85*f8fc7052SJohn Chung char *encoded = malloc(2 * 16); 86*f8fc7052SJohn Chung size_t encoded_len = 0; 87*f8fc7052SJohn Chung if (!encoded) { 88*f8fc7052SJohn Chung printf("Failed to allocate encode output buffer. \n"); 89*f8fc7052SJohn Chung } else { 90*f8fc7052SJohn Chung base64_encode((const char *)vtd_error->RootEntry, 16, encoded, 91*f8fc7052SJohn Chung &encoded_len, 0); 92e407b4c8SLawrence Tang json_object_object_add(section_ir, "rootEntry", 93*f8fc7052SJohn Chung json_object_new_string_len(encoded, 94*f8fc7052SJohn Chung encoded_len)); 95ce0f82bfSLawrence Tang free(encoded); 96*f8fc7052SJohn Chung } 97ce0f82bfSLawrence Tang 98ce0f82bfSLawrence Tang //Context entry. 99*f8fc7052SJohn Chung encoded = malloc(2 * 16); 100*f8fc7052SJohn Chung encoded_len = 0; 101*f8fc7052SJohn Chung if (!encoded) { 102*f8fc7052SJohn Chung printf("Failed to allocate encode output buffer. \n"); 103*f8fc7052SJohn Chung } else { 104*f8fc7052SJohn Chung base64_encode((const char *)vtd_error->ContextEntry, 16, 105*f8fc7052SJohn Chung encoded, &encoded_len, 0); 106e407b4c8SLawrence Tang json_object_object_add(section_ir, "contextEntry", 107*f8fc7052SJohn Chung json_object_new_string_len(encoded, 108*f8fc7052SJohn Chung encoded_len)); 109ce0f82bfSLawrence Tang free(encoded); 110*f8fc7052SJohn Chung } 111db1b7ce2SLawrence Tang 112db1b7ce2SLawrence Tang //PTE entry for all page levels. 113e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level6", 114e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->PteL6)); 115e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level5", 116e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->PteL5)); 117e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level4", 118e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->PteL4)); 119e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level3", 120e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->PteL3)); 121e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level2", 122e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->PteL2)); 123e407b4c8SLawrence Tang json_object_object_add(section_ir, "pageTableEntry_Level1", 124e407b4c8SLawrence Tang json_object_new_uint64(vtd_error->PteL1)); 125db1b7ce2SLawrence Tang 126db1b7ce2SLawrence Tang return section_ir; 127db1b7ce2SLawrence Tang } 128205dd1d7SLawrence Tang 129205dd1d7SLawrence Tang //Converts a single VT-d DMAR CPER-JSON segment into CPER binary, outputting to the given stream. 130205dd1d7SLawrence Tang void ir_section_dmar_vtd_to_cper(json_object *section, FILE *out) 131205dd1d7SLawrence Tang { 132205dd1d7SLawrence Tang EFI_DIRECTED_IO_DMAR_ERROR_DATA *section_cper = 133e407b4c8SLawrence Tang (EFI_DIRECTED_IO_DMAR_ERROR_DATA *)calloc( 134e407b4c8SLawrence Tang 1, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA)); 135205dd1d7SLawrence Tang 136205dd1d7SLawrence Tang //OEM ID. 137e407b4c8SLawrence Tang UINT64 oem_id = json_object_get_uint64( 138e407b4c8SLawrence Tang json_object_object_get(section, "oemID")); 139*f8fc7052SJohn Chung for (int i = 0; i < 6; i++) { 1400a4b3f2dSLawrence Tang section_cper->OemId[i] = (oem_id >> (i * 8)) & 0xFF; 141*f8fc7052SJohn Chung } 142205dd1d7SLawrence Tang 143205dd1d7SLawrence Tang //Registers & basic numeric fields. 144e407b4c8SLawrence Tang section_cper->Version = (UINT8)json_object_get_int( 145e407b4c8SLawrence Tang json_object_object_get(section, "version")); 146e407b4c8SLawrence Tang section_cper->Revision = (UINT8)json_object_get_int( 147e407b4c8SLawrence Tang json_object_object_get(section, "revision")); 148e407b4c8SLawrence Tang section_cper->Capability = json_object_get_uint64( 149e407b4c8SLawrence Tang json_object_object_get(section, "capabilityRegister")); 150e407b4c8SLawrence Tang section_cper->CapabilityEx = json_object_get_uint64( 151e407b4c8SLawrence Tang json_object_object_get(section, "extendedCapabilityRegister")); 152e407b4c8SLawrence Tang section_cper->GlobalCommand = json_object_get_uint64( 153e407b4c8SLawrence Tang json_object_object_get(section, "globalCommandRegister")); 154e407b4c8SLawrence Tang section_cper->GlobalStatus = json_object_get_uint64( 155e407b4c8SLawrence Tang json_object_object_get(section, "globalStatusRegister")); 156e407b4c8SLawrence Tang section_cper->FaultStatus = json_object_get_uint64( 157e407b4c8SLawrence Tang json_object_object_get(section, "faultStatusRegister")); 158205dd1d7SLawrence Tang 159205dd1d7SLawrence Tang //Fault record. 160e407b4c8SLawrence Tang json_object *fault_record = 161e407b4c8SLawrence Tang json_object_object_get(section, "faultRecord"); 162e407b4c8SLawrence Tang EFI_VTD_FAULT_RECORD *fault_record_cper = 163e407b4c8SLawrence Tang (EFI_VTD_FAULT_RECORD *)section_cper->FaultRecord; 164e407b4c8SLawrence Tang fault_record_cper->FaultInformation = json_object_get_uint64( 165e407b4c8SLawrence Tang json_object_object_get(fault_record, "faultInformation")); 166e407b4c8SLawrence Tang fault_record_cper->SourceIdentifier = json_object_get_uint64( 167e407b4c8SLawrence Tang json_object_object_get(fault_record, "sourceIdentifier")); 168e407b4c8SLawrence Tang fault_record_cper->PrivelegeModeRequested = json_object_get_boolean( 169e407b4c8SLawrence Tang json_object_object_get(fault_record, "privelegeModeRequested")); 170e407b4c8SLawrence Tang fault_record_cper->ExecutePermissionRequested = json_object_get_boolean( 171e407b4c8SLawrence Tang json_object_object_get(fault_record, 172e407b4c8SLawrence Tang "executePermissionRequested")); 173e407b4c8SLawrence Tang fault_record_cper->PasidPresent = json_object_get_boolean( 174e407b4c8SLawrence Tang json_object_object_get(fault_record, "pasidPresent")); 175e407b4c8SLawrence Tang fault_record_cper->FaultReason = json_object_get_uint64( 176e407b4c8SLawrence Tang json_object_object_get(fault_record, "faultReason")); 177e407b4c8SLawrence Tang fault_record_cper->PasidValue = json_object_get_uint64( 178e407b4c8SLawrence Tang json_object_object_get(fault_record, "pasidValue")); 179e407b4c8SLawrence Tang fault_record_cper->AddressType = json_object_get_uint64( 180e407b4c8SLawrence Tang json_object_object_get(fault_record, "addressType")); 181e407b4c8SLawrence Tang fault_record_cper->Type = readable_pair_to_integer( 182e407b4c8SLawrence Tang json_object_object_get(fault_record, "type")); 183205dd1d7SLawrence Tang 184205dd1d7SLawrence Tang //Root entry. 185205dd1d7SLawrence Tang json_object *encoded = json_object_object_get(section, "rootEntry"); 186*f8fc7052SJohn Chung char *decoded = malloc(json_object_get_string_len(encoded)); 187*f8fc7052SJohn Chung size_t decoded_len = 0; 188*f8fc7052SJohn Chung if (!decoded) { 189*f8fc7052SJohn Chung printf("Failed to allocate decode output buffer. \n"); 190*f8fc7052SJohn Chung } else { 191*f8fc7052SJohn Chung base64_decode(json_object_get_string(encoded), 192*f8fc7052SJohn Chung json_object_get_string_len(encoded), decoded, 193*f8fc7052SJohn Chung &decoded_len, 0); 194*f8fc7052SJohn Chung memcpy(section_cper->RootEntry, decoded, decoded_len); 195205dd1d7SLawrence Tang free(decoded); 196*f8fc7052SJohn Chung } 197205dd1d7SLawrence Tang //Context entry. 198205dd1d7SLawrence Tang encoded = json_object_object_get(section, "contextEntry"); 199*f8fc7052SJohn Chung decoded = malloc(json_object_get_string_len(encoded)); 200*f8fc7052SJohn Chung decoded_len = 0; 201*f8fc7052SJohn Chung if (!decoded) { 202*f8fc7052SJohn Chung printf("Failed to allocate decode output buffer. \n"); 203*f8fc7052SJohn Chung } else { 204*f8fc7052SJohn Chung base64_decode(json_object_get_string(encoded), 205*f8fc7052SJohn Chung json_object_get_string_len(encoded), decoded, 206*f8fc7052SJohn Chung &decoded_len, 0); 207*f8fc7052SJohn Chung memcpy(section_cper->ContextEntry, decoded, decoded_len); 208205dd1d7SLawrence Tang free(decoded); 209*f8fc7052SJohn Chung } 210205dd1d7SLawrence Tang 211205dd1d7SLawrence Tang //Page table entries. 212e407b4c8SLawrence Tang section_cper->PteL1 = json_object_get_uint64( 213e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level1")); 214e407b4c8SLawrence Tang section_cper->PteL2 = json_object_get_uint64( 215e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level2")); 216e407b4c8SLawrence Tang section_cper->PteL3 = json_object_get_uint64( 217e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level3")); 218e407b4c8SLawrence Tang section_cper->PteL4 = json_object_get_uint64( 219e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level4")); 220e407b4c8SLawrence Tang section_cper->PteL5 = json_object_get_uint64( 221e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level5")); 222e407b4c8SLawrence Tang section_cper->PteL6 = json_object_get_uint64( 223e407b4c8SLawrence Tang json_object_object_get(section, "pageTableEntry_Level6")); 224205dd1d7SLawrence Tang 225205dd1d7SLawrence Tang //Write to stream, free resources. 2263ab351feSLawrence Tang fwrite(section_cper, sizeof(EFI_DIRECTED_IO_DMAR_ERROR_DATA), 1, out); 227205dd1d7SLawrence Tang fflush(out); 228205dd1d7SLawrence Tang free(section_cper); 229205dd1d7SLawrence Tang } 230