blob: 78a7c85f188b1f5d75e25509a1846a67fab34ed7 [file] [log] [blame]
Lei YU3c341df2020-09-27 13:24:53 +08001#include "config.h"
2
John Wangef3194d2024-06-04 15:00:27 +08003#include "types.hpp"
Lei YU6505e9d2020-09-21 17:34:32 +08004
George Liu131de1e2024-06-04 11:07:47 +08005#include <ipmid/api.hpp>
6#include <ipmid/utils.hpp>
George Liu666f96a2024-06-03 19:41:40 +08007#include <phosphor-logging/lg2.hpp>
George Liu131de1e2024-06-04 11:07:47 +08008#include <sdbusplus/bus.hpp>
Lei YU8a454c52020-09-23 16:52:46 +08009
10#include <optional>
11
Lei YU17bc93d2020-09-23 19:55:07 +080012namespace
13{
14constexpr auto FIRMWARE_TYPE_OFFSET = 0;
15constexpr auto FIRMWARE_TYPE_SIZE = 1;
George Liu2ae54232024-04-03 09:40:27 +080016constexpr auto FIRMWARE_VERSION_OFFSET = FIRMWARE_TYPE_OFFSET +
17 FIRMWARE_TYPE_SIZE;
Lei YU17bc93d2020-09-23 19:55:07 +080018constexpr auto FIRMWARE_VERSION_SIZE = 15;
George Liu2ae54232024-04-03 09:40:27 +080019constexpr auto FIRMWARE_BUILDTIME_OFFSET = FIRMWARE_VERSION_OFFSET +
20 FIRMWARE_VERSION_SIZE;
Lei YU17bc93d2020-09-23 19:55:07 +080021constexpr auto FIRMWARE_BUILDTIME_SIZE = 20;
Lei YUebd3d092020-09-27 18:11:48 +080022constexpr auto FIRMWARE_MIN_SIZE = FIRMWARE_BUILDTIME_OFFSET;
Lei YU17bc93d2020-09-23 19:55:07 +080023
24static_assert(FIRMWARE_VERSION_OFFSET == 1);
25static_assert(FIRMWARE_BUILDTIME_OFFSET == 16);
26} // namespace
27
Lei YU6505e9d2020-09-21 17:34:32 +080028namespace ipmi
29{
30
Lei YU8a454c52020-09-23 16:52:46 +080031static void registerOEMFunctions() __attribute__((constructor));
Lei YU8a454c52020-09-23 16:52:46 +080032
John Wangef3194d2024-06-04 15:00:27 +080033struct AssetInfoHeader
34{
35 uint8_t rwFlag;
36 uint8_t deviceType;
37 uint8_t infoType;
38 uint8_t maskAllPresentLen;
39 uint8_t enableStatus;
40 uint8_t maskPresent;
41 uint8_t maskAllPresent;
42 uint8_t allInfoDone;
43 uint16_t totalMessageLen;
44} __attribute__((packed));
45
46enum class bios_version_devname
47{
48 BIOS = 0,
49 ME = 1,
50 IE = 2,
51 PCH = 3,
52 BOARD = 4,
53 MRC = 5,
54 CUSTOM_ID = 6,
55 PCH_STEPPING = 7,
56};
57
58constexpr std::array<std::string_view, 8> bios_devname{
59 "BIOS", "ME", "IE", "PCH", "BOARD", "MRC", "CUSTOM_ID", "PCH_STEPPING",
60};
61
Lei YU8a454c52020-09-23 16:52:46 +080062struct ParsedAssetInfo
Lei YU6505e9d2020-09-21 17:34:32 +080063{
Lei YU8a454c52020-09-23 16:52:46 +080064 uint8_t rwFlag;
65 uint8_t deviceType;
66 uint8_t infoType;
67 uint8_t maskAllPresentLen;
68 std::vector<uint8_t> enableStatus;
69 std::vector<uint8_t> maskPresent;
70 std::vector<uint8_t> maskAllPresent;
71 uint8_t allInfoDone;
72 uint16_t totalMessageLen;
73 std::vector<uint8_t> data;
74};
75
76void dumpAssetInfo(const ParsedAssetInfo& info)
77{
Lei YU6505e9d2020-09-21 17:34:32 +080078 fprintf(stderr,
Lei YU8a454c52020-09-23 16:52:46 +080079 "AssetInfo: rw %d, deviceType 0x%02x, infoType 0x%02x, "
80 "maskAllPresentLen %u\n",
81 info.rwFlag, info.deviceType, info.infoType,
82 info.maskAllPresentLen);
83 fprintf(stderr, "enableStatus ");
84 for (const auto& d : info.enableStatus)
85 {
86 fprintf(stderr, "0x%02x ", d);
87 }
88 fprintf(stderr, "\nmaskPresent ");
89 for (const auto& d : info.maskPresent)
90 {
91 fprintf(stderr, "0x%02x ", d);
92 }
93 fprintf(stderr, "\nmaskAllPresent ");
94 for (const auto& d : info.maskAllPresent)
95 {
96 fprintf(stderr, "0x%02x ", d);
97 }
98 fprintf(stderr, "\nallInfoDone %d, totalMessageLen %u\n", info.allInfoDone,
99 info.totalMessageLen);
100 fprintf(stderr, "data: ");
101 for (const auto& d : info.data)
102 {
103 fprintf(stderr, "0x%02x ", d);
104 }
105 fprintf(stderr, "\n");
106}
107
108std::optional<ParsedAssetInfo> parseAssetInfo(const AssetInfoHeader* h)
109{
110 auto len = h->maskAllPresentLen;
111 if (len == 0)
112 {
113 // This is invalid
114 return {};
115 }
116
117 ParsedAssetInfo info;
118 info.rwFlag = h->rwFlag;
119 info.deviceType = h->deviceType;
120 info.infoType = h->infoType;
121 info.maskAllPresentLen = len;
122 info.enableStatus.resize(len);
123 info.maskPresent.resize(len);
124 info.maskAllPresent.resize(len);
125 const uint8_t* p = &h->enableStatus;
126 memcpy(info.enableStatus.data(), p, len);
127 p += len;
128 memcpy(info.maskPresent.data(), p, len);
129 p += len;
130 memcpy(info.maskAllPresent.data(), p, len);
131 p += len;
132 info.allInfoDone = *p++;
133 info.totalMessageLen = *reinterpret_cast<const uint16_t*>(p);
134 p += sizeof(uint16_t);
135 auto dataLen = info.totalMessageLen - (sizeof(AssetInfoHeader) + 3 * len);
136 info.data.resize(dataLen);
137 memcpy(info.data.data(), p, dataLen);
138
Lei YU17bc93d2020-09-23 19:55:07 +0800139 // dumpAssetInfo(info);
Lei YU8a454c52020-09-23 16:52:46 +0800140 return info;
141}
142
Lei YU17bc93d2020-09-23 19:55:07 +0800143void parseBIOSInfo(const std::vector<uint8_t>& data)
144{
Lei YUebd3d092020-09-27 18:11:48 +0800145 if (data.size() < FIRMWARE_MIN_SIZE)
146 {
147 return;
148 }
Lei YU17bc93d2020-09-23 19:55:07 +0800149 bios_version_devname dev = static_cast<bios_version_devname>(data[0]);
150 std::string version{data.data() + FIRMWARE_VERSION_OFFSET,
151 data.data() + FIRMWARE_VERSION_SIZE};
152 std::string buildTime;
153 if (dev == bios_version_devname::BIOS)
154 {
155 buildTime.assign(reinterpret_cast<const char*>(
156 data.data() + FIRMWARE_BUILDTIME_OFFSET),
157 FIRMWARE_BUILDTIME_SIZE);
Lei YU3c341df2020-09-27 13:24:53 +0800158
George Liu131de1e2024-06-04 11:07:47 +0800159 try
160 {
161 // Set BIOS version
162 std::shared_ptr<sdbusplus::asio::connection> dbus = getSdBus();
163 auto service = getService(*dbus, VERSION_IFACE, BIOS_OBJPATH);
164 setDbusProperty(*dbus, service, BIOS_OBJPATH, VERSION_IFACE,
165 VERSION, version);
166 }
167 catch (const std::exception& e)
168 {
169 lg2::error("Failed to set BIOS version: {VERSION}, error: {ERROR}",
170 "VERSION", version, "ERROR", e);
171 }
Lei YU17bc93d2020-09-23 19:55:07 +0800172 }
173
174 printf("Dev %s, version %s, build time %s\n",
175 bios_devname[static_cast<int>(dev)].data(), version.c_str(),
176 buildTime.c_str());
177}
178
George Liua3a9d2a2024-04-03 09:30:45 +0800179ipmi_ret_t ipmiOemIEIAssetInfo(ipmi_netfn_t /* netfn */, ipmi_cmd_t /* cmd */,
John Wangef3194d2024-06-04 15:00:27 +0800180 ipmi_request_t request,
181 ipmi_response_t /* response */,
George Liua3a9d2a2024-04-03 09:30:45 +0800182 ipmi_data_len_t /* data_len */,
183 ipmi_context_t /* context */)
Lei YU8a454c52020-09-23 16:52:46 +0800184{
185 auto header = reinterpret_cast<AssetInfoHeader*>(request);
Lei YU8a454c52020-09-23 16:52:46 +0800186
187 auto info = parseAssetInfo(header);
188 auto deviceType = info->deviceType;
189 if (deviceType != 0x05)
190 {
George Liu666f96a2024-06-03 19:41:40 +0800191 lg2::info("Device type ({DEVICE_TYPE}) not supported yet",
192 "DEVICE_TYPE", deviceType);
Lei YU8a454c52020-09-23 16:52:46 +0800193 return IPMI_CC_UNSPECIFIED_ERROR;
194 }
195
196 // For now we only support BIOS type
Lei YU17bc93d2020-09-23 19:55:07 +0800197 parseBIOSInfo(info->data);
Lei YU8a454c52020-09-23 16:52:46 +0800198
Lei YU17bc93d2020-09-23 19:55:07 +0800199 return IPMI_CC_OK;
Lei YU6505e9d2020-09-21 17:34:32 +0800200}
201
202void registerOEMFunctions(void)
203{
John Wangef3194d2024-06-04 15:00:27 +0800204 ipmi_register_callback(netFnIei, iei::cmdSetAssetInfo, nullptr,
George Liua3a9d2a2024-04-03 09:30:45 +0800205 ipmiOemIEIAssetInfo, SYSTEM_INTERFACE);
Lei YU6505e9d2020-09-21 17:34:32 +0800206}
207
208} // namespace ipmi