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