linux/lib/pldmfw/pldmfw.c

// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2018-2019, Intel Corporation. */

#include <asm/unaligned.h>
#include <linux/crc32.h>
#include <linux/device.h>
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/pldmfw.h>
#include <linux/slab.h>
#include <linux/uuid.h>

#include "pldmfw_private.h"

/* Internal structure used to store details about the PLDM image file as it is
 * being validated and processed.
 */
struct pldmfw_priv {};

/**
 * pldm_check_fw_space - Verify that the firmware image has space left
 * @data: pointer to private data
 * @offset: offset to start from
 * @length: length to check for
 *
 * Verify that the firmware data can hold a chunk of bytes with the specified
 * offset and length.
 *
 * Returns: zero on success, or -EFAULT if the image does not have enough
 * space left to fit the expected length.
 */
static int
pldm_check_fw_space(struct pldmfw_priv *data, size_t offset, size_t length)
{}

/**
 * pldm_move_fw_offset - Move the current firmware offset forward
 * @data: pointer to private data
 * @bytes_to_move: number of bytes to move the offset forward by
 *
 * Check that there is enough space past the current offset, and then move the
 * offset forward by this amount.
 *
 * Returns: zero on success, or -EFAULT if the image is too small to fit the
 * expected length.
 */
static int
pldm_move_fw_offset(struct pldmfw_priv *data, size_t bytes_to_move)
{}

/**
 * pldm_parse_header - Validate and extract details about the PLDM header
 * @data: pointer to private data
 *
 * Performs initial basic verification of the PLDM image, up to the first
 * firmware record.
 *
 * This includes the following checks and extractions
 *
 *   * Verify that the UUID at the start of the header matches the expected
 *     value as defined in the DSP0267 PLDM specification
 *   * Check that the revision is 0x01
 *   * Extract the total header_size and verify that the image is large enough
 *     to contain at least the length of this header
 *   * Extract the size of the component bitmap length
 *   * Extract a pointer to the start of the record area
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int pldm_parse_header(struct pldmfw_priv *data)
{}

/**
 * pldm_check_desc_tlv_len - Check that the length matches expectation
 * @data: pointer to image details
 * @type: the descriptor type
 * @size: the length from the descriptor header
 *
 * If the descriptor type is one of the documented descriptor types according
 * to the standard, verify that the provided length matches.
 *
 * If the type is not recognized or is VENDOR_DEFINED, return zero.
 *
 * Returns: zero on success, or -EINVAL if the specified size of a standard
 * TLV does not match the expected value defined for that TLV.
 */
static int
pldm_check_desc_tlv_len(struct pldmfw_priv *data, u16 type, u16 size)
{}

/**
 * pldm_parse_desc_tlvs - Check and skip past a number of TLVs
 * @data: pointer to private data
 * @record: pointer to the record this TLV belongs too
 * @desc_count: descriptor count
 *
 * From the current offset, read and extract the descriptor TLVs, updating the
 * current offset each time.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int
pldm_parse_desc_tlvs(struct pldmfw_priv *data, struct pldmfw_record *record, u8 desc_count)
{}

/**
 * pldm_parse_one_record - Verify size of one PLDM record
 * @data: pointer to image details
 * @__record: pointer to the record to check
 *
 * This function checks that the record size does not exceed either the size
 * of the firmware file or the total length specified in the header section.
 *
 * It also verifies that the recorded length of the start of the record
 * matches the size calculated by adding the static structure length, the
 * component bitmap length, the version string length, the length of all
 * descriptor TLVs, and the length of the package data.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int
pldm_parse_one_record(struct pldmfw_priv *data,
		      const struct __pldmfw_record_info *__record)
{}

/**
 * pldm_parse_records - Locate the start of the component area
 * @data: pointer to private data
 *
 * Extract the record count, and loop through each record, searching for the
 * component area.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int pldm_parse_records(struct pldmfw_priv *data)
{}

/**
 * pldm_parse_components - Locate the CRC header checksum
 * @data: pointer to private data
 *
 * Extract the component count, and find the pointer to the component area.
 * Scan through each component searching for the end, which should point to
 * the package header checksum.
 *
 * Extract the package header CRC and save it for verification.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int pldm_parse_components(struct pldmfw_priv *data)
{}

/**
 * pldm_verify_header_crc - Verify that the CRC in the header matches
 * @data: pointer to private data
 *
 * Calculates the 32-bit CRC using the standard IEEE 802.3 CRC polynomial and
 * compares it to the value stored in the header.
 *
 * Returns: zero on success if the CRC matches, or -EBADMSG on an invalid CRC.
 */
