xref: /openbmc/libcper/sections/cper-section-nvidia.c (revision 55968b12e1e0aaaf0e70215e47d8a93706dab21b)
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 
parse_cmet_info(EFI_NVIDIA_REGISTER_DATA * regPtr,UINT8 NumberRegs,size_t size,json_object * section_ir)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 
parse_fwerror(EFI_NVIDIA_REGISTER_DATA * regPtr,UINT8 NumberRegs,size_t size,json_object * section_ir)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 
parse_registers(EFI_NVIDIA_REGISTER_DATA * regPtr,UINT8 NumberRegs,size_t size,json_object * section_ir)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.
cper_section_nvidia_to_ir(const UINT8 * section,UINT32 size)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.
ir_section_nvidia_to_cper(json_object * section,FILE * out)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