blob: c75bf8a8a9ea910d087f38f7e4473c9a6ccde070 [file] [log] [blame]
Karthik Rajagopalan683e0552024-03-07 12:30:43 -08001/**
2 * Describes functions for converting NVIDIA CPER sections from binary and JSON format
3 * into an intermediate format.
4 **/
5
6#include <stdio.h>
Ed Tanous2d17ace2024-08-27 14:45:38 -07007#include <stddef.h>
Karthik Rajagopalan683e0552024-03-07 12:30:43 -08008#include <string.h>
9#include <json.h>
Thu Nguyene42fb482024-10-15 14:43:11 +000010#include <libcper/Cper.h>
11#include <libcper/cper-utils.h>
12#include <libcper/sections/cper-section-nvidia.h>
Ed Tanous50b966f2025-03-11 09:06:19 -070013#include <libcper/log.h>
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -070014#include <string.h>
Karthik Rajagopalan683e0552024-03-07 12:30:43 -080015
Ed Tanous55968b12025-05-06 21:04:52 -070016void 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
46void 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
75void 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
101typedef struct {
102 const char *ip_signature;
103 void (*callback)(EFI_NVIDIA_REGISTER_DATA *, UINT8, size_t,
104 json_object *);
105} NV_SECTION_CALLBACKS;
106
107NV_SECTION_CALLBACKS section_handlers[] = {
108 { "CMET-INFO\0", &parse_cmet_info },
109 { "FWERROR\0", &parse_fwerror },
110 { "", &parse_registers },
111};
112
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800113//Converts a single NVIDIA CPER section into JSON IR.
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700114json_object *cper_section_nvidia_to_ir(const UINT8 *section, UINT32 size,
115 char **desc_string)
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800116{
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700117 *desc_string = malloc(SECTION_DESC_STRING_SIZE);
118 char *property_desc = malloc(EFI_ERROR_DESCRIPTION_STRING_LEN);
119
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800120 if (size < sizeof(EFI_NVIDIA_ERROR_DATA)) {
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700121 free(property_desc);
122 *desc_string = NULL;
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800123 return NULL;
124 }
125
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800126 EFI_NVIDIA_ERROR_DATA *nvidia_error = (EFI_NVIDIA_ERROR_DATA *)section;
Ed Tanous12dbd4f2025-03-08 19:05:01 -0800127
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800128 json_object *section_ir = json_object_new_object();
129
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700130 const char *signature = nvidia_error->Signature;
131 add_untrusted_string(section_ir, "signature", signature,
132 strlen(signature));
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800133
Ed Tanous2d17ace2024-08-27 14:45:38 -0700134 json_object *severity = json_object_new_object();
135 json_object_object_add(severity, "code",
136 json_object_new_uint64(nvidia_error->Severity));
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700137 const char *severity_name = severity_to_string(nvidia_error->Severity);
Ed Tanous2d17ace2024-08-27 14:45:38 -0700138 json_object_object_add(severity, "name",
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700139 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 }
Ed Tanous2d17ace2024-08-27 14:45:38 -0700151 json_object_object_add(section_ir, "severity", severity);
152
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800153 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));
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800158 json_object_object_add(section_ir, "socket",
159 json_object_new_int(nvidia_error->Socket));
Aushim Nagarkattiad6c8802025-06-18 16:45:28 -0700160
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, property_desc_len);
172 // We still want to get as much info as possible, just warn about truncation
173 if (property_desc_len + strlen(*desc_string) >=
174 SECTION_DESC_STRING_SIZE) {
175 cper_print_log("Error: Description string truncated: %s\n",
176 *desc_string);
177 }
178 free(property_desc);
179
Ed Tanous2d17ace2024-08-27 14:45:38 -0700180 json_object_object_add(section_ir, "registerCount",
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800181 json_object_new_int(nvidia_error->NumberRegs));
182 json_object_object_add(
183 section_ir, "instanceBase",
184 json_object_new_uint64(nvidia_error->InstanceBase));
185
Ed Tanous55968b12025-05-06 21:04:52 -0700186 for (long unsigned int i = 0;
187 i < sizeof(section_handlers) / sizeof(section_handlers[0]); i++) {
188 const char *ip_signature = section_handlers[i].ip_signature;
189 if (strncmp(nvidia_error->Signature, ip_signature,
190 strlen(ip_signature)) == 0) {
191 section_handlers[i].callback(&nvidia_error->Register[0],
192 nvidia_error->NumberRegs,
193 size, section_ir);
194 break;
Ed Tanous1bc852a2025-04-09 15:33:12 -0700195 }
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800196 }
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800197 return section_ir;
198}
199
200//Converts a single NVIDIA CPER-JSON section into CPER binary, outputting to the given stream.
201void ir_section_nvidia_to_cper(json_object *section, FILE *out)
202{
203 json_object *regarr = json_object_object_get(section, "registers");
204 int numRegs = json_object_array_length(regarr);
205
Ed Tanous2d17ace2024-08-27 14:45:38 -0700206 size_t section_sz = offsetof(EFI_NVIDIA_ERROR_DATA, Register) +
207 numRegs * sizeof(EFI_NVIDIA_REGISTER_DATA);
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800208 EFI_NVIDIA_ERROR_DATA *section_cper =
209 (EFI_NVIDIA_ERROR_DATA *)calloc(1, section_sz);
210
211 //Signature.
212 strncpy(section_cper->Signature,
213 json_object_get_string(
214 json_object_object_get(section, "signature")),
Patrick Williams379e4922024-08-28 11:14:34 -0400215 sizeof(section_cper->Signature) - 1);
216 section_cper->Signature[sizeof(section_cper->Signature) - 1] = '\0';
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800217
218 //Fields.
219 section_cper->ErrorType = json_object_get_int(
220 json_object_object_get(section, "errorType"));
221 section_cper->ErrorInstance = json_object_get_int(
222 json_object_object_get(section, "errorInstance"));
Ed Tanous2d17ace2024-08-27 14:45:38 -0700223 json_object *severity = json_object_object_get(section, "severity");
224 section_cper->Severity = (UINT8)json_object_get_uint64(
225 json_object_object_get(severity, "code"));
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800226 section_cper->Socket =
227 json_object_get_int(json_object_object_get(section, "socket"));
228 section_cper->NumberRegs = json_object_get_int(
Ed Tanous2d17ace2024-08-27 14:45:38 -0700229 json_object_object_get(section, "registerCount"));
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800230 section_cper->InstanceBase = json_object_get_uint64(
231 json_object_object_get(section, "instanceBase"));
232
233 // Registers (Address Value pairs).
Ed Tanous2d17ace2024-08-27 14:45:38 -0700234 EFI_NVIDIA_REGISTER_DATA *regPtr = section_cper->Register;
235 for (int i = 0; i < numRegs; i++, regPtr++) {
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800236 json_object *reg = json_object_array_get_idx(regarr, i);
Ed Tanous2d17ace2024-08-27 14:45:38 -0700237 regPtr->Address = json_object_get_uint64(
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800238 json_object_object_get(reg, "address"));
Ed Tanous2d17ace2024-08-27 14:45:38 -0700239 regPtr->Value = json_object_get_uint64(
Karthik Rajagopalan683e0552024-03-07 12:30:43 -0800240 json_object_object_get(reg, "value"));
241 }
242
243 //Write to stream, free resources.
244 fwrite(section_cper, section_sz, 1, out);
245 fflush(out);
246 free(section_cper);
247}