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