blob: fe63a70044db8aa5b889bfd710d3a3b56f3699af [file] [log] [blame]
/* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */
/* Copyright 2025 Code Construct */
/*
* `grep 'p.*l.*d.*m' /usr/share/dict/words` found 'palladium', which has
* element symbol Pd.
*/
#include <assert.h>
#include <err.h>
#include <inttypes.h>
#include <libpldm/firmware_update.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PD_PACKAGE_BUFFER (1ul * 1024ul * 1024ul)
static void pd_print_bytes(const char *head, const void *_buf, size_t len,
const char *tail)
{
const uint8_t *buf = _buf;
if (head) {
printf("%s", head);
}
while (len-- > 1) {
printf("%02" PRIx8 " ", *buf++);
}
printf("%02" PRIx8, *buf++);
if (tail) {
printf("%s", tail);
}
}
static void pd_print_variable_field(const char *head,
const struct variable_field *field,
const char *tail)
{
if (head) {
printf("%s", head);
}
if (field && field->ptr) {
fwrite(field->ptr, 1, field->length, stdout);
}
if (tail) {
printf("%s", tail);
}
}
static void pd_print_typed_string(const char *head, size_t type,
const struct variable_field *string,
const char *tail)
{
switch (type) {
case 1:
pd_print_variable_field(head, string, tail);
break;
default:
printf("Unsupported string type: %zu\n", type);
break;
}
}
static void pd_print_descriptor(const char *head,
const struct pldm_descriptor *desc,
const char *tail)
{
if (head) {
printf("%s", head);
}
assert(desc);
switch (desc->descriptor_type) {
case 1: {
uint32_t pen;
memcpy(&pen, desc->descriptor_data, sizeof(pen));
pen = le32toh(pen);
printf("IANA PEN: %" PRIu32, pen);
break;
}
default:
printf("Unsupported descriptor type: %" PRIu16,
desc->descriptor_type);
break;
}
if (tail) {
printf("%s", tail);
}
}
int main(void)
{
struct pldm_package_downstream_device_id_record ddrec;
struct pldm_package_component_image_information info;
struct pldm_package_firmware_device_id_record fdrec;
DEFINE_PLDM_PACKAGE_FORMAT_PIN_FR02H(pin);
pldm_package_header_information_pad hdr;
struct pldm_package_iter iter;
size_t nr_fdrecs = 0;
size_t nr_ddrecs = 0;
size_t nr_infos = 0;
void *package;
int status;
size_t in;
int rc;
status = EXIT_SUCCESS;
package = calloc(PD_PACKAGE_BUFFER, 1);
if (!package) {
err(EXIT_FAILURE, "malloc");
}
in = fread(package, 1, PD_PACKAGE_BUFFER, stdin);
rc = decode_pldm_firmware_update_package(package, in, &pin, &hdr,
&iter);
if (rc < 0) {
warnx("Failed to parse PLDM package: %s\n",
strerrorname_np(-rc));
status = EXIT_FAILURE;
goto cleanup_package;
}
printf("Package header\n");
pd_print_bytes("\tIdentifier: 0x [ ", hdr.package_header_identifier,
sizeof(hdr.package_header_identifier), " ]\n");
printf("\tFormat revision: %" PRIu8 "\n",
hdr.package_header_format_revision);
fwrite("\n", 1, 1, stdout);
foreach_pldm_package_firmware_device_id_record(iter, fdrec, rc)
{
struct pldm_descriptor desc;
printf("Firmware device ID record: %zu\n", nr_fdrecs++);
printf("\tDevice update option flags: %#.8" PRIx32 "\n",
fdrec.device_update_option_flags.value);
pd_print_typed_string(
"\tComponent image set version: ",
fdrec.component_image_set_version_string_type,
&fdrec.component_image_set_version_string, "\n");
pd_print_bytes("\tApplicable components: 0x [ ",
fdrec.applicable_components.bitmap.ptr,
fdrec.applicable_components.bitmap.length,
" ]\n");
printf("\tDescriptors:\n");
foreach_pldm_package_firmware_device_id_record_descriptor(
iter, fdrec, desc, rc)
{
pd_print_descriptor("\t\t", &desc, "\n");
}
if (rc) {
warnx("Failed parsing firmware device ID record descriptors: %s\n",
strerrorname_np(-rc));
status = EXIT_FAILURE;
goto cleanup_package;
}
fwrite("\n", 1, 1, stdout);
}
if (rc) {
warnx("Failed parsing firmware device ID records: %s\n",
strerrorname_np(-rc));
status = EXIT_FAILURE;
goto cleanup_package;
}
foreach_pldm_package_downstream_device_id_record(iter, ddrec, rc)
{
struct pldm_descriptor desc;
printf("Downstream device ID record: %zu\n", nr_ddrecs++);
printf("\tDevice update option flags: %#.4" PRIx32 "\n",
ddrec.update_option_flags.value);
pd_print_typed_string(
"\tSelf-contained activation min version: ",
ddrec.self_contained_activation_min_version_string_type,
&ddrec.self_contained_activation_min_version_string,
"\n");
pd_print_bytes("\tApplicable components: 0x [ ",
ddrec.applicable_components.bitmap.ptr,
ddrec.applicable_components.bitmap.length,
" ]\n");
printf("\tDescriptors:\n");
foreach_pldm_package_downstream_device_id_record_descriptor(
iter, ddrec, desc, rc)
{
pd_print_descriptor("\t\t", &desc, "\n");
}
if (rc) {
warnx("Failed parsing downstream device ID record descriptors: %s\n",
strerrorname_np(-rc));
status = EXIT_FAILURE;
goto cleanup_package;
}
fwrite("\n", 1, 1, stdout);
}
if (rc) {
warnx("Failed parsing downstream device ID records: %s\n",
strerrorname_np(-rc));
status = EXIT_FAILURE;
goto cleanup_package;
}
foreach_pldm_package_component_image_information(iter, info, rc)
{
printf("Component image info: %zu\n", nr_infos++);
printf("\tComponent classification: %" PRIu16 "\n",
info.component_classification);
printf("\tComponent identifier: %" PRIu16 "\n",
info.component_identifier);
printf("\tComponent comparison stamp: %" PRIu32 "\n",
info.component_comparison_stamp);
printf("\tComponent options: %#.4" PRIx16 "\n",
info.component_options.value);
printf("\tRequested activation method: %#.4" PRIx16 "\n",
info.requested_component_activation_method.value);
printf("\tComponent image: %p (%zu)\n",
(void *)info.component_image.ptr,
info.component_image.length);
pd_print_typed_string("\tComponent version: ",
info.component_version_string_type,
&info.component_version_string, "\n");
fwrite("\n", 1, 1, stdout);
}
if (rc) {
warnx("Failed parsing component image information: %s\n",
strerrorname_np(-rc));
status = EXIT_FAILURE;
goto cleanup_package;
}
cleanup_package:
free(package);
exit(status);
}