1 /** 2 * Describes functions for converting NVIDIA CPER sections from binary and JSON format 3 * into an intermediate format. 4 **/ 5 6 #include <stdio.h> 7 #include <stddef.h> 8 #include <string.h> 9 #include <json.h> 10 #include <libcper/Cper.h> 11 #include <libcper/cper-utils.h> 12 #include <libcper/sections/cper-section-nvidia.h> 13 #include <libcper/log.h> 14 15 void parse_cmet_info(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, 16 size_t size, json_object *section_ir) 17 { 18 json_object *regarr = json_object_new_array(); 19 for (int i = 0; i < NumberRegs; i++, regPtr++) { 20 json_object *reg = NULL; 21 if (sizeof(EFI_NVIDIA_ERROR_DATA) + 22 i * sizeof(EFI_NVIDIA_REGISTER_DATA) < 23 size) { 24 reg = json_object_new_object(); 25 add_int_hex_64(reg, "ChannelAddress", regPtr->Address); 26 add_int(reg, "ErrorCount", regPtr->CmetInfo.ErrorCount); 27 add_bool(reg, "ChannelEnabled", 28 regPtr->CmetInfo.ChannelEnabled); 29 add_bool(reg, "ChannelIsSpare", 30 regPtr->CmetInfo.ChannelIsSpare); 31 add_dict(reg, "DisabledReason", 32 regPtr->CmetInfo.DisabledReason, 33 channel_disable_reason_dict, 34 channel_disable_reason_dict_size); 35 } else { 36 reg = json_object_new_null(); 37 } 38 39 json_object_array_add(regarr, reg); 40 } 41 42 json_object_object_add(section_ir, "CMETInfo", regarr); 43 } 44 45 void parse_fwerror(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, 46 size_t size, json_object *section_ir) 47 { 48 (void)NumberRegs; 49 json_object *fwinfo; 50 if (sizeof(EFI_NVIDIA_ERROR_DATA) + sizeof(EFI_NVIDIA_FWERROR) > size) { 51 fwinfo = json_object_new_null(); 52 } else { 53 fwinfo = json_object_new_object(); 54 EFI_NVIDIA_FWERROR *fwerror = (EFI_NVIDIA_FWERROR *)regPtr; 55 add_untrusted_string(fwinfo, "initiating_firmware", 56 fwerror->initiating_firmware, 57 sizeof(fwerror->initiating_firmware)); 58 add_int_hex_64(fwinfo, "task_checkpoint", 59 fwerror->task_checkpoint); 60 add_int_hex_64(fwinfo, "mb1_error_code", 61 fwerror->mb1_error_code); 62 add_untrusted_string(fwinfo, "mb1_version_string", 63 fwerror->mb1_version_string, 64 sizeof(fwerror->mb1_version_string)); 65 add_int_hex_64(fwinfo, "bad_pages_retired_mask", 66 fwerror->bad_pages_retired_mask); 67 add_int_hex_64(fwinfo, "training_or_alias_check_retired_mask", 68 fwerror->training_or_alias_check_retired_mask); 69 } 70 71 json_object_object_add(section_ir, "FWErrorInfo", fwinfo); 72 } 73 74 void parse_registers(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, 75 size_t size, json_object *section_ir) 76 { 77 // Registers (Address Value pairs). 78 json_object *regarr = json_object_new_array(); 79 for (int i = 0; i < NumberRegs; i++, regPtr++) { 80 json_object *reg = NULL; 81 if (sizeof(EFI_NVIDIA_ERROR_DATA) + 82 i * sizeof(EFI_NVIDIA_REGISTER_DATA) < 83 size) { 84 reg = json_object_new_object(); 85 json_object_object_add( 86 reg, "address", 87 json_object_new_uint64(regPtr->Address)); 88 json_object_object_add( 89 reg, "value", 90 json_object_new_uint64(regPtr->Value)); 91 } else { 92 reg = json_object_new_null(); 93 } 94 95 json_object_array_add(regarr, reg); 96 } 97 json_object_object_add(section_ir, "registers", regarr); 98 } 99 100 typedef struct { 101 const char *ip_signature; 102 void (*callback)(EFI_NVIDIA_REGISTER_DATA *, UINT8, size_t, 103 json_object *); 104 } NV_SECTION_CALLBACKS; 105 106 NV_SECTION_CALLBACKS section_handlers[] = { 107 { "CMET-INFO\0", &parse_cmet_info }, 108 { "FWERROR\0", &parse_fwerror }, 109 { "", &parse_registers }, 110 }; 111 112 //Converts a single NVIDIA CPER section into JSON IR. 113 json_object *cper_section_nvidia_to_ir(const UINT8 *section, UINT32 size) 114 { 115 if (size < sizeof(EFI_NVIDIA_ERROR_DATA)) { 116 return NULL; 117 } 118 119 EFI_NVIDIA_ERROR_DATA *nvidia_error = (EFI_NVIDIA_ERROR_DATA *)section; 120 121 json_object *section_ir = json_object_new_object(); 122 123 add_untrusted_string(section_ir, "signature", nvidia_error->Signature, 124 sizeof(nvidia_error->Signature)); 125 126 json_object *severity = json_object_new_object(); 127 json_object_object_add(severity, "code", 128 json_object_new_uint64(nvidia_error->Severity)); 129 json_object_object_add(severity, "name", 130 json_object_new_string(severity_to_string( 131 nvidia_error->Severity))); 132 json_object_object_add(section_ir, "severity", severity); 133 134 json_object_object_add(section_ir, "errorType", 135 json_object_new_int(nvidia_error->ErrorType)); 136 json_object_object_add( 137 section_ir, "errorInstance", 138 json_object_new_int(nvidia_error->ErrorInstance)); 139 json_object_object_add(section_ir, "socket", 140 json_object_new_int(nvidia_error->Socket)); 141 json_object_object_add(section_ir, "registerCount", 142 json_object_new_int(nvidia_error->NumberRegs)); 143 json_object_object_add( 144 section_ir, "instanceBase", 145 json_object_new_uint64(nvidia_error->InstanceBase)); 146 147 for (long unsigned int i = 0; 148 i < sizeof(section_handlers) / sizeof(section_handlers[0]); i++) { 149 const char *ip_signature = section_handlers[i].ip_signature; 150 if (strncmp(nvidia_error->Signature, ip_signature, 151 strlen(ip_signature)) == 0) { 152 section_handlers[i].callback(&nvidia_error->Register[0], 153 nvidia_error->NumberRegs, 154 size, section_ir); 155 break; 156 } 157 } 158 return section_ir; 159 } 160 161 //Converts a single NVIDIA CPER-JSON section into CPER binary, outputting to the given stream. 162 void ir_section_nvidia_to_cper(json_object *section, FILE *out) 163 { 164 json_object *regarr = json_object_object_get(section, "registers"); 165 int numRegs = json_object_array_length(regarr); 166 167 size_t section_sz = offsetof(EFI_NVIDIA_ERROR_DATA, Register) + 168 numRegs * sizeof(EFI_NVIDIA_REGISTER_DATA); 169 EFI_NVIDIA_ERROR_DATA *section_cper = 170 (EFI_NVIDIA_ERROR_DATA *)calloc(1, section_sz); 171 172 //Signature. 173 strncpy(section_cper->Signature, 174 json_object_get_string( 175 json_object_object_get(section, "signature")), 176 sizeof(section_cper->Signature) - 1); 177 section_cper->Signature[sizeof(section_cper->Signature) - 1] = '\0'; 178 179 //Fields. 180 section_cper->ErrorType = json_object_get_int( 181 json_object_object_get(section, "errorType")); 182 section_cper->ErrorInstance = json_object_get_int( 183 json_object_object_get(section, "errorInstance")); 184 json_object *severity = json_object_object_get(section, "severity"); 185 section_cper->Severity = (UINT8)json_object_get_uint64( 186 json_object_object_get(severity, "code")); 187 section_cper->Socket = 188 json_object_get_int(json_object_object_get(section, "socket")); 189 section_cper->NumberRegs = json_object_get_int( 190 json_object_object_get(section, "registerCount")); 191 section_cper->InstanceBase = json_object_get_uint64( 192 json_object_object_get(section, "instanceBase")); 193 194 // Registers (Address Value pairs). 195 EFI_NVIDIA_REGISTER_DATA *regPtr = section_cper->Register; 196 for (int i = 0; i < numRegs; i++, regPtr++) { 197 json_object *reg = json_object_array_get_idx(regarr, i); 198 regPtr->Address = json_object_get_uint64( 199 json_object_object_get(reg, "address")); 200 regPtr->Value = json_object_get_uint64( 201 json_object_object_get(reg, "value")); 202 } 203 204 //Write to stream, free resources. 205 fwrite(section_cper, section_sz, 1, out); 206 fflush(out); 207 free(section_cper); 208 } 209