193a4c0abSBrandon Kim // Copyright 2024 Google LLC
293a4c0abSBrandon Kim //
393a4c0abSBrandon Kim // Licensed under the Apache License, Version 2.0 (the "License");
493a4c0abSBrandon Kim // you may not use this file except in compliance with the License.
593a4c0abSBrandon Kim // You may obtain a copy of the License at
693a4c0abSBrandon Kim //
793a4c0abSBrandon Kim // http://www.apache.org/licenses/LICENSE-2.0
893a4c0abSBrandon Kim //
993a4c0abSBrandon Kim // Unless required by applicable law or agreed to in writing, software
1093a4c0abSBrandon Kim // distributed under the License is distributed on an "AS IS" BASIS,
1193a4c0abSBrandon Kim // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1293a4c0abSBrandon Kim // See the License for the specific language governing permissions and
1393a4c0abSBrandon Kim // limitations under the License.
1493a4c0abSBrandon Kim
1593a4c0abSBrandon Kim #include "bios_setting.hpp"
1693a4c0abSBrandon Kim
1793a4c0abSBrandon Kim #include "commands.hpp"
1893a4c0abSBrandon Kim #include "errors.hpp"
1993a4c0abSBrandon Kim #include "handler.hpp"
2093a4c0abSBrandon Kim
2193a4c0abSBrandon Kim #include <ipmid/api-types.hpp>
2293a4c0abSBrandon Kim #include <stdplus/fd/create.hpp>
2393a4c0abSBrandon Kim #include <stdplus/fd/managed.hpp>
2493a4c0abSBrandon Kim #include <stdplus/fd/ops.hpp>
25*e8929699SBrandon Kim #include <stdplus/numeric/endian.hpp>
2693a4c0abSBrandon Kim #include <stdplus/print.hpp>
27*e8929699SBrandon Kim #include <stdplus/raw.hpp>
2893a4c0abSBrandon Kim
2993a4c0abSBrandon Kim #include <filesystem>
3093a4c0abSBrandon Kim #include <fstream>
3193a4c0abSBrandon Kim #include <span>
3293a4c0abSBrandon Kim #include <vector>
3393a4c0abSBrandon Kim
3493a4c0abSBrandon Kim namespace google
3593a4c0abSBrandon Kim {
3693a4c0abSBrandon Kim namespace ipmi
3793a4c0abSBrandon Kim {
3893a4c0abSBrandon Kim
readBiosSettingFromFile(const std::string & biosSettingPath)3993a4c0abSBrandon Kim std::vector<uint8_t> readBiosSettingFromFile(const std::string& biosSettingPath)
4093a4c0abSBrandon Kim {
4193a4c0abSBrandon Kim std::vector<uint8_t> biosSettings;
4293a4c0abSBrandon Kim try
4393a4c0abSBrandon Kim {
4493a4c0abSBrandon Kim stdplus::ManagedFd managedFd = stdplus::fd::open(
4593a4c0abSBrandon Kim biosSettingPath,
4693a4c0abSBrandon Kim stdplus::fd::OpenFlags(stdplus::fd::OpenAccess::ReadOnly));
4793a4c0abSBrandon Kim biosSettings = stdplus::fd::readAll<std::vector<uint8_t>>(managedFd);
4893a4c0abSBrandon Kim }
4993a4c0abSBrandon Kim catch (const std::exception& e)
5093a4c0abSBrandon Kim {
5193a4c0abSBrandon Kim stdplus::print(stderr, "Read unsuccessful: {}\n", e.what());
5293a4c0abSBrandon Kim return {};
5393a4c0abSBrandon Kim }
5493a4c0abSBrandon Kim return biosSettings;
5593a4c0abSBrandon Kim }
5693a4c0abSBrandon Kim
readBiosSetting(std::span<const uint8_t>,HandlerInterface *,const std::string & biosSettingPath)5793a4c0abSBrandon Kim Resp readBiosSetting(std::span<const uint8_t>, HandlerInterface*,
5893a4c0abSBrandon Kim const std::string& biosSettingPath)
5993a4c0abSBrandon Kim {
6093a4c0abSBrandon Kim std::vector<uint8_t> biosSettings =
6193a4c0abSBrandon Kim readBiosSettingFromFile(biosSettingPath);
6293a4c0abSBrandon Kim size_t settingsLength = biosSettings.size();
6393a4c0abSBrandon Kim if (settingsLength == 0)
6493a4c0abSBrandon Kim {
6593a4c0abSBrandon Kim return ::ipmi::responseRetBytesUnavailable();
6693a4c0abSBrandon Kim }
6793a4c0abSBrandon Kim
6893a4c0abSBrandon Kim // Reply format is: Length of the payload (1 byte) + payload
6993a4c0abSBrandon Kim std::vector<std::uint8_t> reply;
7093a4c0abSBrandon Kim reply.reserve(1 + settingsLength);
7193a4c0abSBrandon Kim reply.emplace_back(static_cast<uint8_t>(settingsLength));
7293a4c0abSBrandon Kim reply.insert(reply.end(), biosSettings.begin(), biosSettings.end());
7393a4c0abSBrandon Kim
7493a4c0abSBrandon Kim return ::ipmi::responseSuccess(SysOEMCommands::SysReadBiosSetting, reply);
7593a4c0abSBrandon Kim }
7693a4c0abSBrandon Kim
writeBiosSetting(std::span<const uint8_t> data,HandlerInterface *,const std::string & biosSettingPath)77*e8929699SBrandon Kim Resp writeBiosSetting(std::span<const uint8_t> data, HandlerInterface*,
78*e8929699SBrandon Kim const std::string& biosSettingPath)
79*e8929699SBrandon Kim {
80*e8929699SBrandon Kim std::uint8_t payloadSize;
81*e8929699SBrandon Kim try
82*e8929699SBrandon Kim {
83*e8929699SBrandon Kim // This subspans the data automatically
84*e8929699SBrandon Kim payloadSize = stdplus::raw::extract<
85*e8929699SBrandon Kim stdplus::EndianPacked<decltype(payloadSize), std::endian::little>>(
86*e8929699SBrandon Kim data);
87*e8929699SBrandon Kim }
88*e8929699SBrandon Kim catch (const std::exception& e)
89*e8929699SBrandon Kim {
90*e8929699SBrandon Kim stdplus::print(stderr, "Extracting payload failed: {}\n", e.what());
91*e8929699SBrandon Kim return ::ipmi::responseReqDataLenInvalid();
92*e8929699SBrandon Kim }
93*e8929699SBrandon Kim
94*e8929699SBrandon Kim if (data.size() != payloadSize)
95*e8929699SBrandon Kim {
96*e8929699SBrandon Kim stdplus::print(stderr, "Invalid command length {} vs. payloadSize {}\n",
97*e8929699SBrandon Kim static_cast<uint32_t>(data.size()),
98*e8929699SBrandon Kim static_cast<uint32_t>(payloadSize));
99*e8929699SBrandon Kim return ::ipmi::responseReqDataLenInvalid();
100*e8929699SBrandon Kim }
101*e8929699SBrandon Kim
102*e8929699SBrandon Kim // Write the setting
103*e8929699SBrandon Kim try
104*e8929699SBrandon Kim {
105*e8929699SBrandon Kim stdplus::ManagedFd managedFd = stdplus::fd::open(
106*e8929699SBrandon Kim biosSettingPath,
107*e8929699SBrandon Kim stdplus::fd::OpenFlags(stdplus::fd::OpenAccess::WriteOnly)
108*e8929699SBrandon Kim .set(stdplus::fd::OpenFlag::Trunc)
109*e8929699SBrandon Kim .set(stdplus::fd::OpenFlag::Create));
110*e8929699SBrandon Kim stdplus::fd::writeExact(managedFd, data);
111*e8929699SBrandon Kim }
112*e8929699SBrandon Kim catch (const std::exception& e)
113*e8929699SBrandon Kim {
114*e8929699SBrandon Kim stdplus::print(stderr, "Write unsuccessful: {}\n", e.what());
115*e8929699SBrandon Kim return ::ipmi::responseRetBytesUnavailable();
116*e8929699SBrandon Kim }
117*e8929699SBrandon Kim
118*e8929699SBrandon Kim // Reply format is: Length of the payload written
119*e8929699SBrandon Kim std::vector<std::uint8_t> reply;
120*e8929699SBrandon Kim reply.reserve(1);
121*e8929699SBrandon Kim reply.emplace_back(static_cast<uint8_t>(payloadSize));
122*e8929699SBrandon Kim
123*e8929699SBrandon Kim return ::ipmi::responseSuccess(SysOEMCommands::SysWriteBiosSetting, reply);
124*e8929699SBrandon Kim }
125*e8929699SBrandon Kim
12693a4c0abSBrandon Kim } // namespace ipmi
12793a4c0abSBrandon Kim } // namespace google
128