xref: /openbmc/phosphor-bmc-code-mgmt/test/create_package/create_pldm_fw_package.cpp (revision 9657070cb86dd010fea961ffc6ed40fa3b1b7565)
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