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