1 2 #include "component_image_info_area.hpp" 3 #include "firmware_device_id_area.hpp" 4 #include "phosphor-logging/lg2.hpp" 5 6 #include <inttypes.h> 7 #include <libpldm/firmware_update.h> 8 9 #include <cstring> 10 #include <fstream> 11 #include <limits> 12 #include <random> 13 14 std::unique_ptr<uint8_t[]> create_pldm_package_buffer( 15 const uint8_t* component_image, size_t component_image_size, 16 const std::optional<uint32_t>& optVendorIANA, 17 const std::optional<std::string>& optCompatible, size_t& size_out) 18 { 19 const size_t size = 512 + component_image_size; 20 auto buffer = std::make_unique<uint8_t[]>(size); 21 uint8_t* b = buffer.get(); 22 memset(b, 0, size); 23 ssize_t i = 0; // index 24 25 // populate uuid 26 // must be this value to align with 27 // https://github.com/openbmc/pldm/blob/master/fw-update/package_parser.cpp#L294 28 uint8_t uuid[PLDM_FWUP_UUID_LENGTH] = { 29 0xF0, 0x18, 0x87, 0x8C, 0xCB, 0x7D, 0x49, 0x43, 30 0x98, 0x00, 0xA0, 0x2F, 0x05, 0x9A, 0xCA, 0x02}; 31 memcpy(b, uuid, PLDM_FWUP_UUID_LENGTH); 32 33 i += PLDM_FWUP_UUID_LENGTH; 34 35 // package header format revision 36 b[i++] = 0x01; 37 // must be 1 to align with 38 // https://github.com/openbmc/pldm/blob/master/fw-update/package_parser.cpp#L294 39 40 // package header size (leave space) 41 ssize_t package_header_size_offset = i; 42 i += 2; 43 44 // package release date time 45 // set timestamp as unknown value 46 b[i + 12] = 15; 47 i += PLDM_TIMESTAMP104_SIZE; 48 49 // component bitmap bit length 50 const uint16_t componentBitmapBitLength = 8; 51 b[i++] = componentBitmapBitLength; 52 b[i++] = 0x00; 53 54 // package_version_string_type 55 b[i++] = 0x01; // type = ASCII 56 57 const char* package_version_str = (const char*)"VersionString1"; 58 // package version string length 59 b[i++] = strlen(package_version_str); 60 61 // package version string 62 for (size_t j = 0; j < strlen(package_version_str); j++) 63 { 64 b[i++] = package_version_str[j]; 65 } 66 67 // --- Firmware Device Identification Area 1.0.0 --- 68 69 i = create_pldm_firmware_device_identification_area_v1_0_0( 70 b, i, optVendorIANA, optCompatible, componentBitmapBitLength); 71 72 // --- Component Image Information Area 1.0.0 --- 73 size_t componentLocationOffsetIndex; 74 i = create_pldm_component_image_info_area_v1_0_0( 75 b, i, component_image_size, componentLocationOffsetIndex); 76 77 // PackageHeaderChecksum (backfill later) 78 const size_t packageHeaderChecksumOffset = i; 79 i += 4; 80 81 // backfill the PackageHeaderSize 82 b[package_header_size_offset + 0] = (i >> 0) & 0xff; 83 b[package_header_size_offset + 1] = (i >> 8) & 0xff; 84 85 // backfill the ComponentLocationOffset 86 b[componentLocationOffsetIndex + 0] = (i >> 0) & 0xff; 87 b[componentLocationOffsetIndex + 1] = (i >> 8) & 0xff; 88 b[componentLocationOffsetIndex + 2] = (i >> 16) & 0xff; 89 b[componentLocationOffsetIndex + 3] = (i >> 24) & 0xff; 90 91 // backfill PackageHeaderChecksum 92 const uint32_t crc = pldm_edac_crc32(b, packageHeaderChecksumOffset); 93 memcpy(b + packageHeaderChecksumOffset, &crc, 4); 94 95 // --- end of the package header --- 96 97 // write the component image 98 for (size_t j = 0; j < component_image_size; j++) 99 { 100 b[i++] = component_image[j]; 101 } 102 103 lg2::debug("wrote {NBYTES} bytes for pldm update package", "NBYTES", i); 104 105 size_out = i; 106 return buffer; 107 } 108 109 static void create_pldm_package_file(std::ofstream& of, 110 const uint8_t* component_image, 111 size_t component_image_size) 112 { 113 size_t size; 114 std::unique_ptr<uint8_t[]> buf = 115 create_pldm_package_buffer(component_image, component_image_size, 116 std::nullopt, std::nullopt, size); 117 uint8_t* b = buf.get(); 118 119 of.write(reinterpret_cast<char*>(b), (long)size); 120 } 121 122 std::optional<std::string> create_pldm_package(uint8_t* component_image, 123 size_t component_image_size) 124 { 125 std::random_device rd; 126 std::mt19937 gen(rd()); 127 std::uniform_int_distribution<> distrib(0, std::numeric_limits<int>::max()); 128 129 std::string filename = 130 std::format("/tmp/pldm-package-{}.bin", distrib(gen)); 131 132 std::ofstream of(filename, std::ofstream::out); 133 134 if (!of.good()) 135 { 136 lg2::error("could not create file: {FILENAME}", "FILENAME", filename); 137 return std::nullopt; 138 } 139 140 create_pldm_package_file(of, component_image, component_image_size); 141 142 of.close(); 143 144 return filename; 145 } 146