blob: 3388a29900b856196d080f76c1f843bf8e396575 [file] [log] [blame]
Patrick Venture01123b22019-06-20 13:49:06 -07001/*
2 * Copyright 2019 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "helper.hpp"
18
19#include "status.hpp"
20#include "tool_errors.hpp"
21
Patrick Venture01123b22019-06-20 13:49:06 -070022#include <ipmiblob/blob_errors.hpp>
Jie Yang328f5202021-03-16 00:52:07 -070023#include <ipmiblob/blob_interface.hpp>
Patrick Venture9b37b092020-05-28 20:58:57 -070024
William A. Kennington IIIcf376632021-10-13 21:40:11 -070025#include <algorithm>
Patrick Venture9b37b092020-05-28 20:58:57 -070026#include <chrono>
William A. Kennington IIIcf376632021-10-13 21:40:11 -070027#include <optional>
Patrick Venture01123b22019-06-20 13:49:06 -070028#include <thread>
Jie Yang328f5202021-03-16 00:52:07 -070029#include <utility>
Patrick Venture01123b22019-06-20 13:49:06 -070030
31namespace host_tool
32{
33
William A. Kennington IIIcf376632021-10-13 21:40:11 -070034template <typename Check>
35static auto pollStat(std::uint16_t session, ipmiblob::BlobInterface* blob,
36 Check&& check)
Patrick Venture01123b22019-06-20 13:49:06 -070037{
38 using namespace std::chrono_literals;
39
William A. Kennington IIIcf376632021-10-13 21:40:11 -070040 constexpr auto maxSleep = 1s;
41 constexpr auto printInterval = 30s;
42 constexpr auto timeout = 30min;
Patrick Venture01123b22019-06-20 13:49:06 -070043
44 try
45 {
William A. Kennington IIIcf376632021-10-13 21:40:11 -070046 auto start = std::chrono::steady_clock::now();
47 auto last_print = start;
48 auto last_check = start;
49 auto check_interval = 50ms;
Patrick Venture01123b22019-06-20 13:49:06 -070050
William A. Kennington IIIcf376632021-10-13 21:40:11 -070051 while (true)
Patrick Venture01123b22019-06-20 13:49:06 -070052 {
53 ipmiblob::StatResponse resp = blob->getStat(session);
William A. Kennington IIIcf376632021-10-13 21:40:11 -070054 auto ret = check(resp);
55 if (ret.has_value())
Patrick Venture01123b22019-06-20 13:49:06 -070056 {
William A. Kennington IIIcf376632021-10-13 21:40:11 -070057 std::fprintf(stderr, "success\n");
58 return std::move(*ret);
Patrick Venture01123b22019-06-20 13:49:06 -070059 }
60
William A. Kennington IIIcf376632021-10-13 21:40:11 -070061 auto cur = std::chrono::steady_clock::now();
62 if (cur - last_print >= printInterval)
Patrick Venture01123b22019-06-20 13:49:06 -070063 {
William A. Kennington IIIcf376632021-10-13 21:40:11 -070064 std::fprintf(stderr, "running\n");
65 last_print = cur;
Patrick Venture01123b22019-06-20 13:49:06 -070066 }
67
William A. Kennington IIIcf376632021-10-13 21:40:11 -070068 auto sleep = check_interval - (cur - last_check);
69 last_check = cur;
70 // Check that we don't timeout immediately after sleeping
71 // to avoid an extra sleep without checking
72 if (cur - start > timeout - sleep)
Patrick Venture01123b22019-06-20 13:49:06 -070073 {
William A. Kennington IIIcf376632021-10-13 21:40:11 -070074 throw ToolException("Stat check timed out");
Patrick Venture01123b22019-06-20 13:49:06 -070075 }
William A. Kennington IIIcf376632021-10-13 21:40:11 -070076 check_interval = std::min<decltype(check_interval)>(
77 check_interval * 2, maxSleep);
78 std::this_thread::sleep_for(sleep);
Patrick Venture01123b22019-06-20 13:49:06 -070079 }
80 }
81 catch (const ipmiblob::BlobException& b)
82 {
83 throw ToolException("blob exception received: " +
84 std::string(b.what()));
85 }
William A. Kennington IIIcf376632021-10-13 21:40:11 -070086}
Patrick Venture01123b22019-06-20 13:49:06 -070087
William A. Kennington IIIcf376632021-10-13 21:40:11 -070088/* Poll an open verification session. Handling closing the session is not yet
89 * owned by this method.
90 */
91void pollStatus(std::uint16_t session, ipmiblob::BlobInterface* blob)
92{
93 pollStat(session, blob,
94 [](const ipmiblob::StatResponse& resp) -> std::optional<bool> {
95 if (resp.metadata.size() != 1)
96 {
97 throw ToolException("Invalid stat metadata");
98 }
99 auto result =
100 static_cast<ipmi_flash::ActionStatus>(resp.metadata[0]);
101 switch (result)
102 {
103 case ipmi_flash::ActionStatus::failed:
104 throw ToolException("BMC reported failure");
105 case ipmi_flash::ActionStatus::unknown:
106 case ipmi_flash::ActionStatus::running:
107 return std::nullopt;
108 case ipmi_flash::ActionStatus::success:
109 return true;
110 default:
111 throw ToolException("Unrecognized action status");
112 }
113 });
Patrick Venture01123b22019-06-20 13:49:06 -0700114}
115
Jie Yang328f5202021-03-16 00:52:07 -0700116/* Poll an open blob session for reading.
117 *
118 * The committing bit indicates that the blob is not available for reading now
119 * and the reader might come back and check the state later.
120 *
121 * Polling finishes under the following conditions:
122 * - The open_read bit set -> stat successful
123 * - The open_read and committing bits unset -> stat failed;
124 * - Blob exception was received;
125 * - Time ran out.
126 * Polling continues when the open_read bit unset and committing bit set.
127 * If the blob is not open_read and not committing, then it is an error to the
128 * reader.
129 */
William A. Kennington IIIf88bcf32021-10-14 02:15:10 -0700130uint32_t pollReadReady(std::uint16_t session, ipmiblob::BlobInterface* blob)
Jie Yang328f5202021-03-16 00:52:07 -0700131{
William A. Kennington IIIcf376632021-10-13 21:40:11 -0700132 return pollStat(
133 session, blob,
134 [](const ipmiblob::StatResponse& resp) -> std::optional<uint32_t> {
135 if (resp.blob_state & ipmiblob::StateFlags::open_read)
Jie Yang328f5202021-03-16 00:52:07 -0700136 {
William A. Kennington IIIcf376632021-10-13 21:40:11 -0700137 return resp.size;
Jie Yang328f5202021-03-16 00:52:07 -0700138 }
William A. Kennington IIIcf376632021-10-13 21:40:11 -0700139 if (resp.blob_state & ipmiblob::StateFlags::committing)
Jie Yang328f5202021-03-16 00:52:07 -0700140 {
William A. Kennington IIIcf376632021-10-13 21:40:11 -0700141 return std::nullopt;
Jie Yang328f5202021-03-16 00:52:07 -0700142 }
William A. Kennington IIIcf376632021-10-13 21:40:11 -0700143 throw ToolException("BMC blob failed to become ready");
144 });
Jie Yang328f5202021-03-16 00:52:07 -0700145}
146
Vivekanand Veeracholanc7fa2c22021-02-18 18:05:41 -0800147void* memcpyAligned(void* destination, const void* source, std::size_t size)
148{
149 std::size_t i = 0;
150 std::size_t bytesCopied = 0;
151
Willy Tufd16f6d2021-09-16 21:31:58 -0700152 if (!(reinterpret_cast<std::uintptr_t>(destination) %
153 sizeof(std::uint64_t)) &&
154 !(reinterpret_cast<std::uintptr_t>(source) % sizeof(std::uint64_t)))
Vivekanand Veeracholanc7fa2c22021-02-18 18:05:41 -0800155 {
156 auto src64 = reinterpret_cast<const volatile std::uint64_t*>(source);
157 auto dest64 = reinterpret_cast<volatile std::uint64_t*>(destination);
158
159 for (i = 0; i < size / sizeof(std::uint64_t); i++)
160 {
161 *dest64++ = *src64++;
162 bytesCopied += sizeof(std::uint64_t);
163 }
164 }
165
166 auto srcMem8 =
167 reinterpret_cast<const volatile std::uint8_t*>(source) + bytesCopied;
168 auto destMem8 =
169 reinterpret_cast<volatile std::uint8_t*>(destination) + bytesCopied;
170
171 for (i = bytesCopied; i < size; i++)
172 {
173 *destMem8++ = *srcMem8++;
174 }
175
176 return destination;
177}
178
Patrick Venture01123b22019-06-20 13:49:06 -0700179} // namespace host_tool