xref: /openbmc/libpldm/tools/pd.c (revision f363bdab8fbe50b2bbb46f48530625ffa040c618)
1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
2 /* Copyright 2025 Code Construct */
3 
4 /*
5  * `grep 'p.*l.*d.*m' /usr/share/dict/words` found 'palladium', which has
6  * element symbol Pd.
7  */
8 
9 #include <assert.h>
10 #include <err.h>
11 #include <inttypes.h>
12 #include <libpldm/firmware_update.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #define PD_PACKAGE_BUFFER (1ul * 1024ul * 1024ul)
18 
pd_print_bytes(const char * head,const void * _buf,size_t len,const char * tail)19 static void pd_print_bytes(const char *head, const void *_buf, size_t len,
20 			   const char *tail)
21 {
22 	const uint8_t *buf = _buf;
23 
24 	if (head) {
25 		printf("%s", head);
26 	}
27 
28 	while (len-- > 1) {
29 		printf("%02" PRIx8 " ", *buf++);
30 	}
31 
32 	printf("%02" PRIx8, *buf++);
33 
34 	if (tail) {
35 		printf("%s", tail);
36 	}
37 }
38 
pd_print_variable_field(const char * head,const struct variable_field * field,const char * tail)39 static void pd_print_variable_field(const char *head,
40 				    const struct variable_field *field,
41 				    const char *tail)
42 {
43 	if (head) {
44 		printf("%s", head);
45 	}
46 
47 	if (field && field->ptr) {
48 		fwrite(field->ptr, 1, field->length, stdout);
49 	}
50 
51 	if (tail) {
52 		printf("%s", tail);
53 	}
54 }
55 
pd_print_typed_string(const char * head,size_t type,const struct variable_field * string,const char * tail)56 static void pd_print_typed_string(const char *head, size_t type,
57 				  const struct variable_field *string,
58 				  const char *tail)
59 {
60 	switch (type) {
61 	case 1:
62 		pd_print_variable_field(head, string, tail);
63 		break;
64 	default:
65 		printf("Unsupported string type: %zu\n", type);
66 		break;
67 	}
68 }
69 
pd_print_descriptor(const char * head,const struct pldm_descriptor * desc,const char * tail)70 static void pd_print_descriptor(const char *head,
71 				const struct pldm_descriptor *desc,
72 				const char *tail)
73 {
74 	if (head) {
75 		printf("%s", head);
76 	}
77 
78 	assert(desc);
79 	switch (desc->descriptor_type) {
80 	case 1: {
81 		uint32_t pen;
82 
83 		memcpy(&pen, desc->descriptor_data, sizeof(pen));
84 		pen = le32toh(pen);
85 		printf("IANA PEN: %" PRIu32, pen);
86 		break;
87 	}
88 	default:
89 		printf("Unsupported descriptor type: %" PRIu16,
90 		       desc->descriptor_type);
91 		break;
92 	}
93 
94 	if (tail) {
95 		printf("%s", tail);
96 	}
97 }
98 
main(void)99 int main(void)
100 {
101 	struct pldm_package_downstream_device_id_record ddrec;
102 	struct pldm_package_component_image_information info;
103 	struct pldm_package_firmware_device_id_record fdrec;
104 	DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR02H(pin);
105 	pldm_package_header_information_pad hdr;
106 	struct pldm_package_iter iter;
107 	size_t nr_fdrecs = 0;
108 	size_t nr_ddrecs = 0;
109 	size_t nr_infos = 0;
110 	void *package;
111 	int status;
112 	size_t in;
113 	int rc;
114 
115 	status = EXIT_SUCCESS;
116 	package = calloc(PD_PACKAGE_BUFFER, 1);
117 	if (!package) {
118 		err(EXIT_FAILURE, "malloc");
119 	}
120 
121 	in = fread(package, 1, PD_PACKAGE_BUFFER, stdin);
122 	rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr,
123 						 &iter);
124 	if (rc < 0) {
125 		warnx("Failed to parse PLDM package: %s\n",
126 		      strerrorname_np(-rc));
127 		status = EXIT_FAILURE;
128 		goto cleanup_package;
129 	}
130 
131 	printf("Package header\n");
132 	pd_print_bytes("\tIdentifier: 0x [ ", hdr.package_header_identifier,
133 		       sizeof(hdr.package_header_identifier), " ]\n");
134 	printf("\tFormat revision: %" PRIu8 "\n",
135 	       hdr.package_header_format_revision);
136 	fwrite("\n", 1, 1, stdout);
137 
138 	foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc)
139 	{
140 		struct pldm_descriptor desc;
141 
142 		printf("Firmware device ID record: %zu\n", nr_fdrecs++);
143 		printf("\tDevice update option flags: %#.8" PRIx32 "\n",
144 		       fdrec.device_update_option_flags.value);
145 		pd_print_typed_string(
146 			"\tComponent image set version: ",
147 			fdrec.component_image_set_version_string_type,
148 			&fdrec.component_image_set_version_string, "\n");
149 		pd_print_bytes("\tApplicable components: 0x [ ",
150 			       fdrec.applicable_components.bitmap.ptr,
151 			       fdrec.applicable_components.bitmap.length,
152 			       " ]\n");
153 
154 		printf("\tDescriptors:\n");
155 		foreach_pldm_package_firmware_device_id_record_descriptor(
156 			iter, fdrec, desc, rc)
157 		{
158 			pd_print_descriptor("\t\t", &desc, "\n");
159 		}
160 		if (rc) {
161 			warnx("Failed parsing firmware device ID record descriptors: %s\n",
162 			      strerrorname_np(-rc));
163 			status = EXIT_FAILURE;
164 			goto cleanup_package;
165 		}
166 		fwrite("\n", 1, 1, stdout);
167 	}
168 	if (rc) {
169 		warnx("Failed parsing firmware device ID records: %s\n",
170 		      strerrorname_np(-rc));
171 		status = EXIT_FAILURE;
172 		goto cleanup_package;
173 	}
174 
175 	foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc)
176 	{
177 		struct pldm_descriptor desc;
178 
179 		printf("Downstream device ID record: %zu\n", nr_ddrecs++);
180 		printf("\tDevice update option flags: %#.4" PRIx32 "\n",
181 		       ddrec.update_option_flags.value);
182 		pd_print_typed_string(
183 			"\tSelf-contained activation min version: ",
184 			ddrec.self_contained_activation_min_version_string_type,
185 			&ddrec.self_contained_activation_min_version_string,
186 			"\n");
187 		pd_print_bytes("\tApplicable components: 0x [ ",
188 			       ddrec.applicable_components.bitmap.ptr,
189 			       ddrec.applicable_components.bitmap.length,
190 			       " ]\n");
191 		printf("\tDescriptors:\n");
192 		foreach_pldm_package_downstream_device_id_record_descriptor(
193 			iter, ddrec, desc, rc)
194 		{
195 			pd_print_descriptor("\t\t", &desc, "\n");
196 		}
197 		if (rc) {
198 			warnx("Failed parsing downstream device ID record descriptors: %s\n",
199 			      strerrorname_np(-rc));
200 			status = EXIT_FAILURE;
201 			goto cleanup_package;
202 		}
203 		fwrite("\n", 1, 1, stdout);
204 	}
205 	if (rc) {
206 		warnx("Failed parsing downstream device ID records: %s\n",
207 		      strerrorname_np(-rc));
208 		status = EXIT_FAILURE;
209 		goto cleanup_package;
210 	}
211 
212 	foreach_pldm_package_component_image_information(iter, info, rc)
213 	{
214 		printf("Component image info: %zu\n", nr_infos++);
215 		printf("\tComponent classification: %" PRIu16 "\n",
216 		       info.component_classification);
217 		printf("\tComponent identifier: %" PRIu16 "\n",
218 		       info.component_identifier);
219 		printf("\tComponent comparison stamp: %" PRIu32 "\n",
220 		       info.component_comparison_stamp);
221 		printf("\tComponent options: %#.4" PRIx16 "\n",
222 		       info.component_options.value);
223 		printf("\tRequested activation method: %#.4" PRIx16 "\n",
224 		       info.requested_component_activation_method.value);
225 		printf("\tComponent image: %p (%zu)\n",
226 		       (void *)info.component_image.ptr,
227 		       info.component_image.length);
228 		pd_print_typed_string("\tComponent version: ",
229 				      info.component_version_string_type,
230 				      &info.component_version_string, "\n");
231 		fwrite("\n", 1, 1, stdout);
232 	}
233 	if (rc) {
234 		warnx("Failed parsing component image information: %s\n",
235 		      strerrorname_np(-rc));
236 		status = EXIT_FAILURE;
237 		goto cleanup_package;
238 	}
239 
240 cleanup_package:
241 	free(package);
242 
243 	exit(status);
244 }
245