0001
0002
0003
0004 #include <asm/unaligned.h>
0005 #include <linux/crc32.h>
0006 #include <linux/device.h>
0007 #include <linux/firmware.h>
0008 #include <linux/kernel.h>
0009 #include <linux/module.h>
0010 #include <linux/pci.h>
0011 #include <linux/pldmfw.h>
0012 #include <linux/slab.h>
0013 #include <linux/uuid.h>
0014
0015 #include "pldmfw_private.h"
0016
0017
0018
0019
0020 struct pldmfw_priv {
0021 struct pldmfw *context;
0022 const struct firmware *fw;
0023
0024
0025 size_t offset;
0026
0027 struct list_head records;
0028 struct list_head components;
0029
0030
0031 const struct __pldm_header *header;
0032 u16 total_header_size;
0033
0034
0035 u16 component_bitmap_len;
0036 u16 bitmap_size;
0037
0038
0039 u16 component_count;
0040 const u8 *component_start;
0041
0042
0043 const u8 *record_start;
0044 u8 record_count;
0045
0046
0047 u32 header_crc;
0048
0049 struct pldmfw_record *matching_record;
0050 };
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064 static int
0065 pldm_check_fw_space(struct pldmfw_priv *data, size_t offset, size_t length)
0066 {
0067 size_t expected_size = offset + length;
0068 struct device *dev = data->context->dev;
0069
0070 if (data->fw->size < expected_size) {
0071 dev_dbg(dev, "Firmware file size smaller than expected. Got %zu bytes, needed %zu bytes\n",
0072 data->fw->size, expected_size);
0073 return -EFAULT;
0074 }
0075
0076 return 0;
0077 }
0078
0079
0080
0081
0082
0083
0084
0085
0086
0087
0088
0089
0090 static int
0091 pldm_move_fw_offset(struct pldmfw_priv *data, size_t bytes_to_move)
0092 {
0093 int err;
0094
0095 err = pldm_check_fw_space(data, data->offset, bytes_to_move);
0096 if (err)
0097 return err;
0098
0099 data->offset += bytes_to_move;
0100
0101 return 0;
0102 }
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117
0118
0119
0120
0121
0122
0123 static int pldm_parse_header(struct pldmfw_priv *data)
0124 {
0125 const struct __pldmfw_record_area *record_area;
0126 struct device *dev = data->context->dev;
0127 const struct __pldm_header *header;
0128 size_t header_size;
0129 int err;
0130
0131 err = pldm_move_fw_offset(data, sizeof(*header));
0132 if (err)
0133 return err;
0134
0135 header = (const struct __pldm_header *)data->fw->data;
0136 data->header = header;
0137
0138 if (!uuid_equal(&header->id, &pldm_firmware_header_id)) {
0139 dev_dbg(dev, "Invalid package header identifier. Expected UUID %pUB, but got %pUB\n",
0140 &pldm_firmware_header_id, &header->id);
0141 return -EINVAL;
0142 }
0143
0144 if (header->revision != PACKAGE_HEADER_FORMAT_REVISION) {
0145 dev_dbg(dev, "Invalid package header revision. Expected revision %u but got %u\n",
0146 PACKAGE_HEADER_FORMAT_REVISION, header->revision);
0147 return -EOPNOTSUPP;
0148 }
0149
0150 data->total_header_size = get_unaligned_le16(&header->size);
0151 header_size = data->total_header_size - sizeof(*header);
0152
0153 err = pldm_check_fw_space(data, data->offset, header_size);
0154 if (err)
0155 return err;
0156
0157 data->component_bitmap_len =
0158 get_unaligned_le16(&header->component_bitmap_len);
0159
0160 if (data->component_bitmap_len % 8 != 0) {
0161 dev_dbg(dev, "Invalid component bitmap length. The length is %u, which is not a multiple of 8\n",
0162 data->component_bitmap_len);
0163 return -EINVAL;
0164 }
0165
0166 data->bitmap_size = data->component_bitmap_len / 8;
0167
0168 err = pldm_move_fw_offset(data, header->version_len);
0169 if (err)
0170 return err;
0171
0172
0173
0174
0175 record_area = (const struct __pldmfw_record_area *)(data->fw->data +
0176 data->offset);
0177
0178 err = pldm_move_fw_offset(data, sizeof(*record_area));
0179 if (err)
0180 return err;
0181
0182 data->record_count = record_area->record_count;
0183 data->record_start = record_area->records;
0184
0185 return 0;
0186 }
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202 static int
0203 pldm_check_desc_tlv_len(struct pldmfw_priv *data, u16 type, u16 size)
0204 {
0205 struct device *dev = data->context->dev;
0206 u16 expected_size;
0207
0208 switch (type) {
0209 case PLDM_DESC_ID_PCI_VENDOR_ID:
0210 case PLDM_DESC_ID_PCI_DEVICE_ID:
0211 case PLDM_DESC_ID_PCI_SUBVENDOR_ID:
0212 case PLDM_DESC_ID_PCI_SUBDEV_ID:
0213 expected_size = 2;
0214 break;
0215 case PLDM_DESC_ID_PCI_REVISION_ID:
0216 expected_size = 1;
0217 break;
0218 case PLDM_DESC_ID_PNP_VENDOR_ID:
0219 expected_size = 3;
0220 break;
0221 case PLDM_DESC_ID_IANA_ENTERPRISE_ID:
0222 case PLDM_DESC_ID_ACPI_VENDOR_ID:
0223 case PLDM_DESC_ID_PNP_PRODUCT_ID:
0224 case PLDM_DESC_ID_ACPI_PRODUCT_ID:
0225 expected_size = 4;
0226 break;
0227 case PLDM_DESC_ID_UUID:
0228 expected_size = 16;
0229 break;
0230 case PLDM_DESC_ID_VENDOR_DEFINED:
0231 return 0;
0232 default:
0233
0234 dev_dbg(dev, "Found unrecognized TLV type 0x%04x\n", type);
0235 return 0;
0236 }
0237
0238 if (size != expected_size) {
0239 dev_dbg(dev, "Found TLV type 0x%04x with unexpected length. Got %u bytes, but expected %u bytes\n",
0240 type, size, expected_size);
0241 return -EINVAL;
0242 }
0243
0244 return 0;
0245 }
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258 static int
0259 pldm_parse_desc_tlvs(struct pldmfw_priv *data, struct pldmfw_record *record, u8 desc_count)
0260 {
0261 const struct __pldmfw_desc_tlv *__desc;
0262 const u8 *desc_start;
0263 u8 i;
0264
0265 desc_start = data->fw->data + data->offset;
0266
0267 pldm_for_each_desc_tlv(i, __desc, desc_start, desc_count) {
0268 struct pldmfw_desc_tlv *desc;
0269 int err;
0270 u16 type, size;
0271
0272 err = pldm_move_fw_offset(data, sizeof(*__desc));
0273 if (err)
0274 return err;
0275
0276 type = get_unaligned_le16(&__desc->type);
0277
0278
0279 size = get_unaligned_le16(&__desc->size);
0280
0281 err = pldm_check_desc_tlv_len(data, type, size);
0282 if (err)
0283 return err;
0284
0285
0286 err = pldm_move_fw_offset(data, size);
0287 if (err)
0288 return err;
0289
0290 desc = kzalloc(sizeof(*desc), GFP_KERNEL);
0291 if (!desc)
0292 return -ENOMEM;
0293
0294 desc->type = type;
0295 desc->size = size;
0296 desc->data = __desc->data;
0297
0298 list_add_tail(&desc->entry, &record->descs);
0299 }
0300
0301 return 0;
0302 }
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319 static int
0320 pldm_parse_one_record(struct pldmfw_priv *data,
0321 const struct __pldmfw_record_info *__record)
0322 {
0323 struct pldmfw_record *record;
0324 size_t measured_length;
0325 int err;
0326 const u8 *bitmap_ptr;
0327 u16 record_len;
0328 int i;
0329
0330
0331 record = kzalloc(sizeof(*record), GFP_KERNEL);
0332 if (!record)
0333 return -ENOMEM;
0334
0335 INIT_LIST_HEAD(&record->descs);
0336 list_add_tail(&record->entry, &data->records);
0337
0338
0339 err = pldm_move_fw_offset(data, sizeof(*__record));
0340 if (err)
0341 return err;
0342
0343 record_len = get_unaligned_le16(&__record->record_len);
0344 record->package_data_len = get_unaligned_le16(&__record->package_data_len);
0345 record->version_len = __record->version_len;
0346 record->version_type = __record->version_type;
0347
0348 bitmap_ptr = data->fw->data + data->offset;
0349
0350
0351 err = pldm_move_fw_offset(data, data->bitmap_size);
0352 if (err)
0353 return err;
0354
0355 record->component_bitmap_len = data->component_bitmap_len;
0356 record->component_bitmap = bitmap_zalloc(record->component_bitmap_len,
0357 GFP_KERNEL);
0358 if (!record->component_bitmap)
0359 return -ENOMEM;
0360
0361 for (i = 0; i < data->bitmap_size; i++)
0362 bitmap_set_value8(record->component_bitmap, bitmap_ptr[i], i * 8);
0363
0364 record->version_string = data->fw->data + data->offset;
0365
0366 err = pldm_move_fw_offset(data, record->version_len);
0367 if (err)
0368 return err;
0369
0370
0371 err = pldm_parse_desc_tlvs(data, record, __record->descriptor_count);
0372 if (err)
0373 return err;
0374
0375 record->package_data = data->fw->data + data->offset;
0376
0377 err = pldm_move_fw_offset(data, record->package_data_len);
0378 if (err)
0379 return err;
0380
0381 measured_length = data->offset - ((const u8 *)__record - data->fw->data);
0382 if (measured_length != record_len) {
0383 dev_dbg(data->context->dev, "Unexpected record length. Measured record length is %zu bytes, expected length is %u bytes\n",
0384 measured_length, record_len);
0385 return -EFAULT;
0386 }
0387
0388 return 0;
0389 }
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400 static int pldm_parse_records(struct pldmfw_priv *data)
0401 {
0402 const struct __pldmfw_component_area *component_area;
0403 const struct __pldmfw_record_info *record;
0404 int err;
0405 u8 i;
0406
0407 pldm_for_each_record(i, record, data->record_start, data->record_count) {
0408 err = pldm_parse_one_record(data, record);
0409 if (err)
0410 return err;
0411 }
0412
0413
0414
0415
0416 component_area = (const struct __pldmfw_component_area *)(data->fw->data + data->offset);
0417
0418 err = pldm_move_fw_offset(data, sizeof(*component_area));
0419 if (err)
0420 return err;
0421
0422 data->component_count =
0423 get_unaligned_le16(&component_area->component_image_count);
0424 data->component_start = component_area->components;
0425
0426 return 0;
0427 }
0428
0429
0430
0431
0432
0433
0434
0435
0436
0437
0438
0439
0440
0441 static int pldm_parse_components(struct pldmfw_priv *data)
0442 {
0443 const struct __pldmfw_component_info *__component;
0444 struct device *dev = data->context->dev;
0445 const u8 *header_crc_ptr;
0446 int err;
0447 u8 i;
0448
0449 pldm_for_each_component(i, __component, data->component_start, data->component_count) {
0450 struct pldmfw_component *component;
0451 u32 offset, size;
0452
0453 err = pldm_move_fw_offset(data, sizeof(*__component));
0454 if (err)
0455 return err;
0456
0457 err = pldm_move_fw_offset(data, __component->version_len);
0458 if (err)
0459 return err;
0460
0461 offset = get_unaligned_le32(&__component->location_offset);
0462 size = get_unaligned_le32(&__component->size);
0463
0464 err = pldm_check_fw_space(data, offset, size);
0465 if (err)
0466 return err;
0467
0468 component = kzalloc(sizeof(*component), GFP_KERNEL);
0469 if (!component)
0470 return -ENOMEM;
0471
0472 component->index = i;
0473 component->classification = get_unaligned_le16(&__component->classification);
0474 component->identifier = get_unaligned_le16(&__component->identifier);
0475 component->comparison_stamp = get_unaligned_le32(&__component->comparison_stamp);
0476 component->options = get_unaligned_le16(&__component->options);
0477 component->activation_method = get_unaligned_le16(&__component->activation_method);
0478 component->version_type = __component->version_type;
0479 component->version_len = __component->version_len;
0480 component->version_string = __component->version_string;
0481 component->component_data = data->fw->data + offset;
0482 component->component_size = size;
0483
0484 list_add_tail(&component->entry, &data->components);
0485 }
0486
0487 header_crc_ptr = data->fw->data + data->offset;
0488
0489 err = pldm_move_fw_offset(data, sizeof(data->header_crc));
0490 if (err)
0491 return err;
0492
0493
0494 if (data->offset != data->total_header_size) {
0495 dev_dbg(dev, "Invalid firmware header size. Expected %u but got %zu\n",
0496 data->total_header_size, data->offset);
0497 return -EFAULT;
0498 }
0499
0500 data->header_crc = get_unaligned_le32(header_crc_ptr);
0501
0502 return 0;
0503 }
0504
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514 static int pldm_verify_header_crc(struct pldmfw_priv *data)
0515 {
0516 struct device *dev = data->context->dev;
0517 u32 calculated_crc;
0518 size_t length;
0519
0520
0521
0522
0523
0524 length = data->offset - sizeof(data->header_crc);
0525 calculated_crc = crc32_le(~0, data->fw->data, length) ^ ~0;
0526
0527 if (calculated_crc != data->header_crc) {
0528 dev_dbg(dev, "Invalid CRC in firmware header. Got 0x%08x but expected 0x%08x\n",
0529 calculated_crc, data->header_crc);
0530 return -EBADMSG;
0531 }
0532
0533 return 0;
0534 }
0535
0536
0537
0538
0539
0540
0541
0542
0543 static void pldmfw_free_priv(struct pldmfw_priv *data)
0544 {
0545 struct pldmfw_component *component, *c_safe;
0546 struct pldmfw_record *record, *r_safe;
0547 struct pldmfw_desc_tlv *desc, *d_safe;
0548
0549 list_for_each_entry_safe(component, c_safe, &data->components, entry) {
0550 list_del(&component->entry);
0551 kfree(component);
0552 }
0553
0554 list_for_each_entry_safe(record, r_safe, &data->records, entry) {
0555 list_for_each_entry_safe(desc, d_safe, &record->descs, entry) {
0556 list_del(&desc->entry);
0557 kfree(desc);
0558 }
0559
0560 if (record->component_bitmap) {
0561 bitmap_free(record->component_bitmap);
0562 record->component_bitmap = NULL;
0563 }
0564
0565 list_del(&record->entry);
0566 kfree(record);
0567 }
0568 }
0569
0570
0571
0572
0573
0574
0575
0576
0577
0578
0579
0580
0581
0582
0583
0584 static int pldm_parse_image(struct pldmfw_priv *data)
0585 {
0586 int err;
0587
0588 if (WARN_ON(!(data->context->dev && data->fw->data && data->fw->size)))
0589 return -EINVAL;
0590
0591 err = pldm_parse_header(data);
0592 if (err)
0593 return err;
0594
0595 err = pldm_parse_records(data);
0596 if (err)
0597 return err;
0598
0599 err = pldm_parse_components(data);
0600 if (err)
0601 return err;
0602
0603 return pldm_verify_header_crc(data);
0604 }
0605
0606
0607 struct pldm_pci_record_id {
0608 int vendor;
0609 int device;
0610 int subsystem_vendor;
0611 int subsystem_device;
0612 };
0613
0614
0615
0616
0617
0618
0619
0620
0621
0622
0623
0624
0625
0626
0627
0628 bool pldmfw_op_pci_match_record(struct pldmfw *context, struct pldmfw_record *record)
0629 {
0630 struct pci_dev *pdev = to_pci_dev(context->dev);
0631 struct pldm_pci_record_id id = {
0632 .vendor = PCI_ANY_ID,
0633 .device = PCI_ANY_ID,
0634 .subsystem_vendor = PCI_ANY_ID,
0635 .subsystem_device = PCI_ANY_ID,
0636 };
0637 struct pldmfw_desc_tlv *desc;
0638
0639 list_for_each_entry(desc, &record->descs, entry) {
0640 u16 value;
0641 int *ptr;
0642
0643 switch (desc->type) {
0644 case PLDM_DESC_ID_PCI_VENDOR_ID:
0645 ptr = &id.vendor;
0646 break;
0647 case PLDM_DESC_ID_PCI_DEVICE_ID:
0648 ptr = &id.device;
0649 break;
0650 case PLDM_DESC_ID_PCI_SUBVENDOR_ID:
0651 ptr = &id.subsystem_vendor;
0652 break;
0653 case PLDM_DESC_ID_PCI_SUBDEV_ID:
0654 ptr = &id.subsystem_device;
0655 break;
0656 default:
0657
0658 continue;
0659 }
0660
0661 value = get_unaligned_le16(desc->data);
0662
0663
0664
0665
0666
0667 if (value)
0668 *ptr = (int)value;
0669 else
0670 *ptr = PCI_ANY_ID;
0671 }
0672
0673 if ((id.vendor == PCI_ANY_ID || id.vendor == pdev->vendor) &&
0674 (id.device == PCI_ANY_ID || id.device == pdev->device) &&
0675 (id.subsystem_vendor == PCI_ANY_ID || id.subsystem_vendor == pdev->subsystem_vendor) &&
0676 (id.subsystem_device == PCI_ANY_ID || id.subsystem_device == pdev->subsystem_device))
0677 return true;
0678 else
0679 return false;
0680 }
0681 EXPORT_SYMBOL(pldmfw_op_pci_match_record);
0682
0683
0684
0685
0686
0687
0688
0689
0690
0691
0692
0693
0694 static int pldm_find_matching_record(struct pldmfw_priv *data)
0695 {
0696 struct pldmfw_record *record;
0697
0698 list_for_each_entry(record, &data->records, entry) {
0699 if (data->context->ops->match_record(data->context, record)) {
0700 data->matching_record = record;
0701 return 0;
0702 }
0703 }
0704
0705 return -ENOENT;
0706 }
0707
0708
0709
0710
0711
0712
0713
0714
0715
0716
0717 static int
0718 pldm_send_package_data(struct pldmfw_priv *data)
0719 {
0720 struct pldmfw_record *record = data->matching_record;
0721 const struct pldmfw_ops *ops = data->context->ops;
0722
0723 return ops->send_package_data(data->context, record->package_data,
0724 record->package_data_len);
0725 }
0726
0727
0728
0729
0730
0731
0732
0733
0734
0735
0736 static int
0737 pldm_send_component_tables(struct pldmfw_priv *data)
0738 {
0739 unsigned long *bitmap = data->matching_record->component_bitmap;
0740 struct pldmfw_component *component;
0741 int err;
0742
0743 list_for_each_entry(component, &data->components, entry) {
0744 u8 index = component->index, transfer_flag = 0;
0745
0746
0747 if (!test_bit(index, bitmap))
0748 continue;
0749
0750
0751
0752
0753 if (index == find_first_bit(bitmap, data->component_bitmap_len))
0754 transfer_flag |= PLDM_TRANSFER_FLAG_START;
0755 if (index == find_last_bit(bitmap, data->component_bitmap_len))
0756 transfer_flag |= PLDM_TRANSFER_FLAG_END;
0757 if (!transfer_flag)
0758 transfer_flag = PLDM_TRANSFER_FLAG_MIDDLE;
0759
0760 err = data->context->ops->send_component_table(data->context,
0761 component,
0762 transfer_flag);
0763 if (err)
0764 return err;
0765 }
0766
0767 return 0;
0768 }
0769
0770
0771
0772
0773
0774
0775
0776
0777
0778
0779 static int pldm_flash_components(struct pldmfw_priv *data)
0780 {
0781 unsigned long *bitmap = data->matching_record->component_bitmap;
0782 struct pldmfw_component *component;
0783 int err;
0784
0785 list_for_each_entry(component, &data->components, entry) {
0786 u8 index = component->index;
0787
0788
0789 if (!test_bit(index, bitmap))
0790 continue;
0791
0792 err = data->context->ops->flash_component(data->context, component);
0793 if (err)
0794 return err;
0795 }
0796
0797 return 0;
0798 }
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810 static int pldm_finalize_update(struct pldmfw_priv *data)
0811 {
0812 if (data->context->ops->finalize_update)
0813 return data->context->ops->finalize_update(data->context);
0814
0815 return 0;
0816 }
0817
0818
0819
0820
0821
0822
0823
0824
0825
0826
0827
0828
0829
0830
0831
0832 int pldmfw_flash_image(struct pldmfw *context, const struct firmware *fw)
0833 {
0834 struct pldmfw_priv *data;
0835 int err;
0836
0837 data = kzalloc(sizeof(*data), GFP_KERNEL);
0838 if (!data)
0839 return -ENOMEM;
0840
0841 INIT_LIST_HEAD(&data->records);
0842 INIT_LIST_HEAD(&data->components);
0843
0844 data->fw = fw;
0845 data->context = context;
0846
0847 err = pldm_parse_image(data);
0848 if (err)
0849 goto out_release_data;
0850
0851 err = pldm_find_matching_record(data);
0852 if (err)
0853 goto out_release_data;
0854
0855 err = pldm_send_package_data(data);
0856 if (err)
0857 goto out_release_data;
0858
0859 err = pldm_send_component_tables(data);
0860 if (err)
0861 goto out_release_data;
0862
0863 err = pldm_flash_components(data);
0864 if (err)
0865 goto out_release_data;
0866
0867 err = pldm_finalize_update(data);
0868
0869 out_release_data:
0870 pldmfw_free_priv(data);
0871 kfree(data);
0872
0873 return err;
0874 }
0875 EXPORT_SYMBOL(pldmfw_flash_image);
0876
0877 MODULE_AUTHOR("Jacob Keller <jacob.e.keller@intel.com>");
0878 MODULE_LICENSE("GPL v2");
0879 MODULE_DESCRIPTION("PLDM firmware flash update library");