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
create_pldm_package_buffer(const uint8_t * component_image,size_t component_image_size,const std::optional<uint32_t> & optVendorIANA,const std::optional<std::string> & optCompatible,size_t & size_out)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
create_pldm_package_file(std::ofstream & of,const uint8_t * component_image,size_t component_image_size)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
create_pldm_package(uint8_t * component_image,size_t component_image_size)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