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