xref: /openbmc/phosphor-ipmi-flash/tools/helper.cpp (revision 42a44c281cce08be0ca6251955f4fb73d30c8ced)
101123b2aSPatrick Venture /*
201123b2aSPatrick Venture  * Copyright 2019 Google Inc.
301123b2aSPatrick Venture  *
401123b2aSPatrick Venture  * Licensed under the Apache License, Version 2.0 (the "License");
501123b2aSPatrick Venture  * you may not use this file except in compliance with the License.
601123b2aSPatrick Venture  * You may obtain a copy of the License at
701123b2aSPatrick Venture  *
801123b2aSPatrick Venture  *     http://www.apache.org/licenses/LICENSE-2.0
901123b2aSPatrick Venture  *
1001123b2aSPatrick Venture  * Unless required by applicable law or agreed to in writing, software
1101123b2aSPatrick Venture  * distributed under the License is distributed on an "AS IS" BASIS,
1201123b2aSPatrick Venture  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1301123b2aSPatrick Venture  * See the License for the specific language governing permissions and
1401123b2aSPatrick Venture  * limitations under the License.
1501123b2aSPatrick Venture  */
1601123b2aSPatrick Venture 
1701123b2aSPatrick Venture #include "helper.hpp"
1801123b2aSPatrick Venture 
1901123b2aSPatrick Venture #include "status.hpp"
2001123b2aSPatrick Venture #include "tool_errors.hpp"
2101123b2aSPatrick Venture 
2201123b2aSPatrick Venture #include <ipmiblob/blob_errors.hpp>
23328f520fSJie Yang #include <ipmiblob/blob_interface.hpp>
249b37b095SPatrick Venture 
25cf37663bSWilliam A. Kennington III #include <algorithm>
269b37b095SPatrick Venture #include <chrono>
27cf37663bSWilliam A. Kennington III #include <optional>
2801123b2aSPatrick Venture #include <thread>
29328f520fSJie Yang #include <utility>
3001123b2aSPatrick Venture 
3101123b2aSPatrick Venture namespace host_tool
3201123b2aSPatrick Venture {
3301123b2aSPatrick Venture 
34cf37663bSWilliam A. Kennington III template <typename Check>
pollStat(std::uint16_t session,ipmiblob::BlobInterface * blob,Check && check)35cf37663bSWilliam A. Kennington III static auto pollStat(std::uint16_t session, ipmiblob::BlobInterface* blob,
36cf37663bSWilliam A. Kennington III                      Check&& check)
3701123b2aSPatrick Venture {
3801123b2aSPatrick Venture     using namespace std::chrono_literals;
3901123b2aSPatrick Venture 
40cf37663bSWilliam A. Kennington III     constexpr auto maxSleep = 1s;
41cf37663bSWilliam A. Kennington III     constexpr auto printInterval = 30s;
42cf37663bSWilliam A. Kennington III     constexpr auto timeout = 30min;
4301123b2aSPatrick Venture 
4401123b2aSPatrick Venture     try
4501123b2aSPatrick Venture     {
46cf37663bSWilliam A. Kennington III         auto start = std::chrono::steady_clock::now();
47cf37663bSWilliam A. Kennington III         auto last_print = start;
48cf37663bSWilliam A. Kennington III         auto last_check = start;
49cf37663bSWilliam A. Kennington III         auto check_interval = 50ms;
5001123b2aSPatrick Venture 
51cf37663bSWilliam A. Kennington III         while (true)
5201123b2aSPatrick Venture         {
5301123b2aSPatrick Venture             ipmiblob::StatResponse resp = blob->getStat(session);
54cf37663bSWilliam A. Kennington III             auto ret = check(resp);
55cf37663bSWilliam A. Kennington III             if (ret.has_value())
5601123b2aSPatrick Venture             {
5701123b2aSPatrick Venture                 std::fprintf(stderr, "success\n");
58cf37663bSWilliam A. Kennington III                 return std::move(*ret);
5901123b2aSPatrick Venture             }
6001123b2aSPatrick Venture 
61cf37663bSWilliam A. Kennington III             auto cur = std::chrono::steady_clock::now();
62cf37663bSWilliam A. Kennington III             if (cur - last_print >= printInterval)
6301123b2aSPatrick Venture             {
64cf37663bSWilliam A. Kennington III                 std::fprintf(stderr, "running\n");
65cf37663bSWilliam A. Kennington III                 last_print = cur;
6601123b2aSPatrick Venture             }
67cf37663bSWilliam A. Kennington III 
68cf37663bSWilliam A. Kennington III             auto sleep = check_interval - (cur - last_check);
69cf37663bSWilliam A. Kennington III             last_check = cur;
70cf37663bSWilliam A. Kennington III             // Check that we don't timeout immediately after sleeping
71cf37663bSWilliam A. Kennington III             // to avoid an extra sleep without checking
72cf37663bSWilliam A. Kennington III             if (cur - start > timeout - sleep)
73cf37663bSWilliam A. Kennington III             {
74cf37663bSWilliam A. Kennington III                 throw ToolException("Stat check timed out");
75cf37663bSWilliam A. Kennington III             }
76cf37663bSWilliam A. Kennington III             check_interval = std::min<decltype(check_interval)>(
77cf37663bSWilliam A. Kennington III                 check_interval * 2, maxSleep);
78cf37663bSWilliam A. Kennington III             std::this_thread::sleep_for(sleep);
7901123b2aSPatrick Venture         }
8001123b2aSPatrick Venture     }
8101123b2aSPatrick Venture     catch (const ipmiblob::BlobException& b)
8201123b2aSPatrick Venture     {
83*42a44c28SPatrick Williams         throw ToolException(
84*42a44c28SPatrick Williams             "blob exception received: " + std::string(b.what()));
8501123b2aSPatrick Venture     }
86f88bcf3bSWilliam A. Kennington III }
87cf37663bSWilliam A. Kennington III 
88cf37663bSWilliam A. Kennington III /* Poll an open verification session.  Handling closing the session is not yet
89cf37663bSWilliam A. Kennington III  * owned by this method.
90cf37663bSWilliam A. Kennington III  */
pollStatus(std::uint16_t session,ipmiblob::BlobInterface * blob)91cf37663bSWilliam A. Kennington III void pollStatus(std::uint16_t session, ipmiblob::BlobInterface* blob)
92cf37663bSWilliam A. Kennington III {
93cf37663bSWilliam A. Kennington III     pollStat(session, blob,
94cf37663bSWilliam A. Kennington III              [](const ipmiblob::StatResponse& resp) -> std::optional<bool> {
95cf37663bSWilliam A. Kennington III                  if (resp.metadata.size() != 1)
96cf37663bSWilliam A. Kennington III                  {
97cf37663bSWilliam A. Kennington III                      throw ToolException("Invalid stat metadata");
98cf37663bSWilliam A. Kennington III                  }
99*42a44c28SPatrick Williams                  auto result =
100*42a44c28SPatrick Williams                      static_cast<ipmi_flash::ActionStatus>(resp.metadata[0]);
101cf37663bSWilliam A. Kennington III                  switch (result)
102cf37663bSWilliam A. Kennington III                  {
103cf37663bSWilliam A. Kennington III                      case ipmi_flash::ActionStatus::failed:
104cf37663bSWilliam A. Kennington III                          throw ToolException("BMC reported failure");
105cf37663bSWilliam A. Kennington III                      case ipmi_flash::ActionStatus::unknown:
106cf37663bSWilliam A. Kennington III                      case ipmi_flash::ActionStatus::running:
107cf37663bSWilliam A. Kennington III                          return std::nullopt;
108cf37663bSWilliam A. Kennington III                      case ipmi_flash::ActionStatus::success:
109cf37663bSWilliam A. Kennington III                          return true;
110cf37663bSWilliam A. Kennington III                      default:
111cf37663bSWilliam A. Kennington III                          throw ToolException("Unrecognized action status");
112cf37663bSWilliam A. Kennington III                  }
113cf37663bSWilliam A. Kennington III              });
11401123b2aSPatrick Venture }
11501123b2aSPatrick Venture 
116328f520fSJie Yang /* Poll an open blob session for reading.
117328f520fSJie Yang  *
118328f520fSJie Yang  * The committing bit indicates that the blob is not available for reading now
119328f520fSJie Yang  * and the reader might come back and check the state later.
120328f520fSJie Yang  *
121328f520fSJie Yang  * Polling finishes under the following conditions:
122328f520fSJie Yang  * - The open_read bit set -> stat successful
123328f520fSJie Yang  * - The open_read and committing bits unset -> stat failed;
124328f520fSJie Yang  * - Blob exception was received;
125328f520fSJie Yang  * - Time ran out.
126328f520fSJie Yang  * Polling continues when the open_read bit unset and committing bit set.
127328f520fSJie Yang  * If the blob is not open_read and not committing, then it is an error to the
128328f520fSJie Yang  * reader.
129328f520fSJie Yang  */
pollReadReady(std::uint16_t session,ipmiblob::BlobInterface * blob)130f88bcf3bSWilliam A. Kennington III uint32_t pollReadReady(std::uint16_t session, ipmiblob::BlobInterface* blob)
131328f520fSJie Yang {
132cf37663bSWilliam A. Kennington III     return pollStat(
133cf37663bSWilliam A. Kennington III         session, blob,
134cf37663bSWilliam A. Kennington III         [](const ipmiblob::StatResponse& resp) -> std::optional<uint32_t> {
135cf37663bSWilliam A. Kennington III             if (resp.blob_state & ipmiblob::StateFlags::open_read)
136328f520fSJie Yang             {
137cf37663bSWilliam A. Kennington III                 return resp.size;
138cf37663bSWilliam A. Kennington III             }
139cf37663bSWilliam A. Kennington III             if (resp.blob_state & ipmiblob::StateFlags::committing)
140328f520fSJie Yang             {
141cf37663bSWilliam A. Kennington III                 return std::nullopt;
142328f520fSJie Yang             }
143cf37663bSWilliam A. Kennington III             throw ToolException("BMC blob failed to become ready");
144cf37663bSWilliam A. Kennington III         });
145328f520fSJie Yang }
146328f520fSJie Yang 
memcpyAligned(void * destination,const void * source,std::size_t size)147c7fa2c28SVivekanand Veeracholan void* memcpyAligned(void* destination, const void* source, std::size_t size)
148c7fa2c28SVivekanand Veeracholan {
149c7fa2c28SVivekanand Veeracholan     std::size_t i = 0;
150c7fa2c28SVivekanand Veeracholan     std::size_t bytesCopied = 0;
151c7fa2c28SVivekanand Veeracholan 
152fd16f6dbSWilly Tu     if (!(reinterpret_cast<std::uintptr_t>(destination) %
153fd16f6dbSWilly Tu           sizeof(std::uint64_t)) &&
154fd16f6dbSWilly Tu         !(reinterpret_cast<std::uintptr_t>(source) % sizeof(std::uint64_t)))
155c7fa2c28SVivekanand Veeracholan     {
156c7fa2c28SVivekanand Veeracholan         auto src64 = reinterpret_cast<const volatile std::uint64_t*>(source);
157c7fa2c28SVivekanand Veeracholan         auto dest64 = reinterpret_cast<volatile std::uint64_t*>(destination);
158c7fa2c28SVivekanand Veeracholan 
159c7fa2c28SVivekanand Veeracholan         for (i = 0; i < size / sizeof(std::uint64_t); i++)
160c7fa2c28SVivekanand Veeracholan         {
161c7fa2c28SVivekanand Veeracholan             *dest64++ = *src64++;
162c7fa2c28SVivekanand Veeracholan             bytesCopied += sizeof(std::uint64_t);
163c7fa2c28SVivekanand Veeracholan         }
164c7fa2c28SVivekanand Veeracholan     }
165c7fa2c28SVivekanand Veeracholan 
1661038836cSPatrick Williams     auto srcMem8 = reinterpret_cast<const volatile std::uint8_t*>(source) +
1671038836cSPatrick Williams                    bytesCopied;
1681038836cSPatrick Williams     auto destMem8 = reinterpret_cast<volatile std::uint8_t*>(destination) +
1691038836cSPatrick Williams                     bytesCopied;
170c7fa2c28SVivekanand Veeracholan 
171c7fa2c28SVivekanand Veeracholan     for (i = bytesCopied; i < size; i++)
172c7fa2c28SVivekanand Veeracholan     {
173c7fa2c28SVivekanand Veeracholan         *destMem8++ = *srcMem8++;
174c7fa2c28SVivekanand Veeracholan     }
175c7fa2c28SVivekanand Veeracholan 
176c7fa2c28SVivekanand Veeracholan     return destination;
177c7fa2c28SVivekanand Veeracholan }
178c7fa2c28SVivekanand Veeracholan 
17901123b2aSPatrick Venture } // namespace host_tool
180