xref: /openbmc/libcper/sections/cper-section-nvidia-events.c (revision 51c1813200b42fa35d49eb0c214339ac479f090d)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <stddef.h>
6 #include <string.h>
7 #include <json.h>
8 #include <libcper/Cper.h>
9 #include <libcper/cper-utils.h>
10 #include <libcper/sections/cper-section-nvidia-events.h>
11 #include <libcper/log.h>
12 #include <string.h>
13 
14 // NVIDIA Event Section GUID
15 EFI_GUID gEfiNvidiaEventErrorSectionGuid = { 0x9068e568,
16 					     0x6ca0,
17 					     0x11f0,
18 					     { 0xae, 0xaf, 0x15, 0x93, 0x43,
19 					       0x59, 0x1e, 0xac } };
20 
21 /**
22  * NVIDIA Event Binary Structure Layout:
23  *
24  * The NVIDIA event CPER section has the following binary memory layout:
25  *
26  * ┌─────────────────────────────────────────────────────────────────────────┐
27  * │ EFI_NVIDIA_EVENT_HEADER                                      (32 bytes) │
28  * ├─────────────────────────────────────────────────────────────────────────┤
29  * │   CHAR8   EventVersion                                                  │
30  * │   CHAR8   EventContextCount      ← Number of contexts that follow       │
31  * │   CHAR8   SourceDeviceType                                              │
32  * │   CHAR8   Reserved1                                                     │
33  * │   UINT16  EventType                                                     │
34  * │   UINT16  EventSubtype                                                  │
35  * │   UINT64  EventLinkId                                                   │
36  * │   CHAR8   Signature[16]                                                 │
37  * └─────────────────────────────────────────────────────────────────────────┘
38  * ┌─────────────────────────────────────────────────────────────────────────┐
39  * │ EFI_NVIDIA_EVENT_INFO_HEADER                                  (3 bytes) │
40  * ├─────────────────────────────────────────────────────────────────────────┤
41  * │   UINT16  InfoVersion                                                   │
42  * │   UINT8   InfoSize        ← Total size (header + device data)           │
43  * └─────────────────────────────────────────────────────────────────────────┘
44  * ┌─────────────────────────────────────────────────────────────────────────┐
45  * │ Device-Specific Event Info         (InfoSize - INFO_HEADER_SIZE bytes)  │
46  * ├─────────────────────────────────────────────────────────────────────────┤
47  * │   e.g., EFI_NVIDIA_CPU_EVENT_INFO                           (29 bytes)  │
48  * │     UINT8   SocketNum                                                   │
49  * │     UINT32  Architecture                                                │
50  * │     UINT32  Ecid[4]                                                     │
51  * │     UINT64  InstanceBase                                                │
52  * └─────────────────────────────────────────────────────────────────────────┘
53  * ┌─────────────────────────────────────────────────────────────────────────┐
54  * │ EFI_NVIDIA_EVENT_CTX_HEADER (Context 0)                      (16 bytes) │
55  * ├─────────────────────────────────────────────────────────────────────────┤
56  * │   UINT32  CtxSize                ← Total size of this context           │
57  * │   UINT16  CtxVersion                                                    │
58  * │   UINT16  Reserved1                                                     │
59  * │   UINT16  DataFormatType         ← OPAQUE(0)/TYPE_1(1)/TYPE_2(2)/etc.   │
60  * │   UINT16  DataFormatVersion                                             │
61  * │   UINT32  DataSize               ← Size of Data[] array below           │
62  * │   UINT8   Data[0]                ← Flexible array member                │
63  * ├─────────────────────────────────────────────────────────────────────────┤
64  * │ Context Data[]                                        (DataSize bytes)  │
65  * ├─────────────────────────────────────────────────────────────────────────┤
66  * │   TYPE_1: Array of EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1  (16 bytes each)    │
67  * │     UINT64  Key                                                         │
68  * │     UINT64  Value                                                       │
69  * │                                                                         │
70  * │   TYPE_2: Array of EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2   (8 bytes each)    │
71  * │     UINT32  Key                                                         │
72  * │     UINT32  Value                                                       │
73  * │                                                                         │
74  * │   TYPE_3: Array of EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3   (8 bytes each)    │
75  * │     UINT64  Value                                                       │
76  * │                                                                         │
77  * │   TYPE_4: Array of EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4   (4 bytes each)    │
78  * │     UINT32  Value                                                       │
79  * │                                                                         │
80  * │   OPAQUE: Device-specific binary format                                 │
81  * └─────────────────────────────────────────────────────────────────────────┘
82  * ┌─────────────────────────────────────────────────────────────────────────┐
83  * │ PADDING (if needed)                        (align to 16-byte boundary)  │
84  * └─────────────────────────────────────────────────────────────────────────┘
85  * ┌─────────────────────────────────────────────────────────────────────────┐
86  * │ EFI_NVIDIA_EVENT_CTX_HEADER (Context 1)                       (8 bytes) │
87  * │   ... (same structure as Context 0)                                     │
88  * └─────────────────────────────────────────────────────────────────────────┘
89  *     ... repeat for EventContextCount total contexts ...
90  *
91  * Note: Each context is padded to 16-byte alignment before the next context begins.
92  */
93 
94 /**
95  * NVIDIA Event JSON IR Structure:
96  *
97  * Maps binary structures (above) to JSON using the field name constants (below).
98  *
99  * {
100  *   "eventHeader": { ... }           → EFI_NVIDIA_EVENT_HEADER
101  *   "eventInfo": { ... }             → EFI_NVIDIA_EVENT_INFO_*
102  *   "eventContexts": [               → Array of contexts            ("eventContext"*)
103  *     {
104  *       "data": {                    → EFI_NVIDIA_EVENT_CTX_DATA_*
105  *         "keyValArray64": [ ... ]   → TYPE_1 (16 bytes each: key64, val64)
106  *         "keyValArray32": [ ... ]   → TYPE_2 ( 8 bytes each: key32, val32)
107  *         "valArray64":  [ ... ]     → TYPE_3 ( 8 bytes each: val64)
108  *         "valArray32":  [ ... ]     → TYPE_4 ( 4 bytes each: val32)
109  *       }
110  *     },
111  *     { ... }
112  *   ]
113  * }
114  */
115 
116 // ============================================================================
117 // Enums
118 typedef enum {
119 	OPAQUE = 0,
120 	TYPE_1 = 1,
121 	TYPE_2 = 2,
122 	TYPE_3 = 3,
123 	TYPE_4 = 4,
124 	// GPU-specific context data types
125 	GPU_INIT_METADATA = 0x8000,
126 	GPU_EVENT_LEGACY_XID = 0x8001,
127 	GPU_RECOMMENDED_ACTIONS = 0x8002
128 } NVIDIA_EVENT_CTX_DATA_TYPE;
129 
130 typedef enum {
131 	CPU = 0,
132 	GPU = 1,
133 	DPU = 2,
134 	NIC = 3,
135 	SWX = 4,
136 	BMC = 5
137 } NVIDIA_EVENT_SRC_DEV;
138 
139 // Callback structures
140 typedef struct {
141 	NVIDIA_EVENT_SRC_DEV srcDev;
142 	UINT8 major_version; // Expected major version for this handler
143 	UINT8 minor_version; // Expected minor version for this handler
144 	void (*callback)(EFI_NVIDIA_EVENT_HEADER *, json_object *);
145 	size_t (*callback_bin)(json_object *, FILE *);
146 	size_t info_size;
147 } NV_EVENT_INFO_CALLBACKS;
148 
149 typedef struct {
150 	NVIDIA_EVENT_SRC_DEV srcDev;
151 	NVIDIA_EVENT_CTX_DATA_TYPE dataFormatType;
152 	void (*callback)(EFI_NVIDIA_EVENT_HEADER *, size_t, size_t,
153 			 json_object *);
154 	size_t (*callback_bin)(json_object *, size_t, FILE *);
155 } NV_EVENT_CTX_CALLBACKS;
156 
157 // Helper functions
158 // CPU info formatters
159 static void parse_cpu_info_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
160 				 json_object *event_info_ir);
161 static size_t parse_cpu_info_to_bin(json_object *event_info_ir, FILE *out);
162 
163 // GPU info formatters
164 static void parse_gpu_info_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
165 				 json_object *event_info_ir);
166 static size_t parse_gpu_info_to_bin(json_object *event_info_ir, FILE *out);
167 
168 // GPU context data formatters
169 static void parse_gpu_ctx_metadata_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
170 					 size_t total_event_size,
171 					 size_t ctx_instance,
172 					 json_object *output_data_ir);
173 static size_t parse_gpu_ctx_metadata_to_bin(json_object *event_ir,
174 					    size_t ctx_instance,
175 					    FILE *output_file_stream);
176 static void
177 parse_gpu_ctx_legacy_xid_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
178 			       size_t total_event_size, size_t ctx_instance,
179 			       json_object *output_data_ir);
180 static size_t parse_gpu_ctx_legacy_xid_to_bin(json_object *event_ir,
181 					      size_t ctx_instance,
182 					      FILE *output_file_stream);
183 static void parse_gpu_ctx_recommended_actions_to_ir(
184 	EFI_NVIDIA_EVENT_HEADER *event_header, size_t total_event_size,
185 	size_t ctx_instance, json_object *output_data_ir);
186 static size_t parse_gpu_ctx_recommended_actions_to_bin(
187 	json_object *event_ir, size_t ctx_instance, FILE *output_file_stream);
188 
189 // Common context data type0 formatters
190 static void parse_common_ctx_type0_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
191 					 size_t total_event_size,
192 					 size_t ctx_instance,
193 					 json_object *output_data_ir);
194 static size_t parse_common_ctx_type0_to_bin(json_object *event_ir,
195 					    size_t ctx_instance,
196 					    FILE *output_file_stream);
197 
198 // Common context data type1 formatters
199 static void parse_common_ctx_type1_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
200 					 size_t total_event_size,
201 					 size_t ctx_instance,
202 					 json_object *output_data_ir);
203 static size_t parse_common_ctx_type1_to_bin(json_object *event_ir,
204 					    size_t ctx_instance,
205 					    FILE *output_file_stream);
206 
207 // Common context data type2 formatters
208 static void parse_common_ctx_type2_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
209 					 size_t total_event_size,
210 					 size_t ctx_instance,
211 					 json_object *output_data_ir);
212 static size_t parse_common_ctx_type2_to_bin(json_object *event_ir,
213 					    size_t ctx_instance,
214 					    FILE *output_file_stream);
215 
216 // Common context data type3 formatters
217 static void parse_common_ctx_type3_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
218 					 size_t total_event_size,
219 					 size_t ctx_instance,
220 					 json_object *output_data_ir);
221 static size_t parse_common_ctx_type3_to_bin(json_object *event_ir,
222 					    size_t ctx_instance,
223 					    FILE *output_file_stream);
224 
225 // Common context data type4 formatters
226 static void parse_common_ctx_type4_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
227 					 size_t total_event_size,
228 					 size_t ctx_instance,
229 					 json_object *output_data_ir);
230 static size_t parse_common_ctx_type4_to_bin(json_object *event_ir,
231 					    size_t ctx_instance,
232 					    FILE *output_file_stream);
233 
234 // Helper: Get pointer to device-specific event info (after headers)
get_event_info(EFI_NVIDIA_EVENT_HEADER * header)235 static inline void *get_event_info(EFI_NVIDIA_EVENT_HEADER *header)
236 {
237 	return (UINT8 *)header + sizeof(EFI_NVIDIA_EVENT_HEADER) +
238 	       sizeof(EFI_NVIDIA_EVENT_INFO_HEADER);
239 }
240 
241 // Helper: Get pointer to event info header (after event header)
242 static inline EFI_NVIDIA_EVENT_INFO_HEADER *
get_event_info_header(EFI_NVIDIA_EVENT_HEADER * header)243 get_event_info_header(EFI_NVIDIA_EVENT_HEADER *header)
244 {
245 	return (EFI_NVIDIA_EVENT_INFO_HEADER *)((UINT8 *)header +
246 						sizeof(EFI_NVIDIA_EVENT_HEADER));
247 }
248 
249 // Helper: Extract major version from event info header (high byte)
get_info_major_version(EFI_NVIDIA_EVENT_INFO_HEADER * header)250 static inline UINT8 get_info_major_version(EFI_NVIDIA_EVENT_INFO_HEADER *header)
251 {
252 	return (UINT8)((header->InfoVersion >> 8) & 0xFF);
253 }
254 
255 // Helper: Extract minor version from event info header (low byte)
get_info_minor_version(EFI_NVIDIA_EVENT_INFO_HEADER * header)256 static inline UINT8 get_info_minor_version(EFI_NVIDIA_EVENT_INFO_HEADER *header)
257 {
258 	return (UINT8)(header->InfoVersion & 0xFF);
259 }
260 
261 // Helper: Check if info major version matches - returns false and logs on mismatch
check_info_major_version(UINT8 maj,UINT8 min,UINT8 exp_maj,const char * operation)262 static bool check_info_major_version(UINT8 maj, UINT8 min, UINT8 exp_maj,
263 				     const char *operation)
264 {
265 	if (maj != exp_maj) {
266 		cper_print_log(
267 			"Error: NVIDIA Event Info major version mismatch: "
268 			"expected %d.x, got %d.%d. Skipping event info %s.\n",
269 			(int)exp_maj, (int)maj, (int)min, operation);
270 		return false;
271 	}
272 	return true;
273 }
274 
275 // Helper: Check if event header version matches - returns false and logs on mismatch
check_event_header_version(UINT16 ver,UINT16 exp_ver,const char * operation)276 static bool check_event_header_version(UINT16 ver, UINT16 exp_ver,
277 				       const char *operation)
278 {
279 	if (ver != exp_ver) {
280 		cper_print_log("Error: NVIDIA Event Header version mismatch: "
281 			       "expected %d, got %d. Skipping event %s.\n",
282 			       (int)exp_ver, (int)ver, operation);
283 		return false;
284 	}
285 	return true;
286 }
287 
288 // Helper: Write zero-padding to align to 16-byte boundary
write_padding_to_16_byte_alignment(size_t bytes_written,FILE * out)289 static void write_padding_to_16_byte_alignment(size_t bytes_written, FILE *out)
290 {
291 	size_t padding = (16 - (bytes_written % 16)) % 16;
292 	if (padding > 0) {
293 		UINT8 zeros[16] = { 0 };
294 		fwrite(zeros, 1, padding, out);
295 	}
296 }
297 
298 // Event info handler callbacks for different device types.
299 // Note: The _to_bin callbacks should return the number of bytes written.
300 //       The caller is responsible for adding 16-byte alignment padding.
301 NV_EVENT_INFO_CALLBACKS nv_event_types[] = {
302 	{ CPU, EFI_NVIDIA_CPU_EVENT_INFO_MAJ, EFI_NVIDIA_CPU_EVENT_INFO_MIN,
303 	  &parse_cpu_info_to_ir, &parse_cpu_info_to_bin,
304 	  sizeof(EFI_NVIDIA_CPU_EVENT_INFO) },
305 	{ GPU, EFI_NVIDIA_GPU_EVENT_INFO_MAJ, EFI_NVIDIA_GPU_EVENT_INFO_MIN,
306 	  &parse_gpu_info_to_ir, &parse_gpu_info_to_bin,
307 	  sizeof(EFI_NVIDIA_GPU_EVENT_INFO) }
308 };
309 
310 // Event context handler callbacks for device-specific opaque data formats.
311 // This is where custom/opaque context data type handlers should be registered.
312 // Add entries here for device types that need special handling beyond the standard TYPE_1-4 formats.
313 // Note: The _to_bin callbacks should return the number of bytes written.
314 //       The caller is responsible for adding 16-byte alignment padding.
315 NV_EVENT_CTX_CALLBACKS event_ctx_handlers[] = {
316 	// GPU-specific context data handlers
317 	{ GPU, GPU_INIT_METADATA, &parse_gpu_ctx_metadata_to_ir,
318 	  &parse_gpu_ctx_metadata_to_bin },
319 	{ GPU, GPU_EVENT_LEGACY_XID, &parse_gpu_ctx_legacy_xid_to_ir,
320 	  &parse_gpu_ctx_legacy_xid_to_bin },
321 	{ GPU, GPU_RECOMMENDED_ACTIONS,
322 	  &parse_gpu_ctx_recommended_actions_to_ir,
323 	  &parse_gpu_ctx_recommended_actions_to_bin }
324 };
325 
326 // Retrieves a pointer to the nth event context within an NVIDIA event structure.
327 // Walks through the event header, event info, and variable-sized contexts with bounds checking.
328 // Returns NULL if the index is out of bounds or if buffer overflow would occur.
329 static inline EFI_NVIDIA_EVENT_CTX_HEADER *
get_event_context_n(EFI_NVIDIA_EVENT_HEADER * event_header,size_t n,size_t total_size)330 get_event_context_n(EFI_NVIDIA_EVENT_HEADER *event_header, size_t n,
331 		    size_t total_size)
332 {
333 	UINT8 *start = (UINT8 *)event_header;
334 	UINT8 *ptr = start + sizeof(EFI_NVIDIA_EVENT_HEADER);
335 	UINT8 *end = start + total_size;
336 
337 	if (ptr + sizeof(EFI_NVIDIA_EVENT_INFO_HEADER) > end) {
338 		return NULL;
339 	}
340 
341 	EFI_NVIDIA_EVENT_INFO_HEADER *info_header =
342 		(EFI_NVIDIA_EVENT_INFO_HEADER *)ptr;
343 	if (ptr + info_header->InfoSize > end) {
344 		return NULL;
345 	}
346 	ptr += info_header->InfoSize;
347 	for (size_t i = 0; i < n; i++) {
348 		if (ptr + sizeof(EFI_NVIDIA_EVENT_CTX_HEADER) > end) {
349 			return NULL;
350 		}
351 		EFI_NVIDIA_EVENT_CTX_HEADER *ctx =
352 			(EFI_NVIDIA_EVENT_CTX_HEADER *)ptr;
353 		if (ptr + ctx->CtxSize > end) {
354 			return NULL;
355 		}
356 		ptr += ctx->CtxSize;
357 	}
358 
359 	if (ptr + sizeof(EFI_NVIDIA_EVENT_CTX_HEADER) > end) {
360 		return NULL;
361 	}
362 	return (EFI_NVIDIA_EVENT_CTX_HEADER *)ptr;
363 }
364 
365 // Gets the nth event context from a JSON IR Event object.
366 // Returns NULL if the eventContexts field doesn't exist, isn't an object,
367 // or if n is out of bounds.
get_event_context_n_ir(json_object * event_ir,size_t n)368 static inline json_object *get_event_context_n_ir(json_object *event_ir,
369 						  size_t n)
370 {
371 	if (event_ir == NULL) {
372 		return NULL;
373 	}
374 
375 	// Get the eventContexts object
376 	json_object *event_contexts_ir =
377 		json_object_object_get(event_ir, "eventContexts");
378 	if (event_contexts_ir == NULL) {
379 		return NULL;
380 	}
381 
382 	// Check if it's an array (preferred structure)
383 	if (json_object_is_type(event_contexts_ir, json_type_array)) {
384 		size_t array_len = json_object_array_length(event_contexts_ir);
385 		if (n >= array_len) {
386 			return NULL;
387 		}
388 		return json_object_array_get_idx(event_contexts_ir, n);
389 	}
390 
391 	// Handle object structure with indexed keys (eventContext0, eventContext1, etc.)
392 	if (json_object_is_type(event_contexts_ir, json_type_object)) {
393 		char key[64];
394 		snprintf(key, sizeof(key), "eventContext%zu", n);
395 		return json_object_object_get(event_contexts_ir, key);
396 	}
397 
398 	return NULL;
399 }
400 
401 // Gets the data object from the nth event context in a JSON IR Event object.
402 // Combines get_event_context_n_ir and extraction of the data field.
403 // Returns NULL if the context doesn't exist, is out of bounds, or has no data.
get_event_context_n_data_ir(json_object * event_ir,size_t n)404 static inline json_object *get_event_context_n_data_ir(json_object *event_ir,
405 						       size_t n)
406 {
407 	json_object *event_context_ir = get_event_context_n_ir(event_ir, n);
408 	if (event_context_ir == NULL) {
409 		return NULL;
410 	}
411 
412 	return json_object_object_get(event_context_ir, "data");
413 }
414 
415 // Parses CPU-specific event info structure into JSON IR format.
416 // Extracts socket number, architecture, ECID array, and instance base.
417 /*
418  * Example JSON IR "data" output:
419  * {
420  *   "SocketNum": 0,
421  *   "Architecture": 2684420096,
422  *   "Ecid1": 1234567890123456789,
423  *   "Ecid2": 9876543210987654321,
424  *   "Ecid3": 5555555555555555555,
425  *   "Ecid4": 1111111111111111111,
426  *   "InstanceBase": 281474976710656
427  * }
428  */
parse_cpu_info_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,json_object * event_info_ir)429 static void parse_cpu_info_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
430 				 json_object *event_info_ir)
431 {
432 	// Verify InfoSize is large enough for CPU event info
433 	EFI_NVIDIA_EVENT_INFO_HEADER *info_header =
434 		get_event_info_header(event_header);
435 	size_t required_size = sizeof(EFI_NVIDIA_EVENT_INFO_HEADER) +
436 			       sizeof(EFI_NVIDIA_CPU_EVENT_INFO);
437 	if (info_header->InfoSize < required_size) {
438 		cper_print_log(
439 			"Error: CPU event info size too small: got %d, need %zu\n",
440 			info_header->InfoSize, required_size);
441 		return;
442 	}
443 
444 	EFI_NVIDIA_CPU_EVENT_INFO *cpu_event_info =
445 		(EFI_NVIDIA_CPU_EVENT_INFO *)get_event_info(event_header);
446 	if (cpu_event_info == NULL) {
447 		return;
448 	}
449 
450 	json_object_object_add(
451 		event_info_ir, "SocketNum",
452 		json_object_new_int64(cpu_event_info->SocketNum));
453 	json_object_object_add(
454 		event_info_ir, "Architecture",
455 		json_object_new_int64(cpu_event_info->Architecture));
456 	json_object_object_add(event_info_ir, "Ecid1",
457 			       json_object_new_uint64(cpu_event_info->Ecid[0]));
458 	json_object_object_add(event_info_ir, "Ecid2",
459 			       json_object_new_uint64(cpu_event_info->Ecid[1]));
460 	json_object_object_add(event_info_ir, "Ecid3",
461 			       json_object_new_uint64(cpu_event_info->Ecid[2]));
462 	json_object_object_add(event_info_ir, "Ecid4",
463 			       json_object_new_uint64(cpu_event_info->Ecid[3]));
464 	json_object_object_add(
465 		event_info_ir, "InstanceBase",
466 		json_object_new_uint64(cpu_event_info->InstanceBase));
467 }
468 // Converts CPU-specific event info from JSON IR to CPER binary format.
469 // Writes socket number, architecture, ECID array, and instance base.
470 // Returns the number of bytes written.
471 /*
472  * ┌─────────────────────────────────────────────────────────────────────────┐
473  * │ EFI_NVIDIA_CPU_EVENT_INFO                                    (32 bytes) │
474  * ├─────────────────────────────────────────────────────────────────────────┤
475  * │   UINT8   SocketNum                                                     │
476  * │   [padding - 3 bytes]                                                   │
477  * │   UINT32  Architecture                                                  │
478  * │   UINT32  Ecid[0]                                                       │
479  * │   UINT32  Ecid[1]                                                       │
480  * │   UINT32  Ecid[2]                                                       │
481  * │   UINT32  Ecid[3]                                                       │
482  * │   UINT64  InstanceBase                                                  │
483  * └─────────────────────────────────────────────────────────────────────────┘
484  */
parse_cpu_info_to_bin(json_object * event_info_ir,FILE * out)485 static size_t parse_cpu_info_to_bin(json_object *event_info_ir, FILE *out)
486 {
487 	EFI_NVIDIA_CPU_EVENT_INFO cpu_event_info = { 0 };
488 	cpu_event_info.SocketNum = json_object_get_int64(
489 		json_object_object_get(event_info_ir, "SocketNum"));
490 	cpu_event_info.Architecture = json_object_get_int64(
491 		json_object_object_get(event_info_ir, "Architecture"));
492 	cpu_event_info.Ecid[0] = json_object_get_uint64(
493 		json_object_object_get(event_info_ir, "Ecid1"));
494 	cpu_event_info.Ecid[1] = json_object_get_uint64(
495 		json_object_object_get(event_info_ir, "Ecid2"));
496 	cpu_event_info.Ecid[2] = json_object_get_uint64(
497 		json_object_object_get(event_info_ir, "Ecid3"));
498 	cpu_event_info.Ecid[3] = json_object_get_uint64(
499 		json_object_object_get(event_info_ir, "Ecid4"));
500 	cpu_event_info.InstanceBase = json_object_get_uint64(
501 		json_object_object_get(event_info_ir, "InstanceBase"));
502 	return fwrite(&cpu_event_info, 1, sizeof(EFI_NVIDIA_CPU_EVENT_INFO),
503 		      out);
504 }
505 
506 // Parses GPU-specific event info structure into JSON IR format.
507 // Extracts version, size, event originator, partitions, and PDI.
508 /*
509  * Example JSON IR "data" output:
510  * {
511  *   "EventOriginator": 2,
512  *   "SourcePartition": 1,
513  *   "SourceSubPartition": 0,
514  *   "Pdi": 9876543210987654321
515  * }
516  */
parse_gpu_info_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,json_object * event_info_ir)517 static void parse_gpu_info_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
518 				 json_object *event_info_ir)
519 {
520 	// Verify InfoSize is large enough for GPU event info
521 	EFI_NVIDIA_EVENT_INFO_HEADER *info_header =
522 		get_event_info_header(event_header);
523 	size_t required_size = sizeof(EFI_NVIDIA_EVENT_INFO_HEADER) +
524 			       sizeof(EFI_NVIDIA_GPU_EVENT_INFO);
525 	if (info_header->InfoSize < required_size) {
526 		cper_print_log(
527 			"Error: GPU event info size too small: got %d, need %zu\n",
528 			info_header->InfoSize, required_size);
529 		return;
530 	}
531 
532 	EFI_NVIDIA_GPU_EVENT_INFO *gpu_event_info =
533 		(EFI_NVIDIA_GPU_EVENT_INFO *)get_event_info(event_header);
534 	if (gpu_event_info == NULL) {
535 		return;
536 	}
537 
538 	json_object_object_add(
539 		event_info_ir, "EventOriginator",
540 		json_object_new_int64(
541 			gpu_event_info->EventOriginator)); // UINT8
542 	json_object_object_add(
543 		event_info_ir, "SourcePartition",
544 		json_object_new_int64(
545 			gpu_event_info->SourcePartition)); // UINT16
546 	json_object_object_add(
547 		event_info_ir, "SourceSubPartition",
548 		json_object_new_int64(
549 			gpu_event_info->SourceSubPartition)); // UINT16
550 	json_object_object_add(
551 		event_info_ir, "Pdi",
552 		json_object_new_uint64(gpu_event_info->Pdi)); // UINT64
553 }
554 
555 // Converts GPU-specific event info from JSON IR to CPER binary format.
556 // Writes version, size, event originator, partitions, and PDI.
557 // Returns the number of bytes written.
558 /*
559  * ┌─────────────────────────────────────────────────────────────────────────┐
560  * │ EFI_NVIDIA_GPU_EVENT_INFO                                    (16 bytes) │
561  * ├─────────────────────────────────────────────────────────────────────────┤
562  * │   UINT8   EventOriginator                                               │
563  * │   UINT16  SourcePartition                                               │
564  * │   UINT16  SourceSubPartition                                            │
565  * │   UINT64  Pdi                                                           │
566  * └─────────────────────────────────────────────────────────────────────────┘
567  */
parse_gpu_info_to_bin(json_object * event_info_ir,FILE * out)568 static size_t parse_gpu_info_to_bin(json_object *event_info_ir, FILE *out)
569 {
570 	EFI_NVIDIA_GPU_EVENT_INFO gpu_event_info = { 0 };
571 
572 	gpu_event_info.EventOriginator = json_object_get_uint64(
573 		json_object_object_get(event_info_ir, "EventOriginator"));
574 	gpu_event_info.SourcePartition = json_object_get_int64(
575 		json_object_object_get(event_info_ir, "SourcePartition"));
576 	gpu_event_info.SourceSubPartition = json_object_get_int64(
577 		json_object_object_get(event_info_ir, "SourceSubPartition"));
578 	gpu_event_info.Pdi = json_object_get_uint64(
579 		json_object_object_get(event_info_ir, "Pdi"));
580 
581 	return fwrite(&gpu_event_info, 1, sizeof(EFI_NVIDIA_GPU_EVENT_INFO),
582 		      out);
583 }
584 
585 // GPU Context Data Handlers
586 
587 // Parses GPU Initialization Metadata (0x1000) context data to JSON IR.
588 // Extracts device info, firmware versions, PCI info, etc.
589 /*
590  * Example JSON IR "data" output (numeric fields in decimal):
591  * {
592  *   "deviceName": "NVIDIA H100 80GB HBM3",
593  *   "firmwareVersion": "96.00.5B.00.01",
594  *   "pfDriverMicrocodeVersion": "535.183.01",
595  *   "pfDriverVersion": "535.183.01",
596  *   "vfDriverVersion": "535.183.01",
597  *   "configuration": 123456789012345,
598  *   "pdi": 9876543210987654321,
599  *   "architectureId": 2684420096,
600  *   "hardwareInfoType": 0,
601  *   "pciInfo": {
602  *     "class": 3,
603  *     "subclass": 2,
604  *     "rev": 161,
605  *     "vendorId": 4318,
606  *     "deviceId": 8711,
607  *     "subsystemVendorId": 4318,
608  *     "subsystemId": 5145,
609  *     "bar0Start": 3758096384,
610  *     "bar0Size": 16777216,
611  *     "bar1Start": 2415919104,
612  *     "bar1Size": 536870912,
613  *     "bar2Start": 2416128000,
614  *     "bar2Size": 33554432
615  *   }
616  * }
617  */
parse_gpu_ctx_metadata_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,size_t total_event_size,size_t ctx_instance,json_object * output_data_ir)618 static void parse_gpu_ctx_metadata_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
619 					 size_t total_event_size,
620 					 size_t ctx_instance,
621 					 json_object *output_data_ir)
622 {
623 	EFI_NVIDIA_EVENT_CTX_HEADER *ctx = get_event_context_n(
624 		event_header, ctx_instance, total_event_size);
625 	if (ctx == NULL) {
626 		return;
627 	}
628 
629 	EFI_NVIDIA_GPU_CTX_METADATA *metadata =
630 		(EFI_NVIDIA_GPU_CTX_METADATA *)ctx->Data;
631 
632 	// String fields - use json_object_new_string to stop at first null (no null padding in JSON)
633 	json_object_object_add(output_data_ir, "deviceName",
634 			       json_object_new_string(metadata->DeviceName));
635 	json_object_object_add(
636 		output_data_ir, "firmwareVersion",
637 		json_object_new_string(metadata->FirmwareVersion));
638 	json_object_object_add(
639 		output_data_ir, "pfDriverMicrocodeVersion",
640 		json_object_new_string(metadata->PfDriverMicrocodeVersion));
641 	json_object_object_add(
642 		output_data_ir, "pfDriverVersion",
643 		json_object_new_string(metadata->PfDriverVersion));
644 	json_object_object_add(
645 		output_data_ir, "vfDriverVersion",
646 		json_object_new_string(metadata->VfDriverVersion));
647 
648 	// Numeric fields
649 	json_object_object_add(output_data_ir, "configuration",
650 			       json_object_new_uint64(metadata->Configuration));
651 	json_object_object_add(output_data_ir, "pdi",
652 			       json_object_new_uint64(metadata->Pdi));
653 	json_object_object_add(output_data_ir, "architectureId",
654 			       json_object_new_int64(metadata->ArchitectureId));
655 	json_object_object_add(
656 		output_data_ir, "hardwareInfoType",
657 		json_object_new_int64(metadata->HardwareInfoType));
658 
659 	// PCI Info (if HardwareInfoType == 0)
660 	if (metadata->HardwareInfoType == 0) {
661 		json_object *pci_info = json_object_new_object();
662 		json_object_object_add(
663 			pci_info, "class",
664 			json_object_new_int64(metadata->PciInfo.Class));
665 		json_object_object_add(
666 			pci_info, "subclass",
667 			json_object_new_int64(metadata->PciInfo.Subclass));
668 		json_object_object_add(
669 			pci_info, "rev",
670 			json_object_new_int64(metadata->PciInfo.Rev));
671 		json_object_object_add(
672 			pci_info, "vendorId",
673 			json_object_new_int64(metadata->PciInfo.VendorId));
674 		json_object_object_add(
675 			pci_info, "deviceId",
676 			json_object_new_int64(metadata->PciInfo.DeviceId));
677 		json_object_object_add(
678 			pci_info, "subsystemVendorId",
679 			json_object_new_int64(
680 				metadata->PciInfo.SubsystemVendorId));
681 		json_object_object_add(
682 			pci_info, "subsystemId",
683 			json_object_new_int64(metadata->PciInfo.SubsystemId));
684 		json_object_object_add(
685 			pci_info, "bar0Start",
686 			json_object_new_uint64(metadata->PciInfo.Bar0Start));
687 		json_object_object_add(
688 			pci_info, "bar0Size",
689 			json_object_new_uint64(metadata->PciInfo.Bar0Size));
690 		json_object_object_add(
691 			pci_info, "bar1Start",
692 			json_object_new_uint64(metadata->PciInfo.Bar1Start));
693 		json_object_object_add(
694 			pci_info, "bar1Size",
695 			json_object_new_uint64(metadata->PciInfo.Bar1Size));
696 		json_object_object_add(
697 			pci_info, "bar2Start",
698 			json_object_new_uint64(metadata->PciInfo.Bar2Start));
699 		json_object_object_add(
700 			pci_info, "bar2Size",
701 			json_object_new_uint64(metadata->PciInfo.Bar2Size));
702 		json_object_object_add(output_data_ir, "pciInfo", pci_info);
703 	}
704 }
705 
706 // Converts GPU Initialization Metadata from JSON IR to binary.
707 // Returns the number of bytes written.
708 /*
709  * ┌─────────────────────────────────────────────────────────────────────────┐
710  * │ EFI_NVIDIA_GPU_CTX_METADATA                                 (192 bytes) │
711  * ├─────────────────────────────────────────────────────────────────────────┤
712  * │   CHAR8   DeviceName[48]                                                │
713  * │   CHAR8   FirmwareVersion[16]                                           │
714  * │   CHAR8   PfDriverMicrocodeVersion[16]                                  │
715  * │   CHAR8   PfDriverVersion[16]                                           │
716  * │   CHAR8   VfDriverVersion[16]                                           │
717  * │   UINT64  Configuration                                                 │
718  * │   UINT64  Pdi                                                           │
719  * │   UINT32  ArchitectureId                                                │
720  * │   UINT8   HardwareInfoType         ← 0=PCI Info, 1-255=Reserved         │
721  * │   union (59 bytes):                                                     │
722  * │     EFI_NVIDIA_GPU_CTX_METADATA_PCI_INFO PciInfo (when type = 0):       │
723  * │       UINT8   Class, Subclass, Rev                                      │
724  * │       UINT16  VendorId, DeviceId, SubsystemVendorId, SubsystemId        │
725  * │       UINT64  Bar0Start, Bar0Size, Bar1Start, Bar1Size, Bar2Start, ...  │
726  * │     UINT8 Reserved[59]             ← for future hardware info types     │
727  * └─────────────────────────────────────────────────────────────────────────┘
728  */
parse_gpu_ctx_metadata_to_bin(json_object * event_ir,size_t ctx_instance,FILE * output_file_stream)729 static size_t parse_gpu_ctx_metadata_to_bin(json_object *event_ir,
730 					    size_t ctx_instance,
731 					    FILE *output_file_stream)
732 {
733 	json_object *event_context_data_ir =
734 		get_event_context_n_data_ir(event_ir, ctx_instance);
735 	if (event_context_data_ir == NULL) {
736 		return 0;
737 	}
738 
739 	EFI_NVIDIA_GPU_CTX_METADATA metadata = { 0 };
740 
741 	// String fields - use memcpy with strnlen to avoid strncpy truncation warnings
742 	const char *str;
743 	str = json_object_get_string(
744 		json_object_object_get(event_context_data_ir, "deviceName"));
745 	if (str) {
746 		memcpy(metadata.DeviceName, str,
747 		       strnlen(str, sizeof(metadata.DeviceName)));
748 	}
749 
750 	str = json_object_get_string(json_object_object_get(
751 		event_context_data_ir, "firmwareVersion"));
752 	if (str) {
753 		memcpy(metadata.FirmwareVersion, str,
754 		       strnlen(str, sizeof(metadata.FirmwareVersion)));
755 	}
756 
757 	str = json_object_get_string(json_object_object_get(
758 		event_context_data_ir, "pfDriverMicrocodeVersion"));
759 	if (str) {
760 		memcpy(metadata.PfDriverMicrocodeVersion, str,
761 		       strnlen(str, sizeof(metadata.PfDriverMicrocodeVersion)));
762 	}
763 
764 	str = json_object_get_string(json_object_object_get(
765 		event_context_data_ir, "pfDriverVersion"));
766 	if (str) {
767 		memcpy(metadata.PfDriverVersion, str,
768 		       strnlen(str, sizeof(metadata.PfDriverVersion)));
769 	}
770 
771 	str = json_object_get_string(json_object_object_get(
772 		event_context_data_ir, "vfDriverVersion"));
773 	if (str) {
774 		memcpy(metadata.VfDriverVersion, str,
775 		       strnlen(str, sizeof(metadata.VfDriverVersion)));
776 	}
777 
778 	// Numeric fields
779 	metadata.Configuration = json_object_get_uint64(
780 		json_object_object_get(event_context_data_ir, "configuration"));
781 	metadata.Pdi = json_object_get_uint64(
782 		json_object_object_get(event_context_data_ir, "pdi"));
783 	metadata.ArchitectureId = json_object_get_int64(json_object_object_get(
784 		event_context_data_ir, "architectureId"));
785 	metadata.HardwareInfoType = json_object_get_int64(
786 		json_object_object_get(event_context_data_ir,
787 				       "hardwareInfoType"));
788 
789 	// PCI Info (if present and HardwareInfoType == 0)
790 	json_object *pci_info =
791 		json_object_object_get(event_context_data_ir, "pciInfo");
792 	if (pci_info != NULL && metadata.HardwareInfoType == 0) {
793 		metadata.PciInfo.Class = json_object_get_int64(
794 			json_object_object_get(pci_info, "class"));
795 		metadata.PciInfo.Subclass = json_object_get_int64(
796 			json_object_object_get(pci_info, "subclass"));
797 		metadata.PciInfo.Rev = json_object_get_int64(
798 			json_object_object_get(pci_info, "rev"));
799 		metadata.PciInfo.VendorId = json_object_get_int64(
800 			json_object_object_get(pci_info, "vendorId"));
801 		metadata.PciInfo.DeviceId = json_object_get_int64(
802 			json_object_object_get(pci_info, "deviceId"));
803 		metadata.PciInfo.SubsystemVendorId = json_object_get_int64(
804 			json_object_object_get(pci_info, "subsystemVendorId"));
805 		metadata.PciInfo.SubsystemId = json_object_get_int64(
806 			json_object_object_get(pci_info, "subsystemId"));
807 		metadata.PciInfo.Bar0Start = json_object_get_uint64(
808 			json_object_object_get(pci_info, "bar0Start"));
809 		metadata.PciInfo.Bar0Size = json_object_get_uint64(
810 			json_object_object_get(pci_info, "bar0Size"));
811 		metadata.PciInfo.Bar1Start = json_object_get_uint64(
812 			json_object_object_get(pci_info, "bar1Start"));
813 		metadata.PciInfo.Bar1Size = json_object_get_uint64(
814 			json_object_object_get(pci_info, "bar1Size"));
815 		metadata.PciInfo.Bar2Start = json_object_get_uint64(
816 			json_object_object_get(pci_info, "bar2Start"));
817 		metadata.PciInfo.Bar2Size = json_object_get_uint64(
818 			json_object_object_get(pci_info, "bar2Size"));
819 	}
820 
821 	return fwrite(&metadata, 1, sizeof(EFI_NVIDIA_GPU_CTX_METADATA),
822 		      output_file_stream);
823 }
824 
825 // Parses GPU Event Legacy Xid (0x1001) context data to JSON IR.
826 // Extracts Xid code and message string.
827 /*
828  * Example JSON IR "data" output:
829  * {
830  *   "xidCode": 79,
831  *   "message": "GPU has fallen off the bus"
832  * }
833  */
834 static void
parse_gpu_ctx_legacy_xid_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,size_t total_event_size,size_t ctx_instance,json_object * output_data_ir)835 parse_gpu_ctx_legacy_xid_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
836 			       size_t total_event_size, size_t ctx_instance,
837 			       json_object *output_data_ir)
838 {
839 	EFI_NVIDIA_EVENT_CTX_HEADER *ctx = get_event_context_n(
840 		event_header, ctx_instance, total_event_size);
841 	if (ctx == NULL) {
842 		return;
843 	}
844 
845 	EFI_NVIDIA_GPU_CTX_LEGACY_XID *xid =
846 		(EFI_NVIDIA_GPU_CTX_LEGACY_XID *)ctx->Data;
847 
848 	json_object_object_add(output_data_ir, "xidCode",
849 			       json_object_new_int64(xid->XidCode));
850 	// Use json_object_new_string to stop at first null terminator (no null padding in JSON)
851 	json_object_object_add(output_data_ir, "message",
852 			       json_object_new_string(xid->Message));
853 }
854 
855 // Converts GPU Event Legacy Xid from JSON IR to binary.
856 // Returns the number of bytes written.
857 /*
858  * ┌─────────────────────────────────────────────────────────────────────────┐
859  * │ EFI_NVIDIA_GPU_CTX_LEGACY_XID                               (240 bytes) │
860  * ├─────────────────────────────────────────────────────────────────────────┤
861  * │   UINT32  XidCode              ← Legacy Xid error code                  │
862  * │   CHAR8   Message[236]         ← NUL-terminated ASCII event message     │
863  * └─────────────────────────────────────────────────────────────────────────┘
864  */
parse_gpu_ctx_legacy_xid_to_bin(json_object * event_ir,size_t ctx_instance,FILE * output_file_stream)865 static size_t parse_gpu_ctx_legacy_xid_to_bin(json_object *event_ir,
866 					      size_t ctx_instance,
867 					      FILE *output_file_stream)
868 {
869 	json_object *event_context_data_ir =
870 		get_event_context_n_data_ir(event_ir, ctx_instance);
871 	if (event_context_data_ir == NULL) {
872 		return 0;
873 	}
874 
875 	EFI_NVIDIA_GPU_CTX_LEGACY_XID xid = { 0 };
876 
877 	xid.XidCode = json_object_get_int64(
878 		json_object_object_get(event_context_data_ir, "xidCode"));
879 
880 	const char *message = json_object_get_string(
881 		json_object_object_get(event_context_data_ir, "message"));
882 	if (message) {
883 		memcpy(xid.Message, message,
884 		       strnlen(message, sizeof(xid.Message)));
885 	}
886 
887 	return fwrite(&xid, 1, sizeof(EFI_NVIDIA_GPU_CTX_LEGACY_XID),
888 		      output_file_stream);
889 }
890 
891 // Parses GPU Recommended Actions (0x1002) context data to JSON IR.
892 // Extracts flags, recovery action, and diagnostic flow code.
893 /*
894  * Example JSON IR "data" output:
895  * {
896  *   "flags": 3,
897  *   "recoveryAction": 2,
898  *   "diagnosticFlow": 0
899  * }
900  */
parse_gpu_ctx_recommended_actions_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,size_t total_event_size,size_t ctx_instance,json_object * output_data_ir)901 static void parse_gpu_ctx_recommended_actions_to_ir(
902 	EFI_NVIDIA_EVENT_HEADER *event_header, size_t total_event_size,
903 	size_t ctx_instance, json_object *output_data_ir)
904 {
905 	EFI_NVIDIA_EVENT_CTX_HEADER *ctx = get_event_context_n(
906 		event_header, ctx_instance, total_event_size);
907 	if (ctx == NULL) {
908 		return;
909 	}
910 
911 	EFI_NVIDIA_GPU_CTX_RECOMMENDED_ACTIONS *actions =
912 		(EFI_NVIDIA_GPU_CTX_RECOMMENDED_ACTIONS *)ctx->Data;
913 
914 	json_object_object_add(output_data_ir, "flags",
915 			       json_object_new_int64(actions->Flags));
916 	json_object_object_add(output_data_ir, "recoveryAction",
917 			       json_object_new_int64(actions->RecoveryAction));
918 	json_object_object_add(output_data_ir, "diagnosticFlow",
919 			       json_object_new_int64(actions->DiagnosticFlow));
920 }
921 
922 // Converts GPU Recommended Actions from JSON IR to binary.
923 // Returns the number of bytes written.
924 /*
925  * ┌─────────────────────────────────────────────────────────────────────────┐
926  * │ EFI_NVIDIA_GPU_CTX_RECOMMENDED_ACTIONS                       (16 bytes) │
927  * ├─────────────────────────────────────────────────────────────────────────┤
928  * │   UINT8   Flags                                                         │
929  * │   UINT8   Reserved1[3]         ← padding                                │
930  * │   UINT16  RecoveryAction                                                │
931  * │   UINT16  DiagnosticFlow       ← 0=Unspecified                          │
932  * │   UINT64  Reserved2            ← padding to 16-byte alignment           │
933  * └─────────────────────────────────────────────────────────────────────────┘
934  */
parse_gpu_ctx_recommended_actions_to_bin(json_object * event_ir,size_t ctx_instance,FILE * output_file_stream)935 static size_t parse_gpu_ctx_recommended_actions_to_bin(json_object *event_ir,
936 						       size_t ctx_instance,
937 						       FILE *output_file_stream)
938 {
939 	json_object *event_context_data_ir =
940 		get_event_context_n_data_ir(event_ir, ctx_instance);
941 	if (event_context_data_ir == NULL) {
942 		return 0;
943 	}
944 
945 	EFI_NVIDIA_GPU_CTX_RECOMMENDED_ACTIONS actions = { 0 };
946 
947 	actions.Flags = json_object_get_int64(
948 		json_object_object_get(event_context_data_ir, "flags"));
949 	actions.RecoveryAction = json_object_get_int64(json_object_object_get(
950 		event_context_data_ir, "recoveryAction"));
951 	actions.DiagnosticFlow = json_object_get_int64(json_object_object_get(
952 		event_context_data_ir, "diagnosticFlow"));
953 
954 	return fwrite(&actions, 1,
955 		      sizeof(EFI_NVIDIA_GPU_CTX_RECOMMENDED_ACTIONS),
956 		      output_file_stream);
957 }
958 
959 // Parses event context data type 0: Opaque data.
960 // Extracts the opaque data from the context data.
961 /*
962  * Example JSON IR "data" output:
963  * {
964  *   "data": "deadbeefcafebabe..."
965  * }
966  */
parse_common_ctx_type0_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,size_t total_event_size,size_t ctx_instance,json_object * output_data_ir)967 static void parse_common_ctx_type0_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
968 					 size_t total_event_size,
969 					 size_t ctx_instance,
970 					 json_object *output_data_ir)
971 {
972 	// Get the nth context
973 	EFI_NVIDIA_EVENT_CTX_HEADER *ctx = get_event_context_n(
974 		event_header, ctx_instance, total_event_size);
975 	if (ctx == NULL) {
976 		cper_print_log(
977 			"Error: Failed to get context %zu for opaque data\n",
978 			ctx_instance);
979 		return;
980 	}
981 
982 	// Verify the context doesn't extend past the event boundary
983 	UINT8 *ctx_start = (UINT8 *)ctx;
984 	UINT8 *event_start = (UINT8 *)event_header;
985 	size_t ctx_offset = ctx_start - event_start;
986 	size_t ctx_total_size =
987 		sizeof(EFI_NVIDIA_EVENT_CTX_HEADER) + ctx->DataSize;
988 
989 	if (ctx_offset + ctx_total_size > total_event_size) {
990 		cper_print_log(
991 			"Error: Opaque context %zu extends past event boundary\n",
992 			ctx_instance);
993 		return;
994 	}
995 
996 	// The opaque data starts right after the context header
997 	UINT8 *opaque_data = (UINT8 *)ctx + sizeof(EFI_NVIDIA_EVENT_CTX_HEADER);
998 	UINT32 data_size = ctx->DataSize;
999 
1000 	// Add the hex-encoded opaque data to JSON output
1001 	add_bytes_hex(output_data_ir, "data", opaque_data, data_size);
1002 }
1003 // Converts opaque context data from JSON IR to binary.
1004 // Returns the number of bytes written.
1005 /*
1006  * ┌─────────────────────────────────────────────────────────────────────────┐
1007  * │ OPAQUE DATA (Context Data Type 0x0000)                 (variable bytes) │
1008  * ├─────────────────────────────────────────────────────────────────────────┤
1009  * │   UINT8   Data[]               ← Device-specific binary data            │
1010  * └─────────────────────────────────────────────────────────────────────────┘
1011  */
parse_common_ctx_type0_to_bin(json_object * event_ir,size_t ctx_instance,FILE * output_file_stream)1012 static size_t parse_common_ctx_type0_to_bin(json_object *event_ir,
1013 					    size_t ctx_instance,
1014 					    FILE *output_file_stream)
1015 {
1016 	// Get the context data using the helper function
1017 	json_object *event_context_data_ir =
1018 		get_event_context_n_data_ir(event_ir, ctx_instance);
1019 
1020 	if (event_context_data_ir == NULL) {
1021 		cper_print_log(
1022 			"Error: Failed to get context %zu data for opaque conversion\n",
1023 			ctx_instance);
1024 		return 0;
1025 	}
1026 
1027 	// Decode the hex data from the "data" field
1028 	size_t decoded_len = 0;
1029 	UINT8 *decoded =
1030 		get_bytes_hex(event_context_data_ir, "data", &decoded_len);
1031 	if (decoded == NULL) {
1032 		cper_print_log("Error: hex decode of opaque data failed\n");
1033 		return 0;
1034 	}
1035 
1036 	// Write the decoded binary data to the output stream
1037 	size_t bytes_written =
1038 		fwrite(decoded, 1, decoded_len, output_file_stream);
1039 	free(decoded);
1040 
1041 	return bytes_written;
1042 }
1043 // Parses event context data type 1: 64-bit key/value pairs.
1044 // Extracts an array of UINT64 key-value pairs from the context data.
1045 /*
1046  * Example JSON IR "data" output:
1047  * {
1048  *   "keyValArray64": [
1049  *     { "key64": 1234567890123456789, "val64": 9876543210987654321 },
1050  *     { "key64": 5555555555555555555, "val64": 1111111111111111111 }
1051  *   ]
1052  * }
1053  */
parse_common_ctx_type1_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,size_t total_event_size,size_t ctx_instance,json_object * output_data_ir)1054 static void parse_common_ctx_type1_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
1055 					 size_t total_event_size,
1056 					 size_t ctx_instance,
1057 					 json_object *output_data_ir)
1058 {
1059 	EFI_NVIDIA_EVENT_CTX_HEADER *ctx = get_event_context_n(
1060 		event_header, ctx_instance, total_event_size);
1061 	if (ctx == NULL) {
1062 		return;
1063 	}
1064 
1065 	// Verify the context data doesn't extend past the event boundary
1066 	UINT8 *event_end = (UINT8 *)event_header + total_event_size;
1067 	UINT8 *data_end = (UINT8 *)ctx->Data + ctx->DataSize;
1068 	if (data_end > event_end) {
1069 		cper_print_log(
1070 			"Error: Type 1 context %zu extends past event boundary\n",
1071 			ctx_instance);
1072 		return;
1073 	}
1074 
1075 	EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1 *data_type1 =
1076 		(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1 *)ctx->Data;
1077 	UINT8 num_elements =
1078 		ctx->DataSize / sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1);
1079 
1080 	json_object *kv64arr = json_object_new_array();
1081 	for (int i = 0; i < num_elements; i++, data_type1++) {
1082 		json_object *kv = NULL;
1083 		kv = json_object_new_object();
1084 		json_object_object_add(kv, "key64",
1085 				       json_object_new_uint64(data_type1->Key));
1086 		json_object_object_add(
1087 			kv, "val64", json_object_new_uint64(data_type1->Value));
1088 
1089 		json_object_array_add(kv64arr, kv);
1090 	}
1091 	json_object_object_add(output_data_ir, "keyValArray64", kv64arr);
1092 }
1093 // Converts event context data type 1 from JSON IR to CPER binary format.
1094 // Writes an array of 64-bit key/value pairs to the output stream.
1095 // Returns the total number of bytes written.
1096 /*
1097  * ┌─────────────────────────────────────────────────────────────────────────┐
1098  * │ EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1 (Context Data Type 0x0001) (16 bytes)  │
1099  * ├─────────────────────────────────────────────────────────────────────────┤
1100  * │   UINT64  Key                  ← 64-bit key                             │
1101  * │   UINT64  Value                ← 64-bit value                           │
1102  * └─────────────────────────────────────────────────────────────────────────┘
1103  * Note: This structure repeats for each key-value pair in the array
1104  */
parse_common_ctx_type1_to_bin(json_object * event_ir,size_t ctx_instance,FILE * output_file_stream)1105 static size_t parse_common_ctx_type1_to_bin(json_object *event_ir,
1106 					    size_t ctx_instance,
1107 					    FILE *output_file_stream)
1108 {
1109 	json_object *event_context_data_ir =
1110 		get_event_context_n_data_ir(event_ir, ctx_instance);
1111 	if (event_context_data_ir == NULL) {
1112 		return 0;
1113 	}
1114 
1115 	// Get the kv64-array that was created by parse_common_ctx_type1_to_ir
1116 	json_object *kv64arr =
1117 		json_object_object_get(event_context_data_ir, "keyValArray64");
1118 	if (kv64arr == NULL) {
1119 		return 0;
1120 	}
1121 
1122 	size_t array_len = json_object_array_length(kv64arr);
1123 	size_t bytes_written = 0;
1124 
1125 	// Iterate through each key-value pair in the array
1126 	for (size_t i = 0; i < array_len; i++) {
1127 		json_object *kv = json_object_array_get_idx(kv64arr, i);
1128 		if (kv == NULL) {
1129 			continue;
1130 		}
1131 
1132 		// Create and populate the binary structure
1133 		EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1 data_type1 = { 0 };
1134 		data_type1.Key = json_object_get_uint64(
1135 			json_object_object_get(kv, "key64"));
1136 		data_type1.Value = json_object_get_uint64(
1137 			json_object_object_get(kv, "val64"));
1138 
1139 		// Write to binary file
1140 		bytes_written +=
1141 			fwrite(&data_type1, 1,
1142 			       sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1),
1143 			       output_file_stream);
1144 	}
1145 	return bytes_written;
1146 }
1147 // Parses event context data type 2: 32-bit key/value pairs.
1148 // Extracts an array of UINT32 key-value pairs from the context data.
1149 /*
1150  * Example JSON IR "data" output:
1151  * {
1152  *   "keyValArray32": [
1153  *     { "key32": 123456789, "val32": 987654321 },
1154  *     { "key32": 555555555, "val32": 111111111 }
1155  *   ]
1156  * }
1157  */
parse_common_ctx_type2_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,size_t total_event_size,size_t ctx_instance,json_object * output_data_ir)1158 static void parse_common_ctx_type2_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
1159 					 size_t total_event_size,
1160 					 size_t ctx_instance,
1161 					 json_object *output_data_ir)
1162 {
1163 	EFI_NVIDIA_EVENT_CTX_HEADER *ctx = get_event_context_n(
1164 		event_header, ctx_instance, total_event_size);
1165 	if (ctx == NULL) {
1166 		return;
1167 	}
1168 
1169 	// Verify the context data doesn't extend past the event boundary
1170 	UINT8 *event_end = (UINT8 *)event_header + total_event_size;
1171 	UINT8 *data_end = (UINT8 *)ctx->Data + ctx->DataSize;
1172 	if (data_end > event_end) {
1173 		cper_print_log(
1174 			"Error: Type 2 context %zu extends past event boundary\n",
1175 			ctx_instance);
1176 		return;
1177 	}
1178 
1179 	EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2 *data_type2 =
1180 		(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2 *)ctx->Data;
1181 	UINT8 num_elements =
1182 		ctx->DataSize / sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2);
1183 
1184 	json_object *kv32arr = json_object_new_array();
1185 	for (int i = 0; i < num_elements; i++, data_type2++) {
1186 		json_object *kv = NULL;
1187 		kv = json_object_new_object();
1188 		json_object_object_add(kv, "key32",
1189 				       json_object_new_uint64(data_type2->Key));
1190 		json_object_object_add(
1191 			kv, "val32", json_object_new_uint64(data_type2->Value));
1192 
1193 		json_object_array_add(kv32arr, kv);
1194 	}
1195 	json_object_object_add(output_data_ir, "keyValArray32", kv32arr);
1196 }
1197 // Converts event context data type 2 from JSON IR to CPER binary format.
1198 // Writes an array of 32-bit key/value pairs to the output stream.
1199 // Returns the total number of bytes written.
1200 /*
1201  * ┌─────────────────────────────────────────────────────────────────────────┐
1202  * │ EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2 (Context Data Type 0x0002)  (8 bytes)  │
1203  * ├─────────────────────────────────────────────────────────────────────────┤
1204  * │   UINT32  Key                  ← 32-bit key                             │
1205  * │   UINT32  Value                ← 32-bit value                           │
1206  * └─────────────────────────────────────────────────────────────────────────┘
1207  * Note: This structure repeats for each key-value pair in the array
1208  */
parse_common_ctx_type2_to_bin(json_object * event_ir,size_t ctx_instance,FILE * output_file_stream)1209 static size_t parse_common_ctx_type2_to_bin(json_object *event_ir,
1210 					    size_t ctx_instance,
1211 					    FILE *output_file_stream)
1212 {
1213 	json_object *event_context_data_ir =
1214 		get_event_context_n_data_ir(event_ir, ctx_instance);
1215 	if (event_context_data_ir == NULL) {
1216 		return 0;
1217 	}
1218 
1219 	// Get the kv32-array that was created by parse_common_ctx_type2_to_ir
1220 	json_object *kv32arr =
1221 		json_object_object_get(event_context_data_ir, "keyValArray32");
1222 	if (kv32arr == NULL) {
1223 		return 0;
1224 	}
1225 
1226 	size_t array_len = json_object_array_length(kv32arr);
1227 	size_t bytes_written = 0;
1228 
1229 	// Iterate through each key-value pair in the array
1230 	for (size_t i = 0; i < array_len; i++) {
1231 		json_object *kv = json_object_array_get_idx(kv32arr, i);
1232 		if (kv == NULL) {
1233 			continue;
1234 		}
1235 
1236 		// Create and populate the binary structure
1237 		EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2 data_type2 = { 0 };
1238 		data_type2.Key = json_object_get_uint64(
1239 			json_object_object_get(kv, "key32"));
1240 		data_type2.Value = json_object_get_uint64(
1241 			json_object_object_get(kv, "val32"));
1242 
1243 		// Write to binary file
1244 		bytes_written +=
1245 			fwrite(&data_type2, 1,
1246 			       sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2),
1247 			       output_file_stream);
1248 	}
1249 	return bytes_written;
1250 }
1251 // Parses event context data type 3: 64-bit values only.
1252 // Extracts an array of UINT64 values (no keys) from the context data.
1253 /*
1254  * Example JSON IR "data" output:
1255  * {
1256  *   "valArray64": [
1257  *     { "val64": 1234567890123456789 },
1258  *     { "val64": 9876543210987654321 }
1259  *   ]
1260  * }
1261  */
parse_common_ctx_type3_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,size_t total_event_size,size_t ctx_instance,json_object * output_data_ir)1262 static void parse_common_ctx_type3_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
1263 					 size_t total_event_size,
1264 					 size_t ctx_instance,
1265 					 json_object *output_data_ir)
1266 {
1267 	EFI_NVIDIA_EVENT_CTX_HEADER *ctx = get_event_context_n(
1268 		event_header, ctx_instance, total_event_size);
1269 	if (ctx == NULL) {
1270 		return;
1271 	}
1272 
1273 	// Verify the context data doesn't extend past the event boundary
1274 	UINT8 *event_end = (UINT8 *)event_header + total_event_size;
1275 	UINT8 *data_end = (UINT8 *)ctx->Data + ctx->DataSize;
1276 	if (data_end > event_end) {
1277 		cper_print_log(
1278 			"Error: Type 3 context %zu extends past event boundary\n",
1279 			ctx_instance);
1280 		return;
1281 	}
1282 
1283 	EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3 *data_type3 =
1284 		(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3 *)ctx->Data;
1285 	UINT8 num_elements =
1286 		ctx->DataSize / sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3);
1287 
1288 	json_object *val64arr = json_object_new_array();
1289 	for (int i = 0; i < num_elements; i++, data_type3++) {
1290 		json_object *v = NULL;
1291 		v = json_object_new_object();
1292 		json_object_object_add(
1293 			v, "val64", json_object_new_uint64(data_type3->Value));
1294 
1295 		json_object_array_add(val64arr, v);
1296 	}
1297 	json_object_object_add(output_data_ir, "valArray64", val64arr);
1298 }
1299 // Converts event context data type 3 from JSON IR to CPER binary format.
1300 // Writes an array of 64-bit values (no keys) to the output stream.
1301 // Returns the total number of bytes written.
1302 /*
1303  * ┌─────────────────────────────────────────────────────────────────────────┐
1304  * │ EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3 (Context Data Type 0x0003)  (8 bytes)  │
1305  * ├─────────────────────────────────────────────────────────────────────────┤
1306  * │   UINT64  Value                ← 64-bit value (no key)                  │
1307  * └─────────────────────────────────────────────────────────────────────────┘
1308  * Note: This structure repeats for each value in the array
1309  */
parse_common_ctx_type3_to_bin(json_object * event_ir,size_t ctx_instance,FILE * output_file_stream)1310 static size_t parse_common_ctx_type3_to_bin(json_object *event_ir,
1311 					    size_t ctx_instance,
1312 					    FILE *output_file_stream)
1313 {
1314 	json_object *event_context_data_ir =
1315 		get_event_context_n_data_ir(event_ir, ctx_instance);
1316 	if (event_context_data_ir == NULL) {
1317 		return 0;
1318 	}
1319 
1320 	// Get the v64-array that was created by parse_common_ctx_type3_to_ir
1321 	json_object *v64arr =
1322 		json_object_object_get(event_context_data_ir, "valArray64");
1323 	if (v64arr == NULL) {
1324 		return 0;
1325 	}
1326 
1327 	size_t array_len = json_object_array_length(v64arr);
1328 	size_t bytes_written = 0;
1329 
1330 	// Iterate through each key-value pair in the array
1331 	for (size_t i = 0; i < array_len; i++) {
1332 		json_object *v = json_object_array_get_idx(v64arr, i);
1333 		if (v == NULL) {
1334 			continue;
1335 		}
1336 
1337 		// Create and populate the binary structure
1338 		EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3 data_type3 = { 0 };
1339 		data_type3.Value = json_object_get_uint64(
1340 			json_object_object_get(v, "val64"));
1341 
1342 		// Write to binary file
1343 		bytes_written +=
1344 			fwrite(&data_type3, 1,
1345 			       sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3),
1346 			       output_file_stream);
1347 	}
1348 	return bytes_written;
1349 }
1350 // Parses event context data type 4: 32-bit values only.
1351 // Extracts an array of UINT32 values (no keys) from the context data.
1352 /*
1353  * Example JSON IR "data" output:
1354  * {
1355  *   "valArray32": [
1356  *     { "val32": 123456789 },
1357  *     { "val32": 987654321 }
1358  *   ]
1359  * }
1360  */
parse_common_ctx_type4_to_ir(EFI_NVIDIA_EVENT_HEADER * event_header,size_t total_event_size,size_t ctx_instance,json_object * output_data_ir)1361 static void parse_common_ctx_type4_to_ir(EFI_NVIDIA_EVENT_HEADER *event_header,
1362 					 size_t total_event_size,
1363 					 size_t ctx_instance,
1364 					 json_object *output_data_ir)
1365 {
1366 	EFI_NVIDIA_EVENT_CTX_HEADER *ctx = get_event_context_n(
1367 		event_header, ctx_instance, total_event_size);
1368 	if (ctx == NULL) {
1369 		return;
1370 	}
1371 
1372 	// Verify the context data doesn't extend past the event boundary
1373 	UINT8 *event_end = (UINT8 *)event_header + total_event_size;
1374 	UINT8 *data_end = (UINT8 *)ctx->Data + ctx->DataSize;
1375 	if (data_end > event_end) {
1376 		cper_print_log(
1377 			"Error: Type 4 context %zu extends past event boundary\n",
1378 			ctx_instance);
1379 		return;
1380 	}
1381 
1382 	EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4 *data_type4 =
1383 		(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4 *)ctx->Data;
1384 	UINT8 num_elements =
1385 		ctx->DataSize / sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4);
1386 
1387 	json_object *val32arr = json_object_new_array();
1388 	for (int i = 0; i < num_elements; i++, data_type4++) {
1389 		json_object *v = NULL;
1390 		v = json_object_new_object();
1391 		json_object_object_add(
1392 			v, "val32", json_object_new_uint64(data_type4->Value));
1393 
1394 		json_object_array_add(val32arr, v);
1395 	}
1396 	json_object_object_add(output_data_ir, "valArray32", val32arr);
1397 }
1398 // Converts event context data type 4 from JSON IR to CPER binary format.
1399 // Writes an array of 32-bit values (no keys) to the output stream.
1400 // Returns the total number of bytes written.
1401 /*
1402  * ┌─────────────────────────────────────────────────────────────────────────┐
1403  * │ EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4 (Context Data Type 0x0004)  (4 bytes)  │
1404  * ├─────────────────────────────────────────────────────────────────────────┤
1405  * │   UINT32  Value                ← 32-bit value (no key)                  │
1406  * └─────────────────────────────────────────────────────────────────────────┘
1407  * Note: This structure repeats for each value in the array
1408  */
parse_common_ctx_type4_to_bin(json_object * event_ir,size_t ctx_instance,FILE * output_file_stream)1409 static size_t parse_common_ctx_type4_to_bin(json_object *event_ir,
1410 					    size_t ctx_instance,
1411 					    FILE *output_file_stream)
1412 {
1413 	json_object *event_context_data_ir =
1414 		get_event_context_n_data_ir(event_ir, ctx_instance);
1415 	if (event_context_data_ir == NULL) {
1416 		return 0;
1417 	}
1418 
1419 	// Get the v32-array that was created by parse_common_ctx_type4_to_ir
1420 	json_object *v32arr =
1421 		json_object_object_get(event_context_data_ir, "valArray32");
1422 	if (v32arr == NULL) {
1423 		return 0;
1424 	}
1425 
1426 	size_t array_len = json_object_array_length(v32arr);
1427 	size_t bytes_written = 0;
1428 
1429 	// Iterate through each key-value pair in the array
1430 	for (size_t i = 0; i < array_len; i++) {
1431 		json_object *v = json_object_array_get_idx(v32arr, i);
1432 		if (v == NULL) {
1433 			continue;
1434 		}
1435 
1436 		// Create and populate the binary structure
1437 		EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4 data_type4 = { 0 };
1438 		data_type4.Value = json_object_get_uint64(
1439 			json_object_object_get(v, "val32"));
1440 
1441 		// Write to binary file
1442 		bytes_written +=
1443 			fwrite(&data_type4, 1,
1444 			       sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4),
1445 			       output_file_stream);
1446 	}
1447 	return bytes_written;
1448 }
1449 // Converts a single NVIDIA event-based CPER section into JSON IR format.
1450 // Parses the event header, device-specific event info, and all event contexts.
1451 // Supports custom handlers for specific device types and data formats.
1452 /*
1453  * Example JSON IR output for a CPU device with Type 1 context:
1454  * {
1455  *   "eventHeader": {
1456  *     "signature": "CPU-FAULT",
1457  *     "version": 1,
1458  *     "sourceDeviceType": 0,
1459  *     "type": 100,
1460  *     "subtype": 200,
1461  *     "linkId": 0
1462  *   },
1463  *   "eventInfo": {
1464  *     "version": 0,
1465  *     "SocketNum": 0,
1466  *     "Architecture": 2684420096,
1467  *     "Ecid1": 1234567890123456789,
1468  *     "Ecid2": 9876543210987654321,
1469  *     "Ecid3": 5555555555555555555,
1470  *     "Ecid4": 1111111111111111111,
1471  *     "InstanceBase": 281474976710656
1472  *   },
1473  *   "eventContexts": {
1474  *     "eventContext0": {
1475  *       "version": 0,
1476  *       "dataFormatType": 1,
1477  *       "dataFormatVersion": 0,
1478  *       "dataSize": 32,
1479  *       "data": {
1480  *         "keyValArray64": [
1481  *           { "key64": 1234567890123456789, "val64": 9876543210987654321 }
1482  *         ]
1483  *       }
1484  *     }
1485  *   }
1486  * }
1487  */
cper_section_nvidia_events_to_ir(const UINT8 * section,UINT32 size,char ** desc_string)1488 json_object *cper_section_nvidia_events_to_ir(const UINT8 *section, UINT32 size,
1489 					      char **desc_string)
1490 {
1491 	EFI_NVIDIA_EVENT_HEADER *event_header =
1492 		(EFI_NVIDIA_EVENT_HEADER *)section;
1493 	// Check event header version compatibility
1494 	if (!check_event_header_version(event_header->EventVersion,
1495 					EFI_NVIDIA_EVENT_HEADER_VERSION,
1496 					"parsing")) {
1497 		return NULL;
1498 	}
1499 
1500 	json_object *event_ir = json_object_new_object();
1501 
1502 	// Parse event header fields
1503 	json_object *event_header_ir = json_object_new_object();
1504 	json_object_object_add(event_ir, "eventHeader", event_header_ir);
1505 	*desc_string = malloc(SECTION_DESC_STRING_SIZE);
1506 	if (*desc_string == NULL) {
1507 		cper_print_log(
1508 			"Error: Failed to allocate memory for description string\n");
1509 		json_object_put(event_ir);
1510 		return NULL;
1511 	}
1512 	int outstr_len = 0;
1513 	const char *signature = event_header->Signature;
1514 	int sig_len = cper_printable_string_length(
1515 		event_header->Signature, sizeof(event_header->Signature));
1516 	if (sig_len <= 0) {
1517 		signature = "";
1518 		sig_len = 0;
1519 	}
1520 	outstr_len = snprintf(*desc_string, SECTION_DESC_STRING_SIZE,
1521 			      "A %.*s Nvidia Event occurred", sig_len,
1522 			      signature);
1523 	if (outstr_len < 0) {
1524 		cper_print_log(
1525 			"Error: Could not write to description string\n");
1526 	} else if (outstr_len > SECTION_DESC_STRING_SIZE) {
1527 		cper_print_log("Error: Description string truncated: %s\n",
1528 			       *desc_string);
1529 	}
1530 	add_untrusted_string(event_header_ir, "signature", signature, 16);
1531 	json_object_object_add(
1532 		event_header_ir, "version",
1533 		json_object_new_int64(event_header->EventVersion));
1534 	static const char *sourceDeviceType[2] = { "CPU", "GPU" };
1535 	add_dict(event_header_ir, "sourceDeviceType",
1536 		 event_header->SourceDeviceType, sourceDeviceType,
1537 		 sizeof(sourceDeviceType) / sizeof(sourceDeviceType[0]));
1538 	json_object_object_add(event_header_ir, "type",
1539 			       json_object_new_int64(event_header->EventType));
1540 	json_object_object_add(
1541 		event_header_ir, "subtype",
1542 		json_object_new_int64(event_header->EventSubtype));
1543 	if (event_header->EventLinkId != 0) {
1544 		json_object_object_add(
1545 			event_header_ir, "linkId",
1546 			json_object_new_uint64(event_header->EventLinkId));
1547 	}
1548 
1549 	// Parse event info structure
1550 	EFI_NVIDIA_EVENT_INFO_HEADER *event_info_header =
1551 		get_event_info_header(event_header);
1552 	json_object *event_info_ir = json_object_new_object();
1553 	json_object_object_add(event_ir, "eventInfo", event_info_ir);
1554 	json_object_object_add(
1555 		event_info_ir, "version",
1556 		json_object_new_int64(event_info_header->InfoVersion));
1557 
1558 	// Extract major and minor version from event info header
1559 	UINT8 info_minor = get_info_minor_version(event_info_header);
1560 	UINT8 info_major = get_info_major_version(event_info_header);
1561 
1562 	// Call device-specific handler to parse additional event info fields
1563 	for (size_t i = 0;
1564 	     i < sizeof(nv_event_types) / sizeof(nv_event_types[0]); i++) {
1565 		if ((NVIDIA_EVENT_SRC_DEV)event_header->SourceDeviceType ==
1566 		    nv_event_types[i].srcDev) {
1567 			// Check version compatibility
1568 			if (!check_info_major_version(
1569 				    info_major, info_minor,
1570 				    nv_event_types[i].major_version,
1571 				    "parsing")) {
1572 				break;
1573 			}
1574 			nv_event_types[i].callback(event_header, event_info_ir);
1575 			break;
1576 		}
1577 	}
1578 	// Parse all event contexts into an array
1579 	json_object *event_contexts_ir = json_object_new_array();
1580 	json_object_object_add(event_ir, "eventContexts", event_contexts_ir);
1581 
1582 	for (size_t i = 0; i < (size_t)event_header->EventContextCount; i++) {
1583 		EFI_NVIDIA_EVENT_CTX_HEADER *ctx =
1584 			get_event_context_n(event_header, i, size);
1585 		if (ctx == NULL) {
1586 			continue;
1587 		}
1588 		// Parse common context header fields
1589 		json_object *event_context_ir = json_object_new_object();
1590 		// Add context to array
1591 		json_object_array_add(event_contexts_ir, event_context_ir);
1592 		json_object_object_add(event_context_ir, "version",
1593 				       json_object_new_int64(ctx->CtxVersion));
1594 		json_object_object_add(
1595 			event_context_ir, "dataFormatType",
1596 			json_object_new_int64(ctx->DataFormatType));
1597 		json_object_object_add(
1598 			event_context_ir, "dataFormatVersion",
1599 			json_object_new_int64(ctx->DataFormatVersion));
1600 		json_object_object_add(event_context_ir, "dataSize",
1601 				       json_object_new_int64(ctx->DataSize));
1602 		json_object *data_ir = json_object_new_object();
1603 		json_object_object_add(event_context_ir, "data", data_ir);
1604 		// Check for device/format-specific custom handler
1605 		bool handler_override_found = false;
1606 		for (size_t handler_idx = 0;
1607 		     handler_idx <
1608 		     sizeof(event_ctx_handlers) / sizeof(event_ctx_handlers[0]);
1609 		     handler_idx++) {
1610 			if (event_ctx_handlers[handler_idx].srcDev ==
1611 				    (NVIDIA_EVENT_SRC_DEV)
1612 					    event_header->SourceDeviceType &&
1613 			    event_ctx_handlers[handler_idx].dataFormatType ==
1614 				    ctx->DataFormatType) {
1615 				if (event_ctx_handlers[handler_idx].callback !=
1616 				    NULL) {
1617 					event_ctx_handlers[handler_idx].callback(
1618 						event_header, size, i, data_ir);
1619 					handler_override_found = true;
1620 					break;
1621 				}
1622 			}
1623 		}
1624 		if (handler_override_found) {
1625 			continue;
1626 		}
1627 		// Use default parser based on data format type
1628 		switch (ctx->DataFormatType) {
1629 		case TYPE_1:
1630 			parse_common_ctx_type1_to_ir(event_header, size, i,
1631 						     data_ir);
1632 			break;
1633 		case TYPE_2:
1634 			parse_common_ctx_type2_to_ir(event_header, size, i,
1635 						     data_ir);
1636 			break;
1637 		case TYPE_3:
1638 			parse_common_ctx_type3_to_ir(event_header, size, i,
1639 						     data_ir);
1640 			break;
1641 		case TYPE_4:
1642 			parse_common_ctx_type4_to_ir(event_header, size, i,
1643 						     data_ir);
1644 			break;
1645 		default:
1646 			parse_common_ctx_type0_to_ir(event_header, size, i,
1647 						     data_ir);
1648 			break;
1649 		}
1650 	}
1651 	return event_ir;
1652 }
1653 // Converts a single NVIDIA event JSON IR structure back into CPER binary format.
1654 // Writes the event header, device-specific event info, and all event contexts to binary.
1655 // Handles 16-byte alignment padding as required by the CPER specification.
1656 /*
1657  * Binary output structure (NVIDIA Event-based CPER):
1658  * ┌─────────────────────────────────────────────────────────────────────────┐
1659  * │ EFI_NVIDIA_EVENT_HEADER                                      (32 bytes) │
1660  * ├─────────────────────────────────────────────────────────────────────────┤
1661  * │ EFI_NVIDIA_EVENT_INFO_HEADER                                  (3 bytes) │
1662  * ├─────────────────────────────────────────────────────────────────────────┤
1663  * │ Device-Specific Event Info                              (variable size) │
1664  * │   e.g., EFI_NVIDIA_CPU_EVENT_INFO (32 bytes)                            │
1665  * │     or  EFI_NVIDIA_GPU_EVENT_INFO (16 bytes)                            │
1666  * ├─────────────────────────────────────────────────────────────────────────┤
1667  * │ PADDING (if needed)                        (align to 16-byte boundary)  │
1668  * ├─────────────────────────────────────────────────────────────────────────┤
1669  * │ EFI_NVIDIA_EVENT_CTX_HEADER (Context 0)                      (16 bytes) │
1670  * ├─────────────────────────────────────────────────────────────────────────┤
1671  * │ Context Data (Type-specific)                            (variable size) │
1672  * ├─────────────────────────────────────────────────────────────────────────┤
1673  * │ PADDING (if needed)                        (align to 16-byte boundary)  │
1674  * ├─────────────────────────────────────────────────────────────────────────┤
1675  * │ EFI_NVIDIA_EVENT_CTX_HEADER (Context N)                      (16 bytes) │
1676  * ├─────────────────────────────────────────────────────────────────────────┤
1677  * │ Context Data (Type-specific)                            (variable size) │
1678  * ├─────────────────────────────────────────────────────────────────────────┤
1679  * │ PADDING (if needed)                        (align to 16-byte boundary)  │
1680  * └─────────────────────────────────────────────────────────────────────────┘
1681  */
ir_section_nvidia_events_to_cper(json_object * section,FILE * out)1682 void ir_section_nvidia_events_to_cper(json_object *section, FILE *out)
1683 {
1684 	json_object *event_header_ir =
1685 		json_object_object_get(section, "eventHeader");
1686 	EFI_NVIDIA_EVENT_HEADER event_header = { 0 };
1687 	event_header.EventVersion = json_object_get_int64(
1688 		json_object_object_get(event_header_ir, "version"));
1689 	// Check event header version compatibility
1690 	if (!check_event_header_version(event_header.EventVersion,
1691 					EFI_NVIDIA_EVENT_HEADER_VERSION,
1692 					"generation")) {
1693 		return;
1694 	}
1695 	json_object *sourceDeviceType_obj;
1696 	if (json_object_object_get_ex(event_header_ir, "sourceDeviceType",
1697 				      &sourceDeviceType_obj)) {
1698 		json_object *raw_obj;
1699 		if (json_object_object_get_ex(sourceDeviceType_obj, "raw",
1700 					      &raw_obj)) {
1701 			event_header.SourceDeviceType =
1702 				json_object_get_uint64(raw_obj);
1703 		}
1704 	}
1705 
1706 	event_header.Reserved1 = 0;
1707 	event_header.EventType = json_object_get_int64(
1708 		json_object_object_get(event_header_ir, "type"));
1709 	event_header.EventSubtype = json_object_get_int64(
1710 		json_object_object_get(event_header_ir, "subtype"));
1711 	event_header.EventLinkId = json_object_get_uint64(
1712 		json_object_object_get(event_header_ir, "linkId"));
1713 
1714 	// Signature is optional - only copy if present
1715 	json_object *signature_obj =
1716 		json_object_object_get(event_header_ir, "signature");
1717 	if (signature_obj != NULL) {
1718 		const char *sig_str = json_object_get_string(signature_obj);
1719 		if (sig_str != NULL) {
1720 			// Copy up to 16 bytes, don't force null termination
1721 			// (signature can be exactly 16 chars with no null terminator)
1722 			size_t sig_len = strlen(sig_str);
1723 			size_t copy_len =
1724 				sig_len < sizeof(event_header.Signature) ?
1725 					sig_len :
1726 					sizeof(event_header.Signature);
1727 			memcpy(event_header.Signature, sig_str, copy_len);
1728 			// Only null-terminate if there's room
1729 			if (sig_len < sizeof(event_header.Signature)) {
1730 				event_header.Signature[sig_len] = '\0';
1731 			}
1732 		}
1733 	}
1734 
1735 	fwrite(&event_header, sizeof(EFI_NVIDIA_EVENT_HEADER), 1, out);
1736 
1737 	json_object *event_info_ir =
1738 		json_object_object_get(section, "eventInfo");
1739 	EFI_NVIDIA_EVENT_INFO_HEADER event_info_header = { 0 };
1740 	event_info_header.InfoVersion = json_object_get_int64(
1741 		json_object_object_get(event_info_ir, "version"));
1742 
1743 	NV_EVENT_INFO_CALLBACKS *nv_event_info_callback = NULL;
1744 	// Extract major and minor version from event info header
1745 	UINT8 info_minor = get_info_minor_version(&event_info_header);
1746 	UINT8 info_major = get_info_major_version(&event_info_header);
1747 	for (size_t i = 0;
1748 	     i < sizeof(nv_event_types) / sizeof(nv_event_types[0]); i++) {
1749 		NV_EVENT_INFO_CALLBACKS *callback = &nv_event_types[i];
1750 		NVIDIA_EVENT_SRC_DEV srcDev =
1751 			(NVIDIA_EVENT_SRC_DEV)event_header.SourceDeviceType;
1752 		if (srcDev != callback->srcDev) {
1753 			continue;
1754 		}
1755 		// Check version compatibility
1756 		if (!check_info_major_version(info_major, info_minor,
1757 					      callback->major_version,
1758 					      "generation")) {
1759 			break;
1760 		}
1761 		nv_event_info_callback = callback;
1762 		break;
1763 	}
1764 	if (nv_event_info_callback == NULL) {
1765 		return;
1766 	}
1767 
1768 	event_info_header.InfoSize = sizeof(EFI_NVIDIA_EVENT_INFO_HEADER) +
1769 				     nv_event_info_callback->info_size;
1770 
1771 	size_t bytes_written = fwrite(&event_info_header, 1,
1772 				      sizeof(EFI_NVIDIA_EVENT_INFO_HEADER),
1773 				      out);
1774 	// Call device-specific handler to parse additional event info fields
1775 	bytes_written +=
1776 		nv_event_info_callback->callback_bin(event_info_ir, out);
1777 
1778 	write_padding_to_16_byte_alignment(bytes_written, out);
1779 
1780 	json_object *event_contexts_ir =
1781 		json_object_object_get(section, "eventContexts");
1782 
1783 	// Check if eventContexts field exists before iterating
1784 	if (event_contexts_ir == NULL) {
1785 		cper_print_log(
1786 			"Warning: Missing eventContexts field in Nvidia Event JSON\n");
1787 		return;
1788 	}
1789 
1790 	// Determine the number of contexts based on whether it's an array or object
1791 	size_t ctx_count = 0;
1792 	bool is_array = json_object_is_type(event_contexts_ir, json_type_array);
1793 	if (is_array) {
1794 		ctx_count = json_object_array_length(event_contexts_ir);
1795 	} else if (json_object_is_type(event_contexts_ir, json_type_object)) {
1796 		// Backward compatibility with old object format
1797 		ctx_count = json_object_object_length(event_contexts_ir);
1798 	}
1799 	event_header.EventContextCount = ctx_count;
1800 
1801 	for (size_t ctx_instance = 0; ctx_instance < ctx_count;
1802 	     ctx_instance++) {
1803 		json_object *value = NULL;
1804 		if (is_array) {
1805 			value = json_object_array_get_idx(event_contexts_ir,
1806 							  ctx_instance);
1807 		} else {
1808 			// Backward compatibility: get by key name
1809 			char key[64];
1810 			snprintf(key, sizeof(key), "eventContext%zu",
1811 				 ctx_instance);
1812 			value = json_object_object_get(event_contexts_ir, key);
1813 		}
1814 		if (value == NULL) {
1815 			continue;
1816 		}
1817 
1818 		EFI_NVIDIA_EVENT_CTX_HEADER ctx = { 0 };
1819 		ctx.CtxVersion = (uint16_t)json_object_get_int64(
1820 			json_object_object_get(value, "version"));
1821 		ctx.DataFormatType = (uint16_t)json_object_get_int64(
1822 			json_object_object_get(value, "dataFormatType"));
1823 		ctx.DataFormatVersion = (uint16_t)json_object_get_int64(
1824 			json_object_object_get(value, "dataFormatVersion"));
1825 		ctx.DataSize = json_object_get_int(
1826 			json_object_object_get(value, "dataSize"));
1827 		bytes_written = fwrite(
1828 			&ctx, 1, sizeof(EFI_NVIDIA_EVENT_CTX_HEADER), out);
1829 
1830 		// Check for device/format-specific custom handler
1831 		bool handler_override_found = false;
1832 		for (size_t j = 0; j < sizeof(event_ctx_handlers) /
1833 					       sizeof(event_ctx_handlers[0]);
1834 		     j++) {
1835 			if (event_ctx_handlers[j].srcDev ==
1836 				    (NVIDIA_EVENT_SRC_DEV)
1837 					    event_header.SourceDeviceType &&
1838 			    event_ctx_handlers[j].dataFormatType ==
1839 				    ctx.DataFormatType) {
1840 				bytes_written +=
1841 					event_ctx_handlers[j].callback_bin(
1842 						section, ctx_instance, out);
1843 				handler_override_found = true;
1844 				break;
1845 			}
1846 		}
1847 		// If no handler override found, use default parser based on data format type
1848 		if (!handler_override_found) {
1849 			switch (ctx.DataFormatType) {
1850 			case TYPE_1:
1851 				bytes_written += parse_common_ctx_type1_to_bin(
1852 					section, ctx_instance, out);
1853 				break;
1854 			case TYPE_2:
1855 				bytes_written += parse_common_ctx_type2_to_bin(
1856 					section, ctx_instance, out);
1857 				break;
1858 			case TYPE_3:
1859 				bytes_written += parse_common_ctx_type3_to_bin(
1860 					section, ctx_instance, out);
1861 				break;
1862 			case TYPE_4:
1863 				bytes_written += parse_common_ctx_type4_to_bin(
1864 					section, ctx_instance, out);
1865 				break;
1866 			default:
1867 				bytes_written += parse_common_ctx_type0_to_bin(
1868 					section, ctx_instance, out);
1869 				break;
1870 			}
1871 		}
1872 		write_padding_to_16_byte_alignment(bytes_written, out);
1873 	}
1874 }
1875