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 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 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 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 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 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