xref: /openbmc/libcper/generator/sections/gen-section-nvidia-events.c (revision 51c1813200b42fa35d49eb0c214339ac479f090d)
1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #include <stdlib.h>
4 #include <stddef.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <libcper/BaseTypes.h>
8 #include <libcper/Cper.h>
9 #include <libcper/generator/gen-utils.h>
10 #include <libcper/generator/sections/gen-section.h>
11 #include <libcper/sections/cper-section-nvidia-events.h>
12 #include <libcper/log.h>
13 
14 // Context data format types
15 #define NVIDIA_CTX_TYPE_OPAQUE 0x0000
16 #define NVIDIA_CTX_TYPE_1      0x0001
17 #define NVIDIA_CTX_TYPE_2      0x0002
18 #define NVIDIA_CTX_TYPE_3      0x0003
19 #define NVIDIA_CTX_TYPE_4      0x0004
20 
21 static const char signatures[][16 + 1] = {
22 	"SOCHUB\0\0\0\0\0\0\0\0\0\0",	 "PCIe\0\0\0\0\0\0\0\0\0\0\0\0",
23 	"L0 RESET\0\0\0\0\0\0\0\0",	 "L1 RESET\0\0\0\0\0\0\0\0",
24 	"L2 RESET\0\0\0\0\0\0\0\0",	 "RAS-TELEMETRY\0\0\0",
25 	"MSS\0\0\0\0\0\0\0\0\0\0\0\0\0", "HUB\0\0\0\0\0\0\0\0\0\0\0\0\0",
26 	"HSM U/I ERROR\0\0\0",		 "HSM\0\0\0\0\0\0\0\0\0\0\0\0\0",
27 	"HSM_FABRIC\0\0\0\0\0\0",	 "FWERROR\0\0\0\0\0\0\0\0\0",
28 	"CCPLEXUCF\0\0\0\0\0\0\0",	 "GPU-STATUS\0\0\0\0\0\0",
29 	"GPU-CONT-GRS\0\0\0\0",
30 };
31 
32 // Helper to calculate context data size based on type
get_context_data_size(UINT16 ctx_type,UINT32 num_elements)33 static size_t get_context_data_size(UINT16 ctx_type, UINT32 num_elements)
34 {
35 	switch (ctx_type) {
36 	case NVIDIA_CTX_TYPE_OPAQUE:
37 		return num_elements; // num_elements = byte count for opaque
38 	case NVIDIA_CTX_TYPE_1:
39 		return num_elements * sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1);
40 	case NVIDIA_CTX_TYPE_2:
41 		return num_elements * sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2);
42 	case NVIDIA_CTX_TYPE_3:
43 		return num_elements * sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3);
44 	case NVIDIA_CTX_TYPE_4:
45 		return num_elements * sizeof(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4);
46 	default:
47 		return 0;
48 	}
49 }
50 
51 // Helper to fill context data based on type
fill_context_data(UINT8 * data,UINT16 ctx_type,UINT32 num_elements)52 static void fill_context_data(UINT8 *data, UINT16 ctx_type, UINT32 num_elements)
53 {
54 	switch (ctx_type) {
55 	case NVIDIA_CTX_TYPE_OPAQUE:
56 		// Fill with random bytes
57 		for (UINT32 i = 0; i < num_elements; i++) {
58 			data[i] = (UINT8)(cper_rand() & 0xFF);
59 		}
60 		break;
61 	case NVIDIA_CTX_TYPE_1: {
62 		EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1 *pairs =
63 			(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_1 *)data;
64 		for (UINT32 i = 0; i < num_elements; i++) {
65 			pairs[i].Key = ((UINT64)cper_rand() << 32) |
66 				       (UINT64)cper_rand();
67 			pairs[i].Value = ((UINT64)cper_rand() << 32) |
68 					 (UINT64)cper_rand();
69 		}
70 		break;
71 	}
72 	case NVIDIA_CTX_TYPE_2: {
73 		EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2 *pairs =
74 			(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_2 *)data;
75 		for (UINT32 i = 0; i < num_elements; i++) {
76 			pairs[i].Key = cper_rand();
77 			pairs[i].Value = cper_rand();
78 		}
79 		break;
80 	}
81 	case NVIDIA_CTX_TYPE_3: {
82 		EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3 *vals =
83 			(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_3 *)data;
84 		for (UINT32 i = 0; i < num_elements; i++) {
85 			vals[i].Value = ((UINT64)cper_rand() << 32) |
86 					(UINT64)cper_rand();
87 		}
88 		break;
89 	}
90 	case NVIDIA_CTX_TYPE_4: {
91 		EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4 *vals =
92 			(EFI_NVIDIA_EVENT_CTX_DATA_TYPE_4 *)data;
93 		for (UINT32 i = 0; i < num_elements; i++) {
94 			vals[i].Value = cper_rand();
95 		}
96 		break;
97 	}
98 	}
99 }
100 
101 // Generates a single pseudo-random NVIDIA Events error section
generate_section_nvidia_events(void ** location,GEN_VALID_BITS_TEST_TYPE validBitsType)102 size_t generate_section_nvidia_events(void **location,
103 				      GEN_VALID_BITS_TEST_TYPE validBitsType)
104 {
105 	(void)validBitsType;
106 
107 	// Select a random signature
108 	int sig_idx =
109 		cper_rand() % (sizeof(signatures) / sizeof(signatures[0]));
110 
111 	// Randomly select device type: 0 = CPU, 1 = GPU
112 	UINT32 deviceType = cper_rand() % 2;
113 
114 	// Calculate size needed
115 	size_t event_header_size = sizeof(EFI_NVIDIA_EVENT_HEADER);
116 	size_t event_info_header_size = sizeof(EFI_NVIDIA_EVENT_INFO_HEADER);
117 	size_t event_info_data_size =
118 		(deviceType == 0) ? sizeof(EFI_NVIDIA_CPU_EVENT_INFO) :
119 				    sizeof(EFI_NVIDIA_GPU_EVENT_INFO);
120 
121 	// Decide number of contexts (0-5 for variety)
122 	UINT32 contextCount = cper_rand() % 6;
123 
124 	// Generate context configurations
125 	UINT16 ctx_types[5];
126 	UINT32 ctx_num_elements[5];
127 	size_t context_data_sizes[5] = { 0 };
128 	size_t context_total_sizes[5] = { 0 }; // header + data (no padding)
129 	size_t total_context_size = 0;
130 
131 	for (UINT32 i = 0; i < contextCount; i++) {
132 		// Randomly select context type (0-4)
133 		ctx_types[i] = cper_rand() % 5;
134 
135 		// Number of elements (2-6 for structured, 16-64 bytes for opaque)
136 		if (ctx_types[i] == NVIDIA_CTX_TYPE_OPAQUE) {
137 			ctx_num_elements[i] =
138 				16 + (cper_rand() % 49); // 16-64 bytes
139 		} else {
140 			ctx_num_elements[i] =
141 				2 + (cper_rand() % 5); // 2-6 elements
142 		}
143 
144 		context_data_sizes[i] = get_context_data_size(
145 			ctx_types[i], ctx_num_elements[i]);
146 
147 		// Context size = header + data (no padding between contexts)
148 		context_total_sizes[i] = sizeof(EFI_NVIDIA_EVENT_CTX_HEADER) +
149 					 context_data_sizes[i];
150 		total_context_size += context_total_sizes[i];
151 	}
152 
153 	// Total section size
154 	size_t total_size = event_header_size + event_info_header_size +
155 			    event_info_data_size + total_context_size;
156 
157 	// Allocate section
158 	UINT8 *section = (UINT8 *)calloc(1, total_size);
159 	if (!section) {
160 		return 0;
161 	}
162 
163 	UINT8 *current = section;
164 
165 	// Fill Event Header
166 	EFI_NVIDIA_EVENT_HEADER *event_header =
167 		(EFI_NVIDIA_EVENT_HEADER *)current;
168 
169 	memcpy(event_header->Signature, signatures[sig_idx],
170 	       sizeof(event_header->Signature));
171 
172 	event_header->EventVersion = 1;
173 	event_header->EventContextCount = contextCount;
174 	event_header->SourceDeviceType = deviceType;
175 	event_header->Reserved1 = 0;
176 	event_header->EventType = cper_rand() % 256;
177 	event_header->EventSubtype = cper_rand() % 256;
178 	event_header->EventLinkId = ((UINT64)cper_rand() << 32) |
179 				    (UINT64)cper_rand();
180 
181 	current += event_header_size;
182 
183 	// Fill Event Info Header
184 	EFI_NVIDIA_EVENT_INFO_HEADER *event_info_header =
185 		(EFI_NVIDIA_EVENT_INFO_HEADER *)current;
186 
187 	if (deviceType == 0) {
188 		// CPU: version 0.0
189 		event_info_header->InfoVersion =
190 			(EFI_NVIDIA_CPU_EVENT_INFO_MAJ << 8) |
191 			EFI_NVIDIA_CPU_EVENT_INFO_MIN;
192 	} else {
193 		// GPU: version 1.0
194 		event_info_header->InfoVersion =
195 			(EFI_NVIDIA_GPU_EVENT_INFO_MAJ << 8) |
196 			EFI_NVIDIA_GPU_EVENT_INFO_MIN;
197 	}
198 	// InfoSize = header size + device-specific info size
199 	event_info_header->InfoSize =
200 		(UINT8)(event_info_header_size + event_info_data_size);
201 
202 	cper_print_log("InfoSize: %d", event_info_header->InfoSize);
203 
204 	current += event_info_header_size;
205 
206 	// Fill Event Info based on device type
207 	if (deviceType == 0) {
208 		// CPU Event Info
209 		EFI_NVIDIA_CPU_EVENT_INFO *cpu_info =
210 			(EFI_NVIDIA_CPU_EVENT_INFO *)current;
211 		cpu_info->SocketNum = cper_rand() % 8;
212 		cpu_info->Architecture = cper_rand();
213 		cpu_info->Ecid[0] = cper_rand();
214 		cpu_info->Ecid[1] = cper_rand();
215 		cpu_info->Ecid[2] = cper_rand();
216 		cpu_info->Ecid[3] = cper_rand();
217 		cpu_info->InstanceBase = ((UINT64)cper_rand() << 32) |
218 					 (UINT64)cper_rand();
219 	} else {
220 		// GPU Event Info
221 		EFI_NVIDIA_GPU_EVENT_INFO *gpu_info =
222 			(EFI_NVIDIA_GPU_EVENT_INFO *)current;
223 		gpu_info->EventOriginator = cper_rand() % 4;
224 		gpu_info->SourcePartition = cper_rand() % 16;
225 		gpu_info->SourceSubPartition = cper_rand() % 8;
226 		gpu_info->Pdi = ((UINT64)cper_rand() << 32) |
227 				(UINT64)cper_rand();
228 	}
229 
230 	current += event_info_data_size;
231 
232 	// Fill Event Contexts with various types
233 	for (UINT32 i = 0; i < contextCount; i++) {
234 		EFI_NVIDIA_EVENT_CTX_HEADER *ctx_header =
235 			(EFI_NVIDIA_EVENT_CTX_HEADER *)current;
236 
237 		// CtxSize = header + data (NOT including padding)
238 		size_t ctx_size = sizeof(EFI_NVIDIA_EVENT_CTX_HEADER) +
239 				  context_data_sizes[i];
240 
241 		ctx_header->CtxSize = (UINT32)ctx_size;
242 		ctx_header->CtxVersion = 0;
243 		ctx_header->Reserved1 = 0;
244 		ctx_header->DataFormatType = ctx_types[i];
245 		ctx_header->DataFormatVersion = 0;
246 		ctx_header->DataSize = (UINT32)context_data_sizes[i];
247 
248 		current += sizeof(EFI_NVIDIA_EVENT_CTX_HEADER);
249 
250 		// Fill context data based on type
251 		fill_context_data(current, ctx_types[i], ctx_num_elements[i]);
252 
253 		current += context_data_sizes[i];
254 	}
255 
256 	// Set return values
257 	*location = section;
258 	return total_size;
259 }
260