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