xref: /openbmc/google-ipmi-sys/bios_setting.cpp (revision e89296998b00d3e92361fdb37152a18566cf4505)
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