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