static int pldm_verify_header_crc(struct pldmfw_priv *data)
{}

/**
 * pldmfw_free_priv - Free memory allocated while parsing the PLDM image
 * @data: pointer to the PLDM data structure
 *
 * Loops through and clears all allocated memory associated with each
 * allocated descriptor, record, and component.
 */
static void pldmfw_free_priv(struct pldmfw_priv *data)
{}

/**
 * pldm_parse_image - parse and extract details from PLDM image
 * @data: pointer to private data
 *
 * Verify that the firmware file contains valid data for a PLDM firmware
 * file. Extract useful pointers and data from the firmware file and store
 * them in the data structure.
 *
 * The PLDM firmware file format is defined in DMTF DSP0267 1.0.0. Care
 * should be taken to use get_unaligned_le* when accessing data from the
 * pointers in data.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int pldm_parse_image(struct pldmfw_priv *data)
{}

/* these are u32 so that we can store PCI_ANY_ID */
struct pldm_pci_record_id {};

/**
 * pldmfw_op_pci_match_record - Check if a PCI device matches the record
 * @context: PLDM fw update structure
 * @record: list of records extracted from the PLDM image
 *
 * Determine of the PCI device associated with this device matches the record
 * data provided.
 *
 * Searches the descriptor TLVs and extracts the relevant descriptor data into
 * a pldm_pci_record_id. This is then compared against the PCI device ID
 * information.
 *
 * Returns: true if the device matches the record, false otherwise.
 */
bool pldmfw_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record)
{}
EXPORT_SYMBOL();

/**
 * pldm_find_matching_record - Find the first matching PLDM record
 * @data: pointer to private data
 *
 * Search through PLDM records and find the first matching entry. It is
 * expected that only one entry matches.
 *
 * Store a pointer to the matching record, if found.
 *
 * Returns: zero on success, or -ENOENT if no matching record is found.
 */
static int pldm_find_matching_record(struct pldmfw_priv *data)
{}

/**
 * pldm_send_package_data - Send firmware the package data for the record
 * @data: pointer to private data
 *
 * Send the package data associated with the matching record to the firmware,
 * using the send_pkg_data operation.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int
pldm_send_package_data(struct pldmfw_priv *data)
{}

/**
 * pldm_send_component_tables - Send component table information to firmware
 * @data: pointer to private data
 *
 * Loop over each component, sending the applicable components to the firmware
 * via the send_component_table operation.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int
pldm_send_component_tables(struct pldmfw_priv *data)
{}

/**
 * pldm_flash_components - Program each component to device flash
 * @data: pointer to private data
 *
 * Loop through each component that is active for the matching device record,
 * and send it to the device driver for flashing.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
static int pldm_flash_components(struct pldmfw_priv *data)
{}

/**
 * pldm_finalize_update - Finalize the device flash update
 * @data: pointer to private data
 *
 * Tell the device driver to perform any remaining logic to complete the
 * device update.
 *
 * Returns: zero on success, or a PLFM_FWU error indicating the reason for
 * failure.
 */
static int pldm_finalize_update(struct pldmfw_priv *data)
{}

/**
 * pldmfw_flash_image - Write a PLDM-formatted firmware image to the device
 * @context: ops and data for firmware update
 * @fw: firmware object pointing to the relevant firmware file to program
 *
 * Parse the data for a given firmware file, verifying that it is a valid PLDM
 * formatted image that matches this device.
 *
 * Extract the device record Package Data and Component Tables and send them
 * to the device firmware. Extract and write the flash data for each of the
 * components indicated in the firmware file.
 *
 * Returns: zero on success, or a negative error code on failure.
 */
int pldmfw_flash_image(struct pldmfw *context, const struct firmware *fw)
{}
EXPORT_SYMBOL();

MODULE_AUTHOR();
MODULE_DESCRIPTION();