linux/lib/pldmfw/pldmfw.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/* Copyright (C) 2018-2019, Intel Corporation. */
   3
   4#include <asm/unaligned.h>
   5#include <linux/crc32.h>
   6#include <linux/device.h>
   7#include <linux/firmware.h>
   8#include <linux/kernel.h>
   9#include <linux/module.h>
  10#include <linux/pci.h>
  11#include <linux/pldmfw.h>
  12#include <linux/slab.h>
  13#include <linux/uuid.h>
  14
  15#include "pldmfw_private.h"
  16
  17/* Internal structure used to store details about the PLDM image file as it is
  18 * being validated and processed.
  19 */
  20struct pldmfw_priv {
  21        struct pldmfw *context;
  22        const struct firmware *fw;
  23
  24        /* current offset of firmware image */
  25        size_t offset;
  26
  27        struct list_head records;
  28        struct list_head components;
  29
  30        /* PLDM Firmware Package Header */
  31        const struct __pldm_header *header;
  32        u16 total_header_size;
  33
  34        /* length of the component bitmap */
  35        u16 component_bitmap_len;
  36        u16 bitmap_size;
  37
  38        /* Start of the component image information */
  39        u16 component_count;
  40        const u8 *component_start;
  41
  42        /* Start pf the firmware device id records */
  43        const u8 *record_start;
  44        u8 record_count;
  45
  46        /* The CRC at the end of the package header */
  47        u32 header_crc;
  48
  49        struct pldmfw_record *matching_record;
  50};
  51
  52/**
  53 * pldm_check_fw_space - Verify that the firmware image has space left
  54 * @data: pointer to private data
  55 * @offset: offset to start from
  56 * @length: length to check for
  57 *
  58 * Verify that the firmware data can hold a chunk of bytes with the specified
  59 * offset and length.
  60 *
  61 * Returns: zero on success, or -EFAULT if the image does not have enough
  62 * space left to fit the expected length.
  63 */
  64static int
  65pldm_check_fw_space(struct pldmfw_priv *data, size_t offset, size_t length)
  66{
  67        size_t expected_size = offset + length;
  68        struct device *dev = data->context->dev;
  69
  70        if (data->fw->size < expected_size) {
  71                dev_dbg(dev, "Firmware file size smaller than expected. Got %zu bytes, needed %zu bytes\n",
  72                        data->fw->size, expected_size);
  73                return -EFAULT;
  74        }
  75
  76        return 0;
  77}
  78
  79/**
  80 * pldm_move_fw_offset - Move the current firmware offset forward
  81 * @data: pointer to private data
  82 * @bytes_to_move: number of bytes to move the offset forward by
  83 *
  84 * Check that there is enough space past the current offset, and then move the
  85 * offset forward by this amount.
  86 *
  87 * Returns: zero on success, or -EFAULT if the image is too small to fit the
  88 * expected length.
  89 */
  90static int
  91pldm_move_fw_offset(struct pldmfw_priv *data, size_t bytes_to_move)
  92{
  93        int err;
  94
  95        err = pldm_check_fw_space(data, data->offset, bytes_to_move);
  96        if (err)
  97                return err;
  98
  99        data->offset += bytes_to_move;
 100
 101        return 0;
 102}
 103
 104/**
 105 * pldm_parse_header - Validate and extract details about the PLDM header
 106 * @data: pointer to private data
 107 *
 108 * Performs initial basic verification of the PLDM image, up to the first
 109 * firmware record.
 110 *
 111 * This includes the following checks and extractions
 112 *
 113 *   * Verify that the UUID at the start of the header matches the expected
 114 *     value as defined in the DSP0267 PLDM specification
 115 *   * Check that the revision is 0x01
 116 *   * Extract the total header_size and verify that the image is large enough
 117 *     to contain at least the length of this header
 118 *   * Extract the size of the component bitmap length
 119 *   * Extract a pointer to the start of the record area
 120 *
 121 * Returns: zero on success, or a negative error code on failure.
 122 */
 123static int pldm_parse_header(struct pldmfw_priv *data)
 124{
 125        const struct __pldmfw_record_area *record_area;
 126        struct device *dev = data->context->dev;
 127        const struct __pldm_header *header;
 128        size_t header_size;
 129        int err;
 130
 131        err = pldm_move_fw_offset(data, sizeof(*header));
 132        if (err)
 133                return err;
 134
 135        header = (const struct __pldm_header *)data->fw->data;
 136        data->header = header;
 137
 138        if (!uuid_equal(&header->id, &pldm_firmware_header_id)) {
 139                dev_dbg(dev, "Invalid package header identifier. Expected UUID %pUB, but got %pUB\n",
 140                        &pldm_firmware_header_id, &header->id);
 141                return -EINVAL;
 142        }
 143
 144        if (header->revision != PACKAGE_HEADER_FORMAT_REVISION) {
 145                dev_dbg(dev, "Invalid package header revision. Expected revision %u but got %u\n",
 146                        PACKAGE_HEADER_FORMAT_REVISION, header->revision);
 147                return -EOPNOTSUPP;
 148        }
 149
 150        data->total_header_size = get_unaligned_le16(&header->size);
 151        header_size = data->total_header_size - sizeof(*header);
 152
 153        err = pldm_check_fw_space(data, data->offset, header_size);
 154        if (err)
 155                return err;
 156
 157        data->component_bitmap_len =
 158                get_unaligned_le16(&header->component_bitmap_len);
 159
 160        if (data->component_bitmap_len % 8 != 0) {
 161                dev_dbg(dev, "Invalid component bitmap length. The length is %u, which is not a multiple of 8\n",
 162                        data->component_bitmap_len);
 163                return -EINVAL;
 164        }
 165
 166        data->bitmap_size = data->component_bitmap_len / 8;
 167
 168        err = pldm_move_fw_offset(data, header->version_len);
 169        if (err)
 170                return err;
 171
 172        /* extract a pointer to the record area, which just follows the main
 173         * PLDM header data.
 174         */
 175        record_area = (const struct __pldmfw_record_area *)(data->fw->data +
 176                                                         data->offset);
 177
 178        err = pldm_move_fw_offset(data, sizeof(*record_area));
 179        if (err)
 180                return err;
 181
 182        data->record_count = record_area->record_count;
 183        data->record_start = record_area->records;
 184
 185        return 0;
 186}
 187
 188/**
 189 * pldm_check_desc_tlv_len - Check that the length matches expectation
 190 * @data: pointer to image details
 191 * @type: the descriptor type
 192 * @size: the length from the descriptor header
 193 *
 194 * If the descriptor type is one of the documented descriptor types according
 195 * to the standard, verify that the provided length matches.
 196 *
 197 * If the type is not recognized or is VENDOR_DEFINED, return zero.
 198 *
 199 * Returns: zero on success, or -EINVAL if the specified size of a standard
 200 * TLV does not match the expected value defined for that TLV.
 201 */
 202static int
 203pldm_check_desc_tlv_len(struct pldmfw_priv *data, u16 type, u16 size)
 204{
 205        struct device *dev = data->context->dev;
 206        u16 expected_size;
 207
 208        switch (type) {
 209        case PLDM_DESC_ID_PCI_VENDOR_ID:
 210        case PLDM_DESC_ID_PCI_DEVICE_ID:
 211        case PLDM_DESC_ID_PCI_SUBVENDOR_ID:
 212        case PLDM_DESC_ID_PCI_SUBDEV_ID:
 213                expected_size = 2;
 214                break;
 215        case PLDM_DESC_ID_PCI_REVISION_ID:
 216                expected_size = 1;
 217                break;
 218        case PLDM_DESC_ID_PNP_VENDOR_ID:
 219                expected_size = 3;
 220                break;
 221        case PLDM_DESC_ID_IANA_ENTERPRISE_ID:
 222        case PLDM_DESC_ID_ACPI_VENDOR_ID:
 223        case PLDM_DESC_ID_PNP_PRODUCT_ID:
 224        case PLDM_DESC_ID_ACPI_PRODUCT_ID:
 225                expected_size = 4;
 226                break;
 227        case PLDM_DESC_ID_UUID:
 228                expected_size = 16;
 229                break;
 230        case PLDM_DESC_ID_VENDOR_DEFINED:
 231                return 0;
 232        default:
 233                /* Do not report an error on an unexpected TLV */
 234                dev_dbg(dev, "Found unrecognized TLV type 0x%04x\n", type);
 235                return 0;
 236        }
 237
 238        if (size != expected_size) {
 239                dev_dbg(dev, "Found TLV type 0x%04x with unexpected length. Got %u bytes, but expected %u bytes\n",
 240                        type, size, expected_size);
 241                return -EINVAL;
 242        }
 243
 244        return 0;
 245}
 246
 247/**
 248 * pldm_parse_desc_tlvs - Check and skip past a number of TLVs
 249 * @data: pointer to private data
 250 * @record: pointer to the record this TLV belongs too
 251 * @desc_count: descriptor count
 252 *
 253 * From the current offset, read and extract the descriptor TLVs, updating the
 254 * current offset each time.
 255 *
 256 * Returns: zero on success, or a negative error code on failure.
 257 */
 258static int
 259pldm_parse_desc_tlvs(struct pldmfw_priv *data, struct pldmfw_record *record, u8 desc_count)
 260{
 261        const struct __pldmfw_desc_tlv *__desc;
 262        const u8 *desc_start;
 263        u8 i;
 264
 265        desc_start = data->fw->data + data->offset;
 266
 267        pldm_for_each_desc_tlv(i, __desc, desc_start, desc_count) {
 268                struct pldmfw_desc_tlv *desc;
 269                int err;
 270                u16 type, size;
 271
 272                err = pldm_move_fw_offset(data, sizeof(*__desc));
 273                if (err)
 274                        return err;
 275
 276                type = get_unaligned_le16(&__desc->type);
 277
 278                /* According to DSP0267, this only includes the data field */
 279                size = get_unaligned_le16(&__desc->size);
 280
 281                err = pldm_check_desc_tlv_len(data, type, size);
 282                if (err)
 283                        return err;
 284
 285                /* check that we have space and move the offset forward */
 286                err = pldm_move_fw_offset(data, size);
 287                if (err)
 288                        return err;
 289
 290                desc = kzalloc(sizeof(*desc), GFP_KERNEL);
 291                if (!desc)
 292                        return -ENOMEM;
 293
 294                desc->type = type;
 295                desc->size = size;
 296                desc->data = __desc->data;
 297
 298                list_add_tail(&desc->entry, &record->descs);
 299        }
 300
 301        return 0;
 302}
 303
 304/**
 305 * pldm_parse_one_record - Verify size of one PLDM record
 306 * @data: pointer to image details
 307 * @__record: pointer to the record to check
 308 *
 309 * This function checks that the record size does not exceed either the size
 310 * of the firmware file or the total length specified in the header section.
 311 *
 312 * It also verifies that the recorded length of the start of the record
 313 * matches the size calculated by adding the static structure length, the
 314 * component bitmap length, the version string length, the length of all
 315 * descriptor TLVs, and the length of the package data.
 316 *
 317 * Returns: zero on success, or a negative error code on failure.
 318 */
 319static int
 320pldm_parse_one_record(struct pldmfw_priv *data,
 321                      const struct __pldmfw_record_info *__record)
 322{
 323        struct pldmfw_record *record;
 324        size_t measured_length;
 325        int err;
 326        const u8 *bitmap_ptr;
 327        u16 record_len;
 328        int i;
 329
 330        /* Make a copy and insert it into the record list */
 331        record = kzalloc(sizeof(*record), GFP_KERNEL);
 332        if (!record)
 333                return -ENOMEM;
 334
 335        INIT_LIST_HEAD(&record->descs);
 336        list_add_tail(&record->entry, &data->records);
 337
 338        /* Then check that we have space and move the offset */
 339        err = pldm_move_fw_offset(data, sizeof(*__record));
 340        if (err)
 341                return err;
 342
 343        record_len = get_unaligned_le16(&__record->record_len);
 344        record->package_data_len = get_unaligned_le16(&__record->package_data_len);
 345        record->version_len = __record->version_len;
 346        record->version_type = __record->version_type;
 347
 348        bitmap_ptr = data->fw->data + data->offset;
 349
 350        /* check that we have space for the component bitmap length */
 351        err = pldm_move_fw_offset(data, data->bitmap_size);
 352        if (err)
 353                return err;
 354
 355        record->component_bitmap_len = data->component_bitmap_len;
 356        record->component_bitmap = bitmap_zalloc(record->component_bitmap_len,
 357                                                 GFP_KERNEL);
 358        if (!record->component_bitmap)
 359                return -ENOMEM;
 360
 361        for (i = 0; i < data->bitmap_size; i++)
 362                bitmap_set_value8(record->component_bitmap, bitmap_ptr[i], i * 8);
 363
 364        record->version_string = data->fw->data + data->offset;
 365
 366        err = pldm_move_fw_offset(data, record->version_len);
 367        if (err)
 368                return err;
 369
 370        /* Scan through the descriptor TLVs and find the end */
 371        err = pldm_parse_desc_tlvs(data, record, __record->descriptor_count);
 372        if (err)
 373                return err;
 374
 375        record->package_data = data->fw->data + data->offset;
 376
 377        err = pldm_move_fw_offset(data, record->package_data_len);
 378        if (err)
 379                return err;
 380
 381        measured_length = data->offset - ((const u8 *)__record - data->fw->data);
 382        if (measured_length != record_len) {
 383                dev_dbg(data->context->dev, "Unexpected record length. Measured record length is %zu bytes, expected length is %u bytes\n",
 384                        measured_length, record_len);
 385                return -EFAULT;
 386        }
 387
 388        return 0;
 389}
 390
 391/**
 392 * pldm_parse_records - Locate the start of the component area
 393 * @data: pointer to private data
 394 *
 395 * Extract the record count, and loop through each record, searching for the
 396 * component area.
 397 *
 398 * Returns: zero on success, or a negative error code on failure.
 399 */
 400static int pldm_parse_records(struct pldmfw_priv *data)
 401{
 402        const struct __pldmfw_component_area *component_area;
 403        const struct __pldmfw_record_info *record;
 404        int err;
 405        u8 i;
 406
 407        pldm_for_each_record(i, record, data->record_start, data->record_count) {
 408                err = pldm_parse_one_record(data, record);
 409                if (err)
 410                        return err;
 411        }
 412
 413        /* Extract a pointer to the component area, which just follows the
 414         * PLDM device record data.
 415         */
 416        component_area = (const struct __pldmfw_component_area *)(data->fw->data + data->offset);
 417
 418        err = pldm_move_fw_offset(data, sizeof(*component_area));
 419        if (err)
 420                return err;
 421
 422        data->component_count =
 423                get_unaligned_le16(&component_area->component_image_count);
 424        data->component_start = component_area->components;
 425
 426        return 0;
 427}
 428
 429/**
 430 * pldm_parse_components - Locate the CRC header checksum
 431 * @data: pointer to private data
 432 *
 433 * Extract the component count, and find the pointer to the component area.
 434 * Scan through each component searching for the end, which should point to
 435 * the package header checksum.
 436 *
 437 * Extract the package header CRC and save it for verification.
 438 *
 439 * Returns: zero on success, or a negative error code on failure.
 440 */
 441static int pldm_parse_components(struct pldmfw_priv *data)
 442{
 443        const struct __pldmfw_component_info *__component;
 444        struct device *dev = data->context->dev;
 445        const u8 *header_crc_ptr;
 446        int err;
 447        u8 i;
 448
 449        pldm_for_each_component(i, __component, data->component_start, data->component_count) {
 450                struct pldmfw_component *component;
 451                u32 offset, size;
 452
 453                err = pldm_move_fw_offset(data, sizeof(*__component));
 454                if (err)
 455                        return err;
 456
 457                err = pldm_move_fw_offset(data, __component->version_len);
 458                if (err)
 459                        return err;
 460
 461                offset = get_unaligned_le32(&__component->location_offset);
 462                size = get_unaligned_le32(&__component->size);
 463
 464                err = pldm_check_fw_space(data, offset, size);
 465                if (err)
 466                        return err;
 467
 468                component = kzalloc(sizeof(*component), GFP_KERNEL);
 469                if (!component)
 470                        return -ENOMEM;
 471
 472                component->index = i;
 473                component->classification = get_unaligned_le16(&__component->classification);
 474                component->identifier = get_unaligned_le16(&__component->identifier);
 475                component->comparison_stamp = get_unaligned_le32(&__component->comparison_stamp);
 476                component->options = get_unaligned_le16(&__component->options);
 477                component->activation_method = get_unaligned_le16(&__component->activation_method);
 478                component->version_type = __component->version_type;
 479                component->version_len = __component->version_len;
 480                component->version_string = __component->version_string;
 481                component->component_data = data->fw->data + offset;
 482                component->component_size = size;
 483
 484                list_add_tail(&component->entry, &data->components);
 485        }
 486
 487        header_crc_ptr = data->fw->data + data->offset;
 488
 489        err = pldm_move_fw_offset(data, sizeof(data->header_crc));
 490        if (err)
 491                return err;
 492
 493        /* Make sure that we reached the expected offset */
 494        if (data->offset != data->total_header_size) {
 495                dev_dbg(dev, "Invalid firmware header size. Expected %u but got %zu\n",
 496                        data->total_header_size, data->offset);
 497                return -EFAULT;
 498        }
 499
 500        data->header_crc = get_unaligned_le32(header_crc_ptr);
 501
 502        return 0;
 503}
 504
 505/**
 506 * pldm_verify_header_crc - Verify that the CRC in the header matches
 507 * @data: pointer to private data
 508 *
 509 * Calculates the 32-bit CRC using the standard IEEE 802.3 CRC polynomial and
 510 * compares it to the value stored in the header.
 511 *
 512 * Returns: zero on success if the CRC matches, or -EBADMSG on an invalid CRC.
 513 */
 514static int pldm_verify_header_crc(struct pldmfw_priv *data)
 515{
 516        struct device *dev = data->context->dev;
 517        u32 calculated_crc;
 518        size_t length;
 519
 520        /* Calculate the 32-bit CRC of the header header contents up to but
 521         * not including the checksum. Note that the Linux crc32_le function
 522         * does not perform an expected final XOR.
 523         */
 524        length = data->offset - sizeof(data->header_crc);
 525        calculated_crc = crc32_le(~0, data->fw->data, length) ^ ~0;
 526
 527        if (calculated_crc != data->header_crc) {
 528                dev_dbg(dev, "Invalid CRC in firmware header. Got 0x%08x but expected 0x%08x\n",
 529                        calculated_crc, data->header_crc);
 530                return -EBADMSG;
 531        }
 532
 533        return 0;
 534}
 535
 536/**
 537 * pldmfw_free_priv - Free memory allocated while parsing the PLDM image
 538 * @data: pointer to the PLDM data structure
 539 *
 540 * Loops through and clears all allocated memory associated with each
 541 * allocated descriptor, record, and component.
 542 */
 543static void pldmfw_free_priv(struct pldmfw_priv *data)
 544{
 545        struct pldmfw_component *component, *c_safe;
 546        struct pldmfw_record *record, *r_safe;
 547        struct pldmfw_desc_tlv *desc, *d_safe;
 548
 549        list_for_each_entry_safe(component, c_safe, &data->components, entry) {
 550                list_del(&component->entry);
 551                kfree(component);
 552        }
 553
 554        list_for_each_entry_safe(record, r_safe, &data->records, entry) {
 555                list_for_each_entry_safe(desc, d_safe, &record->descs, entry) {
 556                        list_del(&desc->entry);
 557                        kfree(desc);
 558                }
 559
 560                if (record->component_bitmap) {
 561                        bitmap_free(record->component_bitmap);
 562                        record->component_bitmap = NULL;
 563                }
 564
 565                list_del(&record->entry);
 566                kfree(record);
 567        }
 568}
 569
 570/**
 571 * pldm_parse_image - parse and extract details from PLDM image
 572 * @data: pointer to private data
 573 *
 574 * Verify that the firmware file contains valid data for a PLDM firmware
 575 * file. Extract useful pointers and data from the firmware file and store
 576 * them in the data structure.
 577 *
 578 * The PLDM firmware file format is defined in DMTF DSP0267 1.0.0. Care
 579 * should be taken to use get_unaligned_le* when accessing data from the
 580 * pointers in data.
 581 *
 582 * Returns: zero on success, or a negative error code on failure.
 583 */
 584static int pldm_parse_image(struct pldmfw_priv *data)
 585{
 586        int err;
 587
 588        if (WARN_ON(!(data->context->dev && data->fw->data && data->fw->size)))
 589                return -EINVAL;
 590
 591        err = pldm_parse_header(data);
 592        if (err)
 593                return err;
 594
 595        err = pldm_parse_records(data);
 596        if (err)
 597                return err;
 598
 599        err = pldm_parse_components(data);
 600        if (err)
 601                return err;
 602
 603        return pldm_verify_header_crc(data);
 604}
 605
 606/* these are u32 so that we can store PCI_ANY_ID */
 607struct pldm_pci_record_id {
 608        int vendor;
 609        int device;
 610        int subsystem_vendor;
 611        int subsystem_device;
 612};
 613
 614/**
 615 * pldmfw_op_pci_match_record - Check if a PCI device matches the record
 616 * @context: PLDM fw update structure
 617 * @record: list of records extracted from the PLDM image
 618 *
 619 * Determine of the PCI device associated with this device matches the record
 620 * data provided.
 621 *
 622 * Searches the descriptor TLVs and extracts the relevant descriptor data into
 623 * a pldm_pci_record_id. This is then compared against the PCI device ID
 624 * information.
 625 *
 626 * Returns: true if the device matches the record, false otherwise.
 627 */
 628bool pldmfw_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record)
 629{
 630        struct pci_dev *pdev = to_pci_dev(context->dev);
 631        struct pldm_pci_record_id id = {
 632                .vendor = PCI_ANY_ID,
 633                .device = PCI_ANY_ID,
 634                .subsystem_vendor = PCI_ANY_ID,
 635                .subsystem_device = PCI_ANY_ID,
 636        };
 637        struct pldmfw_desc_tlv *desc;
 638
 639        list_for_each_entry(desc, &record->descs, entry) {
 640                u16 value;
 641                int *ptr;
 642
 643                switch (desc->type) {
 644                case PLDM_DESC_ID_PCI_VENDOR_ID:
 645                        ptr = &id.vendor;
 646                        break;
 647                case PLDM_DESC_ID_PCI_DEVICE_ID:
 648                        ptr = &id.device;
 649                        break;
 650                case PLDM_DESC_ID_PCI_SUBVENDOR_ID:
 651                        ptr = &id.subsystem_vendor;
 652                        break;
 653                case PLDM_DESC_ID_PCI_SUBDEV_ID:
 654                        ptr = &id.subsystem_device;
 655                        break;
 656                default:
 657                        /* Skip unrelated TLVs */
 658                        continue;
 659                }
 660
 661                value = get_unaligned_le16(desc->data);
 662                /* A value of zero for one of the descriptors is sometimes
 663                 * used when the record should ignore this field when matching
 664                 * device. For example if the record applies to any subsystem
 665                 * device or vendor.
 666                 */
 667                if (value)
 668                        *ptr = (int)value;
 669                else
 670                        *ptr = PCI_ANY_ID;
 671        }
 672
 673        if ((id.vendor == PCI_ANY_ID || id.vendor == pdev->vendor) &&
 674            (id.device == PCI_ANY_ID || id.device == pdev->device) &&
 675            (id.subsystem_vendor == PCI_ANY_ID || id.subsystem_vendor == pdev->subsystem_vendor) &&
 676            (id.subsystem_device == PCI_ANY_ID || id.subsystem_device == pdev->subsystem_device))
 677                return true;
 678        else
 679                return false;
 680}
 681EXPORT_SYMBOL(pldmfw_op_pci_match_record);
 682
 683/**
 684 * pldm_find_matching_record - Find the first matching PLDM record
 685 * @data: pointer to private data
 686 *
 687 * Search through PLDM records and find the first matching entry. It is
 688 * expected that only one entry matches.
 689 *
 690 * Store a pointer to the matching record, if found.
 691 *
 692 * Returns: zero on success, or -ENOENT if no matching record is found.
 693 */
 694static int pldm_find_matching_record(struct pldmfw_priv *data)
 695{
 696        struct pldmfw_record *record;
 697
 698        list_for_each_entry(record, &data->records, entry) {
 699                if (data->context->ops->match_record(data->context, record)) {
 700                        data->matching_record = record;
 701                        return 0;
 702                }
 703        }
 704
 705        return -ENOENT;
 706}
 707
 708/**
 709 * pldm_send_package_data - Send firmware the package data for the record
 710 * @data: pointer to private data
 711 *
 712 * Send the package data associated with the matching record to the firmware,
 713 * using the send_pkg_data operation.
 714 *
 715 * Returns: zero on success, or a negative error code on failure.
 716 */
 717static int
 718pldm_send_package_data(struct pldmfw_priv *data)
 719{
 720        struct pldmfw_record *record = data->matching_record;
 721        const struct pldmfw_ops *ops = data->context->ops;
 722
 723        return ops->send_package_data(data->context, record->package_data,
 724                                      record->package_data_len);
 725}
 726
 727/**
 728 * pldm_send_component_tables - Send component table information to firmware
 729 * @data: pointer to private data
 730 *
 731 * Loop over each component, sending the applicable components to the firmware
 732 * via the send_component_table operation.
 733 *
 734 * Returns: zero on success, or a negative error code on failure.
 735 */
 736static int
 737pldm_send_component_tables(struct pldmfw_priv *data)
 738{
 739        unsigned long *bitmap = data->matching_record->component_bitmap;
 740        struct pldmfw_component *component;
 741        int err;
 742
 743        list_for_each_entry(component, &data->components, entry) {
 744                u8 index = component->index, transfer_flag = 0;
 745
 746                /* Skip components which are not intended for this device */
 747                if (!test_bit(index, bitmap))
 748                        continue;
 749
 750                /* determine whether this is the start, middle, end, or both
 751                 * the start and end of the component tables
 752                 */
 753                if (index == find_first_bit(bitmap, data->component_bitmap_len))
 754                        transfer_flag |= PLDM_TRANSFER_FLAG_START;
 755                if (index == find_last_bit(bitmap, data->component_bitmap_len))
 756                        transfer_flag |= PLDM_TRANSFER_FLAG_END;
 757                if (!transfer_flag)
 758                        transfer_flag = PLDM_TRANSFER_FLAG_MIDDLE;
 759
 760                err = data->context->ops->send_component_table(data->context,
 761                                                               component,
 762                                                               transfer_flag);
 763                if (err)
 764                        return err;
 765        }
 766
 767        return 0;
 768}
 769
 770/**
 771 * pldm_flash_components - Program each component to device flash
 772 * @data: pointer to private data
 773 *
 774 * Loop through each component that is active for the matching device record,
 775 * and send it to the device driver for flashing.
 776 *
 777 * Returns: zero on success, or a negative error code on failure.
 778 */
 779static int pldm_flash_components(struct pldmfw_priv *data)
 780{
 781        unsigned long *bitmap = data->matching_record->component_bitmap;
 782        struct pldmfw_component *component;
 783        int err;
 784
 785        list_for_each_entry(component, &data->components, entry) {
 786                u8 index = component->index;
 787
 788                /* Skip components which are not intended for this device */
 789                if (!test_bit(index, bitmap))
 790                        continue;
 791
 792                err = data->context->ops->flash_component(data->context, component);
 793                if (err)
 794                        return err;
 795        }
 796
 797        return 0;
 798}
 799
 800/**
 801 * pldm_finalize_update - Finalize the device flash update
 802 * @data: pointer to private data
 803 *
 804 * Tell the device driver to perform any remaining logic to complete the
 805 * device update.
 806 *
 807 * Returns: zero on success, or a PLFM_FWU error indicating the reason for
 808 * failure.
 809 */
 810static int pldm_finalize_update(struct pldmfw_priv *data)
 811{
 812        if (data->context->ops->finalize_update)
 813                return data->context->ops->finalize_update(data->context);
 814
 815        return 0;
 816}
 817
 818/**
 819 * pldmfw_flash_image - Write a PLDM-formatted firmware image to the device
 820 * @context: ops and data for firmware update
 821 * @fw: firmware object pointing to the relevant firmware file to program
 822 *
 823 * Parse the data for a given firmware file, verifying that it is a valid PLDM
 824 * formatted image that matches this device.
 825 *
 826 * Extract the device record Package Data and Component Tables and send them
 827 * to the device firmware. Extract and write the flash data for each of the
 828 * components indicated in the firmware file.
 829 *
 830 * Returns: zero on success, or a negative error code on failure.
 831 */
 832int pldmfw_flash_image(struct pldmfw *context, const struct firmware *fw)
 833{
 834        struct pldmfw_priv *data;
 835        int err;
 836
 837        data = kzalloc(sizeof(*data), GFP_KERNEL);
 838        if (!data)
 839                return -ENOMEM;
 840
 841        INIT_LIST_HEAD(&data->records);
 842        INIT_LIST_HEAD(&data->components);
 843
 844        data->fw = fw;
 845        data->context = context;
 846
 847        err = pldm_parse_image(data);
 848        if (err)
 849                goto out_release_data;
 850
 851        err = pldm_find_matching_record(data);
 852        if (err)
 853                goto out_release_data;
 854
 855        err = pldm_send_package_data(data);
 856        if (err)
 857                goto out_release_data;
 858
 859        err = pldm_send_component_tables(data);
 860        if (err)
 861                goto out_release_data;
 862
 863        err = pldm_flash_components(data);
 864        if (err)
 865                goto out_release_data;
 866
 867        err = pldm_finalize_update(data);
 868
 869out_release_data:
 870        pldmfw_free_priv(data);
 871        kfree(data);
 872
 873        return err;
 874}
 875EXPORT_SYMBOL(pldmfw_flash_image);
 876
 877MODULE_AUTHOR("Jacob Keller <jacob.e.keller@intel.com>");
 878MODULE_LICENSE("GPL v2");
 879MODULE_DESCRIPTION("PLDM firmware flash update library");
 880