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 #include <string.h> 15 16 void parse_cmet_info(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, 17 size_t size, json_object *section_ir) 18 { 19 json_object *regarr = json_object_new_array(); 20 for (int i = 0; i < NumberRegs; i++, regPtr++) { 21 json_object *reg = NULL; 22 if (sizeof(EFI_NVIDIA_ERROR_DATA) + 23 i * sizeof(EFI_NVIDIA_REGISTER_DATA) < 24 size) { 25 reg = json_object_new_object(); 26 add_int_hex_64(reg, "ChannelAddress", regPtr->Address); 27 add_int(reg, "ErrorCount", regPtr->CmetInfo.ErrorCount); 28 add_bool(reg, "ChannelEnabled", 29 regPtr->CmetInfo.ChannelEnabled); 30 add_bool(reg, "ChannelIsSpare", 31 regPtr->CmetInfo.ChannelIsSpare); 32 add_dict(reg, "DisabledReason", 33 regPtr->CmetInfo.DisabledReason, 34 channel_disable_reason_dict, 35 channel_disable_reason_dict_size); 36 } else { 37 reg = json_object_new_null(); 38 } 39 40 json_object_array_add(regarr, reg); 41 } 42 43 json_object_object_add(section_ir, "CMETInfo", regarr); 44 } 45 46 void parse_fwerror(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, 47 size_t size, json_object *section_ir) 48 { 49 (void)NumberRegs; 50 json_object *fwinfo; 51 if (sizeof(EFI_NVIDIA_ERROR_DATA) + sizeof(EFI_NVIDIA_FWERROR) > size) { 52 fwinfo = json_object_new_null(); 53 } else { 54 fwinfo = json_object_new_object(); 55 EFI_NVIDIA_FWERROR *fwerror = (EFI_NVIDIA_FWERROR *)regPtr; 56 add_untrusted_string(fwinfo, "initiating_firmware", 57 fwerror->initiating_firmware, 58 sizeof(fwerror->initiating_firmware)); 59 add_int_hex_64(fwinfo, "task_checkpoint", 60 fwerror->task_checkpoint); 61 add_int_hex_64(fwinfo, "mb1_error_code", 62 fwerror->mb1_error_code); 63 add_untrusted_string(fwinfo, "mb1_version_string", 64 fwerror->mb1_version_string, 65 sizeof(fwerror->mb1_version_string)); 66 add_int_hex_64(fwinfo, "bad_pages_retired_mask", 67 fwerror->bad_pages_retired_mask); 68 add_int_hex_64(fwinfo, "training_or_alias_check_retired_mask", 69 fwerror->training_or_alias_check_retired_mask); 70 } 71 72 json_object_object_add(section_ir, "FWErrorInfo", fwinfo); 73 } 74 75 void parse_registers(EFI_NVIDIA_REGISTER_DATA *regPtr, UINT8 NumberRegs, 76 size_t size, json_object *section_ir) 77 { 78 // Registers (Address Value pairs). 79 json_object *regarr = json_object_new_array(); 80 for (int i = 0; i < NumberRegs; i++, regPtr++) { 81 json_object *reg = NULL; 82 if (sizeof(EFI_NVIDIA_ERROR_DATA) + 83 i * sizeof(EFI_NVIDIA_REGISTER_DATA) < 84 size) { 85 reg = json_object_new_object(); 86 json_object_object_add( 87 reg, "address", 88 json_object_new_uint64(regPtr->Address)); 89 json_object_object_add( 90 reg, "value", 91 json_object_new_uint64(regPtr->Value)); 92 } else { 93 reg = json_object_new_null(); 94 } 95 96 json_object_array_add(regarr, reg); 97 } 98 json_object_object_add(section_ir, "registers", regarr); 99 } 100 101 typedef struct { 102 const char *ip_signature; 103 void (*callback)(EFI_NVIDIA_REGISTER_DATA *, UINT8, size_t, 104 json_object *); 105 } NV_SECTION_CALLBACKS; 106 107 NV_SECTION_CALLBACKS section_handlers[] = { 108 { "CMET-INFO\0", &parse_cmet_info }, 109 { "FWERROR\0", &parse_fwerror }, 110 { "", &parse_registers }, 111 }; 112 113 //Converts a single NVIDIA CPER section into JSON IR. 114 json_object *cper_section_nvidia_to_ir(const UINT8 *section, UINT32 size, 115 char **desc_string) 116 { 117 *desc_string = malloc(SECTION_DESC_STRING_SIZE); 118 char *property_desc = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN); 119 120 if (size < sizeof(EFI_NVIDIA_ERROR_DATA)) { 121 free(property_desc); 122 *desc_string = NULL; 123 return NULL; 124 } 125 126 EFI_NVIDIA_ERROR_DATA *nvidia_error = (EFI_NVIDIA_ERROR_DATA *)section; 127 128 json_object *section_ir = json_object_new_object(); 129 130 const char *signature = nvidia_error->Signature; 131 add_untrusted_string(section_ir, "signature", signature, 132 strlen(signature)); 133 134 json_object *severity = json_object_new_object(); 135 json_object_object_add(severity, "code", 136 json_object_new_uint64(nvidia_error->Severity)); 137 const char *severity_name = severity_to_string(nvidia_error->Severity); 138 json_object_object_add(severity, "name", 139 json_object_new_string(severity_name)); 140 int outstr_len = 0; 141 outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE, 142 "A %s %s NVIDIA Error occurred", severity_name, 143 signature); 144 if (outstr_len < 0) { 145 cper_print_log( 146 "Error: Could not write to description string\n"); 147 } else if (outstr_len > SECTION_DESC_STRING_SIZE) { 148 cper_print_log("Error: Description string truncated: %s\n", 149 *desc_string); 150 } 151 json_object_object_add(section_ir, "severity", severity); 152 153 json_object_object_add(section_ir, "errorType", 154 json_object_new_int(nvidia_error->ErrorType)); 155 json_object_object_add( 156 section_ir, "errorInstance", 157 json_object_new_int(nvidia_error->ErrorInstance)); 158 json_object_object_add(section_ir, "socket", 159 json_object_new_int(nvidia_error->Socket)); 160 161 outstr_len = snprintf(property_desc, EFI_ERROR_DESCRIPTION_STRING_LEN, 162 " on CPU %d", nvidia_error->Socket); 163 if (outstr_len < 0) { 164 cper_print_log("Error: Could not write to property string\n"); 165 } else if (outstr_len > EFI_ERROR_DESCRIPTION_STRING_LEN) { 166 cper_print_log("Error: Property string truncated: %s\n", 167 property_desc); 168 } 169 170 int property_desc_len = strlen(property_desc); 171 strncat(*desc_string, property_desc, 172 SECTION_DESC_STRING_SIZE - strlen(*desc_string) - 1); 173 // We still want to get as much info as possible, just warn about truncation 174 if (property_desc_len + strlen(*desc_string) >= 175 SECTION_DESC_STRING_SIZE) { 176 cper_print_log("Error: Description string truncated: %s\n", 177 *desc_string); 178 } 179 free(property_desc); 180 181 json_object_object_add(section_ir, "registerCount", 182 json_object_new_int(nvidia_error->NumberRegs)); 183 json_object_object_add( 184 section_ir, "instanceBase", 185 json_object_new_uint64(nvidia_error->InstanceBase)); 186 187 for (long unsigned int i = 0; 188 i < sizeof(section_handlers) / sizeof(section_handlers[0]); i++) { 189 const char *ip_signature = section_handlers[i].ip_signature; 190 if (strncmp(nvidia_error->Signature, ip_signature, 191 strlen(ip_signature)) == 0) { 192 section_handlers[i].callback(&nvidia_error->Register[0], 193 nvidia_error->NumberRegs, 194 size, section_ir); 195 break; 196 } 197 } 198 return section_ir; 199 } 200 201 //Converts a single NVIDIA CPER-JSON section into CPER binary, outputting to the given stream. 202 void ir_section_nvidia_to_cper(json_object *section, FILE *out) 203 { 204 json_object *regarr = json_object_object_get(section, "registers"); 205 int numRegs = json_object_array_length(regarr); 206 207 size_t section_sz = offsetof(EFI_NVIDIA_ERROR_DATA, Register) + 208 numRegs * sizeof(EFI_NVIDIA_REGISTER_DATA); 209 EFI_NVIDIA_ERROR_DATA *section_cper = 210 (EFI_NVIDIA_ERROR_DATA *)calloc(1, section_sz); 211 212 //Signature. 213 strncpy(section_cper->Signature, 214 json_object_get_string( 215 json_object_object_get(section, "signature")), 216 sizeof(section_cper->Signature) - 1); 217 section_cper->Signature[sizeof(section_cper->Signature) - 1] = '\0'; 218 219 //Fields. 220 section_cper->ErrorType = json_object_get_int( 221 json_object_object_get(section, "errorType")); 222 section_cper->ErrorInstance = json_object_get_int( 223 json_object_object_get(section, "errorInstance")); 224 json_object *severity = json_object_object_get(section, "severity"); 225 section_cper->Severity = (UINT8)json_object_get_uint64( 226 json_object_object_get(severity, "code")); 227 section_cper->Socket = 228 json_object_get_int(json_object_object_get(section, "socket")); 229 section_cper->NumberRegs = json_object_get_int( 230 json_object_object_get(section, "registerCount")); 231 section_cper->InstanceBase = json_object_get_uint64( 232 json_object_object_get(section, "instanceBase")); 233 234 // Registers (Address Value pairs). 235 EFI_NVIDIA_REGISTER_DATA *regPtr = section_cper->Register; 236 for (int i = 0; i < numRegs; i++, regPtr++) { 237 json_object *reg = json_object_array_get_idx(regarr, i); 238 regPtr->Address = json_object_get_uint64( 239 json_object_object_get(reg, "address")); 240 regPtr->Value = json_object_get_uint64( 241 json_object_object_get(reg, "value")); 242 } 243 244 //Write to stream, free resources. 245 fwrite(section_cper, section_sz, 1, out); 246 fflush(out); 247 free(section_cper); 248 } 249