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